Skip to content

Commit 9f67cbd

Browse files
committed
Merge branch 'ps/reftable-iteration-perf'
The code to iterate over refs with the reftable backend has seen some optimization. * ps/reftable-iteration-perf: reftable/reader: add comments to `table_iter_next()` reftable/record: don't try to reallocate ref record name reftable/block: swap buffers instead of copying reftable/pq: allocation-less comparison of entry keys reftable/merged: skip comparison for records of the same subiter reftable/merged: allocation-less dropping of shadowed records reftable/record: introduce function to compare records by key
2 parents 2744009 + c68ca7a commit 9f67cbd

File tree

7 files changed

+100
-37
lines changed

7 files changed

+100
-37
lines changed

reftable/block.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,7 @@ int block_iter_next(struct block_iter *it, struct reftable_record *rec)
339339
return -1;
340340
string_view_consume(&in, n);
341341

342-
strbuf_reset(&it->last_key);
343-
strbuf_addbuf(&it->last_key, &it->key);
342+
strbuf_swap(&it->last_key, &it->key);
344343
it->next_off += start.len - in.len;
345344
return 0;
346345
}

reftable/merged.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ static void merged_iter_close(void *p)
4949
for (size_t i = 0; i < mi->stack_len; i++)
5050
reftable_iterator_destroy(&mi->stack[i]);
5151
reftable_free(mi->stack);
52-
strbuf_release(&mi->key);
53-
strbuf_release(&mi->entry_key);
5452
}
5553

