Skip to content

Commit bc62765

Browse files
committed
Merge branch 'ps/reftable-strbuf'
Implements a new reftable-specific strbuf replacement to reduce reftable's dependency on Git-specific data structures. * ps/reftable-strbuf: reftable: handle trivial `reftable_buf` errors reftable/stack: adapt `stack_filename()` to handle allocation failures reftable/record: adapt `reftable_record_key()` to handle allocation failures reftable/stack: adapt `format_name()` to handle allocation failures t/unit-tests: check for `reftable_buf` allocation errors reftable/blocksource: adapt interface name reftable: convert from `strbuf` to `reftable_buf` reftable/basics: provide new `reftable_buf` interface reftable: stop using `strbuf_addf()` reftable: stop using `strbuf_addbuf()`
2 parents 6a11438 + 20590cd commit bc62765

24 files changed

+728
-452
lines changed

reftable/basics.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ license that can be found in the LICENSE file or at
99
#define REFTABLE_ALLOW_BANNED_ALLOCATORS
1010
#include "basics.h"
1111
#include "reftable-basics.h"
12+
#include "reftable-error.h"
1213

1314
static void *(*reftable_malloc_ptr)(size_t sz);
1415
static void *(*reftable_realloc_ptr)(void *, size_t);
@@ -69,6 +70,79 @@ void reftable_set_alloc(void *(*malloc)(size_t),
6970
reftable_free_ptr = free;
7071
}
7172

73+
void reftable_buf_init(struct reftable_buf *buf)
74+
{
75+
struct reftable_buf empty = REFTABLE_BUF_INIT;
76+
*buf = empty;
77+
}
78+
79+
void reftable_buf_release(struct reftable_buf *buf)
80+
{
81+
reftable_free(buf->buf);
82+
reftable_buf_init(buf);
83+
}
84+
85+
void reftable_buf_reset(struct reftable_buf *buf)
86+
{
87+
if (buf->alloc) {
88+
buf->len = 0;
89+
buf->buf[0] = '\0';
90+
}
91+
}
92+
93+
int reftable_buf_setlen(struct reftable_buf *buf, size_t len)
94+
{
95+
if (len > buf->len)
96+
return -1;
97+
if (len == buf->len)
98+
return 0;
99+
buf->buf[len] = '\0';
100+
buf->len = len;
101+
return 0;
102+
}
103+
104+
int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b)
105+
{
106+
size_t len = a->len < b->len ? a->len : b->len;
107+
if (len) {
108+
int cmp = memcmp(a->buf, b->buf, len);
109+
if (cmp)
110+
return cmp;
111+
}
112+
return a->len < b->len ? -1 : a->len != b->len;
113+
}
114+
115+
int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len)
116+
{
117+
size_t newlen = buf->len + len;
118+
119+
if (newlen + 1 > buf->alloc) {
120+
char *reallocated = buf->buf;
121+
REFTABLE_ALLOC_GROW(reallocated, newlen + 1, buf->alloc);
122+
if (!reallocated)
123+
return REFTABLE_OUT_OF_MEMORY_ERROR;
124+
buf->buf = reallocated;
125+
}
126+
127+
memcpy(buf->buf + buf->len, data, len);
128+
buf->buf[newlen] = '\0';
129+
buf->len = newlen;
130+
131+
return 0;
132+
}
133+
134+
int reftable_buf_addstr(struct reftable_buf *buf, const char *s)
135+
{
136+
return reftable_buf_add(buf, s, strlen(s));
137+
}
138+
139+
char *reftable_buf_detach(struct reftable_buf *buf)
140+
{
141+
char *result = buf->buf;
142+
reftable_buf_init(buf);
143+
return result;
144+
}
145+
72146
void put_be24(uint8_t *out, uint32_t i)
73147
{
74148
out[0] = (uint8_t)((i >> 16) & 0xff);
@@ -186,7 +260,7 @@ int names_equal(const char **a, const char **b)
186260
return a[i] == b[i];
187261
}
188262

