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