Skip to content

Commit e742e7d

Browse files
spkrkagitster
authored andcommitted
commit-reach: optimize queue scan in paint_down_to_common
paint_down_to_common() terminates when every commit remaining in its priority queue is STALE. This was checked by queue_has_nonstale(), which performed an O(n) linear scan of the entire queue on every iteration, resulting in O(n*m) total overhead where n is the queue size and m is the number of commits processed. Replace this with an O(1) nonstale_count that tracks the number of non-stale commits currently in the queue. The counter is incremented by maybe_enqueue() and decremented on dequeue and by mark_stale() when a commit transitions to STALE while still in the queue. Since each commit appears at most once (guaranteed by the ENQUEUED flag from the previous commit), the counter is exact. ahead_behind() also uses queue_has_nonstale() and will be converted in the next commit. Signed-off-by: Kristofer Karlsson <krka@spotify.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 1d0d67d commit e742e7d

1 file changed

Lines changed: 23 additions & 5 deletions

File tree

commit-reach.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,25 @@ static int compare_commits_by_gen(const void *_a, const void *_b)
4040
return 0;
4141
}
4242

43-
static void maybe_enqueue(struct prio_queue *queue, struct commit *c)
43+
static void maybe_enqueue(struct prio_queue *queue, struct commit *c,
44+
int *nonstale_count)
4445
{
4546
if (c->object.flags & ENQUEUED)
4647
return;
4748
c->object.flags |= ENQUEUED;
4849
prio_queue_put(queue, c);
50+
if (!(c->object.flags & STALE))
51+
(*nonstale_count)++;
52+
}
53+
54+
static void mark_stale(struct commit *c, unsigned queued_flag,
55+
int *nonstale_count)
56+
{
57+
if (!(c->object.flags & STALE)) {
58+
if (c->object.flags & queued_flag)
59+
(*nonstale_count)--;
60+
c->object.flags |= STALE;
61+
}
4962
}
5063

5164
static int queue_has_nonstale(struct prio_queue *queue)
@@ -68,6 +81,7 @@ static int paint_down_to_common(struct repository *r,
6881
{
6982
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
7083
int i;
84+
int nonstale_count = 0;
7185
timestamp_t last_gen = GENERATION_NUMBER_INFINITY;
7286
struct commit_list **tail = result;
7387

@@ -79,20 +93,22 @@ static int paint_down_to_common(struct repository *r,
7993
commit_list_append(one, result);
8094
return 0;
8195
}
82-
maybe_enqueue(&queue, one);
96+
maybe_enqueue(&queue, one, &nonstale_count);
8397

8498
for (i = 0; i < n; i++) {
8599
twos[i]->object.flags |= PARENT2;
86-
maybe_enqueue(&queue, twos[i]);
100+
maybe_enqueue(&queue, twos[i], &nonstale_count);
87101
}
88102

89-
while (queue_has_nonstale(&queue)) {
103+
while (nonstale_count > 0) {
90104
struct commit *commit = prio_queue_get(&queue);
91105
struct commit_list *parents;
92106
int flags;
93107
timestamp_t generation = commit_graph_generation(commit);
94108

95109
commit->object.flags &= ~ENQUEUED;
110+
if (!(commit->object.flags & STALE))
111+
nonstale_count--;
96112

97113
if (min_generation && generation > last_gen)
98114
BUG("bad generation skip %"PRItime" > %"PRItime" at %s",
@@ -134,8 +150,10 @@ static int paint_down_to_common(struct repository *r,
134150
return error(_("could not parse commit %s"),
135151
oid_to_hex(&p->object.oid));
136152
}
153+
if (flags & STALE)
154+
mark_stale(p, ENQUEUED, &nonstale_count);
137155
p->object.flags |= flags;
138-
maybe_enqueue(&queue, p);
156+
maybe_enqueue(&queue, p, &nonstale_count);
139157
}
140158
}
141159

0 commit comments

Comments
 (0)