Skip to content

Commit adb5d2c

Browse files
pks-tgitster
authored andcommitted
reftable/record: introduce function to compare records by key
In some places we need to sort reftable records by their keys to determine their ordering. This is done by first formatting the keys into a `struct strbuf` and then using `strbuf_cmp()` to compare them. This logic is needlessly roundabout and can end up costing quite a bit of CPU cycles, both due to the allocation and formatting logic. Introduce a new `reftable_record_cmp()` function that knows how to compare two records with each other without requiring allocations. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bc7ee2e commit adb5d2c

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

reftable/record.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,6 @@ static int reftable_ref_record_is_deletion_void(const void *p)
430430
(const struct reftable_ref_record *)p);
431431
}
432432

433-
434433
static int reftable_ref_record_equal_void(const void *a,
435434
const void *b, int hash_size)
436435
{
@@ -439,6 +438,13 @@ static int reftable_ref_record_equal_void(const void *a,
439438
return reftable_ref_record_equal(ra, rb, hash_size);
440439
}
441440

441+
static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
442+
{
443+
const struct reftable_ref_record *a = _a;
444+
const struct reftable_ref_record *b = _b;
445+
return strcmp(a->refname, b->refname);
446+
}
447+
442448
static void reftable_ref_record_print_void(const void *rec,
443449
int hash_size)
444450
{
@@ -455,6 +461,7 @@ static struct reftable_record_vtable reftable_ref_record_vtable = {
455461
.release = &reftable_ref_record_release_void,
456462
.is_deletion = &reftable_ref_record_is_deletion_void,
457463
.equal = &reftable_ref_record_equal_void,
464+
.cmp = &reftable_ref_record_cmp_void,
458465
.print = &reftable_ref_record_print_void,
459466
};
460467

@@ -625,6 +632,25 @@ static int reftable_obj_record_equal_void(const void *a, const void *b, int hash
625632
return 1;
626633
}
627634

635+
static int reftable_obj_record_cmp_void(const void *_a, const void *_b)
636+
{
637+
const struct reftable_obj_record *a = _a;
638+
const struct reftable_obj_record *b = _b;
639+
int cmp;
640+
641+
cmp = memcmp(a->hash_prefix, b->hash_prefix,
642+
a->hash_prefix_len > b->hash_prefix_len ?
643+
a->hash_prefix_len : b->hash_prefix_len);
644+
if (cmp)
645+
return cmp;
646+
647+
/*
648+
* When the prefix is the same then the object record that is longer is
649+
* considered to be bigger.
650+
*/
651+
return a->hash_prefix_len - b->hash_prefix_len;
652+
}
653+
628654
static struct reftable_record_vtable reftable_obj_record_vtable = {
629655
.key = &reftable_obj_record_key,
630656
.type = BLOCK_TYPE_OBJ,
@@ -635,6 +661,7 @@ static struct reftable_record_vtable reftable_obj_record_vtable = {
635661
.release = &reftable_obj_record_release,
636662
.is_deletion = &not_a_deletion,
637663
.equal = &reftable_obj_record_equal_void,
664+
.cmp = &reftable_obj_record_cmp_void,
638665
.print = &reftable_obj_record_print,
639666
};
640667

@@ -953,6 +980,22 @@ static int reftable_log_record_equal_void(const void *a,
953980
hash_size);
954981
}
955982

983+
static int reftable_log_record_cmp_void(const void *_a, const void *_b)
984+
{
985+
const struct reftable_log_record *a = _a;
986+
const struct reftable_log_record *b = _b;
987+
int cmp = strcmp(a->refname, b->refname);
988+
if (cmp)
989+
return cmp;
990+
991+
/*
992+
* Note that the comparison here is reversed. This is because the
993+
* update index is reversed when comparing keys. For reference, see how
994+
* we handle this in reftable_log_record_key()`.
995+
*/
996+
return b->update_index - a->update_index;
997+
}
998+
956999
int reftable_log_record_equal(const struct reftable_log_record *a,
9571000
const struct reftable_log_record *b, int hash_size)
9581001
{
@@ -1002,6 +1045,7 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
10021045
.release = &reftable_log_record_release_void,
10031046
.is_deletion = &reftable_log_record_is_deletion_void,
10041047
.equal = &reftable_log_record_equal_void,
1048+
.cmp = &reftable_log_record_cmp_void,
10051049
.print = &reftable_log_record_print_void,
10061050
};
10071051

@@ -1077,6 +1121,13 @@ static int reftable_index_record_equal(const void *a, const void *b, int hash_si
10771121
return ia->offset == ib->offset && !strbuf_cmp(&ia->last_key, &ib->last_key);
10781122
}
10791123

1124+
static int reftable_index_record_cmp(const void *_a, const void *_b)
1125+
{
1126+
const struct reftable_index_record *a = _a;
1127+
const struct reftable_index_record *b = _b;
1128+
return strbuf_cmp(&a->last_key, &b->last_key);
1129+
}
1130+
10801131
static void reftable_index_record_print(const void *rec, int hash_size)
10811132
{
10821133
const struct reftable_index_record *idx = rec;
@@ -1094,6 +1145,7 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
10941145
.release = &reftable_index_record_release,
10951146
.is_deletion = &not_a_deletion,
10961147
.equal = &reftable_index_record_equal,
1148+
.cmp = &reftable_index_record_cmp,
10971149
.print = &reftable_index_record_print,
10981150
};
10991151

@@ -1147,6 +1199,14 @@ int reftable_record_is_deletion(struct reftable_record *rec)
11471199
reftable_record_data(rec));
11481200
}
11491201

1202+
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b)
1203+
{
1204+
if (a->type != b->type)
1205+
BUG("cannot compare reftable records of different type");
1206+
return reftable_record_vtable(a)->cmp(
1207+
reftable_record_data(a), reftable_record_data(b));
1208+
}
1209+
11501210
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
11511211
{
11521212
if (a->type != b->type)

reftable/record.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ struct reftable_record_vtable {
6262
/* Are two records equal? This assumes they have the same type. Returns 0 for non-equal. */
6363
int (*equal)(const void *a, const void *b, int hash_size);
6464

65+
/*
66+
* Compare keys of two records with each other. The records must have
67+
* the same type.
68+
*/
69+
int (*cmp)(const void *a, const void *b);
70+
6571
/* Print on stdout, for debugging. */
6672
void (*print)(const void *rec, int hash_size);
6773
};
@@ -114,6 +120,7 @@ struct reftable_record {
114120
};
115121

116122
/* see struct record_vtable */
123+
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
117124
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
118125
void reftable_record_print(struct reftable_record *rec, int hash_size);
119126
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);

0 commit comments

Comments
 (0)