Git 2.47-rc0
[git.git] / negotiator / default.c
blobc479da9b09157077c0a8a4548c95fef35c95c0d4
1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
4 #include "default.h"
5 #include "../commit.h"
6 #include "../fetch-negotiator.h"
7 #include "../prio-queue.h"
8 #include "../refs.h"
9 #include "../repository.h"
10 #include "../tag.h"
12 /* Remember to update object flag allocation in object.h */
13 #define COMMON (1U << 2)
14 #define COMMON_REF (1U << 3)
15 #define SEEN (1U << 4)
16 #define POPPED (1U << 5)
18 static int marked;
20 struct negotiation_state {
21 struct prio_queue rev_list;
22 int non_common_revs;
25 static void rev_list_push(struct negotiation_state *ns,
26 struct commit *commit, int mark)
28 if (!(commit->object.flags & mark)) {
29 commit->object.flags |= mark;
31 if (repo_parse_commit(the_repository, commit))
32 return;
34 prio_queue_put(&ns->rev_list, commit);
36 if (!(commit->object.flags & COMMON))
37 ns->non_common_revs++;
41 static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
42 int flag UNUSED,
43 void *cb_data UNUSED)
45 struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
47 if (o && o->type == OBJ_COMMIT)
48 clear_commit_marks((struct commit *)o,
49 COMMON | COMMON_REF | SEEN | POPPED);
50 return 0;
54 * This function marks a rev and its ancestors as common.
55 * In some cases, it is desirable to mark only the ancestors (for example
56 * when only the server does not yet know that they are common).
58 static void mark_common(struct negotiation_state *ns, struct commit *commit,
59 int ancestors_only, int dont_parse)
61 struct prio_queue queue = { NULL };
63 if (!commit || (commit->object.flags & COMMON))
64 return;
66 prio_queue_put(&queue, commit);
67 if (!ancestors_only) {
68 commit->object.flags |= COMMON;
70 if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
71 ns->non_common_revs--;
73 while ((commit = prio_queue_get(&queue))) {
74 struct object *o = (struct object *)commit;
76 if (!(o->flags & SEEN))
77 rev_list_push(ns, commit, SEEN);
78 else {
79 struct commit_list *parents;
81 if (!o->parsed && !dont_parse)
82 if (repo_parse_commit(the_repository, commit))
83 continue;
85 for (parents = commit->parents;
86 parents;
87 parents = parents->next) {
88 struct commit *p = parents->item;
90 if (p->object.flags & COMMON)
91 continue;
93 p->object.flags |= COMMON;
95 if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
96 ns->non_common_revs--;
98 prio_queue_put(&queue, parents->item);
103 clear_prio_queue(&queue);
107 * Get the next rev to send, ignoring the common.
109 static const struct object_id *get_rev(struct negotiation_state *ns)
111 struct commit *commit = NULL;
113 while (commit == NULL) {
114 unsigned int mark;
115 struct commit_list *parents;
117 if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
118 return NULL;
120 commit = prio_queue_get(&ns->rev_list);
121 repo_parse_commit(the_repository, commit);
122 parents = commit->parents;
124 commit->object.flags |= POPPED;
125 if (!(commit->object.flags & COMMON))
126 ns->non_common_revs--;
128 if (commit->object.flags & COMMON) {
129 /* do not send "have", and ignore ancestors */
130 commit = NULL;
131 mark = COMMON | SEEN;
132 } else if (commit->object.flags & COMMON_REF)
133 /* send "have", and ignore ancestors */
134 mark = COMMON | SEEN;
135 else
136 /* send "have", also for its ancestors */
137 mark = SEEN;
139 while (parents) {
140 if (!(parents->item->object.flags & SEEN))
141 rev_list_push(ns, parents->item, mark);
142 if (mark & COMMON)
143 mark_common(ns, parents->item, 1, 0);
144 parents = parents->next;
148 return &commit->object.oid;
151 static void known_common(struct fetch_negotiator *n, struct commit *c)
153 if (!(c->object.flags & SEEN)) {
154 rev_list_push(n->data, c, COMMON_REF | SEEN);
155 mark_common(n->data, c, 1, 1);
159 static void add_tip(struct fetch_negotiator *n, struct commit *c)
161 n->known_common = NULL;
162 rev_list_push(n->data, c, SEEN);
165 static const struct object_id *next(struct fetch_negotiator *n)
167 n->known_common = NULL;
168 n->add_tip = NULL;
169 return get_rev(n->data);
172 static int ack(struct fetch_negotiator *n, struct commit *c)
174 int known_to_be_common = !!(c->object.flags & COMMON);
175 mark_common(n->data, c, 0, 1);
176 return known_to_be_common;
179 static void release(struct fetch_negotiator *n)
181 clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
182 FREE_AND_NULL(n->data);
185 void default_negotiator_init(struct fetch_negotiator *negotiator)
187 struct negotiation_state *ns;
188 negotiator->known_common = known_common;
189 negotiator->add_tip = add_tip;
190 negotiator->next = next;
191 negotiator->ack = ack;
192 negotiator->release = release;
193 negotiator->data = CALLOC_ARRAY(ns, 1);
194 ns->rev_list.compare = compare_commits_by_commit_date;
196 if (marked)
197 refs_for_each_ref(get_main_ref_store(the_repository),
198 clear_marks, NULL);
199 marked = 1;