]> git.ipfire.org Git - thirdparty/git.git/blame - bisect.c
bisect: use the new generic "sha1_pos" function to lookup sha1
[thirdparty/git.git] / bisect.c
CommitLineData
a2ad79ce
CC
1#include "cache.h"
2#include "commit.h"
3#include "diff.h"
4#include "revision.h"
4eb5b646 5#include "sha1-lookup.h"
a2ad79ce
CC
6#include "bisect.h"
7
95188648
CC
8static unsigned char (*skipped_sha1)[20];
9static int skipped_sha1_nr;
10
a2ad79ce
CC
11/* bits #0-15 in revision.h */
12
13#define COUNTED (1u<<16)
14
15/*
16 * This is a truly stupid algorithm, but it's only
17 * used for bisection, and we just don't care enough.
18 *
19 * We care just barely enough to avoid recursing for
20 * non-merge entries.
21 */
22static int count_distance(struct commit_list *entry)
23{
24 int nr = 0;
25
26 while (entry) {
27 struct commit *commit = entry->item;
28 struct commit_list *p;
29
30 if (commit->object.flags & (UNINTERESTING | COUNTED))
31 break;
32 if (!(commit->object.flags & TREESAME))
33 nr++;
34 commit->object.flags |= COUNTED;
35 p = commit->parents;
36 entry = p;
37 if (p) {
38 p = p->next;
39 while (p) {
40 nr += count_distance(p);
41 p = p->next;
42 }
43 }
44 }
45
46 return nr;
47}
48
49static void clear_distance(struct commit_list *list)
50{
51 while (list) {
52 struct commit *commit = list->item;
53 commit->object.flags &= ~COUNTED;
54 list = list->next;
55 }
56}
57
58#define DEBUG_BISECT 0
59
60static inline int weight(struct commit_list *elem)
61{
62 return *((int*)(elem->item->util));
63}
64
65static inline void weight_set(struct commit_list *elem, int weight)
66{
67 *((int*)(elem->item->util)) = weight;
68}
69
70static int count_interesting_parents(struct commit *commit)
71{
72 struct commit_list *p;
73 int count;
74
75 for (count = 0, p = commit->parents; p; p = p->next) {
76 if (p->item->object.flags & UNINTERESTING)
77 continue;
78 count++;
79 }
80 return count;
81}
82
83static inline int halfway(struct commit_list *p, int nr)
84{
85 /*
86 * Don't short-cut something we are not going to return!
87 */
88 if (p->item->object.flags & TREESAME)
89 return 0;
90 if (DEBUG_BISECT)
91 return 0;
92 /*
93 * 2 and 3 are halfway of 5.
94 * 3 is halfway of 6 but 2 and 4 are not.
95 */
96 switch (2 * weight(p) - nr) {
97 case -1: case 0: case 1:
98 return 1;
99 default:
100 return 0;
101 }
102}
103
104#if !DEBUG_BISECT
105#define show_list(a,b,c,d) do { ; } while (0)
106#else
107static void show_list(const char *debug, int counted, int nr,
108 struct commit_list *list)
109{
110 struct commit_list *p;
111
112 fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr);
113
114 for (p = list; p; p = p->next) {
115 struct commit_list *pp;
116 struct commit *commit = p->item;
117 unsigned flags = commit->object.flags;
118 enum object_type type;
119 unsigned long size;
120 char *buf = read_sha1_file(commit->object.sha1, &type, &size);
121 char *ep, *sp;
122
123 fprintf(stderr, "%c%c%c ",
124 (flags & TREESAME) ? ' ' : 'T',
125 (flags & UNINTERESTING) ? 'U' : ' ',
126 (flags & COUNTED) ? 'C' : ' ');
127 if (commit->util)
128 fprintf(stderr, "%3d", weight(p));
129 else
130 fprintf(stderr, "---");
131 fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1));
132 for (pp = commit->parents; pp; pp = pp->next)
133 fprintf(stderr, " %.*s", 8,
134 sha1_to_hex(pp->item->object.sha1));
135
136 sp = strstr(buf, "\n\n");
137 if (sp) {
138 sp += 2;
139 for (ep = sp; *ep && *ep != '\n'; ep++)
140 ;
141 fprintf(stderr, " %.*s", (int)(ep - sp), sp);
142 }
143 fprintf(stderr, "\n");
144 }
145}
146#endif /* DEBUG_BISECT */
147
148static struct commit_list *best_bisection(struct commit_list *list, int nr)
149{
150 struct commit_list *p, *best;
151 int best_distance = -1;
152
153 best = list;
154 for (p = list; p; p = p->next) {
155 int distance;
156 unsigned flags = p->item->object.flags;
157
158 if (flags & TREESAME)
159 continue;
160 distance = weight(p);
161 if (nr - distance < distance)
162 distance = nr - distance;
163 if (distance > best_distance) {
164 best = p;
165 best_distance = distance;
166 }
167 }
168
169 return best;
170}
171
172struct commit_dist {
173 struct commit *commit;
174 int distance;
175};
176
177static int compare_commit_dist(const void *a_, const void *b_)
178{
179 struct commit_dist *a, *b;
180
181 a = (struct commit_dist *)a_;
182 b = (struct commit_dist *)b_;
183 if (a->distance != b->distance)
184 return b->distance - a->distance; /* desc sort */
185 return hashcmp(a->commit->object.sha1, b->commit->object.sha1);
186}
187
188static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr)
189{
190 struct commit_list *p;
191 struct commit_dist *array = xcalloc(nr, sizeof(*array));
192 int cnt, i;
193
194 for (p = list, cnt = 0; p; p = p->next) {
195 int distance;
196 unsigned flags = p->item->object.flags;
197
198 if (flags & TREESAME)
199 continue;
200 distance = weight(p);
201 if (nr - distance < distance)
202 distance = nr - distance;
203 array[cnt].commit = p->item;
204 array[cnt].distance = distance;
205 cnt++;
206 }
207 qsort(array, cnt, sizeof(*array), compare_commit_dist);
208 for (p = list, i = 0; i < cnt; i++) {
209 struct name_decoration *r = xmalloc(sizeof(*r) + 100);
210 struct object *obj = &(array[i].commit->object);
211
212 sprintf(r->name, "dist=%d", array[i].distance);
213 r->next = add_decoration(&name_decoration, obj, r);
214 p->item = array[i].commit;
215 p = p->next;
216 }
217 if (p)
218 p->next = NULL;
219 free(array);
220 return list;
221}
222
223/*
224 * zero or positive weight is the number of interesting commits it can
225 * reach, including itself. Especially, weight = 0 means it does not
226 * reach any tree-changing commits (e.g. just above uninteresting one
227 * but traversal is with pathspec).
228 *
229 * weight = -1 means it has one parent and its distance is yet to
230 * be computed.
231 *
232 * weight = -2 means it has more than one parent and its distance is
233 * unknown. After running count_distance() first, they will get zero
234 * or positive distance.
235 */
236static struct commit_list *do_find_bisection(struct commit_list *list,
237 int nr, int *weights,
238 int find_all)
239{
240 int n, counted;
241 struct commit_list *p;
242
243 counted = 0;
244
245 for (n = 0, p = list; p; p = p->next) {
246 struct commit *commit = p->item;
247 unsigned flags = commit->object.flags;
248
249 p->item->util = &weights[n++];
250 switch (count_interesting_parents(commit)) {
251 case 0:
252 if (!(flags & TREESAME)) {
253 weight_set(p, 1);
254 counted++;
255 show_list("bisection 2 count one",
256 counted, nr, list);
257 }
258 /*
259 * otherwise, it is known not to reach any
260 * tree-changing commit and gets weight 0.
261 */
262 break;
263 case 1:
264 weight_set(p, -1);
265 break;
266 default:
267 weight_set(p, -2);
268 break;
269 }
270 }
271
272 show_list("bisection 2 initialize", counted, nr, list);
273
274 /*
275 * If you have only one parent in the resulting set
276 * then you can reach one commit more than that parent
277 * can reach. So we do not have to run the expensive
278 * count_distance() for single strand of pearls.
279 *
280 * However, if you have more than one parents, you cannot
281 * just add their distance and one for yourself, since
282 * they usually reach the same ancestor and you would
283 * end up counting them twice that way.
284 *
285 * So we will first count distance of merges the usual
286 * way, and then fill the blanks using cheaper algorithm.
287 */
288 for (p = list; p; p = p->next) {
289 if (p->item->object.flags & UNINTERESTING)
290 continue;
291 if (weight(p) != -2)
292 continue;
293 weight_set(p, count_distance(p));
294 clear_distance(list);
295
296 /* Does it happen to be at exactly half-way? */
297 if (!find_all && halfway(p, nr))
298 return p;
299 counted++;
300 }
301
302 show_list("bisection 2 count_distance", counted, nr, list);
303
304 while (counted < nr) {
305 for (p = list; p; p = p->next) {
306 struct commit_list *q;
307 unsigned flags = p->item->object.flags;
308
309 if (0 <= weight(p))
310 continue;
311 for (q = p->item->parents; q; q = q->next) {
312 if (q->item->object.flags & UNINTERESTING)
313 continue;
314 if (0 <= weight(q))
315 break;
316 }
317 if (!q)
318 continue;
319
320 /*
321 * weight for p is unknown but q is known.
322 * add one for p itself if p is to be counted,
323 * otherwise inherit it from q directly.
324 */
325 if (!(flags & TREESAME)) {
326 weight_set(p, weight(q)+1);
327 counted++;
328 show_list("bisection 2 count one",
329 counted, nr, list);
330 }
331 else
332 weight_set(p, weight(q));
333
334 /* Does it happen to be at exactly half-way? */
335 if (!find_all && halfway(p, nr))
336 return p;
337 }
338 }
339
340 show_list("bisection 2 counted all", counted, nr, list);
341
342 if (!find_all)
343 return best_bisection(list, nr);
344 else
345 return best_bisection_sorted(list, nr);
346}
347
348struct commit_list *find_bisection(struct commit_list *list,
349 int *reaches, int *all,
350 int find_all)
351{
352 int nr, on_list;
353 struct commit_list *p, *best, *next, *last;
354 int *weights;
355
356 show_list("bisection 2 entry", 0, 0, list);
357
358 /*
359 * Count the number of total and tree-changing items on the
360 * list, while reversing the list.
361 */
362 for (nr = on_list = 0, last = NULL, p = list;
363 p;
364 p = next) {
365 unsigned flags = p->item->object.flags;
366
367 next = p->next;
368 if (flags & UNINTERESTING)
369 continue;
370 p->next = last;
371 last = p;
372 if (!(flags & TREESAME))
373 nr++;
374 on_list++;
375 }
376 list = last;
377 show_list("bisection 2 sorted", 0, nr, list);
378
379 *all = nr;
380 weights = xcalloc(on_list, sizeof(*weights));
381
382 /* Do the real work of finding bisection commit. */
383 best = do_find_bisection(list, nr, weights, find_all);
384 if (best) {
385 if (!find_all)
386 best->next = NULL;
387 *reaches = weight(best);
388 }
389 free(weights);
390 return best;
391}
392
95188648
CC
393static int skipcmp(const void *a, const void *b)
394{
395 return hashcmp(a, b);
396}
397
398static void prepare_skipped(void)
399{
400 qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp);
401}
402
4eb5b646
CC
403static const unsigned char *skipped_sha1_access(size_t index, void *table)
404{
405 unsigned char (*skipped)[20] = table;
406 return skipped[index];
407}
408
95188648
CC
409static int lookup_skipped(unsigned char *sha1)
410{
4eb5b646
CC
411 return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr,
412 skipped_sha1_access);
95188648
CC
413}
414
415struct commit_list *filter_skipped(struct commit_list *list,
416 struct commit_list **tried,
417 int show_all)
418{
419 struct commit_list *filtered = NULL, **f = &filtered;
420
421 *tried = NULL;
422
423 if (!skipped_sha1_nr)
424 return list;
425
426 prepare_skipped();
427
428 while (list) {
429 struct commit_list *next = list->next;
430 list->next = NULL;
431 if (0 <= lookup_skipped(list->item->object.sha1)) {
432 /* Move current to tried list */
433 *tried = list;
434 tried = &list->next;
435 } else {
436 if (!show_all)
437 return list;
438 /* Move current to filtered list */
439 *f = list;
440 f = &list->next;
441 }
442 list = next;
443 }
444
445 return filtered;
446}