]> git.ipfire.org Git - thirdparty/git.git/blame - negotiator/default.c
Merge branch 'jc/bisect-doc' into maint-2.43
[thirdparty/git.git] / negotiator / default.c
CommitLineData
4f6728d5 1#include "git-compat-util.h"
ec062838
JT
2#include "default.h"
3#include "../commit.h"
4#include "../fetch-negotiator.h"
5#include "../prio-queue.h"
6#include "../refs.h"
d1cbe1e6 7#include "../repository.h"
ec062838
JT
8#include "../tag.h"
9
10/* Remember to update object flag allocation in object.h */
11#define COMMON (1U << 2)
12#define COMMON_REF (1U << 3)
13#define SEEN (1U << 4)
14#define POPPED (1U << 5)
15
16static int marked;
17
18struct negotiation_state {
19 struct prio_queue rev_list;
20 int non_common_revs;
21};
22
23static void rev_list_push(struct negotiation_state *ns,
24 struct commit *commit, int mark)
25{
26 if (!(commit->object.flags & mark)) {
27 commit->object.flags |= mark;
28
ecb5091f 29 if (repo_parse_commit(the_repository, commit))
ec062838
JT
30 return;
31
32 prio_queue_put(&ns->rev_list, commit);
33
34 if (!(commit->object.flags & COMMON))
35 ns->non_common_revs++;
36 }
37}
38
39static int clear_marks(const char *refname, const struct object_id *oid,
5cf88fd8
ÆAB
40 int flag UNUSED,
41 void *cb_data UNUSED)
ec062838 42{
3a2a1dc1 43 struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
ec062838
JT
44
45 if (o && o->type == OBJ_COMMIT)
46 clear_commit_marks((struct commit *)o,
47 COMMON | COMMON_REF | SEEN | POPPED);
48 return 0;
49}
50
51/*
52 * This function marks a rev and its ancestors as common.
53 * In some cases, it is desirable to mark only the ancestors (for example
54 * when only the server does not yet know that they are common).
55 */
56static void mark_common(struct negotiation_state *ns, struct commit *commit,
57 int ancestors_only, int dont_parse)
58{
8e21ff5e
HX
59 struct prio_queue queue = { NULL };
60
61 if (!commit || (commit->object.flags & COMMON))
62 return;
63
64 prio_queue_put(&queue, commit);
65 if (!ancestors_only) {
66 commit->object.flags |= COMMON;
ec062838 67
8e21ff5e
HX
68 if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
69 ns->non_common_revs--;
70 }
71 while ((commit = prio_queue_get(&queue))) {
72 struct object *o = (struct object *)commit;
ec062838
JT
73
74 if (!(o->flags & SEEN))
75 rev_list_push(ns, commit, SEEN);
76 else {
77 struct commit_list *parents;
78
ec062838 79 if (!o->parsed && !dont_parse)
ecb5091f 80 if (repo_parse_commit(the_repository, commit))
8e21ff5e 81 continue;
ec062838
JT
82
83 for (parents = commit->parents;
84 parents;
8e21ff5e
HX
85 parents = parents->next) {
86 struct commit *p = parents->item;
87
88 if (p->object.flags & COMMON)
89 continue;
90
91 p->object.flags |= COMMON;
92
93 if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
94 ns->non_common_revs--;
95
96 prio_queue_put(&queue, parents->item);
97 }
ec062838
JT
98 }
99 }
8e21ff5e
HX
100
101 clear_prio_queue(&queue);
ec062838
JT
102}
103
104/*
105 * Get the next rev to send, ignoring the common.
106 */
107static const struct object_id *get_rev(struct negotiation_state *ns)
108{
109 struct commit *commit = NULL;
110
111 while (commit == NULL) {
112 unsigned int mark;
113 struct commit_list *parents;
114
115 if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
116 return NULL;
117
118 commit = prio_queue_get(&ns->rev_list);
ecb5091f 119 repo_parse_commit(the_repository, commit);
ec062838
JT
120 parents = commit->parents;
121
122 commit->object.flags |= POPPED;
123 if (!(commit->object.flags & COMMON))
124 ns->non_common_revs--;
125
126 if (commit->object.flags & COMMON) {
127 /* do not send "have", and ignore ancestors */
128 commit = NULL;
129 mark = COMMON | SEEN;
130 } else if (commit->object.flags & COMMON_REF)
131 /* send "have", and ignore ancestors */
132 mark = COMMON | SEEN;
133 else
134 /* send "have", also for its ancestors */
135 mark = SEEN;
136
137 while (parents) {
138 if (!(parents->item->object.flags & SEEN))
139 rev_list_push(ns, parents->item, mark);
140 if (mark & COMMON)
141 mark_common(ns, parents->item, 1, 0);
142 parents = parents->next;
143 }
144 }
145
146 return &commit->object.oid;
147}
148
149static void known_common(struct fetch_negotiator *n, struct commit *c)
150{
151 if (!(c->object.flags & SEEN)) {
152 rev_list_push(n->data, c, COMMON_REF | SEEN);
153 mark_common(n->data, c, 1, 1);
154 }
155}
156
157static void add_tip(struct fetch_negotiator *n, struct commit *c)
158{
159 n->known_common = NULL;
160 rev_list_push(n->data, c, SEEN);
161}
162
163static const struct object_id *next(struct fetch_negotiator *n)
164{
165 n->known_common = NULL;
166 n->add_tip = NULL;
167 return get_rev(n->data);
168}
169
170static int ack(struct fetch_negotiator *n, struct commit *c)
171{
172 int known_to_be_common = !!(c->object.flags & COMMON);
173 mark_common(n->data, c, 0, 1);
174 return known_to_be_common;
175}
176
177static void release(struct fetch_negotiator *n)
178{
179 clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
180 FREE_AND_NULL(n->data);
181}
182
183void default_negotiator_init(struct fetch_negotiator *negotiator)
184{
185 struct negotiation_state *ns;
186 negotiator->known_common = known_common;
187 negotiator->add_tip = add_tip;
188 negotiator->next = next;
189 negotiator->ack = ack;
190 negotiator->release = release;
ca56dadb 191 negotiator->data = CALLOC_ARRAY(ns, 1);
ec062838
JT
192 ns->rev_list.compare = compare_commits_by_commit_date;
193
194 if (marked)
195 for_each_ref(clear_marks, NULL);
196 marked = 1;
197}