189-
int common_prefix_size(struct strbuf *a, struct strbuf *b)
263+
int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b)
190264
{
191265
int p = 0;
192266
for (; p < a->len && p < b->len; p++) {

reftable/basics.h

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,64 @@ license that can be found in the LICENSE file or at
1616
#include "system.h"
1717
#include "reftable-basics.h"
1818

19+
struct reftable_buf {
20+
size_t alloc;
21+
size_t len;
22+
char *buf;
23+
};
24+
#define REFTABLE_BUF_INIT { 0 }
25+
26+
/*
27+
* Initialize the buffer such that it is ready for use. This is equivalent to
28+
* using REFTABLE_BUF_INIT for stack-allocated variables.
29+
*/
30+
void reftable_buf_init(struct reftable_buf *buf);
31+
32+
/*
33+
* Release memory associated with the buffer. The buffer is reinitialized such
34+
* that it can be reused for subsequent operations.
35+
*/
36+
void reftable_buf_release(struct reftable_buf *buf);
37+
38+
/*
39+
* Reset the buffer such that it is effectively empty, without releasing the
40+
* memory that this structure holds on to. This is equivalent to calling
41+
* `reftable_buf_setlen(buf, 0)`.
42+
*/
43+
void reftable_buf_reset(struct reftable_buf *buf);
44+
45+
/*
46+
* Trim the buffer to a shorter length by updating the `len` member and writing
47+
* a NUL byte to `buf[len]`. Returns 0 on success, -1 when `len` points outside
48+
* of the array.
49+
*/
50+
int reftable_buf_setlen(struct reftable_buf *buf, size_t len);
51+
52+
/*
53+
* Lexicographically compare the two buffers. Returns 0 when both buffers have
54+
* the same contents, -1 when `a` is lexicographically smaller than `b`, and 1
55+
* otherwise.
56+
*/
57+
int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b);
58+
59+
/*
60+
* Append `len` bytes from `data` to the buffer. This function works with
61+
* arbitrary byte sequences, including ones that contain embedded NUL
62+
* characters. As such, we use `void *` as input type. Returns 0 on success,
63+
* REFTABLE_OUT_OF_MEMORY_ERROR on allocation failure.
64+
*/
65+
int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len);
66+
67+
/* Equivalent to `reftable_buf_add(buf, s, strlen(s))`. */
68+
int reftable_buf_addstr(struct reftable_buf *buf, const char *s);
69+
70+
/*
71+
* Detach the buffer from the structure such that the underlying memory is now
72+
* owned by the caller. The buffer is reinitialized such that it can be reused
73+
* for subsequent operations.
74+
*/
75+
char *reftable_buf_detach(struct reftable_buf *buf);
76+
1977
/* Bigendian en/decoding of integers */
2078

2179
void put_be24(uint8_t *out, uint32_t i);
@@ -88,8 +146,7 @@ char *reftable_strdup(const char *str);
88146
#endif
89147

90148
/* Find the longest shared prefix size of `a` and `b` */
91-
struct strbuf;
92-
int common_prefix_size(struct strbuf *a, struct strbuf *b);
149+
int common_prefix_size(struct reftable_buf *a, struct reftable_buf *b);
93150

94151
int hash_size(uint32_t id);
95152

reftable/block.c

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ int footer_size(int version)
3838
}
3939

4040
static int block_writer_register_restart(struct block_writer *w, int n,
41-
int is_restart, struct strbuf *key)
41+
int is_restart, struct reftable_buf *key)
4242
{
43-
int rlen = w->restart_len;
43+
int rlen, err;
44+
45+
rlen = w->restart_len;
4446
if (rlen >= MAX_RESTARTS) {
4547
is_restart = 0;
4648
}
@@ -59,8 +61,11 @@ static int block_writer_register_restart(struct block_writer *w, int n,
5961

6062
w->next += n;
6163

62-
strbuf_reset(&w->last_key);
63-
strbuf_addbuf(&w->last_key, key);
64+
reftable_buf_reset(&w->last_key);
65+
err = reftable_buf_add(&w->last_key, key->buf, key->len);
66+
if (err < 0)
67+
return err;
68+
6469
w->entries++;
6570
return 0;
6671
}
@@ -98,8 +103,8 @@ uint8_t block_writer_type(struct block_writer *bw)
98103
empty key. */
99104
int block_writer_add(struct block_writer *w, struct reftable_record *rec)
100105
{
101-
struct strbuf empty = STRBUF_INIT;
102-
struct strbuf last =
106+
struct reftable_buf empty = REFTABLE_BUF_INIT;
107+
struct reftable_buf last =
103108
w->entries % w->restart_interval == 0 ? empty : w->last_key;
104109
struct string_view out = {
105110
.buf = w->buf + w->next,
@@ -109,31 +114,38 @@ int block_writer_add(struct block_writer *w, struct reftable_record *rec)
109114
struct string_view start = out;
110115

111116
int is_restart = 0;
112-
struct strbuf key = STRBUF_INIT;
117+
struct reftable_buf key = REFTABLE_BUF_INIT;
113118
int n = 0;
114-
int err = -1;
119+
int err;
120+
121+
err = reftable_record_key(rec, &key);
122+
if (err < 0)
123+
goto done;
115124

116-
reftable_record_key(rec, &key);
117125
if (!key.len) {
118126
err = REFTABLE_API_ERROR;
119127
goto done;
120128
}
121129

122130
n = reftable_encode_key(&is_restart, out, last, key,
123131
reftable_record_val_type(rec));
124-
if (n < 0)
132+
if (n < 0) {
133+
err = -1;
125134
goto done;
135+
}
126136
string_view_consume(&out, n);
127137

128138
n = reftable_record_encode(rec, out, w->hash_size);
129-
if (n < 0)
139+
if (n < 0) {
140+
err = -1;
130141
goto done;
142+
}
131143
string_view_consume(&out, n);
132144

133145
err = block_writer_register_restart(w, start.len - out.len, is_restart,
134146
&key);
135147
done:
136-
strbuf_release(&key);
148+
reftable_buf_release(&key);
137149
return err;
138150
}
139151

@@ -325,7 +337,7 @@ uint8_t block_reader_type(const struct block_reader *r)
325337
return r->block.data[r->header_off];
326338
}
327339

328-
int block_reader_first_key(const struct block_reader *br, struct strbuf *key)
340+
int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key)
329341
{
330342
int off = br->header_off + 4, n;
331343
struct string_view in = {
@@ -334,7 +346,7 @@ int block_reader_first_key(const struct block_reader *br, struct strbuf *key)
334346
};
335347
uint8_t extra = 0;
336348

337-
strbuf_reset(key);
349+
reftable_buf_reset(key);
338350

339351
n = reftable_decode_key(key, &extra, in);
340352
if (n < 0)
@@ -355,13 +367,13 @@ void block_iter_seek_start(struct block_iter *it, const struct block_reader *br)
355367
it->block = br->block.data;
356368
it->block_len = br->block_len;
357369
it->hash_size = br->hash_size;
358-
strbuf_reset(&it->last_key);
370+
reftable_buf_reset(&it->last_key);
359371
it->next_off = br->header_off + 4;
360372
}
361373

