mirror of
https://github.com/git/git
synced 2024-10-01 06:05:20 +00:00
Merge branch 'ps/reftable-reflog-iteration-perf'
The code to iterate over reflogs in the reftable has been optimized to reduce memory allocation and deallocation. Reviewed-by: Josh Steadmon <steadmon@google.com> cf. <Ze9eX-aaWoVaqsPP@google.com> * ps/reftable-reflog-iteration-perf: refs/reftable: track last log record name via strbuf reftable/record: use scratch buffer when decoding records reftable/record: reuse message when decoding log records reftable/record: reuse refnames when decoding log records reftable/record: avoid copying author info reftable/record: convert old and new object IDs to arrays refs/reftable: reload correct stack when creating reflog iter
This commit is contained in:
commit
e8c1cda9a9
|
@ -171,23 +171,6 @@ static int should_write_log(struct ref_store *refs, const char *refname)
|
|||
}
|
||||
}
|
||||
|
||||
static void clear_reftable_log_record(struct reftable_log_record *log)
|
||||
{
|
||||
switch (log->value_type) {
|
||||
case REFTABLE_LOG_UPDATE:
|
||||
/*
|
||||
* When we write log records, the hashes are owned by the
|
||||
* caller and thus shouldn't be free'd.
|
||||
*/
|
||||
log->value.update.old_hash = NULL;
|
||||
log->value.update.new_hash = NULL;
|
||||
break;
|
||||
case REFTABLE_LOG_DELETION:
|
||||
break;
|
||||
}
|
||||
reftable_log_record_release(log);
|
||||
}
|
||||
|
||||
static void fill_reftable_log_record(struct reftable_log_record *log)
|
||||
{
|
||||
const char *info = git_committer_info(0);
|
||||
|
@ -1106,8 +1089,8 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
|
|||
fill_reftable_log_record(log);
|
||||
log->update_index = ts;
|
||||
log->refname = xstrdup(u->refname);
|
||||
log->value.update.new_hash = u->new_oid.hash;
|
||||
log->value.update.old_hash = tx_update->current_oid.hash;
|
||||
memcpy(log->value.update.new_hash, u->new_oid.hash, GIT_MAX_RAWSZ);
|
||||
memcpy(log->value.update.old_hash, tx_update->current_oid.hash, GIT_MAX_RAWSZ);
|
||||
log->value.update.message =
|
||||
xstrndup(u->msg, arg->refs->write_options.block_size / 2);
|
||||
}
|
||||
|
@ -1162,7 +1145,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
|
|||
done:
|
||||
assert(ret != REFTABLE_API_ERROR);
|
||||
for (i = 0; i < logs_nr; i++)
|
||||
clear_reftable_log_record(&logs[i]);
|
||||
reftable_log_record_release(&logs[i]);
|
||||
free(logs);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1279,13 +1262,13 @@ static int write_create_symref_table(struct reftable_writer *writer, void *cb_da
|
|||
log.update_index = ts;
|
||||
log.value.update.message = xstrndup(create->logmsg,
|
||||
create->refs->write_options.block_size / 2);
|
||||
log.value.update.new_hash = new_oid.hash;
|
||||
memcpy(log.value.update.new_hash, new_oid.hash, GIT_MAX_RAWSZ);
|
||||
if (refs_resolve_ref_unsafe(&create->refs->base, create->refname,
|
||||
RESOLVE_REF_READING, &old_oid, NULL))
|
||||
log.value.update.old_hash = old_oid.hash;
|
||||
memcpy(log.value.update.old_hash, old_oid.hash, GIT_MAX_RAWSZ);
|
||||
|
||||
ret = reftable_writer_add_log(writer, &log);
|
||||
clear_reftable_log_record(&log);
|
||||
reftable_log_record_release(&log);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1424,7 +1407,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
|
|||
logs[logs_nr].update_index = deletion_ts;
|
||||
logs[logs_nr].value.update.message =
|
||||
xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2);
|
||||
logs[logs_nr].value.update.old_hash = old_ref.value.val1;
|
||||
memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
|
||||
logs_nr++;
|
||||
|
||||
ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid, &head_referent, &head_type);
|
||||
|
@ -1456,7 +1439,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
|
|||
logs[logs_nr].update_index = creation_ts;
|
||||
logs[logs_nr].value.update.message =
|
||||
xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2);
|
||||
logs[logs_nr].value.update.new_hash = old_ref.value.val1;
|
||||
memcpy(logs[logs_nr].value.update.new_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
|
||||
logs_nr++;
|
||||
|
||||
/*
|
||||
|
@ -1519,10 +1502,6 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
|
|||
for (i = 0; i < logs_nr; i++) {
|
||||
if (!strcmp(logs[i].refname, "HEAD"))
|
||||
continue;
|
||||
if (logs[i].value.update.old_hash == old_ref.value.val1)
|
||||
logs[i].value.update.old_hash = NULL;
|
||||
if (logs[i].value.update.new_hash == old_ref.value.val1)
|
||||
logs[i].value.update.new_hash = NULL;
|
||||
logs[i].refname = NULL;
|
||||
reftable_log_record_release(&logs[i]);
|
||||
}
|
||||
|
@ -1600,7 +1579,7 @@ struct reftable_reflog_iterator {
|
|||
struct reftable_ref_store *refs;
|
||||
struct reftable_iterator iter;
|
||||
struct reftable_log_record log;
|
||||
char *last_name;
|
||||
struct strbuf last_name;
|
||||
int err;
|
||||
};
|
||||
|
||||
|
@ -1619,15 +1598,15 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
|
|||
* we've already produced this name. This could be faster by
|
||||
* seeking directly to reflog@update_index==0.
|
||||
*/
|
||||
if (iter->last_name && !strcmp(iter->log.refname, iter->last_name))
|
||||
if (!strcmp(iter->log.refname, iter->last_name.buf))
|
||||
continue;
|
||||
|
||||
if (check_refname_format(iter->log.refname,
|
||||
REFNAME_ALLOW_ONELEVEL))
|
||||
continue;
|
||||
|
||||
free(iter->last_name);
|
||||
iter->last_name = xstrdup(iter->log.refname);
|
||||
strbuf_reset(&iter->last_name);
|
||||
strbuf_addstr(&iter->last_name, iter->log.refname);
|
||||
iter->base.refname = iter->log.refname;
|
||||
|
||||
break;
|
||||
|
@ -1660,7 +1639,7 @@ static int reftable_reflog_iterator_abort(struct ref_iterator *ref_iterator)
|
|||
(struct reftable_reflog_iterator *)ref_iterator;
|
||||
reftable_log_record_release(&iter->log);
|
||||
reftable_iterator_destroy(&iter->iter);
|
||||
free(iter->last_name);
|
||||
strbuf_release(&iter->last_name);
|
||||
free(iter);
|
||||
return ITER_DONE;
|
||||
}
|
||||
|
@ -1680,13 +1659,14 @@ static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftabl
|
|||
|
||||
iter = xcalloc(1, sizeof(*iter));
|
||||
base_ref_iterator_init(&iter->base, &reftable_reflog_iterator_vtable);
|
||||
strbuf_init(&iter->last_name, 0);
|
||||
iter->refs = refs;
|
||||
|
||||
ret = refs->err;
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
ret = reftable_stack_reload(refs->main_stack);
|
||||
ret = reftable_stack_reload(stack);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
|
@ -2184,7 +2164,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
|
|||
dest->value_type = REFTABLE_LOG_DELETION;
|
||||
} else {
|
||||
if ((flags & EXPIRE_REFLOGS_REWRITE) && last_hash)
|
||||
dest->value.update.old_hash = last_hash;
|
||||
memcpy(dest->value.update.old_hash, last_hash, GIT_MAX_RAWSZ);
|
||||
last_hash = logs[i].value.update.new_hash;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -332,7 +332,8 @@ int block_iter_next(struct block_iter *it, struct reftable_record *rec)
|
|||
return REFTABLE_FORMAT_ERROR;
|
||||
|
||||
string_view_consume(&in, n);
|
||||
n = reftable_record_decode(rec, it->last_key, extra, in, it->br->hash_size);
|
||||
n = reftable_record_decode(rec, it->last_key, extra, in, it->br->hash_size,
|
||||
&it->scratch);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
string_view_consume(&in, n);
|
||||
|
@ -369,6 +370,7 @@ int block_iter_seek(struct block_iter *it, struct strbuf *want)
|
|||
void block_iter_close(struct block_iter *it)
|
||||
{
|
||||
strbuf_release(&it->last_key);
|
||||
strbuf_release(&it->scratch);
|
||||
}
|
||||
|
||||
int block_reader_seek(struct block_reader *br, struct block_iter *it,
|
||||
|
|
|
@ -84,10 +84,12 @@ struct block_iter {
|
|||
|
||||
/* key for last entry we read. */
|
||||
struct strbuf last_key;
|
||||
struct strbuf scratch;
|
||||
};
|
||||
|
||||
#define BLOCK_ITER_INIT { \
|
||||
.last_key = STRBUF_INIT, \
|
||||
.scratch = STRBUF_INIT, \
|
||||
}
|
||||
|
||||
/* initializes a block reader. */
|
||||
|
|
|
@ -289,16 +289,13 @@ merged_table_from_log_records(struct reftable_log_record **logs,
|
|||
|
||||
static void test_merged_logs(void)
|
||||
{
|
||||
uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
|
||||
uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
|
||||
uint8_t hash3[GIT_SHA1_RAWSZ] = { 3 };
|
||||
struct reftable_log_record r1[] = {
|
||||
{
|
||||
.refname = "a",
|
||||
.update_index = 2,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value.update = {
|
||||
.old_hash = hash2,
|
||||
.old_hash = { 2 },
|
||||
/* deletion */
|
||||
.name = "jane doe",
|
||||
.email = "jane@invalid",
|
||||
|
@ -310,8 +307,8 @@ static void test_merged_logs(void)
|
|||
.update_index = 1,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value.update = {
|
||||
.old_hash = hash1,
|
||||
.new_hash = hash2,
|
||||
.old_hash = { 1 },
|
||||
.new_hash = { 2 },
|
||||
.name = "jane doe",
|
||||
.email = "jane@invalid",
|
||||
.message = "message1",
|
||||
|
@ -324,7 +321,7 @@ static void test_merged_logs(void)
|
|||
.update_index = 3,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value.update = {
|
||||
.new_hash = hash3,
|
||||
.new_hash = { 3 },
|
||||
.name = "jane doe",
|
||||
.email = "jane@invalid",
|
||||
.message = "message3",
|
||||
|
|
|
@ -77,18 +77,15 @@ static void write_table(char ***names, struct strbuf *buf, int N,
|
|||
}
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
uint8_t hash[GIT_SHA256_RAWSZ] = { 0 };
|
||||
char name[100];
|
||||
int n;
|
||||
|
||||
set_test_hash(hash, i);
|
||||
|
||||
snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
|
||||
|
||||
log.refname = name;
|
||||
log.update_index = update_index;
|
||||
log.value_type = REFTABLE_LOG_UPDATE;
|
||||
log.value.update.new_hash = hash;
|
||||
set_test_hash(log.value.update.new_hash, i);
|
||||
log.value.update.message = "message";
|
||||
|
||||
n = reftable_writer_add_log(w, &log);
|
||||
|
@ -137,13 +134,10 @@ static void test_log_buffer_size(void)
|
|||
/* This tests buffer extension for log compression. Must use a random
|
||||
hash, to ensure that the compressed part is larger than the original.
|
||||
*/
|
||||
uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
|
||||
for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
|
||||
hash1[i] = (uint8_t)(git_rand() % 256);
|
||||
hash2[i] = (uint8_t)(git_rand() % 256);
|
||||
log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256);
|
||||
log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256);
|
||||
}
|
||||
log.value.update.old_hash = hash1;
|
||||
log.value.update.new_hash = hash2;
|
||||
reftable_writer_set_limits(w, update_index, update_index);
|
||||
err = reftable_writer_add_log(w, &log);
|
||||
EXPECT_ERR(err);
|
||||
|
@ -161,25 +155,26 @@ static void test_log_overflow(void)
|
|||
.block_size = ARRAY_SIZE(msg),
|
||||
};
|
||||
int err;
|
||||
struct reftable_log_record
|
||||
log = { .refname = "refs/heads/master",
|
||||
.update_index = 0xa,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = { .update = {
|
||||
.name = "Han-Wen Nienhuys",
|
||||
.email = "hanwen@google.com",
|
||||
.tz_offset = 100,
|
||||
.time = 0x5e430672,
|
||||
.message = msg,
|
||||
} } };
|
||||
struct reftable_log_record log = {
|
||||
.refname = "refs/heads/master",
|
||||
.update_index = 0xa,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = {
|
||||
.update = {
|
||||
.old_hash = { 1 },
|
||||
.new_hash = { 2 },
|
||||
.name = "Han-Wen Nienhuys",
|
||||
.email = "hanwen@google.com",
|
||||
.tz_offset = 100,
|
||||
.time = 0x5e430672,
|
||||
.message = msg,
|
||||
},
|
||||
},
|
||||
};
|
||||
struct reftable_writer *w =
|
||||
reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
|
||||
|
||||
uint8_t hash1[GIT_SHA1_RAWSZ] = {1}, hash2[GIT_SHA1_RAWSZ] = { 2 };
|
||||
|
||||
memset(msg, 'x', sizeof(msg) - 1);
|
||||
log.value.update.old_hash = hash1;
|
||||
log.value.update.new_hash = hash2;
|
||||
reftable_writer_set_limits(w, update_index, update_index);
|
||||
err = reftable_writer_add_log(w, &log);
|
||||
EXPECT(err == REFTABLE_ENTRY_TOO_BIG_ERROR);
|
||||
|
@ -219,16 +214,13 @@ static void test_log_write_read(void)
|
|||
EXPECT_ERR(err);
|
||||
}
|
||||
for (i = 0; i < N; i++) {
|
||||
uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
|
||||
struct reftable_log_record log = { NULL };
|
||||
set_test_hash(hash1, i);
|
||||
set_test_hash(hash2, i + 1);
|
||||
|
||||
log.refname = names[i];
|
||||
log.update_index = i;
|
||||
log.value_type = REFTABLE_LOG_UPDATE;
|
||||
log.value.update.old_hash = hash1;
|
||||
log.value.update.new_hash = hash2;
|
||||
set_test_hash(log.value.update.old_hash, i);
|
||||
set_test_hash(log.value.update.new_hash, i + 1);
|
||||
|
||||
err = reftable_writer_add_log(w, &log);
|
||||
EXPECT_ERR(err);
|
||||
|
@ -298,18 +290,15 @@ static void test_log_zlib_corruption(void)
|
|||
struct reftable_writer *w =
|
||||
reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
|
||||
const struct reftable_stats *stats = NULL;
|
||||
uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
|
||||
uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
|
||||
char message[100] = { 0 };
|
||||
int err, i, n;
|
||||
|
||||
struct reftable_log_record log = {
|
||||
.refname = "refname",
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = {
|
||||
.update = {
|
||||
.new_hash = hash1,
|
||||
.old_hash = hash2,
|
||||
.new_hash = { 1 },
|
||||
.old_hash = { 2 },
|
||||
.name = "My Name",
|
||||
.email = "myname@invalid",
|
||||
.message = message,
|
||||
|
@ -821,13 +810,12 @@ static void test_write_multiple_indices(void)
|
|||
}
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
unsigned char hash[GIT_SHA1_RAWSZ] = {i};
|
||||
struct reftable_log_record log = {
|
||||
.update_index = 1,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value.update = {
|
||||
.old_hash = hash,
|
||||
.new_hash = hash,
|
||||
.old_hash = { i },
|
||||
.new_hash = { i },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -374,7 +374,7 @@ static int reftable_ref_record_encode(const void *rec, struct string_view s,
|
|||
|
||||
static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
||||
uint8_t val_type, struct string_view in,
|
||||
int hash_size)
|
||||
int hash_size, struct strbuf *scratch)
|
||||
{
|
||||
struct reftable_ref_record *r = rec;
|
||||
struct string_view start = in;
|
||||
|
@ -425,13 +425,12 @@ static int reftable_ref_record_decode(void *rec, struct strbuf key,
|
|||
break;
|
||||
|
||||
case REFTABLE_REF_SYMREF: {
|
||||
struct strbuf dest = STRBUF_INIT;
|
||||
int n = decode_string(&dest, in);
|
||||
int n = decode_string(scratch, in);
|
||||
if (n < 0) {
|
||||
return -1;
|
||||
}
|
||||
string_view_consume(&in, n);
|
||||
r->value.symref = dest.buf;
|
||||
r->value.symref = strbuf_detach(scratch, NULL);
|
||||
} break;
|
||||
|
||||
case REFTABLE_REF_DELETION:
|
||||
|
@ -579,7 +578,7 @@ static int reftable_obj_record_encode(const void *rec, struct string_view s,
|
|||
|
||||
static int reftable_obj_record_decode(void *rec, struct strbuf key,
|
||||
uint8_t val_type, struct string_view in,
|
||||
int hash_size)
|
||||
int hash_size, struct strbuf *scratch UNUSED)
|
||||
{
|
||||
struct string_view start = in;
|
||||
struct reftable_obj_record *r = rec;
|
||||
|
@ -765,16 +764,10 @@ static void reftable_log_record_copy_from(void *rec, const void *src_rec,
|
|||
xstrdup(dst->value.update.message);
|
||||
}
|
||||
|
||||
if (dst->value.update.new_hash) {
|
||||
REFTABLE_ALLOC_ARRAY(dst->value.update.new_hash, hash_size);
|
||||
memcpy(dst->value.update.new_hash,
|
||||
src->value.update.new_hash, hash_size);
|
||||
}
|
||||
if (dst->value.update.old_hash) {
|
||||
REFTABLE_ALLOC_ARRAY(dst->value.update.old_hash, hash_size);
|
||||
memcpy(dst->value.update.old_hash,
|
||||
src->value.update.old_hash, hash_size);
|
||||
}
|
||||
memcpy(dst->value.update.new_hash,
|
||||
src->value.update.new_hash, hash_size);
|
||||
memcpy(dst->value.update.old_hash,
|
||||
src->value.update.old_hash, hash_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -792,8 +785,6 @@ void reftable_log_record_release(struct reftable_log_record *r)
|
|||
case REFTABLE_LOG_DELETION:
|
||||
break;
|
||||
case REFTABLE_LOG_UPDATE:
|
||||
reftable_free(r->value.update.new_hash);
|
||||
reftable_free(r->value.update.old_hash);
|
||||
reftable_free(r->value.update.name);
|
||||
reftable_free(r->value.update.email);
|
||||
reftable_free(r->value.update.message);
|
||||
|
@ -810,33 +801,20 @@ static uint8_t reftable_log_record_val_type(const void *rec)
|
|||
return reftable_log_record_is_deletion(log) ? 0 : 1;
|
||||
}
|
||||
|
||||
static uint8_t zero[GIT_SHA256_RAWSZ] = { 0 };
|
||||
|
||||
static int reftable_log_record_encode(const void *rec, struct string_view s,
|
||||
int hash_size)
|
||||
{
|
||||
const struct reftable_log_record *r = rec;
|
||||
struct string_view start = s;
|
||||
int n = 0;
|
||||
uint8_t *oldh = NULL;
|
||||
uint8_t *newh = NULL;
|
||||
if (reftable_log_record_is_deletion(r))
|
||||
return 0;
|
||||
|
||||
oldh = r->value.update.old_hash;
|
||||
newh = r->value.update.new_hash;
|
||||
if (!oldh) {
|
||||
oldh = zero;
|
||||
}
|
||||
if (!newh) {
|
||||
newh = zero;
|
||||
}
|
||||
|
||||
if (s.len < 2 * hash_size)
|
||||
return -1;
|
||||
|
||||
memcpy(s.buf, oldh, hash_size);
|
||||
memcpy(s.buf + hash_size, newh, hash_size);
|
||||
memcpy(s.buf, r->value.update.old_hash, hash_size);
|
||||
memcpy(s.buf + hash_size, r->value.update.new_hash, hash_size);
|
||||
string_view_consume(&s, 2 * hash_size);
|
||||
|
||||
n = encode_string(r->value.update.name ? r->value.update.name : "", s);
|
||||
|
@ -872,19 +850,18 @@ static int reftable_log_record_encode(const void *rec, struct string_view s,
|
|||
|
||||
static int reftable_log_record_decode(void *rec, struct strbuf key,
|
||||
uint8_t val_type, struct string_view in,
|
||||
int hash_size)
|
||||
int hash_size, struct strbuf *scratch)
|
||||
{
|
||||
struct string_view start = in;
|
||||
struct reftable_log_record *r = rec;
|
||||
uint64_t max = 0;
|
||||
uint64_t ts = 0;
|
||||
struct strbuf dest = STRBUF_INIT;
|
||||
int n;
|
||||
|
||||
if (key.len <= 9 || key.buf[key.len - 9] != 0)
|
||||
return REFTABLE_FORMAT_ERROR;
|
||||
|
||||
r->refname = reftable_realloc(r->refname, key.len - 8);
|
||||
REFTABLE_ALLOC_GROW(r->refname, key.len - 8, r->refname_cap);
|
||||
memcpy(r->refname, key.buf, key.len - 8);
|
||||
ts = get_be64(key.buf + key.len - 8);
|
||||
|
||||
|
@ -893,9 +870,8 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
if (val_type != r->value_type) {
|
||||
switch (r->value_type) {
|
||||
case REFTABLE_LOG_UPDATE:
|
||||
FREE_AND_NULL(r->value.update.old_hash);
|
||||
FREE_AND_NULL(r->value.update.new_hash);
|
||||
FREE_AND_NULL(r->value.update.message);
|
||||
r->value.update.message_cap = 0;
|
||||
FREE_AND_NULL(r->value.update.email);
|
||||
FREE_AND_NULL(r->value.update.name);
|
||||
break;
|
||||
|
@ -911,36 +887,43 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
if (in.len < 2 * hash_size)
|
||||
return REFTABLE_FORMAT_ERROR;
|
||||
|
||||
r->value.update.old_hash =
|
||||
reftable_realloc(r->value.update.old_hash, hash_size);
|
||||
r->value.update.new_hash =
|
||||
reftable_realloc(r->value.update.new_hash, hash_size);
|
||||
|
||||
memcpy(r->value.update.old_hash, in.buf, hash_size);
|
||||
memcpy(r->value.update.new_hash, in.buf + hash_size, hash_size);
|
||||
|
||||
string_view_consume(&in, 2 * hash_size);
|
||||
|
||||
n = decode_string(&dest, in);
|
||||
n = decode_string(scratch, in);
|
||||
if (n < 0)
|
||||
goto done;
|
||||
string_view_consume(&in, n);
|
||||
|
||||
r->value.update.name =
|
||||
reftable_realloc(r->value.update.name, dest.len + 1);
|
||||
memcpy(r->value.update.name, dest.buf, dest.len);
|
||||
r->value.update.name[dest.len] = 0;
|
||||
/*
|
||||
* In almost all cases we can expect the reflog name to not change for
|
||||
* reflog entries as they are tied to the local identity, not to the
|
||||
* target commits. As an optimization for this common case we can thus
|
||||
* skip copying over the name in case it's accurate already.
|
||||
*/
|
||||
if (!r->value.update.name ||
|
||||
strcmp(r->value.update.name, scratch->buf)) {
|
||||
r->value.update.name =
|
||||
reftable_realloc(r->value.update.name, scratch->len + 1);
|
||||
memcpy(r->value.update.name, scratch->buf, scratch->len);
|
||||
r->value.update.name[scratch->len] = 0;
|
||||
}
|
||||
|
||||
strbuf_reset(&dest);
|
||||
n = decode_string(&dest, in);
|
||||
n = decode_string(scratch, in);
|
||||
if (n < 0)
|
||||
goto done;
|
||||
string_view_consume(&in, n);
|
||||
|
||||
r->value.update.email =
|
||||
reftable_realloc(r->value.update.email, dest.len + 1);
|
||||
memcpy(r->value.update.email, dest.buf, dest.len);
|
||||
r->value.update.email[dest.len] = 0;
|
||||
/* Same as above, but for the reflog email. */
|
||||
if (!r->value.update.email ||
|
||||
strcmp(r->value.update.email, scratch->buf)) {
|
||||
r->value.update.email =
|
||||
reftable_realloc(r->value.update.email, scratch->len + 1);
|
||||
memcpy(r->value.update.email, scratch->buf, scratch->len);
|
||||
r->value.update.email[scratch->len] = 0;
|
||||
}
|
||||
|
||||
ts = 0;
|
||||
n = get_var_int(&ts, &in);
|
||||
|
@ -954,22 +937,19 @@ static int reftable_log_record_decode(void *rec, struct strbuf key,
|
|||
r->value.update.tz_offset = get_be16(in.buf);
|
||||
string_view_consume(&in, 2);
|
||||
|
||||
strbuf_reset(&dest);
|
||||
n = decode_string(&dest, in);
|
||||
n = decode_string(scratch, in);
|
||||
if (n < 0)
|
||||
goto done;
|
||||
string_view_consume(&in, n);
|
||||
|
||||
r->value.update.message =
|
||||
reftable_realloc(r->value.update.message, dest.len + 1);
|
||||
memcpy(r->value.update.message, dest.buf, dest.len);
|
||||
r->value.update.message[dest.len] = 0;
|
||||
REFTABLE_ALLOC_GROW(r->value.update.message, scratch->len + 1,
|
||||
r->value.update.message_cap);
|
||||
memcpy(r->value.update.message, scratch->buf, scratch->len);
|
||||
r->value.update.message[scratch->len] = 0;
|
||||
|
||||
strbuf_release(&dest);
|
||||
return start.len - in.len;
|
||||
|
||||
done:
|
||||
strbuf_release(&dest);
|
||||
return REFTABLE_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
|
@ -985,17 +965,6 @@ static int null_streq(char *a, char *b)
|
|||
return 0 == strcmp(a, b);
|
||||
}
|
||||
|
||||
static int zero_hash_eq(uint8_t *a, uint8_t *b, int sz)
|
||||
{
|
||||
if (!a)
|
||||
a = zero;
|
||||
|
||||
if (!b)
|
||||
b = zero;
|
||||
|
||||
return !memcmp(a, b, sz);
|
||||
}
|
||||
|
||||
static int reftable_log_record_equal_void(const void *a,
|
||||
const void *b, int hash_size)
|
||||
{
|
||||
|
@ -1039,10 +1008,10 @@ int reftable_log_record_equal(const struct reftable_log_record *a,
|
|||
b->value.update.email) &&
|
||||
null_streq(a->value.update.message,
|
||||
b->value.update.message) &&
|
||||
zero_hash_eq(a->value.update.old_hash,
|
||||
b->value.update.old_hash, hash_size) &&
|
||||
zero_hash_eq(a->value.update.new_hash,
|
||||
b->value.update.new_hash, hash_size);
|
||||
!memcmp(a->value.update.old_hash,
|
||||
b->value.update.old_hash, hash_size) &&
|
||||
!memcmp(a->value.update.new_hash,
|
||||
b->value.update.new_hash, hash_size);
|
||||
}
|
||||
|
||||
abort();
|
||||
|
@ -1120,7 +1089,7 @@ static int reftable_index_record_encode(const void *rec, struct string_view out,
|
|||
|
||||
static int reftable_index_record_decode(void *rec, struct strbuf key,
|
||||
uint8_t val_type, struct string_view in,
|
||||
int hash_size)
|
||||
int hash_size, struct strbuf *scratch UNUSED)
|
||||
{
|
||||
struct string_view start = in;
|
||||
struct reftable_index_record *r = rec;
|
||||
|
@ -1201,10 +1170,12 @@ uint8_t reftable_record_val_type(struct reftable_record *rec)
|
|||
}
|
||||
|
||||
int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
|
||||
uint8_t extra, struct string_view src, int hash_size)
|
||||
uint8_t extra, struct string_view src, int hash_size,
|
||||
struct strbuf *scratch)
|
||||
{
|
||||
return reftable_record_vtable(rec)->decode(reftable_record_data(rec),
|
||||
key, extra, src, hash_size);
|
||||
key, extra, src, hash_size,
|
||||
scratch);
|
||||
}
|
||||
|
||||
void reftable_record_release(struct reftable_record *rec)
|
||||
|
|
|
@ -55,7 +55,8 @@ struct reftable_record_vtable {
|
|||
|
||||
/* decode data from `src` into the record. */
|
||||
int (*decode)(void *rec, struct strbuf key, uint8_t extra,
|
||||
struct string_view src, int hash_size);
|
||||
struct string_view src, int hash_size,
|
||||
struct strbuf *scratch);
|
||||
|
||||
/* deallocate and null the record. */
|
||||
void (*release)(void *rec);
|
||||
|
@ -138,7 +139,7 @@ int reftable_record_encode(struct reftable_record *rec, struct string_view dest,
|
|||
int hash_size);
|
||||
int reftable_record_decode(struct reftable_record *rec, struct strbuf key,
|
||||
uint8_t extra, struct string_view src,
|
||||
int hash_size);
|
||||
int hash_size, struct strbuf *scratch);
|
||||
int reftable_record_is_deletion(struct reftable_record *rec);
|
||||
|
||||
static inline uint8_t reftable_record_type(struct reftable_record *rec)
|
||||
|
|
|
@ -99,6 +99,7 @@ static void set_hash(uint8_t *h, int j)
|
|||
|
||||
static void test_reftable_ref_record_roundtrip(void)
|
||||
{
|
||||
struct strbuf scratch = STRBUF_INIT;
|
||||
int i = 0;
|
||||
|
||||
for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) {
|
||||
|
@ -140,7 +141,7 @@ static void test_reftable_ref_record_roundtrip(void)
|
|||
EXPECT(n > 0);
|
||||
|
||||
/* decode into a non-zero reftable_record to test for leaks. */
|
||||
m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ);
|
||||
m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch);
|
||||
EXPECT(n == m);
|
||||
|
||||
EXPECT(reftable_ref_record_equal(&in.u.ref, &out.u.ref,
|
||||
|
@ -150,6 +151,8 @@ static void test_reftable_ref_record_roundtrip(void)
|
|||
strbuf_release(&key);
|
||||
reftable_record_release(&out);
|
||||
}
|
||||
|
||||
strbuf_release(&scratch);
|
||||
}
|
||||
|
||||
static void test_reftable_log_record_equal(void)
|
||||
|
@ -175,7 +178,6 @@ static void test_reftable_log_record_equal(void)
|
|||
static void test_reftable_log_record_roundtrip(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct reftable_log_record in[] = {
|
||||
{
|
||||
.refname = xstrdup("refs/heads/master"),
|
||||
|
@ -183,8 +185,6 @@ static void test_reftable_log_record_roundtrip(void)
|
|||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = {
|
||||
.update = {
|
||||
.old_hash = reftable_malloc(GIT_SHA1_RAWSZ),
|
||||
.new_hash = reftable_malloc(GIT_SHA1_RAWSZ),
|
||||
.name = xstrdup("han-wen"),
|
||||
.email = xstrdup("hanwen@google.com"),
|
||||
.message = xstrdup("test"),
|
||||
|
@ -202,15 +202,10 @@ static void test_reftable_log_record_roundtrip(void)
|
|||
.refname = xstrdup("branch"),
|
||||
.update_index = 33,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = {
|
||||
.update = {
|
||||
.old_hash = reftable_malloc(GIT_SHA1_RAWSZ),
|
||||
.new_hash = reftable_malloc(GIT_SHA1_RAWSZ),
|
||||
/* rest of fields left empty. */
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
struct strbuf scratch = STRBUF_INIT;
|
||||
|
||||
set_test_hash(in[0].value.update.new_hash, 1);
|
||||
set_test_hash(in[0].value.update.old_hash, 2);
|
||||
set_test_hash(in[2].value.update.new_hash, 3);
|
||||
|
@ -231,8 +226,6 @@ static void test_reftable_log_record_roundtrip(void)
|
|||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = {
|
||||
.update = {
|
||||
.new_hash = reftable_calloc(GIT_SHA1_RAWSZ, 1),
|
||||
.old_hash = reftable_calloc(GIT_SHA1_RAWSZ, 1),
|
||||
.name = xstrdup("old name"),
|
||||
.email = xstrdup("old@email"),
|
||||
.message = xstrdup("old message"),
|
||||
|
@ -252,7 +245,7 @@ static void test_reftable_log_record_roundtrip(void)
|
|||
EXPECT(n >= 0);
|
||||
valtype = reftable_record_val_type(&rec);
|
||||
m = reftable_record_decode(&out, key, valtype, dest,
|
||||
GIT_SHA1_RAWSZ);
|
||||
GIT_SHA1_RAWSZ, &scratch);
|
||||
EXPECT(n == m);
|
||||
|
||||
EXPECT(reftable_log_record_equal(&in[i], &out.u.log,
|
||||
|
@ -261,6 +254,8 @@ static void test_reftable_log_record_roundtrip(void)
|
|||
strbuf_release(&key);
|
||||
reftable_record_release(&out);
|
||||
}
|
||||
|
||||
strbuf_release(&scratch);
|
||||
}
|
||||
|
||||
static void test_u24_roundtrip(void)
|
||||
|
@ -310,23 +305,27 @@ static void test_reftable_obj_record_roundtrip(void)
|
|||
{
|
||||
uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 };
|
||||
uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 };
|
||||
struct reftable_obj_record recs[3] = { {
|
||||
.hash_prefix = testHash1,
|
||||
.hash_prefix_len = 5,
|
||||
.offsets = till9,
|
||||
.offset_len = 3,
|
||||
},
|
||||
{
|
||||
.hash_prefix = testHash1,
|
||||
.hash_prefix_len = 5,
|
||||
.offsets = till9,
|
||||
.offset_len = 9,
|
||||
},
|
||||
{
|
||||
.hash_prefix = testHash1,
|
||||
.hash_prefix_len = 5,
|
||||
} };
|
||||
struct reftable_obj_record recs[3] = {
|
||||
{
|
||||
.hash_prefix = testHash1,
|
||||
.hash_prefix_len = 5,
|
||||
.offsets = till9,
|
||||
.offset_len = 3,
|
||||
},
|
||||
{
|
||||
.hash_prefix = testHash1,
|
||||
.hash_prefix_len = 5,
|
||||
.offsets = till9,
|
||||
.offset_len = 9,
|
||||
},
|
||||
{
|
||||
.hash_prefix = testHash1,
|
||||
.hash_prefix_len = 5,
|
||||
},
|
||||
};
|
||||
struct strbuf scratch = STRBUF_INIT;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(recs); i++) {
|
||||
uint8_t buffer[1024] = { 0 };
|
||||
struct string_view dest = {
|
||||
|
@ -350,13 +349,15 @@ static void test_reftable_obj_record_roundtrip(void)
|
|||
EXPECT(n > 0);
|
||||
extra = reftable_record_val_type(&in);
|
||||
m = reftable_record_decode(&out, key, extra, dest,
|
||||
GIT_SHA1_RAWSZ);
|
||||
GIT_SHA1_RAWSZ, &scratch);
|
||||
EXPECT(n == m);
|
||||
|
||||
EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
|
||||
strbuf_release(&key);
|
||||
reftable_record_release(&out);
|
||||
}
|
||||
|
||||
strbuf_release(&scratch);
|
||||
}
|
||||
|
||||
static void test_reftable_index_record_roundtrip(void)
|
||||
|
@ -373,6 +374,7 @@ static void test_reftable_index_record_roundtrip(void)
|
|||
.buf = buffer,
|
||||
.len = sizeof(buffer),
|
||||
};
|
||||
struct strbuf scratch = STRBUF_INIT;
|
||||
struct strbuf key = STRBUF_INIT;
|
||||
struct reftable_record out = {
|
||||
.type = BLOCK_TYPE_INDEX,
|
||||
|
@ -390,13 +392,15 @@ static void test_reftable_index_record_roundtrip(void)
|
|||
EXPECT(n > 0);
|
||||
|
||||
extra = reftable_record_val_type(&in);
|
||||
m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ);
|
||||
m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ,
|
||||
&scratch);
|
||||
EXPECT(m == n);
|
||||
|
||||
EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ));
|
||||
|
||||
reftable_record_release(&out);
|
||||
strbuf_release(&key);
|
||||
strbuf_release(&scratch);
|
||||
strbuf_release(&in.u.idx.last_key);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ int reftable_ref_record_equal(const struct reftable_ref_record *a,
|
|||
/* reftable_log_record holds a reflog entry */
|
||||
struct reftable_log_record {
|
||||
char *refname;
|
||||
size_t refname_cap;
|
||||
uint64_t update_index; /* logical timestamp of a transactional update.
|
||||
*/
|
||||
|
||||
|
@ -88,13 +89,14 @@ struct reftable_log_record {
|
|||
|
||||
union {
|
||||
struct {
|
||||
uint8_t *new_hash;
|
||||
uint8_t *old_hash;
|
||||
unsigned char new_hash[GIT_MAX_RAWSZ];
|
||||
unsigned char old_hash[GIT_MAX_RAWSZ];
|
||||
char *name;
|
||||
char *email;
|
||||
uint64_t time;
|
||||
int16_t tz_offset;
|
||||
char *message;
|
||||
size_t message_cap;
|
||||
} update;
|
||||
} value;
|
||||
};
|
||||
|
|
|
@ -468,8 +468,6 @@ static void test_reftable_stack_add(void)
|
|||
logs[i].refname = xstrdup(buf);
|
||||
logs[i].update_index = N + i + 1;
|
||||
logs[i].value_type = REFTABLE_LOG_UPDATE;
|
||||
|
||||
logs[i].value.update.new_hash = reftable_malloc(GIT_SHA1_RAWSZ);
|
||||
logs[i].value.update.email = xstrdup("identity@invalid");
|
||||
set_test_hash(logs[i].value.update.new_hash, i);
|
||||
}
|
||||
|
@ -547,16 +545,17 @@ static void test_reftable_stack_log_normalize(void)
|
|||
};
|
||||
struct reftable_stack *st = NULL;
|
||||
char *dir = get_tmp_dir(__LINE__);
|
||||
|
||||
uint8_t h1[GIT_SHA1_RAWSZ] = { 0x01 }, h2[GIT_SHA1_RAWSZ] = { 0x02 };
|
||||
|
||||
struct reftable_log_record input = { .refname = "branch",
|
||||
.update_index = 1,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = { .update = {
|
||||
.new_hash = h1,
|
||||
.old_hash = h2,
|
||||
} } };
|
||||
struct reftable_log_record input = {
|
||||
.refname = "branch",
|
||||
.update_index = 1,
|
||||
.value_type = REFTABLE_LOG_UPDATE,
|
||||
.value = {
|
||||
.update = {
|
||||
.new_hash = { 1 },
|
||||
.old_hash = { 2 },
|
||||
},
|
||||
},
|
||||
};
|
||||
struct reftable_log_record dest = {
|
||||
.update_index = 0,
|
||||
};
|
||||
|
@ -627,8 +626,6 @@ static void test_reftable_stack_tombstone(void)
|
|||
logs[i].update_index = 42;
|
||||
if (i % 2 == 0) {
|
||||
logs[i].value_type = REFTABLE_LOG_UPDATE;
|
||||
logs[i].value.update.new_hash =
|
||||
reftable_malloc(GIT_SHA1_RAWSZ);
|
||||
set_test_hash(logs[i].value.update.new_hash, i);
|
||||
logs[i].value.update.email =
|
||||
xstrdup("identity@invalid");
|
||||
|
@ -810,7 +807,6 @@ static void test_reflog_expire(void)
|
|||
logs[i].update_index = i;
|
||||
logs[i].value_type = REFTABLE_LOG_UPDATE;
|
||||
logs[i].value.update.time = i;
|
||||
logs[i].value.update.new_hash = reftable_malloc(GIT_SHA1_RAWSZ);
|
||||
logs[i].value.update.email = xstrdup("identity@invalid");
|
||||
set_test_hash(logs[i].value.update.new_hash, i);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue