Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2
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"
11
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)
17
18 static int marked;
19
20 struct negotiation_state {
21 struct prio_queue rev_list;
22 int non_common_revs;
23 };
24
25 static void rev_list_push(struct negotiation_state *ns,
26 struct commit *commit, int mark)
27 {
28 if (!(commit->object.flags & mark)) {
29 commit->object.flags |= mark;
30
31 if (repo_parse_commit(the_repository, commit))
32 return;
33
34 prio_queue_put(&ns->rev_list, commit);
35
36 if (!(commit->object.flags & COMMON))
37 ns->non_common_revs++;
38 }
39 }
40
41 static int clear_marks(const struct reference *ref, void *cb_data UNUSED)
42 {
43 struct object *o = deref_tag(the_repository, parse_object(the_repository, ref->oid),
44 ref->name, 0);
45
46 if (o && o->type == OBJ_COMMIT)
47 clear_commit_marks((struct commit *)o,
48 COMMON | COMMON_REF | SEEN | POPPED);
49 return 0;
50 }
51
52 /*
53 * This function marks a rev and its ancestors as common.
54 * In some cases, it is desirable to mark only the ancestors (for example
55 * when only the server does not yet know that they are common).
56 */
57 static void mark_common(struct negotiation_state *ns, struct commit *commit,
58 int ancestors_only, int dont_parse)
59 {
60 struct commit_stack stack = COMMIT_STACK_INIT;
61
62 if (!commit || (commit->object.flags & COMMON))
63 return;
64
65 commit_stack_push(&stack, commit);
66 if (!ancestors_only) {
67 commit->object.flags |= COMMON;
68
69 if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
70 ns->non_common_revs--;
71 }
72 while ((commit = commit_stack_pop(&stack))) {
73 struct object *o = (struct object *)commit;
74
75 if (!(o->flags & SEEN))
76 rev_list_push(ns, commit, SEEN);
77 else {
78 struct commit_list *parents;
79
80 if (!o->parsed && !dont_parse)
81 if (repo_parse_commit(the_repository, commit))
82 continue;
83
84 for (parents = commit->parents;
85 parents;
86 parents = parents->next) {
87 struct commit *p = parents->item;
88
89 if (p->object.flags & COMMON)
90 continue;
91
92 p->object.flags |= COMMON;
93
94 if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
95 ns->non_common_revs--;
96
97 commit_stack_push(&stack, parents->item);
98 }
99 }
100 }
101
102 commit_stack_clear(&stack);
103 }
104
105 /*
106 * Get the next rev to send, ignoring the common.
107 */
108 static const struct object_id *get_rev(struct negotiation_state *ns)
109 {
110 struct commit *commit = NULL;
111
112 while (commit == NULL) {
113 unsigned int mark;
114 struct commit_list *parents;
115
116 if (ns->non_common_revs == 0)
117 return NULL;
118
119 commit = prio_queue_get(&ns->rev_list);
120 if (!commit)
121 return NULL;
122 repo_parse_commit(the_repository, commit);
123 parents = commit->parents;
124
125 commit->object.flags |= POPPED;
126 if (!(commit->object.flags & COMMON))
127 ns->non_common_revs--;
128
129 if (commit->object.flags & COMMON) {
130 /* do not send "have", and ignore ancestors */
131 commit = NULL;
132 mark = COMMON | SEEN;
133 } else if (commit->object.flags & COMMON_REF)
134 /* send "have", and ignore ancestors */
135 mark = COMMON | SEEN;
136 else
137 /* send "have", also for its ancestors */
138 mark = SEEN;
139
140 while (parents) {
141 if (!(parents->item->object.flags & SEEN))
142 rev_list_push(ns, parents->item, mark);
143 if (mark & COMMON)
144 mark_common(ns, parents->item, 1, 0);
145 parents = parents->next;
146 }
147 }
148
149 return &commit->object.oid;
150 }
151
152 static void known_common(struct fetch_negotiator *n, struct commit *c)
153 {
154 if (!(c->object.flags & SEEN)) {
155 rev_list_push(n->data, c, COMMON_REF | SEEN);
156 mark_common(n->data, c, 1, 1);
157 }
158 }
159
160 static void add_tip(struct fetch_negotiator *n, struct commit *c)
161 {
162 n->known_common = NULL;
163 rev_list_push(n->data, c, SEEN);
164 }
165
166 static const struct object_id *next(struct fetch_negotiator *n)
167 {
168 n->known_common = NULL;
169 n->add_tip = NULL;
170 return get_rev(n->data);
171 }
172
173 static int ack(struct fetch_negotiator *n, struct commit *c)
174 {
175 int known_to_be_common = !!(c->object.flags & COMMON);
176 mark_common(n->data, c, 0, 1);
177 return known_to_be_common;
178 }
179
180 static void have_sent(struct fetch_negotiator *n, struct commit *c)
181 {
182 if (repo_parse_commit(the_repository, c))
183 return;
184 mark_common(n->data, c, 0, 0);
185 }
186
187 static void release(struct fetch_negotiator *n)
188 {
189 clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
190 FREE_AND_NULL(n->data);
191 }
192
193 void default_negotiator_init(struct fetch_negotiator *negotiator)
194 {
195 struct negotiation_state *ns;
196 negotiator->known_common = known_common;
197 negotiator->add_tip = add_tip;
198 negotiator->next = next;
199 negotiator->ack = ack;
200 negotiator->have_sent = have_sent;
201 negotiator->release = release;
202 negotiator->data = CALLOC_ARRAY(ns, 1);
203 ns->rev_list.compare = compare_commits_by_commit_date;
204
205 if (marked)
206 refs_for_each_ref(get_main_ref_store(the_repository),
207 clear_marks, NULL);
208 marked = 1;
209 }