47120c1cd87c1df97d28c7d687bedbc69338806a
   1#include "cache.h"
   2#include "commit.h"
   3#include "diff.h"
   4#include "revision.h"
   5#include "sha1-lookup.h"
   6#include "bisect.h"
   7
   8static unsigned char (*skipped_sha1)[20];
   9static int skipped_sha1_nr;
  10
  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
 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
 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
 409static int lookup_skipped(unsigned char *sha1)
 410{
 411        return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr,
 412                        skipped_sha1_access);
 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}