commit-reach: move can_all_from_reach_with_flags

There are several commit walks in the codebase. Group them together into a new commit-reach.c file and corresponding header. After we group these walks into one place, we can reduce duplicate logic by calling equivalent methods. The can_all_from_reach_with_flags method is used in a stateful way by upload-pack.c. The parameters are very flexible, so we will be able to use its commit walking logic for many other callers. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Jul 20, 2018 at 16:33 UTC ba3ca1edce70d9d2d0eea1ac69377ae786e9413a
4 files changed +80 -71
commit-reach.c
+63
@@ -10,6 +10,7 @@
10 #include "commit-reach.h"
11
12 /* Remember to update object flag allocation in object.h */
13 +#define REACHABLE (1u<<15)
14 #define PARENT1 (1u<<16)
15 #define PARENT2 (1u<<17)
16 #define STALE (1u<<18)
@@ -532,3 +533,65 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
533 return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
534 return is_descendant_of(commit, list);
535 }
536 +
537 +int reachable(struct commit *from, unsigned int with_flag,
538 + unsigned int assign_flag, time_t min_commit_date)
539 +{
540 + struct prio_queue work = { compare_commits_by_commit_date };
541 +
542 + prio_queue_put(&work, from);
543 + while (work.nr) {
544 + struct commit_list *list;
545 + struct commit *commit = prio_queue_get(&work);
546 +
547 + if (commit->object.flags & with_flag) {
548 + from->object.flags |= assign_flag;
549 + break;
550 + }
551 + if (!commit->object.parsed)
552 + parse_object(the_repository, &commit->object.oid);
553 + if (commit->object.flags & REACHABLE)
554 + continue;
555 + commit->object.flags |= REACHABLE;
556 + if (commit->date < min_commit_date)
557 + continue;
558 + for (list = commit->parents; list; list = list->next) {
559 + struct commit *parent = list->item;
560 + if (!(parent->object.flags & REACHABLE))
561 + prio_queue_put(&work, parent);
562 + }
563 + }
564 + from->object.flags |= REACHABLE;
565 + clear_commit_marks(from, REACHABLE);
566 + clear_prio_queue(&work);
567 + return (from->object.flags & assign_flag);
568 +}
569 +
570 +int can_all_from_reach_with_flag(struct object_array *from,
571 + unsigned int with_flag,
572 + unsigned int assign_flag,
573 + time_t min_commit_date)
574 +{
575 + int i;
576 +
577 + for (i = 0; i < from->nr; i++) {
578 + struct object *from_one = from->objects[i].item;
579 +
580 + if (from_one->flags & assign_flag)
581 + continue;
582 + from_one = deref_tag(the_repository, from_one, "a from object", 0);
583 + if (!from_one || from_one->type != OBJ_COMMIT) {
584 + /* no way to tell if this is reachable by
585 + * looking at the ancestry chain alone, so
586 + * leave a note to ourselves not to worry about
587 + * this object anymore.
588 + */
589 + from->objects[i].item->flags |= assign_flag;
590 + continue;
591 + }
592 + if (!reachable((struct commit *)from_one, with_flag, assign_flag,
593 + min_commit_date))
594 + return 0;
595 + }
596 + return 1;
597 +}
commit-reach.h
+14
@@ -59,4 +59,18 @@ define_commit_slab(contains_cache, enum contains_result);
59 int commit_contains(struct ref_filter *filter, struct commit *commit,
60 struct commit_list *list, struct contains_cache *cache);
61
62 +int reachable(struct commit *from, unsigned int with_flag,
63 + unsigned int assign_flag, time_t min_commit_date);
64 +
65 +/*
66 + * Determine if every commit in 'from' can reach at least one commit
67 + * that is marked with 'with_flag'. As we traverse, use 'assign_flag'
68 + * as a marker for commits that are already visited. Do not walk
69 + * commits with date below 'min_commit_date'.
70 + */
71 +int can_all_from_reach_with_flag(struct object_array *from,
72 + unsigned int with_flag,
73 + unsigned int assign_flag,
74 + time_t min_commit_date);
75 +
76 #endif
object.h
+2 -2
@@ -60,12 +60,12 @@ struct object_array {
60 * revision.h: 0---------10 26
61 * fetch-pack.c: 0----5
62 * walker.c: 0-2
63 - * upload-pack.c: 4 11----------------19
63 + * upload-pack.c: 4 11-----14 16-----19
64 * builtin/blame.c: 12-13
65 * bisect.c: 16
66 * bundle.c: 16
67 * http-push.c: 16-----19
68 - * commit-reach.c: 16-----19
68 + * commit-reach.c: 15-------19
69 * sha1-name.c: 20
70 * list-objects-filter.c: 21
71 * builtin/fsck.c: 0--3
upload-pack.c
+1 -69
@@ -24,13 +24,13 @@
24 #include "quote.h"
25 #include "upload-pack.h"
26 #include "serve.h"
27 +#include "commit-reach.h"
28
29 /* Remember to update object flag allocation in object.h */
30 #define THEY_HAVE (1u << 11)
31 #define OUR_REF (1u << 12)
32 #define WANTED (1u << 13)
33 #define COMMON_KNOWN (1u << 14)
33 -#define REACHABLE (1u << 15)
34
35 #define SHALLOW (1u << 16)
36 #define NOT_SHALLOW (1u << 17)
@@ -336,74 +336,6 @@ static int got_oid(const char *hex, struct object_id *oid)
336 return 0;
337 }
338
339 -static int reachable(struct commit *from, unsigned int with_flag,
340 - unsigned int assign_flag, time_t min_commit_date)
341 -{
342 - struct prio_queue work = { compare_commits_by_commit_date };
343 -
344 - prio_queue_put(&work, from);
345 - while (work.nr) {
346 - struct commit_list *list;
347 - struct commit *commit = prio_queue_get(&work);
348 -
349 - if (commit->object.flags & with_flag) {
350 - from->object.flags |= assign_flag;
351 - break;
352 - }
353 - if (!commit->object.parsed)
354 - parse_object(the_repository, &commit->object.oid);
355 - if (commit->object.flags & REACHABLE)
356 - continue;
357 - commit->object.flags |= REACHABLE;
358 - if (commit->date < min_commit_date)
359 - continue;
360 - for (list = commit->parents; list; list = list->next) {
361 - struct commit *parent = list->item;
362 - if (!(parent->object.flags & REACHABLE))
363 - prio_queue_put(&work, parent);
364 - }
365 - }
366 - from->object.flags |= REACHABLE;
367 - clear_commit_marks(from, REACHABLE);
368 - clear_prio_queue(&work);
369 - return (from->object.flags & assign_flag);
370 -}
371 -
372 -/*
373 - * Determine if every commit in 'from' can reach at least one commit
374 - * that is marked with 'with_flag'. As we traverse, use 'assign_flag'
375 - * as a marker for commits that are already visited. Do not walk
376 - * commits with date below 'min_commit_date'.
377 - */
378 -static int can_all_from_reach_with_flag(struct object_array *from,
379 - unsigned int with_flag,
380 - unsigned int assign_flag,
381 - time_t min_commit_date)
382 -{
383 - int i;
384 -
385 - for (i = 0; i < from->nr; i++) {
386 - struct object *from_one = from->objects[i].item;
387 -
388 - if (from_one->flags & assign_flag)
389 - continue;
390 - from_one = deref_tag(the_repository, from_one, "a from object", 0);
391 - if (!from_one || from_one->type != OBJ_COMMIT) {
392 - /* no way to tell if this is reachable by
393 - * looking at the ancestry chain alone, so
394 - * leave a note to ourselves not to worry about
395 - * this object anymore.
396 - */
397 - from->objects[i].item->flags |= assign_flag;
398 - continue;
399 - }
400 - if (!reachable((struct commit *)from_one, with_flag, assign_flag,
401 - min_commit_date))
402 - return 0;
403 - }
404 - return 1;
405 -}
406 -
339 static int ok_to_give_up(void)
340 {
341 if (!have_obj.nr)