Skip to content

Commit e8f91e3

Browse files
peffgitster
authored andcommittedJul 15, 2014
prio-queue: make output stable with respect to insertion
If two items are added to a prio_queue and compare equal, they currently come out in an apparently random order (this order is deterministic for a particular sequence of insertions and removals, but does not necessarily match the insertion order). This makes it unlike using a date-ordered commit_list, which is one of the main types we would like to replace with it (because prio_queue does not suffer from O(n) insertions). We can make the priority queue stable by keeping an insertion counter for each element, and using it to break ties. This does increase the memory usage of the structure (one int per element), but in practice it does not seem to affect runtime. A best-of-five "git rev-list --topo-order" on linux.git showed less than 1% difference (well within the run-to-run noise). In an ideal world, we would offer both stable and unstable priority queues (the latter to try to maximize performance). However, given the lack of a measurable performance difference, it is not worth the extra code. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6d63baa commit e8f91e3

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed
 

‎prio-queue.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33

44
static inline int compare(struct prio_queue *queue, int i, int j)
55
{
6-
int cmp = queue->compare(queue->array[i], queue->array[j],
6+
int cmp = queue->compare(queue->array[i].data, queue->array[j].data,
77
queue->cb_data);
8+
if (!cmp)
9+
cmp = queue->array[i].ctr - queue->array[j].ctr;
810
return cmp;
911
}
1012

1113
static inline void swap(struct prio_queue *queue, int i, int j)
1214
{
13-
void *tmp = queue->array[i];
15+
struct prio_queue_entry tmp = queue->array[i];
1416
queue->array[i] = queue->array[j];
1517
queue->array[j] = tmp;
1618
}
@@ -31,6 +33,7 @@ void clear_prio_queue(struct prio_queue *queue)
3133
queue->nr = 0;
3234
queue->alloc = 0;
3335
queue->array = NULL;
36+
queue->insertion_ctr = 0;
3437
}
3538

3639
void prio_queue_put(struct prio_queue *queue, void *thing)
@@ -39,7 +42,9 @@ void prio_queue_put(struct prio_queue *queue, void *thing)
3942

4043
/* Append at the end */
4144
ALLOC_GROW(queue->array, queue->nr + 1, queue->alloc);
42-
queue->array[queue->nr++] = thing;
45+
queue->array[queue->nr].ctr = queue->insertion_ctr++;
46+
queue->array[queue->nr].data = thing;
47+
queue->nr++;
4348
if (!queue->compare)
4449
return; /* LIFO */
4550

@@ -61,9 +66,9 @@ void *prio_queue_get(struct prio_queue *queue)
6166
if (!queue->nr)
6267
return NULL;
6368
if (!queue->compare)
64-
return queue->array[--queue->nr]; /* LIFO */
69+
return queue->array[--queue->nr].data; /* LIFO */
6570

66-
result = queue->array[0];
71+
result = queue->array[0].data;
6772
if (!--queue->nr)
6873
return result;
6974

‎prio-queue.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,17 @@
2121
*/
2222
typedef int (*prio_queue_compare_fn)(const void *one, const void *two, void *cb_data);
2323

24+
struct prio_queue_entry {
25+
unsigned ctr;
26+
void *data;
27+
};
28+
2429
struct prio_queue {
2530
prio_queue_compare_fn compare;
31+
unsigned insertion_ctr;
2632
void *cb_data;
2733
int alloc, nr;
28-
void **array;
34+
struct prio_queue_entry *array;
2935
};
3036

3137
/*

0 commit comments

Comments
 (0)