5654
static int merged_iter_advance_nonnull_subiter(struct merged_iter *mi,
@@ -105,14 +103,19 @@ static int merged_iter_next_entry(struct merged_iter *mi,
105103
such a deployment, the loop below must be changed to collect all
106104
entries for the same key, and return new the newest one.
107105
*/
108-
reftable_record_key(&entry.rec, &mi->entry_key);
109106
while (!merged_iter_pqueue_is_empty(mi->pq)) {
110107
struct pq_entry top = merged_iter_pqueue_top(mi->pq);
111-
int cmp = 0;
112-
113-
reftable_record_key(&top.rec, &mi->key);
108+
int cmp;
109+
110+
/*
111+
* When the next entry comes from the same queue as the current
112+
* entry then it must by definition be larger. This avoids a
113+
* comparison in the most common case.
114+
*/
115+
if (top.index == entry.index)
116+
break;
114117

115-
cmp = strbuf_cmp(&mi->key, &mi->entry_key);
118+
cmp = reftable_record_cmp(&top.rec, &entry.rec);
116119
if (cmp > 0)
117120
break;
118121

@@ -243,8 +246,6 @@ static int merged_table_seek_record(struct reftable_merged_table *mt,
243246
.typ = reftable_record_type(rec),
244247
.hash_id = mt->hash_id,
245248
.suppress_deletions = mt->suppress_deletions,
246-
.key = STRBUF_INIT,
247-
.entry_key = STRBUF_INIT,
248249
};
249250
struct merged_iter *p;
250251
int err;

reftable/merged.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ struct merged_iter {
3131
uint8_t typ;
3232
int suppress_deletions;
3333
struct merged_iter_pqueue pq;
34-
struct strbuf key;
35-
struct strbuf entry_key;
3634
};
3735

3836
void merged_table_release(struct reftable_merged_table *mt);

reftable/pq.c

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,9 @@ license that can be found in the LICENSE file or at
1414

1515
int pq_less(struct pq_entry *a, struct pq_entry *b)
1616
{
17-
struct strbuf ak = STRBUF_INIT;
18-
struct strbuf bk = STRBUF_INIT;
19-
int cmp = 0;
20-
reftable_record_key(&a->rec, &ak);
21-
reftable_record_key(&b->rec, &bk);
22-
23-
cmp = strbuf_cmp(&ak, &bk);
24-
25-
strbuf_release(&ak);
26-
strbuf_release(&bk);
27-
17+
int cmp = reftable_record_cmp(&a->rec, &b->rec);
2818
if (cmp == 0)
2919
return a->index > b->index;
30-
3120
return cmp < 0;
3221
}
3322

reftable/reader.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -357,24 +357,32 @@ static int table_iter_next(struct table_iter *ti, struct reftable_record *rec)
357357

358358
while (1) {
359359
struct table_iter next = TABLE_ITER_INIT;
360-
int err = 0;
361-
if (ti->is_finished) {
360+
int err;
361+
362+
if (ti->is_finished)
362363
return 1;
363-
}
364364

365+
/*
366+
* Check whether the current block still has more records. If
367+
* so, return it. If the iterator returns positive then the
368+
* current block has been exhausted.
369+
*/
365370
err = table_iter_next_in_block(ti, rec);
366-
if (err <= 0) {
371+
if (err <= 0)
367372
return err;
368-
}
369373

374+
/*
375+
* Otherwise, we need to continue to the next block in the
376+
* table and retry. If there are no more blocks then the
377+
* iterator is drained.
378+
*/
370379
err = table_iter_next_block(&next, ti);
371-
if (err != 0) {
372-
ti->is_finished = 1;
373-
}
374380
table_iter_block_done(ti);
375-
if (err != 0) {
381+
if (err) {
382+
ti->is_finished = 1;
376383
return err;
377384
}
385+
378386
table_iter_copy_from(ti, &next);
379387
block_iter_close(&next.bi);
380388
}

reftable/record.c

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,11 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
377377

378378
assert(hash_size > 0);
379379

380-
r->refname = reftable_realloc(r->refname, key.len + 1);
380+
r->refname = reftable_malloc(key.len + 1);
381381
memcpy(r->refname, key.buf, key.len);
382-
r->update_index = update_index;
383382
r->refname[key.len] = 0;
383+
384+
r->update_index = update_index;
384385
r->value_type = val_type;
385386
switch (val_type) {
386387
case REFTABLE_REF_VAL1:
@@ -430,7 +431,6 @@ static int reftable_ref_record_is_deletion_void(const void *p)
430431
(const struct reftable_ref_record *)p);
431432
}
432433

433-
434434
static int reftable_ref_record_equal_void(const void *a,
435435
const void *b, int hash_size)
436436
{
@@ -439,6 +439,13 @@ static int reftable_ref_record_equal_void(const void *a,
439439
return reftable_ref_record_equal(ra, rb, hash_size);
440440
}
441441

442+
static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
443+
{
444+
const struct reftable_ref_record *a = _a;
445+
const struct reftable_ref_record *b = _b;
446+
return strcmp(a->refname, b->refname);
447+
}
448+
442449
static void reftable_ref_record_print_void(const void *rec,
443450
int hash_size)
444451
{
@@ -455,6 +462,7 @@ static struct reftable_record_vtable reftable_ref_record_vtable = {
455462
.release = &reftable_ref_record_release_void,
456463
.is_deletion = &reftable_ref_record_is_deletion_void,
457464
.equal = &reftable_ref_record_equal_void,
465+
.cmp = &reftable_ref_record_cmp_void,
458466
.print = &reftable_ref_record_print_void,
459467
};
460468

@@ -627,6 +635,25 @@ static int reftable_obj_record_equal_void(const void *a, const void *b, int hash
627635
return 1;
628636
}
629637

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

@@ -955,6 +983,22 @@ static int reftable_log_record_equal_void(const void *a,
955983
hash_size);
956984
}
957985

986+
static int reftable_log_record_cmp_void(const void *_a, const void *_b)
987+
{
988+
const struct reftable_log_record *a = _a;
989+
const struct reftable_log_record *b = _b;
990+
int cmp = strcmp(a->refname, b->refname);
991+
if (cmp)
992+
return cmp;
993+
994+
/*
995+
* Note that the comparison here is reversed. This is because the
996+
* update index is reversed when comparing keys. For reference, see how
997+
* we handle this in reftable_log_record_key()`.
998+
*/
999+
return b->update_index - a->update_index;
1000+
}
1001+
9581002
int reftable_log_record_equal(const struct reftable_log_record *a,
9591003
const struct reftable_log_record *b, int hash_size)
9601004
{
@@ -1004,6 +1048,7 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
10041048
.release = &reftable_log_record_release_void,
10051049
.is_deletion = &reftable_log_record_is_deletion_void,
10061050
.equal = &reftable_log_record_equal_void,
1051+
.cmp = &reftable_log_record_cmp_void,
10071052
.print = &reftable_log_record_print_void,
10081053
};
10091054

@@ -1079,6 +1124,13 @@ static int reftable_index_record_equal(const void *a, const void *b, int hash_si
10791124
return ia->offset == ib->offset && !strbuf_cmp(&ia->last_key, &ib->last_key);
10801125
}
10811126

1127+
static int reftable_index_record_cmp(const void *_a, const void *_b)
1128+
{
1129+
const struct reftable_index_record *a = _a;
1130+
const struct reftable_index_record *b = _b;
1131+
return strbuf_cmp(&a->last_key, &b->last_key);
1132+
}
1133+
10821134
static void reftable_index_record_print(const void *rec, int hash_size)
10831135
{
10841136
const struct reftable_index_record *idx = rec;
@@ -1096,6 +1148,7 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
10961148
.release = &reftable_index_record_release,
10971149
.is_deletion = &not_a_deletion,
10981150
.equal = &reftable_index_record_equal,
1151+
.cmp = &reftable_index_record_cmp,
10991152
.print = &reftable_index_record_print,
11001153
};
11011154

@@ -1149,6 +1202,14 @@ int reftable_record_is_deletion(struct reftable_record *rec)
11491202
reftable_record_data(rec));
11501203
}
11511204

1205+
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b)
1206+
{
1207+
if (a->type != b->type)
1208+
BUG("cannot compare reftable records of different type");
1209+
return reftable_record_vtable(a)->cmp(
1210+
reftable_record_data(a), reftable_record_data(b));
1211+
}
1212+
11521213
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size)
11531214
{
11541215
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
void reftable_record_init(struct reftable_record *rec, uint8_t typ);
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)