362374
struct restart_needle_less_args {
363375
int error;
364-
struct strbuf needle;
376+
struct reftable_buf needle;
365377
const struct block_reader *reader;
366378
};
367379

@@ -433,7 +445,7 @@ int block_iter_next(struct block_iter *it, struct reftable_record *rec)
433445

434446
void block_iter_reset(struct block_iter *it)
435447
{
436-
strbuf_reset(&it->last_key);
448+
reftable_buf_reset(&it->last_key);
437449
it->next_off = 0;
438450
it->block = NULL;
439451
it->block_len = 0;
@@ -442,12 +454,12 @@ void block_iter_reset(struct block_iter *it)
442454

443455
void block_iter_close(struct block_iter *it)
444456
{
445-
strbuf_release(&it->last_key);
446-
strbuf_release(&it->scratch);
457+
reftable_buf_release(&it->last_key);
458+
reftable_buf_release(&it->scratch);
447459
}
448460

449461
int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
450-
struct strbuf *want)
462+
struct reftable_buf *want)
451463
{
452464
struct restart_needle_less_args args = {
453465
.needle = *want,
@@ -522,6 +534,10 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
522534
goto done;
523535
}
524536

537+
err = reftable_record_key(&rec, &it->last_key);
538+
if (err < 0)
539+
goto done;
540+
525541
/*
526542
* Check whether the current key is greater or equal to the
527543
* sought-after key. In case it is greater we know that the
@@ -536,8 +552,7 @@ int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
536552
* to `last_key` now, and naturally all keys share a prefix
537553
* with themselves.
538554
*/
539-
reftable_record_key(&rec, &it->last_key);
540-
if (strbuf_cmp(&it->last_key, want) >= 0) {
555+
if (reftable_buf_cmp(&it->last_key, want) >= 0) {
541556
it->next_off = prev_off;
542557
goto done;
543558
}
@@ -554,7 +569,7 @@ void block_writer_release(struct block_writer *bw)
554569
REFTABLE_FREE_AND_NULL(bw->zstream);
555570
REFTABLE_FREE_AND_NULL(bw->restarts);
556571
REFTABLE_FREE_AND_NULL(bw->compressed);
557-
strbuf_release(&bw->last_key);
572+
reftable_buf_release(&bw->last_key);
558573
/* the block is not owned. */
559574
}
560575

reftable/block.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct block_writer {
3838
uint32_t restart_len;
3939
uint32_t restart_cap;
4040

41-
struct strbuf last_key;
41+
struct reftable_buf last_key;
4242
int entries;
4343
};
4444

@@ -98,7 +98,7 @@ void block_reader_release(struct block_reader *br);
9898
uint8_t block_reader_type(const struct block_reader *r);
9999

100100
/* Decodes the first key in the block */
101-
int block_reader_first_key(const struct block_reader *br, struct strbuf *key);
101+
int block_reader_first_key(const struct block_reader *br, struct reftable_buf *key);
102102

103103
/* Iterate over entries in a block */
104104
struct block_iter {
@@ -109,21 +109,21 @@ struct block_iter {
109109
int hash_size;
110110

111111
/* key for last entry we read. */
112-
struct strbuf last_key;
113-
struct strbuf scratch;
112+
struct reftable_buf last_key;
113+
struct reftable_buf scratch;
114114
};
115115

116116
#define BLOCK_ITER_INIT { \
117-
.last_key = STRBUF_INIT, \
118-
.scratch = STRBUF_INIT, \
117+
.last_key = REFTABLE_BUF_INIT, \
118+
.scratch = REFTABLE_BUF_INIT, \
119119
}
120120

121121
/* Position `it` at start of the block */
122122
void block_iter_seek_start(struct block_iter *it, const struct block_reader *br);
123123

124124
/* Position `it` to the `want` key in the block */
125125
int block_iter_seek_key(struct block_iter *it, const struct block_reader *br,
126-
struct strbuf *want);
126+
struct reftable_buf *want);
127127

128128
/* return < 0 for error, 0 for OK, > 0 for EOF. */
129129
int block_iter_next(struct block_iter *it, struct reftable_record *rec);

0 commit comments

Comments
 (0)