Merge branch 'ps/reftable-drop-generic' into ps/reftable-concurrent-compaction
* ps/reftable-drop-generic: (24 commits) reftable/generic: drop interface t/helper: refactor to not use `struct reftable_table` t/helper: use `hash_to_hex_algop()` to print hashes t/helper: inline printing of reftable records t/helper: inline `reftable_table_print()` t/helper: inline `reftable_stack_print_directory()` t/helper: inline `reftable_reader_print_file()` t/helper: inline `reftable_dump_main()` reftable/dump: drop unused `compact_stack()` reftable/generic: move generic iterator code into iterator interface reftable/iter: drop double-checking logic reftable/stack: open-code reading refs reftable/merged: stop using generic tables in the merged table reftable/merged: rename `reftable_new_merged_table()` reftable/merged: expose functions to initialize iterators reftable/stack: handle locked tables during auto-compaction reftable/stack: fix corruption on concurrent compaction reftable/stack: use lock_file when adding table to "tables.list" reftable/stack: do not die when fsyncing lock file files reftable/stack: simplify tracking of table locks ...maint
commit
f975a3a38c
2
Makefile
2
Makefile
|
@ -2674,13 +2674,11 @@ REFTABLE_OBJS += reftable/merged.o
|
|||
REFTABLE_OBJS += reftable/pq.o
|
||||
REFTABLE_OBJS += reftable/reader.o
|
||||
REFTABLE_OBJS += reftable/record.o
|
||||
REFTABLE_OBJS += reftable/generic.o
|
||||
REFTABLE_OBJS += reftable/stack.o
|
||||
REFTABLE_OBJS += reftable/tree.o
|
||||
REFTABLE_OBJS += reftable/writer.o
|
||||
|
||||
REFTABLE_TEST_OBJS += reftable/block_test.o
|
||||
REFTABLE_TEST_OBJS += reftable/dump.o
|
||||
REFTABLE_TEST_OBJS += reftable/pq_test.o
|
||||
REFTABLE_TEST_OBJS += reftable/readwrite_test.o
|
||||
REFTABLE_TEST_OBJS += reftable/stack_test.o
|
||||
|
|
111
reftable/dump.c
111
reftable/dump.c
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 Google LLC
|
||||
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://developers.google.com/open-source/licenses/bsd
|
||||
*/
|
||||
|
||||
#include "git-compat-util.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "reftable-blocksource.h"
|
||||
#include "reftable-error.h"
|
||||
#include "reftable-record.h"
|
||||
#include "reftable-tests.h"
|
||||
#include "reftable-writer.h"
|
||||
#include "reftable-iterator.h"
|
||||
#include "reftable-reader.h"
|
||||
#include "reftable-stack.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
static int compact_stack(const char *stackdir)
|
||||
{
|
||||
struct reftable_stack *stack = NULL;
|
||||
struct reftable_write_options opts = { 0 };
|
||||
|
||||
int err = reftable_new_stack(&stack, stackdir, &opts);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
err = reftable_stack_compact_all(stack, NULL);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
done:
|
||||
if (stack) {
|
||||
reftable_stack_destroy(stack);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf("usage: dump [-cst] arg\n\n"
|
||||
"options: \n"
|
||||
" -c compact\n"
|
||||
" -b dump blocks\n"
|
||||
" -t dump table\n"
|
||||
" -s dump stack\n"
|
||||
" -6 sha256 hash format\n"
|
||||
" -h this help\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
int reftable_dump_main(int argc, char *const *argv)
|
||||
{
|
||||
int err = 0;
|
||||
int opt_dump_blocks = 0;
|
||||
int opt_dump_table = 0;
|
||||
int opt_dump_stack = 0;
|
||||
int opt_compact = 0;
|
||||
uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
|
||||
const char *arg = NULL, *argv0 = argv[0];
|
||||
|
||||
for (; argc > 1; argv++, argc--)
|
||||
if (*argv[1] != '-')
|
||||
break;
|
||||
else if (!strcmp("-b", argv[1]))
|
||||
opt_dump_blocks = 1;
|
||||
else if (!strcmp("-t", argv[1]))
|
||||
opt_dump_table = 1;
|
||||
else if (!strcmp("-6", argv[1]))
|
||||
opt_hash_id = GIT_SHA256_FORMAT_ID;
|
||||
else if (!strcmp("-s", argv[1]))
|
||||
opt_dump_stack = 1;
|
||||
else if (!strcmp("-c", argv[1]))
|
||||
opt_compact = 1;
|
||||
else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
|
||||
print_help();
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "need argument\n");
|
||||
print_help();
|
||||
return 2;
|
||||
}
|
||||
|
||||
arg = argv[1];
|
||||
|
||||
if (opt_dump_blocks) {
|
||||
err = reftable_reader_print_blocks(arg);
|
||||
} else if (opt_dump_table) {
|
||||
err = reftable_reader_print_file(arg);
|
||||
} else if (opt_dump_stack) {
|
||||
err = reftable_stack_print_directory(arg, opt_hash_id);
|
||||
} else if (opt_compact) {
|
||||
err = compact_stack(arg);
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv0, arg,
|
||||
reftable_error_str(err));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 Google LLC
|
||||
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://developers.google.com/open-source/licenses/bsd
|
||||
*/
|
||||
|
||||
#include "constants.h"
|
||||
#include "record.h"
|
||||
#include "generic.h"
|
||||
#include "reftable-iterator.h"
|
||||
#include "reftable-generic.h"
|
||||
|
||||
void table_init_iter(struct reftable_table *tab,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
{
|
||||
|
||||
tab->ops->init_iter(tab->table_arg, it, typ);
|
||||
}
|
||||
|
||||
void reftable_table_init_ref_iter(struct reftable_table *tab,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
table_init_iter(tab, it, BLOCK_TYPE_REF);
|
||||
}
|
||||
|
||||
void reftable_table_init_log_iter(struct reftable_table *tab,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
table_init_iter(tab, it, BLOCK_TYPE_LOG);
|
||||
}
|
||||
|
||||
int reftable_iterator_seek_ref(struct reftable_iterator *it,
|
||||
const char *name)
|
||||
{
|
||||
struct reftable_record want = {
|
||||
.type = BLOCK_TYPE_REF,
|
||||
.u.ref = {
|
||||
.refname = (char *)name,
|
||||
},
|
||||
};
|
||||
return it->ops->seek(it->iter_arg, &want);
|
||||
}
|
||||
|
||||
int reftable_iterator_seek_log_at(struct reftable_iterator *it,
|
||||
const char *name, uint64_t update_index)
|
||||
{
|
||||
struct reftable_record want = {
|
||||
.type = BLOCK_TYPE_LOG,
|
||||
.u.log = {
|
||||
.refname = (char *)name,
|
||||
.update_index = update_index,
|
||||
},
|
||||
};
|
||||
return it->ops->seek(it->iter_arg, &want);
|
||||
}
|
||||
|
||||
int reftable_iterator_seek_log(struct reftable_iterator *it,
|
||||
const char *name)
|
||||
{
|
||||
return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
|
||||
}
|
||||
|
||||
int reftable_table_read_ref(struct reftable_table *tab, const char *name,
|
||||
struct reftable_ref_record *ref)
|
||||
{
|
||||
struct reftable_iterator it = { NULL };
|
||||
int err;
|
||||
|
||||
reftable_table_init_ref_iter(tab, &it);
|
||||
|
||||
err = reftable_iterator_seek_ref(&it, name);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
err = reftable_iterator_next_ref(&it, ref);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
if (strcmp(ref->refname, name) ||
|
||||
reftable_ref_record_is_deletion(ref)) {
|
||||
reftable_ref_record_release(ref);
|
||||
err = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
reftable_iterator_destroy(&it);
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_table_print(struct reftable_table *tab) {
|
||||
struct reftable_iterator it = { NULL };
|
||||
struct reftable_ref_record ref = { NULL };
|
||||
struct reftable_log_record log = { NULL };
|
||||
uint32_t hash_id = reftable_table_hash_id(tab);
|
||||
int err;
|
||||
|
||||
reftable_table_init_ref_iter(tab, &it);
|
||||
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
while (1) {
|
||||
err = reftable_iterator_next_ref(&it, &ref);
|
||||
if (err > 0) {
|
||||
break;
|
||||
}
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
reftable_ref_record_print(&ref, hash_id);
|
||||
}
|
||||
reftable_iterator_destroy(&it);
|
||||
reftable_ref_record_release(&ref);
|
||||
|
||||
reftable_table_init_log_iter(tab, &it);
|
||||
|
||||
err = reftable_iterator_seek_log(&it, "");
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
while (1) {
|
||||
err = reftable_iterator_next_log(&it, &log);
|
||||
if (err > 0) {
|
||||
break;
|
||||
}
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
reftable_log_record_print(&log, hash_id);
|
||||
}
|
||||
reftable_iterator_destroy(&it);
|
||||
reftable_log_record_release(&log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t reftable_table_max_update_index(struct reftable_table *tab)
|
||||
{
|
||||
return tab->ops->max_update_index(tab->table_arg);
|
||||
}
|
||||
|
||||
uint64_t reftable_table_min_update_index(struct reftable_table *tab)
|
||||
{
|
||||
return tab->ops->min_update_index(tab->table_arg);
|
||||
}
|
||||
|
||||
uint32_t reftable_table_hash_id(struct reftable_table *tab)
|
||||
{
|
||||
return tab->ops->hash_id(tab->table_arg);
|
||||
}
|
||||
|
||||
void reftable_iterator_destroy(struct reftable_iterator *it)
|
||||
{
|
||||
if (!it->ops) {
|
||||
return;
|
||||
}
|
||||
it->ops->close(it->iter_arg);
|
||||
it->ops = NULL;
|
||||
FREE_AND_NULL(it->iter_arg);
|
||||
}
|
||||
|
||||
int reftable_iterator_next_ref(struct reftable_iterator *it,
|
||||
struct reftable_ref_record *ref)
|
||||
{
|
||||
struct reftable_record rec = {
|
||||
.type = BLOCK_TYPE_REF,
|
||||
.u = {
|
||||
.ref = *ref
|
||||
},
|
||||
};
|
||||
int err = iterator_next(it, &rec);
|
||||
*ref = rec.u.ref;
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_iterator_next_log(struct reftable_iterator *it,
|
||||
struct reftable_log_record *log)
|
||||
{
|
||||
struct reftable_record rec = {
|
||||
.type = BLOCK_TYPE_LOG,
|
||||
.u = {
|
||||
.log = *log,
|
||||
},
|
||||
};
|
||||
int err = iterator_next(it, &rec);
|
||||
*log = rec.u.log;
|
||||
return err;
|
||||
}
|
||||
|
||||
int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
|
||||
{
|
||||
return it->ops->seek(it->iter_arg, want);
|
||||
}
|
||||
|
||||
int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
|
||||
{
|
||||
return it->ops->next(it->iter_arg, rec);
|
||||
}
|
||||
|
||||
static int empty_iterator_seek(void *arg, struct reftable_record *want)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int empty_iterator_next(void *arg, struct reftable_record *rec)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void empty_iterator_close(void *arg)
|
||||
{
|
||||
}
|
||||
|
||||
static struct reftable_iterator_vtable empty_vtable = {
|
||||
.seek = &empty_iterator_seek,
|
||||
.next = &empty_iterator_next,
|
||||
.close = &empty_iterator_close,
|
||||
};
|
||||
|
||||
void iterator_set_empty(struct reftable_iterator *it)
|
||||
{
|
||||
assert(!it->ops);
|
||||
it->iter_arg = NULL;
|
||||
it->ops = &empty_vtable;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 Google LLC
|
||||
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://developers.google.com/open-source/licenses/bsd
|
||||
*/
|
||||
|
||||
#ifndef GENERIC_H
|
||||
#define GENERIC_H
|
||||
|
||||
#include "record.h"
|
||||
#include "reftable-generic.h"
|
||||
|
||||
/* generic interface to reftables */
|
||||
struct reftable_table_vtable {
|
||||
void (*init_iter)(void *tab, struct reftable_iterator *it, uint8_t typ);
|
||||
uint32_t (*hash_id)(void *tab);
|
||||
uint64_t (*min_update_index)(void *tab);
|
||||
uint64_t (*max_update_index)(void *tab);
|
||||
};
|
||||
|
||||
void table_init_iter(struct reftable_table *tab,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ);
|
||||
|
||||
struct reftable_iterator_vtable {
|
||||
int (*seek)(void *iter_arg, struct reftable_record *want);
|
||||
int (*next)(void *iter_arg, struct reftable_record *rec);
|
||||
void (*close)(void *iter_arg);
|
||||
};
|
||||
|
||||
void iterator_set_empty(struct reftable_iterator *it);
|
||||
int iterator_seek(struct reftable_iterator *it, struct reftable_record *want);
|
||||
int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
|
||||
|
||||
#endif
|
126
reftable/iter.c
126
reftable/iter.c
|
@ -11,11 +11,47 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
#include "system.h"
|
||||
|
||||
#include "block.h"
|
||||
#include "generic.h"
|
||||
#include "constants.h"
|
||||
#include "reader.h"
|
||||
#include "reftable-error.h"
|
||||
|
||||
int iterator_seek(struct reftable_iterator *it, struct reftable_record *want)
|
||||
{
|
||||
return it->ops->seek(it->iter_arg, want);
|
||||
}
|
||||
|
||||
int iterator_next(struct reftable_iterator *it, struct reftable_record *rec)
|
||||
{
|
||||
return it->ops->next(it->iter_arg, rec);
|
||||
}
|
||||
|
||||
static int empty_iterator_seek(void *arg, struct reftable_record *want)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int empty_iterator_next(void *arg, struct reftable_record *rec)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void empty_iterator_close(void *arg)
|
||||
{
|
||||
}
|
||||
|
||||
static struct reftable_iterator_vtable empty_vtable = {
|
||||
.seek = &empty_iterator_seek,
|
||||
.next = &empty_iterator_next,
|
||||
.close = &empty_iterator_close,
|
||||
};
|
||||
|
||||
void iterator_set_empty(struct reftable_iterator *it)
|
||||
{
|
||||
assert(!it->ops);
|
||||
it->iter_arg = NULL;
|
||||
it->ops = &empty_vtable;
|
||||
}
|
||||
|
||||
static void filtering_ref_iterator_close(void *iter_arg)
|
||||
{
|
||||
struct filtering_ref_iterator *fri = iter_arg;
|
||||
|
@ -42,26 +78,6 @@ static int filtering_ref_iterator_next(void *iter_arg,
|
|||
break;
|
||||
}
|
||||
|
||||
if (fri->double_check) {
|
||||
struct reftable_iterator it = { NULL };
|
||||
|
||||
reftable_table_init_ref_iter(&fri->tab, &it);
|
||||
|
||||
err = reftable_iterator_seek_ref(&it, ref->refname);
|
||||
if (err == 0)
|
||||
err = reftable_iterator_next_ref(&it, ref);
|
||||
|
||||
reftable_iterator_destroy(&it);
|
||||
|
||||
if (err < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (err > 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ref->value_type == REFTABLE_REF_VAL2 &&
|
||||
(!memcmp(fri->oid.buf, ref->value.val2.target_value,
|
||||
fri->oid.len) ||
|
||||
|
@ -201,3 +217,71 @@ void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
|
|||
it->iter_arg = itr;
|
||||
it->ops = &indexed_table_ref_iter_vtable;
|
||||
}
|
||||
|
||||
void reftable_iterator_destroy(struct reftable_iterator *it)
|
||||
{
|
||||
if (!it->ops)
|
||||
return;
|
||||
it->ops->close(it->iter_arg);
|
||||
it->ops = NULL;
|
||||
FREE_AND_NULL(it->iter_arg);
|
||||
}
|
||||
|
||||
int reftable_iterator_seek_ref(struct reftable_iterator *it,
|
||||
const char *name)
|
||||
{
|
||||
struct reftable_record want = {
|
||||
.type = BLOCK_TYPE_REF,
|
||||
.u.ref = {
|
||||
.refname = (char *)name,
|
||||
},
|
||||
};
|
||||
return it->ops->seek(it->iter_arg, &want);
|
||||
}
|
||||
|
||||
int reftable_iterator_next_ref(struct reftable_iterator *it,
|
||||
struct reftable_ref_record *ref)
|
||||
{
|
||||
struct reftable_record rec = {
|
||||
.type = BLOCK_TYPE_REF,
|
||||
.u = {
|
||||
.ref = *ref
|
||||
},
|
||||
};
|
||||
int err = iterator_next(it, &rec);
|
||||
*ref = rec.u.ref;
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_iterator_seek_log_at(struct reftable_iterator *it,
|
||||
const char *name, uint64_t update_index)
|
||||
{
|
||||
struct reftable_record want = {
|
||||
.type = BLOCK_TYPE_LOG,
|
||||
.u.log = {
|
||||
.refname = (char *)name,
|
||||
.update_index = update_index,
|
||||
},
|
||||
};
|
||||
return it->ops->seek(it->iter_arg, &want);
|
||||
}
|
||||
|
||||
int reftable_iterator_seek_log(struct reftable_iterator *it,
|
||||
const char *name)
|
||||
{
|
||||
return reftable_iterator_seek_log_at(it, name, ~((uint64_t) 0));
|
||||
}
|
||||
|
||||
int reftable_iterator_next_log(struct reftable_iterator *it,
|
||||
struct reftable_log_record *log)
|
||||
{
|
||||
struct reftable_record rec = {
|
||||
.type = BLOCK_TYPE_LOG,
|
||||
.u = {
|
||||
.log = *log,
|
||||
},
|
||||
};
|
||||
int err = iterator_next(it, &rec);
|
||||
*log = rec.u.log;
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -14,12 +14,36 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
#include "record.h"
|
||||
|
||||
#include "reftable-iterator.h"
|
||||
#include "reftable-generic.h"
|
||||
|
||||
/*
|
||||
* The virtual function table for implementing generic reftable iterators.
|
||||
*/
|
||||
struct reftable_iterator_vtable {
|
||||
int (*seek)(void *iter_arg, struct reftable_record *want);
|
||||
int (*next)(void *iter_arg, struct reftable_record *rec);
|
||||
void (*close)(void *iter_arg);
|
||||
};
|
||||
|
||||
/*
|
||||
* Position the iterator at the wanted record such that a call to
|
||||
* `iterator_next()` would return that record, if it exists.
|
||||
*/
|
||||
int iterator_seek(struct reftable_iterator *it, struct reftable_record *want);
|
||||
|
||||
/*
|
||||
* Yield the next record and advance the iterator. Returns <0 on error, 0 when
|
||||
* a record was yielded, and >0 when the iterator hit an error.
|
||||
*/
|
||||
int iterator_next(struct reftable_iterator *it, struct reftable_record *rec);
|
||||
|
||||
/*
|
||||
* Set up the iterator such that it behaves the same as an iterator with no
|
||||
* entries.
|
||||
*/
|
||||
void iterator_set_empty(struct reftable_iterator *it);
|
||||
|
||||
/* iterator that produces only ref records that point to `oid` */
|
||||
struct filtering_ref_iterator {
|
||||
int double_check;
|
||||
struct reftable_table tab;
|
||||
struct strbuf oid;
|
||||
struct reftable_iterator it;
|
||||
};
|
||||
|
|
|
@ -11,8 +11,8 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
#include "constants.h"
|
||||
#include "iter.h"
|
||||
#include "pq.h"
|
||||
#include "reader.h"
|
||||
#include "record.h"
|
||||
#include "generic.h"
|
||||
#include "reftable-merged.h"
|
||||
#include "reftable-error.h"
|
||||
#include "system.h"
|
||||
|
@ -25,7 +25,7 @@ struct merged_subiter {
|
|||
struct merged_iter {
|
||||
struct merged_subiter *subiters;
|
||||
struct merged_iter_pqueue pq;
|
||||
size_t stack_len;
|
||||
size_t subiters_len;
|
||||
int suppress_deletions;
|
||||
ssize_t advance_index;
|
||||
};
|
||||
|
@ -38,12 +38,12 @@ static void merged_iter_init(struct merged_iter *mi,
|
|||
mi->advance_index = -1;
|
||||
mi->suppress_deletions = mt->suppress_deletions;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(mi->subiters, mt->stack_len);
|
||||
for (size_t i = 0; i < mt->stack_len; i++) {
|
||||
REFTABLE_CALLOC_ARRAY(mi->subiters, mt->readers_len);
|
||||
for (size_t i = 0; i < mt->readers_len; i++) {
|
||||
reftable_record_init(&mi->subiters[i].rec, typ);
|
||||
table_init_iter(&mt->stack[i], &mi->subiters[i].iter, typ);
|
||||
reader_init_iter(mt->readers[i], &mi->subiters[i].iter, typ);
|
||||
}
|
||||
mi->stack_len = mt->stack_len;
|
||||
mi->subiters_len = mt->readers_len;
|
||||
}
|
||||
|
||||
static void merged_iter_close(void *p)
|
||||
|
@ -51,7 +51,7 @@ static void merged_iter_close(void *p)
|
|||
struct merged_iter *mi = p;
|
||||
|
||||
merged_iter_pqueue_release(&mi->pq);
|
||||
for (size_t i = 0; i < mi->stack_len; i++) {
|
||||
for (size_t i = 0; i < mi->subiters_len; i++) {
|
||||
reftable_iterator_destroy(&mi->subiters[i].iter);
|
||||
reftable_record_release(&mi->subiters[i].rec);
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ static int merged_iter_seek(struct merged_iter *mi, struct reftable_record *want
|
|||
|
||||
mi->advance_index = -1;
|
||||
|
||||
for (size_t i = 0; i < mi->stack_len; i++) {
|
||||
for (size_t i = 0; i < mi->subiters_len; i++) {
|
||||
err = iterator_seek(&mi->subiters[i].iter, want);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -192,8 +192,8 @@ static void iterator_from_merged_iter(struct reftable_iterator *it,
|
|||
it->ops = &merged_iter_vtable;
|
||||
}
|
||||
|
||||
int reftable_new_merged_table(struct reftable_merged_table **dest,
|
||||
struct reftable_table *stack, size_t n,
|
||||
int reftable_merged_table_new(struct reftable_merged_table **dest,
|
||||
struct reftable_reader **readers, size_t n,
|
||||
uint32_t hash_id)
|
||||
{
|
||||
struct reftable_merged_table *m = NULL;
|
||||
|
@ -201,10 +201,10 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
|
|||
uint64_t first_min = 0;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
uint64_t min = reftable_table_min_update_index(&stack[i]);
|
||||
uint64_t max = reftable_table_max_update_index(&stack[i]);
|
||||
uint64_t min = reftable_reader_min_update_index(readers[i]);
|
||||
uint64_t max = reftable_reader_max_update_index(readers[i]);
|
||||
|
||||
if (reftable_table_hash_id(&stack[i]) != hash_id) {
|
||||
if (reftable_reader_hash_id(readers[i]) != hash_id) {
|
||||
return REFTABLE_FORMAT_ERROR;
|
||||
}
|
||||
if (i == 0 || min < first_min) {
|
||||
|
@ -216,8 +216,8 @@ int reftable_new_merged_table(struct reftable_merged_table **dest,
|
|||
}
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(m, 1);
|
||||
m->stack = stack;
|
||||
m->stack_len = n;
|
||||
m->readers = readers;
|
||||
m->readers_len = n;
|
||||
m->min = first_min;
|
||||
m->max = last_max;
|
||||
m->hash_id = hash_id;
|
||||
|
@ -229,7 +229,6 @@ void reftable_merged_table_free(struct reftable_merged_table *mt)
|
|||
{
|
||||
if (!mt)
|
||||
return;
|
||||
FREE_AND_NULL(mt->stack);
|
||||
reftable_free(mt);
|
||||
}
|
||||
|
||||
|
@ -254,44 +253,19 @@ void merged_table_init_iter(struct reftable_merged_table *mt,
|
|||
iterator_from_merged_iter(it, mi);
|
||||
}
|
||||
|
||||
void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
merged_table_init_iter(mt, it, BLOCK_TYPE_REF);
|
||||
}
|
||||
|
||||
void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it)
|
||||
{
|
||||
merged_table_init_iter(mt, it, BLOCK_TYPE_LOG);
|
||||
}
|
||||
|
||||
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *mt)
|
||||
{
|
||||
return mt->hash_id;
|
||||
}
|
||||
|
||||
static void reftable_merged_table_init_iter_void(void *tab,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
{
|
||||
merged_table_init_iter(tab, it, typ);
|
||||
}
|
||||
|
||||
static uint32_t reftable_merged_table_hash_id_void(void *tab)
|
||||
{
|
||||
return reftable_merged_table_hash_id(tab);
|
||||
}
|
||||
|
||||
static uint64_t reftable_merged_table_min_update_index_void(void *tab)
|
||||
{
|
||||
return reftable_merged_table_min_update_index(tab);
|
||||
}
|
||||
|
||||
static uint64_t reftable_merged_table_max_update_index_void(void *tab)
|
||||
{
|
||||
return reftable_merged_table_max_update_index(tab);
|
||||
}
|
||||
|
||||
static struct reftable_table_vtable merged_table_vtable = {
|
||||
.init_iter = reftable_merged_table_init_iter_void,
|
||||
.hash_id = reftable_merged_table_hash_id_void,
|
||||
.min_update_index = reftable_merged_table_min_update_index_void,
|
||||
.max_update_index = reftable_merged_table_max_update_index_void,
|
||||
};
|
||||
|
||||
void reftable_table_from_merged_table(struct reftable_table *tab,
|
||||
struct reftable_merged_table *merged)
|
||||
{
|
||||
assert(!tab->ops);
|
||||
tab->ops = &merged_table_vtable;
|
||||
tab->table_arg = merged;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
#include "system.h"
|
||||
|
||||
struct reftable_merged_table {
|
||||
struct reftable_table *stack;
|
||||
size_t stack_len;
|
||||
struct reftable_reader **readers;
|
||||
size_t readers_len;
|
||||
uint32_t hash_id;
|
||||
|
||||
/* If unset, produce deletions. This is useful for compaction. For the
|
||||
|
|
|
@ -11,11 +11,9 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
#include "system.h"
|
||||
#include "block.h"
|
||||
#include "constants.h"
|
||||
#include "generic.h"
|
||||
#include "iter.h"
|
||||
#include "record.h"
|
||||
#include "reftable-error.h"
|
||||
#include "reftable-generic.h"
|
||||
|
||||
uint64_t block_source_size(struct reftable_block_source *source)
|
||||
{
|
||||
|
@ -605,9 +603,9 @@ static void iterator_from_table_iter(struct reftable_iterator *it,
|
|||
it->ops = &table_iter_vtable;
|
||||
}
|
||||
|
||||
static void reader_init_iter(struct reftable_reader *r,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
void reader_init_iter(struct reftable_reader *r,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
{
|
||||
struct reftable_reader_offsets *offs = reader_offsets_for(r, typ);
|
||||
|
||||
|
@ -735,8 +733,6 @@ static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
|
|||
*filter = empty;
|
||||
|
||||
strbuf_add(&filter->oid, oid, oid_len);
|
||||
reftable_table_from_reader(&filter->tab, r);
|
||||
filter->double_check = 0;
|
||||
iterator_from_table_iter(&filter->it, ti);
|
||||
|
||||
iterator_from_filtering_ref_iterator(it, filter);
|
||||
|
@ -761,66 +757,6 @@ uint64_t reftable_reader_min_update_index(struct reftable_reader *r)
|
|||
return r->min_update_index;
|
||||
}
|
||||
|
||||
/* generic table interface. */
|
||||
|
||||
static void reftable_reader_init_iter_void(void *tab,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ)
|
||||
{
|
||||
reader_init_iter(tab, it, typ);
|
||||
}
|
||||
|
||||
static uint32_t reftable_reader_hash_id_void(void *tab)
|
||||
{
|
||||
return reftable_reader_hash_id(tab);
|
||||
}
|
||||
|
||||
static uint64_t reftable_reader_min_update_index_void(void *tab)
|
||||
{
|
||||
return reftable_reader_min_update_index(tab);
|
||||
}
|
||||
|
||||
static uint64_t reftable_reader_max_update_index_void(void *tab)
|
||||
{
|
||||
return reftable_reader_max_update_index(tab);
|
||||
}
|
||||
|
||||
static struct reftable_table_vtable reader_vtable = {
|
||||
.init_iter = reftable_reader_init_iter_void,
|
||||
.hash_id = reftable_reader_hash_id_void,
|
||||
.min_update_index = reftable_reader_min_update_index_void,
|
||||
.max_update_index = reftable_reader_max_update_index_void,
|
||||
};
|
||||
|
||||
void reftable_table_from_reader(struct reftable_table *tab,
|
||||
struct reftable_reader *reader)
|
||||
{
|
||||
assert(!tab->ops);
|
||||
tab->ops = &reader_vtable;
|
||||
tab->table_arg = reader;
|
||||
}
|
||||
|
||||
|
||||
int reftable_reader_print_file(const char *tablename)
|
||||
{
|
||||
struct reftable_block_source src = { NULL };
|
||||
int err = reftable_block_source_from_file(&src, tablename);
|
||||
struct reftable_reader *r = NULL;
|
||||
struct reftable_table tab = { NULL };
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
err = reftable_new_reader(&r, &src, tablename);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
reftable_table_from_reader(&tab, r);
|
||||
err = reftable_table_print(&tab);
|
||||
done:
|
||||
reftable_reader_free(r);
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_reader_print_blocks(const char *tablename)
|
||||
{
|
||||
struct {
|
||||
|
|
|
@ -57,6 +57,10 @@ int init_reader(struct reftable_reader *r, struct reftable_block_source *source,
|
|||
void reader_close(struct reftable_reader *r);
|
||||
const char *reader_name(struct reftable_reader *r);
|
||||
|
||||
void reader_init_iter(struct reftable_reader *r,
|
||||
struct reftable_iterator *it,
|
||||
uint8_t typ);
|
||||
|
||||
/* initialize a block reader to read from `r` */
|
||||
int reader_init_block_reader(struct reftable_reader *r, struct block_reader *br,
|
||||
uint64_t next_off, uint8_t want_typ);
|
||||
|
|
|
@ -259,58 +259,6 @@ static void reftable_ref_record_copy_from(void *rec, const void *src_rec,
|
|||
}
|
||||
}
|
||||
|
||||
static char hexdigit(int c)
|
||||
{
|
||||
if (c <= 9)
|
||||
return '0' + c;
|
||||
return 'a' + (c - 10);
|
||||
}
|
||||
|
||||
static void hex_format(char *dest, const unsigned char *src, int hash_size)
|
||||
{
|
||||
assert(hash_size > 0);
|
||||
if (src) {
|
||||
int i = 0;
|
||||
for (i = 0; i < hash_size; i++) {
|
||||
dest[2 * i] = hexdigit(src[i] >> 4);
|
||||
dest[2 * i + 1] = hexdigit(src[i] & 0xf);
|
||||
}
|
||||
dest[2 * hash_size] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void reftable_ref_record_print_sz(const struct reftable_ref_record *ref,
|
||||
int hash_size)
|
||||
{
|
||||
char hex[GIT_MAX_HEXSZ + 1] = { 0 }; /* BUG */
|
||||
printf("ref{%s(%" PRIu64 ") ", ref->refname, ref->update_index);
|
||||
switch (ref->value_type) {
|
||||
case REFTABLE_REF_SYMREF:
|
||||
printf("=> %s", ref->value.symref);
|
||||
break;
|
||||
case REFTABLE_REF_VAL2:
|
||||
hex_format(hex, ref->value.val2.value, hash_size);
|
||||
printf("val 2 %s", hex);
|
||||
hex_format(hex, ref->value.val2.target_value,
|
||||
hash_size);
|
||||
printf("(T %s)", hex);
|
||||
break;
|
||||
case REFTABLE_REF_VAL1:
|
||||
hex_format(hex, ref->value.val1, hash_size);
|
||||
printf("val 1 %s", hex);
|
||||
break;
|
||||
case REFTABLE_REF_DELETION:
|
||||
printf("delete");
|
||||
break;
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
void reftable_ref_record_print(const struct reftable_ref_record *ref,
|
||||
uint32_t hash_id) {
|
||||
reftable_ref_record_print_sz(ref, hash_size(hash_id));
|
||||
}
|
||||
|
||||
static void reftable_ref_record_release_void(void *rec)
|
||||
{
|
||||
reftable_ref_record_release(rec);
|
||||
|
@ -480,12 +428,6 @@ static int reftable_ref_record_cmp_void(const void *_a, const void *_b)
|
|||
return strcmp(a->refname, b->refname);
|
||||
}
|
||||
|
||||
static void reftable_ref_record_print_void(const void *rec,
|
||||
int hash_size)
|
||||
{
|
||||
reftable_ref_record_print_sz((struct reftable_ref_record *) rec, hash_size);
|
||||
}
|
||||
|
||||
static struct reftable_record_vtable reftable_ref_record_vtable = {
|
||||
.key = &reftable_ref_record_key,
|
||||
.type = BLOCK_TYPE_REF,
|
||||
|
@ -497,7 +439,6 @@ static struct reftable_record_vtable reftable_ref_record_vtable = {
|
|||
.is_deletion = &reftable_ref_record_is_deletion_void,
|
||||
.equal = &reftable_ref_record_equal_void,
|
||||
.cmp = &reftable_ref_record_cmp_void,
|
||||
.print = &reftable_ref_record_print_void,
|
||||
};
|
||||
|
||||
static void reftable_obj_record_key(const void *r, struct strbuf *dest)
|
||||
|
@ -516,21 +457,6 @@ static void reftable_obj_record_release(void *rec)
|
|||
memset(obj, 0, sizeof(struct reftable_obj_record));
|
||||
}
|
||||
|
||||
static void reftable_obj_record_print(const void *rec, int hash_size)
|
||||
{
|
||||
const struct reftable_obj_record *obj = rec;
|
||||
char hex[GIT_MAX_HEXSZ + 1] = { 0 };
|
||||
struct strbuf offset_str = STRBUF_INIT;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < obj->offset_len; i++)
|
||||
strbuf_addf(&offset_str, "%" PRIu64 " ", obj->offsets[i]);
|
||||
hex_format(hex, obj->hash_prefix, obj->hash_prefix_len);
|
||||
printf("prefix %s (len %d), offsets [%s]\n",
|
||||
hex, obj->hash_prefix_len, offset_str.buf);
|
||||
strbuf_release(&offset_str);
|
||||
}
|
||||
|
||||
static void reftable_obj_record_copy_from(void *rec, const void *src_rec,
|
||||
int hash_size)
|
||||
{
|
||||
|
@ -701,41 +627,8 @@ static struct reftable_record_vtable reftable_obj_record_vtable = {
|
|||
.is_deletion = ¬_a_deletion,
|
||||
.equal = &reftable_obj_record_equal_void,
|
||||
.cmp = &reftable_obj_record_cmp_void,
|
||||
.print = &reftable_obj_record_print,
|
||||
};
|
||||
|
||||
static void reftable_log_record_print_sz(struct reftable_log_record *log,
|
||||
int hash_size)
|
||||
{
|
||||
char hex[GIT_MAX_HEXSZ + 1] = { 0 };
|
||||
|
||||
switch (log->value_type) {
|
||||
case REFTABLE_LOG_DELETION:
|
||||
printf("log{%s(%" PRIu64 ") delete\n", log->refname,
|
||||
log->update_index);
|
||||
break;
|
||||
case REFTABLE_LOG_UPDATE:
|
||||
printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
|
||||
log->refname, log->update_index,
|
||||
log->value.update.name ? log->value.update.name : "",
|
||||
log->value.update.email ? log->value.update.email : "",
|
||||
log->value.update.time,
|
||||
log->value.update.tz_offset);
|
||||
hex_format(hex, log->value.update.old_hash, hash_size);
|
||||
printf("%s => ", hex);
|
||||
hex_format(hex, log->value.update.new_hash, hash_size);
|
||||
printf("%s\n\n%s\n}\n", hex,
|
||||
log->value.update.message ? log->value.update.message : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reftable_log_record_print(struct reftable_log_record *log,
|
||||
uint32_t hash_id)
|
||||
{
|
||||
reftable_log_record_print_sz(log, hash_size(hash_id));
|
||||
}
|
||||
|
||||
static void reftable_log_record_key(const void *r, struct strbuf *dest)
|
||||
{
|
||||
const struct reftable_log_record *rec =
|
||||
|
@ -1039,11 +932,6 @@ static int reftable_log_record_is_deletion_void(const void *p)
|
|||
(const struct reftable_log_record *)p);
|
||||
}
|
||||
|
||||
static void reftable_log_record_print_void(const void *rec, int hash_size)
|
||||
{
|
||||
reftable_log_record_print_sz((struct reftable_log_record*)rec, hash_size);
|
||||
}
|
||||
|
||||
static struct reftable_record_vtable reftable_log_record_vtable = {
|
||||
.key = &reftable_log_record_key,
|
||||
.type = BLOCK_TYPE_LOG,
|
||||
|
@ -1055,7 +943,6 @@ static struct reftable_record_vtable reftable_log_record_vtable = {
|
|||
.is_deletion = &reftable_log_record_is_deletion_void,
|
||||
.equal = &reftable_log_record_equal_void,
|
||||
.cmp = &reftable_log_record_cmp_void,
|
||||
.print = &reftable_log_record_print_void,
|
||||
};
|
||||
|
||||
static void reftable_index_record_key(const void *r, struct strbuf *dest)
|
||||
|
@ -1137,13 +1024,6 @@ static int reftable_index_record_cmp(const void *_a, const void *_b)
|
|||
return strbuf_cmp(&a->last_key, &b->last_key);
|
||||
}
|
||||
|
||||
static void reftable_index_record_print(const void *rec, int hash_size)
|
||||
{
|
||||
const struct reftable_index_record *idx = rec;
|
||||
/* TODO: escape null chars? */
|
||||
printf("\"%s\" %" PRIu64 "\n", idx->last_key.buf, idx->offset);
|
||||
}
|
||||
|
||||
static struct reftable_record_vtable reftable_index_record_vtable = {
|
||||
.key = &reftable_index_record_key,
|
||||
.type = BLOCK_TYPE_INDEX,
|
||||
|
@ -1155,7 +1035,6 @@ static struct reftable_record_vtable reftable_index_record_vtable = {
|
|||
.is_deletion = ¬_a_deletion,
|
||||
.equal = &reftable_index_record_equal,
|
||||
.cmp = &reftable_index_record_cmp,
|
||||
.print = &reftable_index_record_print,
|
||||
};
|
||||
|
||||
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest)
|
||||
|
@ -1334,9 +1213,3 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ)
|
|||
BUG("unhandled record type");
|
||||
}
|
||||
}
|
||||
|
||||
void reftable_record_print(struct reftable_record *rec, int hash_size)
|
||||
{
|
||||
printf("'%c': ", rec->type);
|
||||
reftable_record_vtable(rec)->print(reftable_record_data(rec), hash_size);
|
||||
}
|
||||
|
|
|
@ -136,7 +136,6 @@ void reftable_record_init(struct reftable_record *rec, uint8_t typ);
|
|||
/* see struct record_vtable */
|
||||
int reftable_record_cmp(struct reftable_record *a, struct reftable_record *b);
|
||||
int reftable_record_equal(struct reftable_record *a, struct reftable_record *b, int hash_size);
|
||||
void reftable_record_print(struct reftable_record *rec, int hash_size);
|
||||
void reftable_record_key(struct reftable_record *rec, struct strbuf *dest);
|
||||
void reftable_record_copy_from(struct reftable_record *rec,
|
||||
struct reftable_record *src, int hash_size);
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 Google LLC
|
||||
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file or at
|
||||
https://developers.google.com/open-source/licenses/bsd
|
||||
*/
|
||||
|
||||
#ifndef REFTABLE_GENERIC_H
|
||||
#define REFTABLE_GENERIC_H
|
||||
|
||||
#include "reftable-iterator.h"
|
||||
|
||||
struct reftable_table_vtable;
|
||||
|
||||
/*
|
||||
* Provides a unified API for reading tables, either merged tables, or single
|
||||
* readers. */
|
||||
struct reftable_table {
|
||||
struct reftable_table_vtable *ops;
|
||||
void *table_arg;
|
||||
};
|
||||
|
||||
void reftable_table_init_ref_iter(struct reftable_table *tab,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
void reftable_table_init_log_iter(struct reftable_table *tab,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* returns the hash ID from a generic reftable_table */
|
||||
uint32_t reftable_table_hash_id(struct reftable_table *tab);
|
||||
|
||||
/* returns the max update_index covered by this table. */
|
||||
uint64_t reftable_table_max_update_index(struct reftable_table *tab);
|
||||
|
||||
/* returns the min update_index covered by this table. */
|
||||
uint64_t reftable_table_min_update_index(struct reftable_table *tab);
|
||||
|
||||
/* convenience function to read a single ref. Returns < 0 for error, 0
|
||||
for success, and 1 if ref not found. */
|
||||
int reftable_table_read_ref(struct reftable_table *tab, const char *name,
|
||||
struct reftable_ref_record *ref);
|
||||
|
||||
/* dump table contents onto stdout for debugging */
|
||||
int reftable_table_print(struct reftable_table *tab);
|
||||
|
||||
#endif
|
|
@ -26,16 +26,24 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
/* A merged table is implements seeking/iterating over a stack of tables. */
|
||||
struct reftable_merged_table;
|
||||
|
||||
/* A generic reftable; see below. */
|
||||
struct reftable_table;
|
||||
struct reftable_reader;
|
||||
|
||||
/* reftable_new_merged_table creates a new merged table. It takes ownership of
|
||||
the stack array.
|
||||
*/
|
||||
int reftable_new_merged_table(struct reftable_merged_table **dest,
|
||||
struct reftable_table *stack, size_t n,
|
||||
/*
|
||||
* reftable_merged_table_new creates a new merged table. The readers must be
|
||||
* kept alive as long as the merged table is still in use.
|
||||
*/
|
||||
int reftable_merged_table_new(struct reftable_merged_table **dest,
|
||||
struct reftable_reader **readers, size_t n,
|
||||
uint32_t hash_id);
|
||||
|
||||
/* Initialize a merged table iterator for reading refs. */
|
||||
void reftable_merged_table_init_ref_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* Initialize a merged table iterator for reading logs. */
|
||||
void reftable_merged_table_init_log_iterator(struct reftable_merged_table *mt,
|
||||
struct reftable_iterator *it);
|
||||
|
||||
/* returns the max update_index covered by this merged table. */
|
||||
uint64_t
|
||||
reftable_merged_table_max_update_index(struct reftable_merged_table *mt);
|
||||
|
@ -50,8 +58,4 @@ void reftable_merged_table_free(struct reftable_merged_table *m);
|
|||
/* return the hash ID of the merged table. */
|
||||
uint32_t reftable_merged_table_hash_id(struct reftable_merged_table *m);
|
||||
|
||||
/* create a generic table from reftable_merged_table */
|
||||
void reftable_table_from_merged_table(struct reftable_table *tab,
|
||||
struct reftable_merged_table *table);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
/* The reader struct is a handle to an open reftable file. */
|
||||
struct reftable_reader;
|
||||
|
||||
/* Generic table. */
|
||||
struct reftable_table;
|
||||
|
||||
/* reftable_new_reader opens a reftable for reading. If successful,
|
||||
* returns 0 code and sets pp. The name is used for creating a
|
||||
* stack. Typically, it is the basename of the file. The block source
|
||||
|
@ -60,12 +57,6 @@ uint64_t reftable_reader_max_update_index(struct reftable_reader *r);
|
|||
/* return the min_update_index for a table */
|
||||
uint64_t reftable_reader_min_update_index(struct reftable_reader *r);
|
||||
|
||||
/* creates a generic table from a file reader. */
|
||||
void reftable_table_from_reader(struct reftable_table *tab,
|
||||
struct reftable_reader *reader);
|
||||
|
||||
/* print table onto stdout for debugging. */
|
||||
int reftable_reader_print_file(const char *tablename);
|
||||
/* print blocks onto stdout for debugging. */
|
||||
int reftable_reader_print_blocks(const char *tablename);
|
||||
|
||||
|
|
|
@ -60,10 +60,6 @@ const unsigned char *reftable_ref_record_val2(const struct reftable_ref_record *
|
|||
/* returns whether 'ref' represents a deletion */
|
||||
int reftable_ref_record_is_deletion(const struct reftable_ref_record *ref);
|
||||
|
||||
/* prints a reftable_ref_record onto stdout. Useful for debugging. */
|
||||
void reftable_ref_record_print(const struct reftable_ref_record *ref,
|
||||
uint32_t hash_id);
|
||||
|
||||
/* frees and nulls all pointer values inside `ref`. */
|
||||
void reftable_ref_record_release(struct reftable_ref_record *ref);
|
||||
|
||||
|
@ -111,8 +107,4 @@ void reftable_log_record_release(struct reftable_log_record *log);
|
|||
int reftable_log_record_equal(const struct reftable_log_record *a,
|
||||
const struct reftable_log_record *b, int hash_size);
|
||||
|
||||
/* dumps a reftable_log_record on stdout, for debugging/testing. */
|
||||
void reftable_log_record_print(struct reftable_log_record *log,
|
||||
uint32_t hash_id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -140,7 +140,4 @@ struct reftable_compaction_stats {
|
|||
struct reftable_compaction_stats *
|
||||
reftable_stack_compaction_stats(struct reftable_stack *st);
|
||||
|
||||
/* print the entire stack represented by the directory */
|
||||
int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,5 @@ int record_test_main(int argc, const char **argv);
|
|||
int readwrite_test_main(int argc, const char **argv);
|
||||
int stack_test_main(int argc, const char **argv);
|
||||
int tree_test_main(int argc, const char **argv);
|
||||
int reftable_dump_main(int argc, char *const *argv);
|
||||
|
||||
#endif
|
||||
|
|
317
reftable/stack.c
317
reftable/stack.c
|
@ -14,7 +14,6 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
#include "merged.h"
|
||||
#include "reader.h"
|
||||
#include "reftable-error.h"
|
||||
#include "reftable-generic.h"
|
||||
#include "reftable-record.h"
|
||||
#include "reftable-merged.h"
|
||||
#include "writer.h"
|
||||
|
@ -225,13 +224,11 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
|
|||
const char **names,
|
||||
int reuse_open)
|
||||
{
|
||||
size_t cur_len = !st->merged ? 0 : st->merged->stack_len;
|
||||
size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
|
||||
struct reftable_reader **cur = stack_copy_readers(st, cur_len);
|
||||
size_t names_len = names_length(names);
|
||||
struct reftable_reader **new_readers =
|
||||
reftable_calloc(names_len, sizeof(*new_readers));
|
||||
struct reftable_table *new_tables =
|
||||
reftable_calloc(names_len, sizeof(*new_tables));
|
||||
size_t new_readers_len = 0;
|
||||
struct reftable_merged_table *new_merged = NULL;
|
||||
struct strbuf table_path = STRBUF_INIT;
|
||||
|
@ -267,17 +264,15 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
|
|||
}
|
||||
|
||||
new_readers[new_readers_len] = rd;
|
||||
reftable_table_from_reader(&new_tables[new_readers_len], rd);
|
||||
new_readers_len++;
|
||||
}
|
||||
|
||||
/* success! */
|
||||
err = reftable_new_merged_table(&new_merged, new_tables,
|
||||
err = reftable_merged_table_new(&new_merged, new_readers,
|
||||
new_readers_len, st->opts.hash_id);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
new_tables = NULL;
|
||||
st->readers_len = new_readers_len;
|
||||
if (st->merged)
|
||||
reftable_merged_table_free(st->merged);
|
||||
|
@ -309,7 +304,6 @@ done:
|
|||
reftable_reader_free(new_readers[i]);
|
||||
}
|
||||
reftable_free(new_readers);
|
||||
reftable_free(new_tables);
|
||||
reftable_free(cur);
|
||||
strbuf_release(&table_path);
|
||||
return err;
|
||||
|
@ -520,7 +514,7 @@ static int stack_uptodate(struct reftable_stack *st)
|
|||
}
|
||||
}
|
||||
|
||||
if (names[st->merged->stack_len]) {
|
||||
if (names[st->merged->readers_len]) {
|
||||
err = 1;
|
||||
goto done;
|
||||
}
|
||||
|
@ -567,7 +561,7 @@ static void format_name(struct strbuf *dest, uint64_t min, uint64_t max)
|
|||
}
|
||||
|
||||
struct reftable_addition {
|
||||
struct tempfile *lock_file;
|
||||
struct lock_file tables_list_lock;
|
||||
struct reftable_stack *stack;
|
||||
|
||||
char **new_tables;
|
||||
|
@ -581,13 +575,13 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
|
|||
struct reftable_stack *st)
|
||||
{
|
||||
struct strbuf lock_file_name = STRBUF_INIT;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
add->stack = st;
|
||||
|
||||
strbuf_addf(&lock_file_name, "%s.lock", st->list_file);
|
||||
|
||||
add->lock_file = create_tempfile(lock_file_name.buf);
|
||||
if (!add->lock_file) {
|
||||
err = hold_lock_file_for_update(&add->tables_list_lock, st->list_file,
|
||||
LOCK_NO_DEREF);
|
||||
if (err < 0) {
|
||||
if (errno == EEXIST) {
|
||||
err = REFTABLE_LOCK_ERROR;
|
||||
} else {
|
||||
|
@ -596,7 +590,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
|
|||
goto done;
|
||||
}
|
||||
if (st->opts.default_permissions) {
|
||||
if (chmod(add->lock_file->filename.buf, st->opts.default_permissions) < 0) {
|
||||
if (chmod(get_lock_file_path(&add->tables_list_lock),
|
||||
st->opts.default_permissions) < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
@ -635,7 +630,7 @@ static void reftable_addition_close(struct reftable_addition *add)
|
|||
add->new_tables_len = 0;
|
||||
add->new_tables_cap = 0;
|
||||
|
||||
delete_tempfile(&add->lock_file);
|
||||
rollback_lock_file(&add->tables_list_lock);
|
||||
strbuf_release(&nm);
|
||||
}
|
||||
|
||||
|
@ -651,14 +646,14 @@ void reftable_addition_destroy(struct reftable_addition *add)
|
|||
int reftable_addition_commit(struct reftable_addition *add)
|
||||
{
|
||||
struct strbuf table_list = STRBUF_INIT;
|
||||
int lock_file_fd = get_tempfile_fd(add->lock_file);
|
||||
int lock_file_fd = get_lock_file_fd(&add->tables_list_lock);
|
||||
int err = 0;
|
||||
size_t i;
|
||||
|
||||
if (add->new_tables_len == 0)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < add->stack->merged->stack_len; i++) {
|
||||
for (i = 0; i < add->stack->merged->readers_len; i++) {
|
||||
strbuf_addstr(&table_list, add->stack->readers[i]->name);
|
||||
strbuf_addstr(&table_list, "\n");
|
||||
}
|
||||
|
@ -674,10 +669,13 @@ int reftable_addition_commit(struct reftable_addition *add)
|
|||
goto done;
|
||||
}
|
||||
|
||||
fsync_component_or_die(FSYNC_COMPONENT_REFERENCE, lock_file_fd,
|
||||
get_tempfile_path(add->lock_file));
|
||||
err = fsync_component(FSYNC_COMPONENT_REFERENCE, lock_file_fd);
|
||||
if (err < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = rename_tempfile(&add->lock_file, add->stack->list_file);
|
||||
err = commit_lock_file(&add->tables_list_lock);
|
||||
if (err < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
|
@ -835,7 +833,7 @@ done:
|
|||
|
||||
uint64_t reftable_stack_next_update_index(struct reftable_stack *st)
|
||||
{
|
||||
int sz = st->merged->stack_len;
|
||||
int sz = st->merged->readers_len;
|
||||
if (sz > 0)
|
||||
return reftable_reader_max_update_index(st->readers[sz - 1]) +
|
||||
1;
|
||||
|
@ -902,30 +900,23 @@ static int stack_write_compact(struct reftable_stack *st,
|
|||
size_t first, size_t last,
|
||||
struct reftable_log_expiry_config *config)
|
||||
{
|
||||
size_t subtabs_len = last - first + 1;
|
||||
struct reftable_table *subtabs = reftable_calloc(
|
||||
last - first + 1, sizeof(*subtabs));
|
||||
struct reftable_merged_table *mt = NULL;
|
||||
struct reftable_iterator it = { NULL };
|
||||
struct reftable_ref_record ref = { NULL };
|
||||
struct reftable_log_record log = { NULL };
|
||||
size_t subtabs_len = last - first + 1;
|
||||
uint64_t entries = 0;
|
||||
int err = 0;
|
||||
|
||||
for (size_t i = first, j = 0; i <= last; i++) {
|
||||
struct reftable_reader *t = st->readers[i];
|
||||
reftable_table_from_reader(&subtabs[j++], t);
|
||||
st->stats.bytes += t->size;
|
||||
}
|
||||
for (size_t i = first; i <= last; i++)
|
||||
st->stats.bytes += st->readers[i]->size;
|
||||
reftable_writer_set_limits(wr, st->readers[first]->min_update_index,
|
||||
st->readers[last]->max_update_index);
|
||||
|
||||
err = reftable_new_merged_table(&mt, subtabs, subtabs_len,
|
||||
err = reftable_merged_table_new(&mt, st->readers + first, subtabs_len,
|
||||
st->opts.hash_id);
|
||||
if (err < 0) {
|
||||
reftable_free(subtabs);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
merged_table_init_iter(mt, &it, BLOCK_TYPE_REF);
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
|
@ -995,6 +986,15 @@ done:
|
|||
return err;
|
||||
}
|
||||
|
||||
enum stack_compact_range_flags {
|
||||
/*
|
||||
* Perform a best-effort compaction. That is, even if we cannot lock
|
||||
* all tables in the specified range, we will try to compact the
|
||||
* remaining slice.
|
||||
*/
|
||||
STACK_COMPACT_RANGE_BEST_EFFORT = (1 << 0),
|
||||
};
|
||||
|
||||
/*
|
||||
* Compact all tables in the range `[first, last)` into a single new table.
|
||||
*
|
||||
|
@ -1006,7 +1006,8 @@ done:
|
|||
*/
|
||||
static int stack_compact_range(struct reftable_stack *st,
|
||||
size_t first, size_t last,
|
||||
struct reftable_log_expiry_config *expiry)
|
||||
struct reftable_log_expiry_config *expiry,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct strbuf tables_list_buf = STRBUF_INIT;
|
||||
struct strbuf new_table_name = STRBUF_INIT;
|
||||
|
@ -1016,7 +1017,9 @@ static int stack_compact_range(struct reftable_stack *st,
|
|||
struct lock_file *table_locks = NULL;
|
||||
struct tempfile *new_table = NULL;
|
||||
int is_empty_table = 0, err = 0;
|
||||
size_t i;
|
||||
size_t first_to_replace, last_to_replace;
|
||||
size_t i, nlocks = 0;
|
||||
char **names = NULL;
|
||||
|
||||
if (first > last || (!expiry && first == last)) {
|
||||
err = 0;
|
||||
|
@ -1046,19 +1049,47 @@ static int stack_compact_range(struct reftable_stack *st,
|
|||
/*
|
||||
* Lock all tables in the user-provided range. This is the slice of our
|
||||
* stack which we'll compact.
|
||||
*
|
||||
* Note that we lock tables in reverse order from last to first. The
|
||||
* intent behind this is to allow a newer process to perform best
|
||||
* effort compaction of tables that it has added in the case where an
|
||||
* older process is still busy compacting tables which are preexisting
|
||||
* from the point of view of the newer process.
|
||||
*/
|
||||
REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1);
|
||||
for (i = first; i <= last; i++) {
|
||||
stack_filename(&table_name, st, reader_name(st->readers[i]));
|
||||
for (i = last + 1; i > first; i--) {
|
||||
stack_filename(&table_name, st, reader_name(st->readers[i - 1]));
|
||||
|
||||
err = hold_lock_file_for_update(&table_locks[i - first],
|
||||
err = hold_lock_file_for_update(&table_locks[nlocks],
|
||||
table_name.buf, LOCK_NO_DEREF);
|
||||
if (err < 0) {
|
||||
if (errno == EEXIST)
|
||||
/*
|
||||
* When the table is locked already we may do a
|
||||
* best-effort compaction and compact only the tables
|
||||
* that we have managed to lock so far. This of course
|
||||
* requires that we have been able to lock at least two
|
||||
* tables, otherwise there would be nothing to compact.
|
||||
* In that case, we return a lock error to our caller.
|
||||
*/
|
||||
if (errno == EEXIST && last - (i - 1) >= 2 &&
|
||||
flags & STACK_COMPACT_RANGE_BEST_EFFORT) {
|
||||
err = 0;
|
||||
/*
|
||||
* The subtraction is to offset the index, the
|
||||
* addition is to only compact up to the table
|
||||
* of the preceding iteration. They obviously
|
||||
* cancel each other out, but that may be
|
||||
* non-obvious when it was omitted.
|
||||
*/
|
||||
first = (i - 1) + 1;
|
||||
break;
|
||||
} else if (errno == EEXIST) {
|
||||
err = REFTABLE_LOCK_ERROR;
|
||||
else
|
||||
goto done;
|
||||
} else {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1066,7 +1097,7 @@ static int stack_compact_range(struct reftable_stack *st,
|
|||
* run into file descriptor exhaustion when we compress a lot
|
||||
* of tables.
|
||||
*/
|
||||
err = close_lock_file_gently(&table_locks[i - first]);
|
||||
err = close_lock_file_gently(&table_locks[nlocks++]);
|
||||
if (err < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
|
@ -1119,6 +1150,100 @@ static int stack_compact_range(struct reftable_stack *st,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* As we have unlocked the stack while compacting our slice of tables
|
||||
* it may have happened that a concurrently running process has updated
|
||||
* the stack while we were compacting. In that case, we need to check
|
||||
* whether the tables that we have just compacted still exist in the
|
||||
* stack in the exact same order as we have compacted them.
|
||||
*
|
||||
* If they do exist, then it is fine to continue and replace those
|
||||
* tables with our compacted version. If they don't, then we need to
|
||||
* abort.
|
||||
*/
|
||||
err = stack_uptodate(st);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
if (err > 0) {
|
||||
ssize_t new_offset = -1;
|
||||
int fd;
|
||||
|
||||
fd = open(st->list_file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
err = REFTABLE_IO_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = fd_read_lines(fd, &names);
|
||||
close(fd);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Search for the offset of the first table that we have
|
||||
* compacted in the updated "tables.list" file.
|
||||
*/
|
||||
for (size_t i = 0; names[i]; i++) {
|
||||
if (strcmp(names[i], st->readers[first]->name))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We have found the first entry. Verify that all the
|
||||
* subsequent tables we have compacted still exist in
|
||||
* the modified stack in the exact same order as we
|
||||
* have compacted them.
|
||||
*/
|
||||
for (size_t j = 1; j < last - first + 1; j++) {
|
||||
const char *old = first + j < st->merged->readers_len ?
|
||||
st->readers[first + j]->name : NULL;
|
||||
const char *new = names[i + j];
|
||||
|
||||
/*
|
||||
* If some entries are missing or in case the tables
|
||||
* have changed then we need to bail out. Again, this
|
||||
* shouldn't ever happen because we have locked the
|
||||
* tables we are compacting.
|
||||
*/
|
||||
if (!old || !new || strcmp(old, new)) {
|
||||
err = REFTABLE_OUTDATED_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
new_offset = i;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case we didn't find our compacted tables in the stack we
|
||||
* need to bail out. In theory, this should have never happened
|
||||
* because we locked the tables we are compacting.
|
||||
*/
|
||||
if (new_offset < 0) {
|
||||
err = REFTABLE_OUTDATED_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have found the new range that we want to replace, so
|
||||
* let's update the range of tables that we want to replace.
|
||||
*/
|
||||
first_to_replace = new_offset;
|
||||
last_to_replace = last + (new_offset - first);
|
||||
} else {
|
||||
/*
|
||||
* `fd_read_lines()` uses a `NULL` sentinel to indicate that
|
||||
* the array is at its end. As we use `free_names()` to free
|
||||
* the array, we need to include this sentinel value here and
|
||||
* thus have to allocate `readers_len + 1` many entries.
|
||||
*/
|
||||
REFTABLE_CALLOC_ARRAY(names, st->merged->readers_len + 1);
|
||||
for (size_t i = 0; i < st->merged->readers_len; i++)
|
||||
names[i] = xstrdup(st->readers[i]->name);
|
||||
first_to_replace = first;
|
||||
last_to_replace = last;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the resulting compacted table is not empty, then we need to move
|
||||
* it into place now.
|
||||
|
@ -1141,12 +1266,12 @@ static int stack_compact_range(struct reftable_stack *st,
|
|||
* have just written. In case the compacted table became empty we
|
||||
* simply skip writing it.
|
||||
*/
|
||||
for (i = 0; i < first; i++)
|
||||
strbuf_addf(&tables_list_buf, "%s\n", st->readers[i]->name);
|
||||
for (i = 0; i < first_to_replace; i++)
|
||||
strbuf_addf(&tables_list_buf, "%s\n", names[i]);
|
||||
if (!is_empty_table)
|
||||
strbuf_addf(&tables_list_buf, "%s\n", new_table_name.buf);
|
||||
for (i = last + 1; i < st->merged->stack_len; i++)
|
||||
strbuf_addf(&tables_list_buf, "%s\n", st->readers[i]->name);
|
||||
for (i = last_to_replace + 1; names[i]; i++)
|
||||
strbuf_addf(&tables_list_buf, "%s\n", names[i]);
|
||||
|
||||
err = write_in_full(get_lock_file_fd(&tables_list_lock),
|
||||
tables_list_buf.buf, tables_list_buf.len);
|
||||
|
@ -1183,8 +1308,8 @@ static int stack_compact_range(struct reftable_stack *st,
|
|||
* Delete the old tables. They may still be in use by concurrent
|
||||
* readers, so it is expected that unlinking tables may fail.
|
||||
*/
|
||||
for (i = first; i <= last; i++) {
|
||||
struct lock_file *table_lock = &table_locks[i - first];
|
||||
for (i = 0; i < nlocks; i++) {
|
||||
struct lock_file *table_lock = &table_locks[i];
|
||||
char *table_path = get_locked_file_path(table_lock);
|
||||
unlink(table_path);
|
||||
free(table_path);
|
||||
|
@ -1192,34 +1317,36 @@ static int stack_compact_range(struct reftable_stack *st,
|
|||
|
||||
done:
|
||||
rollback_lock_file(&tables_list_lock);
|
||||
for (i = first; table_locks && i <= last; i++)
|
||||
rollback_lock_file(&table_locks[i - first]);
|
||||
for (i = 0; table_locks && i < nlocks; i++)
|
||||
rollback_lock_file(&table_locks[i]);
|
||||
reftable_free(table_locks);
|
||||
|
||||
delete_tempfile(&new_table);
|
||||
strbuf_release(&new_table_name);
|
||||
strbuf_release(&new_table_path);
|
||||
|
||||
strbuf_release(&tables_list_buf);
|
||||
strbuf_release(&table_name);
|
||||
free_names(names);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int stack_compact_range_stats(struct reftable_stack *st,
|
||||
size_t first, size_t last,
|
||||
struct reftable_log_expiry_config *config,
|
||||
unsigned int flags)
|
||||
{
|
||||
int err = stack_compact_range(st, first, last, config, flags);
|
||||
if (err == REFTABLE_LOCK_ERROR)
|
||||
st->stats.failures++;
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_stack_compact_all(struct reftable_stack *st,
|
||||
struct reftable_log_expiry_config *config)
|
||||
{
|
||||
return stack_compact_range(st, 0, st->merged->stack_len ?
|
||||
st->merged->stack_len - 1 : 0, config);
|
||||
}
|
||||
|
||||
static int stack_compact_range_stats(struct reftable_stack *st,
|
||||
size_t first, size_t last,
|
||||
struct reftable_log_expiry_config *config)
|
||||
{
|
||||
int err = stack_compact_range(st, first, last, config);
|
||||
if (err == REFTABLE_LOCK_ERROR)
|
||||
st->stats.failures++;
|
||||
return err;
|
||||
size_t last = st->merged->readers_len ? st->merged->readers_len - 1 : 0;
|
||||
return stack_compact_range_stats(st, 0, last, config, 0);
|
||||
}
|
||||
|
||||
static int segment_size(struct segment *s)
|
||||
|
@ -1305,14 +1432,15 @@ struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
|
|||
|
||||
static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
|
||||
{
|
||||
uint64_t *sizes =
|
||||
reftable_calloc(st->merged->stack_len, sizeof(*sizes));
|
||||
int version = (st->opts.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
|
||||
int overhead = header_size(version) - 1;
|
||||
int i = 0;
|
||||
for (i = 0; i < st->merged->stack_len; i++) {
|
||||
uint64_t *sizes;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(sizes, st->merged->readers_len);
|
||||
|
||||
for (size_t i = 0; i < st->merged->readers_len; i++)
|
||||
sizes[i] = st->readers[i]->size - overhead;
|
||||
}
|
||||
|
||||
return sizes;
|
||||
}
|
||||
|
||||
|
@ -1320,12 +1448,12 @@ int reftable_stack_auto_compact(struct reftable_stack *st)
|
|||
{
|
||||
uint64_t *sizes = stack_table_sizes_for_compaction(st);
|
||||
struct segment seg =
|
||||
suggest_compaction_segment(sizes, st->merged->stack_len,
|
||||
suggest_compaction_segment(sizes, st->merged->readers_len,
|
||||
st->opts.auto_compaction_factor);
|
||||
reftable_free(sizes);
|
||||
if (segment_size(&seg) > 0)
|
||||
return stack_compact_range_stats(st, seg.start, seg.end - 1,
|
||||
NULL);
|
||||
NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1339,9 +1467,28 @@ reftable_stack_compaction_stats(struct reftable_stack *st)
|
|||
int reftable_stack_read_ref(struct reftable_stack *st, const char *refname,
|
||||
struct reftable_ref_record *ref)
|
||||
{
|
||||
struct reftable_table tab = { NULL };
|
||||
reftable_table_from_merged_table(&tab, reftable_stack_merged_table(st));
|
||||
return reftable_table_read_ref(&tab, refname, ref);
|
||||
struct reftable_iterator it = { 0 };
|
||||
int ret;
|
||||
|
||||
reftable_merged_table_init_ref_iterator(st->merged, &it);
|
||||
ret = reftable_iterator_seek_ref(&it, refname);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = reftable_iterator_next_ref(&it, ref);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (strcmp(ref->refname, refname) ||
|
||||
reftable_ref_record_is_deletion(ref)) {
|
||||
reftable_ref_record_release(ref);
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
reftable_iterator_destroy(&it);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int reftable_stack_read_log(struct reftable_stack *st, const char *refname,
|
||||
|
@ -1455,23 +1602,3 @@ done:
|
|||
reftable_addition_destroy(add);
|
||||
return err;
|
||||
}
|
||||
|
||||
int reftable_stack_print_directory(const char *stackdir, uint32_t hash_id)
|
||||
{
|
||||
struct reftable_stack *stack = NULL;
|
||||
struct reftable_write_options opts = { .hash_id = hash_id };
|
||||
struct reftable_merged_table *merged = NULL;
|
||||
struct reftable_table table = { NULL };
|
||||
|
||||
int err = reftable_new_stack(&stack, stackdir, &opts);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
merged = reftable_stack_merged_table(stack);
|
||||
reftable_table_from_merged_table(&table, merged);
|
||||
err = reftable_table_print(&table);
|
||||
done:
|
||||
if (stack)
|
||||
reftable_stack_destroy(stack);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,34 @@ static int write_test_ref(struct reftable_writer *wr, void *arg)
|
|||
return reftable_writer_add_ref(wr, ref);
|
||||
}
|
||||
|
||||
static void write_n_ref_tables(struct reftable_stack *st,
|
||||
size_t n)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int disable_auto_compact;
|
||||
int err;
|
||||
|
||||
disable_auto_compact = st->opts.disable_auto_compact;
|
||||
st->opts.disable_auto_compact = 1;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct reftable_ref_record ref = {
|
||||
.update_index = reftable_stack_next_update_index(st),
|
||||
.value_type = REFTABLE_REF_VAL1,
|
||||
};
|
||||
|
||||
strbuf_addf(&buf, "refs/heads/branch-%04u", (unsigned) i);
|
||||
ref.refname = buf.buf;
|
||||
set_test_hash(ref.value.val1, i);
|
||||
|
||||
err = reftable_stack_add(st, &write_test_ref, &ref);
|
||||
EXPECT_ERR(err);
|
||||
}
|
||||
|
||||
st->opts.disable_auto_compact = disable_auto_compact;
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
struct write_log_arg {
|
||||
struct reftable_log_record *log;
|
||||
uint64_t update_index;
|
||||
|
@ -151,13 +179,6 @@ static void test_reftable_stack_add_one(void)
|
|||
EXPECT(0 == strcmp("master", dest.value.symref));
|
||||
EXPECT(st->readers_len > 0);
|
||||
|
||||
printf("testing print functionality:\n");
|
||||
err = reftable_stack_print_directory(dir, GIT_SHA1_FORMAT_ID);
|
||||
EXPECT_ERR(err);
|
||||
|
||||
err = reftable_stack_print_directory(dir, GIT_SHA256_FORMAT_ID);
|
||||
EXPECT(err == REFTABLE_FORMAT_ERROR);
|
||||
|
||||
#ifndef GIT_WINDOWS_NATIVE
|
||||
strbuf_addstr(&scratch, dir);
|
||||
strbuf_addstr(&scratch, "/tables.list");
|
||||
|
@ -319,9 +340,9 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void)
|
|||
* all tables in the stack.
|
||||
*/
|
||||
if (i != n)
|
||||
EXPECT(st->merged->stack_len == i + 1);
|
||||
EXPECT(st->merged->readers_len == i + 1);
|
||||
else
|
||||
EXPECT(st->merged->stack_len == 1);
|
||||
EXPECT(st->merged->readers_len == 1);
|
||||
}
|
||||
|
||||
reftable_stack_destroy(st);
|
||||
|
@ -347,7 +368,7 @@ static void test_reftable_stack_auto_compaction_fails_gracefully(void)
|
|||
|
||||
err = reftable_stack_add(st, write_test_ref, &ref);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(st->merged->stack_len == 1);
|
||||
EXPECT(st->merged->readers_len == 1);
|
||||
EXPECT(st->stats.attempts == 0);
|
||||
EXPECT(st->stats.failures == 0);
|
||||
|
||||
|
@ -362,7 +383,7 @@ static void test_reftable_stack_auto_compaction_fails_gracefully(void)
|
|||
ref.update_index = 2;
|
||||
err = reftable_stack_add(st, write_test_ref, &ref);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(st->merged->stack_len == 2);
|
||||
EXPECT(st->merged->readers_len == 2);
|
||||
EXPECT(st->stats.attempts == 1);
|
||||
EXPECT(st->stats.failures == 1);
|
||||
|
||||
|
@ -853,7 +874,7 @@ static void test_reftable_stack_auto_compaction(void)
|
|||
|
||||
err = reftable_stack_auto_compact(st);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(i < 3 || st->merged->stack_len < 2 * fastlog2(i));
|
||||
EXPECT(i < 3 || st->merged->readers_len < 2 * fastlog2(i));
|
||||
}
|
||||
|
||||
EXPECT(reftable_stack_compaction_stats(st)->entries_written <
|
||||
|
@ -863,6 +884,47 @@ static void test_reftable_stack_auto_compaction(void)
|
|||
clear_dir(dir);
|
||||
}
|
||||
|
||||
static void test_reftable_stack_auto_compaction_with_locked_tables(void)
|
||||
{
|
||||
struct reftable_write_options opts = {
|
||||
.disable_auto_compact = 1,
|
||||
};
|
||||
struct reftable_stack *st = NULL;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char *dir = get_tmp_dir(__LINE__);
|
||||
int err;
|
||||
|
||||
err = reftable_new_stack(&st, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
|
||||
write_n_ref_tables(st, 5);
|
||||
EXPECT(st->merged->readers_len == 5);
|
||||
|
||||
/*
|
||||
* Given that all tables we have written should be roughly the same
|
||||
* size, we expect that auto-compaction will want to compact all of the
|
||||
* tables. Locking any of the tables will keep it from doing so.
|
||||
*/
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[2]->name);
|
||||
write_file_buf(buf.buf, "", 0);
|
||||
|
||||
/*
|
||||
* When parts of the stack are locked, then auto-compaction does a best
|
||||
* effort compaction of those tables which aren't locked. So while this
|
||||
* would in theory compact all tables, due to the preexisting lock we
|
||||
* only compact the newest two tables.
|
||||
*/
|
||||
err = reftable_stack_auto_compact(st);
|
||||
EXPECT_ERR(err);
|
||||
EXPECT(st->stats.failures == 0);
|
||||
EXPECT(st->merged->readers_len == 4);
|
||||
|
||||
reftable_stack_destroy(st);
|
||||
strbuf_release(&buf);
|
||||
clear_dir(dir);
|
||||
}
|
||||
|
||||
static void test_reftable_stack_add_performs_auto_compaction(void)
|
||||
{
|
||||
struct reftable_write_options opts = { 0 };
|
||||
|
@ -901,9 +963,9 @@ static void test_reftable_stack_add_performs_auto_compaction(void)
|
|||
* all tables in the stack.
|
||||
*/
|
||||
if (i != n)
|
||||
EXPECT(st->merged->stack_len == i + 1);
|
||||
EXPECT(st->merged->readers_len == i + 1);
|
||||
else
|
||||
EXPECT(st->merged->stack_len == 1);
|
||||
EXPECT(st->merged->readers_len == 1);
|
||||
}
|
||||
|
||||
reftable_stack_destroy(st);
|
||||
|
@ -911,30 +973,51 @@ static void test_reftable_stack_add_performs_auto_compaction(void)
|
|||
clear_dir(dir);
|
||||
}
|
||||
|
||||
static void test_reftable_stack_compaction_with_locked_tables(void)
|
||||
{
|
||||
struct reftable_write_options opts = {
|
||||
.disable_auto_compact = 1,
|
||||
};
|
||||
struct reftable_stack *st = NULL;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char *dir = get_tmp_dir(__LINE__);
|
||||
int err;
|
||||
|
||||
err = reftable_new_stack(&st, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
|
||||
write_n_ref_tables(st, 3);
|
||||
EXPECT(st->merged->readers_len == 3);
|
||||
|
||||
/* Lock one of the tables that we're about to compact. */
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[1]->name);
|
||||
write_file_buf(buf.buf, "", 0);
|
||||
|
||||
/*
|
||||
* Compaction is expected to fail given that we were not able to
|
||||
* compact all tables.
|
||||
*/
|
||||
err = reftable_stack_compact_all(st, NULL);
|
||||
EXPECT(err == REFTABLE_LOCK_ERROR);
|
||||
EXPECT(st->stats.failures == 1);
|
||||
EXPECT(st->merged->readers_len == 3);
|
||||
|
||||
reftable_stack_destroy(st);
|
||||
strbuf_release(&buf);
|
||||
clear_dir(dir);
|
||||
}
|
||||
|
||||
static void test_reftable_stack_compaction_concurrent(void)
|
||||
{
|
||||
struct reftable_write_options opts = { 0 };
|
||||
struct reftable_stack *st1 = NULL, *st2 = NULL;
|
||||
char *dir = get_tmp_dir(__LINE__);
|
||||
int err, i;
|
||||
int N = 3;
|
||||
int err;
|
||||
|
||||
err = reftable_new_stack(&st1, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
char name[100];
|
||||
struct reftable_ref_record ref = {
|
||||
.refname = name,
|
||||
.update_index = reftable_stack_next_update_index(st1),
|
||||
.value_type = REFTABLE_REF_SYMREF,
|
||||
.value.symref = (char *) "master",
|
||||
};
|
||||
snprintf(name, sizeof(name), "branch%04d", i);
|
||||
|
||||
err = reftable_stack_add(st1, &write_test_ref, &ref);
|
||||
EXPECT_ERR(err);
|
||||
}
|
||||
write_n_ref_tables(st1, 3);
|
||||
|
||||
err = reftable_new_stack(&st2, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
|
@ -965,25 +1048,11 @@ static void test_reftable_stack_compaction_concurrent_clean(void)
|
|||
struct reftable_write_options opts = { 0 };
|
||||
struct reftable_stack *st1 = NULL, *st2 = NULL, *st3 = NULL;
|
||||
char *dir = get_tmp_dir(__LINE__);
|
||||
int err, i;
|
||||
int N = 3;
|
||||
int err;
|
||||
|
||||
err = reftable_new_stack(&st1, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
char name[100];
|
||||
struct reftable_ref_record ref = {
|
||||
.refname = name,
|
||||
.update_index = reftable_stack_next_update_index(st1),
|
||||
.value_type = REFTABLE_REF_SYMREF,
|
||||
.value.symref = (char *) "master",
|
||||
};
|
||||
snprintf(name, sizeof(name), "branch%04d", i);
|
||||
|
||||
err = reftable_stack_add(st1, &write_test_ref, &ref);
|
||||
EXPECT_ERR(err);
|
||||
}
|
||||
write_n_ref_tables(st1, 3);
|
||||
|
||||
err = reftable_new_stack(&st2, dir, &opts);
|
||||
EXPECT_ERR(err);
|
||||
|
@ -1016,9 +1085,11 @@ int stack_test_main(int argc, const char *argv[])
|
|||
RUN_TEST(test_reftable_stack_add);
|
||||
RUN_TEST(test_reftable_stack_add_one);
|
||||
RUN_TEST(test_reftable_stack_auto_compaction);
|
||||
RUN_TEST(test_reftable_stack_auto_compaction_with_locked_tables);
|
||||
RUN_TEST(test_reftable_stack_add_performs_auto_compaction);
|
||||
RUN_TEST(test_reftable_stack_compaction_concurrent);
|
||||
RUN_TEST(test_reftable_stack_compaction_concurrent_clean);
|
||||
RUN_TEST(test_reftable_stack_compaction_with_locked_tables);
|
||||
RUN_TEST(test_reftable_stack_hash_id);
|
||||
RUN_TEST(test_reftable_stack_lock_failure);
|
||||
RUN_TEST(test_reftable_stack_log_normalize);
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
#include "git-compat-util.h"
|
||||
#include "hash.h"
|
||||
#include "hex.h"
|
||||
#include "reftable/system.h"
|
||||
#include "reftable/reftable-error.h"
|
||||
#include "reftable/reftable-merged.h"
|
||||
#include "reftable/reftable-reader.h"
|
||||
#include "reftable/reftable-stack.h"
|
||||
#include "reftable/reftable-tests.h"
|
||||
#include "test-tool.h"
|
||||
|
||||
|
@ -13,7 +20,187 @@ int cmd__reftable(int argc, const char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf("usage: dump [-st] arg\n\n"
|
||||
"options: \n"
|
||||
" -b dump blocks\n"
|
||||
" -t dump table\n"
|
||||
" -s dump stack\n"
|
||||
" -6 sha256 hash format\n"
|
||||
" -h this help\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
static int dump_table(struct reftable_merged_table *mt)
|
||||
{
|
||||
struct reftable_iterator it = { NULL };
|
||||
struct reftable_ref_record ref = { NULL };
|
||||
struct reftable_log_record log = { NULL };
|
||||
const struct git_hash_algo *algop;
|
||||
int err;
|
||||
|
||||
reftable_merged_table_init_ref_iterator(mt, &it);
|
||||
err = reftable_iterator_seek_ref(&it, "");
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
algop = &hash_algos[hash_algo_by_id(reftable_merged_table_hash_id(mt))];
|
||||
|
||||
while (1) {
|
||||
err = reftable_iterator_next_ref(&it, &ref);
|
||||
if (err > 0)
|
||||
break;
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
printf("ref{%s(%" PRIu64 ") ", ref.refname, ref.update_index);
|
||||
switch (ref.value_type) {
|
||||
case REFTABLE_REF_SYMREF:
|
||||
printf("=> %s", ref.value.symref);
|
||||
break;
|
||||
case REFTABLE_REF_VAL2:
|
||||
printf("val 2 %s", hash_to_hex_algop(ref.value.val2.value, algop));
|
||||
printf("(T %s)", hash_to_hex_algop(ref.value.val2.target_value, algop));
|
||||
break;
|
||||
case REFTABLE_REF_VAL1:
|
||||
printf("val 1 %s", hash_to_hex_algop(ref.value.val1, algop));
|
||||
break;
|
||||
case REFTABLE_REF_DELETION:
|
||||
printf("delete");
|
||||
break;
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
reftable_iterator_destroy(&it);
|
||||
reftable_ref_record_release(&ref);
|
||||
|
||||
reftable_merged_table_init_log_iterator(mt, &it);
|
||||
err = reftable_iterator_seek_log(&it, "");
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
while (1) {
|
||||
err = reftable_iterator_next_log(&it, &log);
|
||||
if (err > 0)
|
||||
break;
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
switch (log.value_type) {
|
||||
case REFTABLE_LOG_DELETION:
|
||||
printf("log{%s(%" PRIu64 ") delete\n", log.refname,
|
||||
log.update_index);
|
||||
break;
|
||||
case REFTABLE_LOG_UPDATE:
|
||||
printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n",
|
||||
log.refname, log.update_index,
|
||||
log.value.update.name ? log.value.update.name : "",
|
||||
log.value.update.email ? log.value.update.email : "",
|
||||
log.value.update.time,
|
||||
log.value.update.tz_offset);
|
||||
printf("%s => ", hash_to_hex_algop(log.value.update.old_hash, algop));
|
||||
printf("%s\n\n%s\n}\n", hash_to_hex_algop(log.value.update.new_hash, algop),
|
||||
log.value.update.message ? log.value.update.message : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
reftable_iterator_destroy(&it);
|
||||
reftable_log_record_release(&log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_stack(const char *stackdir, uint32_t hash_id)
|
||||
{
|
||||
struct reftable_stack *stack = NULL;
|
||||
struct reftable_write_options opts = { .hash_id = hash_id };
|
||||
struct reftable_merged_table *merged = NULL;
|
||||
|
||||
int err = reftable_new_stack(&stack, stackdir, &opts);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
merged = reftable_stack_merged_table(stack);
|
||||
err = dump_table(merged);
|
||||
done:
|
||||
if (stack)
|
||||
reftable_stack_destroy(stack);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dump_reftable(const char *tablename)
|
||||
{
|
||||
struct reftable_block_source src = { 0 };
|
||||
struct reftable_merged_table *mt = NULL;
|
||||
struct reftable_reader *r = NULL;
|
||||
int err;
|
||||
|
||||
err = reftable_block_source_from_file(&src, tablename);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
err = reftable_new_reader(&r, &src, tablename);
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
err = reftable_merged_table_new(&mt, &r, 1,
|
||||
reftable_reader_hash_id(r));
|
||||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
err = dump_table(mt);
|
||||
|
||||
done:
|
||||
reftable_merged_table_free(mt);
|
||||
reftable_reader_free(r);
|
||||
return err;
|
||||
}
|
||||
|
||||
int cmd__dump_reftable(int argc, const char **argv)
|
||||
{
|
||||
return reftable_dump_main(argc, (char *const *)argv);
|
||||
int err = 0;
|
||||
int opt_dump_blocks = 0;
|
||||
int opt_dump_table = 0;
|
||||
int opt_dump_stack = 0;
|
||||
uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID;
|
||||
const char *arg = NULL, *argv0 = argv[0];
|
||||
|
||||
for (; argc > 1; argv++, argc--)
|
||||
if (*argv[1] != '-')
|
||||
break;
|
||||
else if (!strcmp("-b", argv[1]))
|
||||
opt_dump_blocks = 1;
|
||||
else if (!strcmp("-t", argv[1]))
|
||||
opt_dump_table = 1;
|
||||
else if (!strcmp("-6", argv[1]))
|
||||
opt_hash_id = GIT_SHA256_FORMAT_ID;
|
||||
else if (!strcmp("-s", argv[1]))
|
||||
opt_dump_stack = 1;
|
||||
else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) {
|
||||
print_help();
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "need argument\n");
|
||||
print_help();
|
||||
return 2;
|
||||
}
|
||||
|
||||
arg = argv[1];
|
||||
|
||||
if (opt_dump_blocks) {
|
||||
err = reftable_reader_print_blocks(arg);
|
||||
} else if (opt_dump_table) {
|
||||
err = dump_reftable(arg);
|
||||
} else if (opt_dump_stack) {
|
||||
err = dump_stack(arg, opt_hash_id);
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "%s: %s: %s\n", argv0, arg,
|
||||
reftable_error_str(err));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -478,19 +478,26 @@ test_expect_success "$command: auto compaction" '
|
|||
|
||||
test_oid blob17_2 | git hash-object -w --stdin &&
|
||||
|
||||
# Lock all tables write some refs. Auto-compaction will be
|
||||
# unable to compact tables and thus fails gracefully, leaving
|
||||
# the stack in a sub-optimal state.
|
||||
ls .git/reftable/*.ref |
|
||||
# Lock all tables, write some refs. Auto-compaction will be
|
||||
# unable to compact tables and thus fails gracefully,
|
||||
# compacting only those tables which are not locked.
|
||||
ls .git/reftable/*.ref | sort |
|
||||
while read table
|
||||
do
|
||||
touch "$table.lock" || exit 1
|
||||
touch "$table.lock" &&
|
||||
basename "$table" >>tables.expect || exit 1
|
||||
done &&
|
||||
test_line_count = 2 .git/reftable/tables.list &&
|
||||
git branch B &&
|
||||
git branch C &&
|
||||
rm .git/reftable/*.lock &&
|
||||
test_line_count = 4 .git/reftable/tables.list &&
|
||||
|
||||
# The new tables are auto-compacted, but the locked tables are
|
||||
# left intact.
|
||||
test_line_count = 3 .git/reftable/tables.list &&
|
||||
head -n 2 .git/reftable/tables.list >tables.head &&
|
||||
test_cmp tables.expect tables.head &&
|
||||
|
||||
rm .git/reftable/*.lock &&
|
||||
git $command --auto &&
|
||||
test_line_count = 1 .git/reftable/tables.list
|
||||
)
|
||||
|
|
|
@ -12,7 +12,6 @@ https://developers.google.com/open-source/licenses/bsd
|
|||
#include "reftable/merged.h"
|
||||
#include "reftable/reader.h"
|
||||
#include "reftable/reftable-error.h"
|
||||
#include "reftable/reftable-generic.h"
|
||||
#include "reftable/reftable-merged.h"
|
||||
#include "reftable/reftable-writer.h"
|
||||
|
||||
|
@ -94,10 +93,8 @@ merged_table_from_records(struct reftable_ref_record **refs,
|
|||
struct strbuf *buf, const size_t n)
|
||||
{
|
||||
struct reftable_merged_table *mt = NULL;
|
||||
struct reftable_table *tabs;
|
||||
int err;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(tabs, n);
|
||||
REFTABLE_CALLOC_ARRAY(*readers, n);
|
||||
REFTABLE_CALLOC_ARRAY(*source, n);
|
||||
|
||||
|
@ -108,10 +105,9 @@ merged_table_from_records(struct reftable_ref_record **refs,
|
|||
err = reftable_new_reader(&(*readers)[i], &(*source)[i],
|
||||
"name");
|
||||
check(!err);
|
||||
reftable_table_from_reader(&tabs[i], (*readers)[i]);
|
||||
}
|
||||
|
||||
err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
|
||||
err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
|
||||
check(!err);
|
||||
return mt;
|
||||
}
|
||||
|
@ -272,10 +268,8 @@ merged_table_from_log_records(struct reftable_log_record **logs,
|
|||
struct strbuf *buf, const size_t n)
|
||||
{
|
||||
struct reftable_merged_table *mt = NULL;
|
||||
struct reftable_table *tabs;
|
||||
int err;
|
||||
|
||||
REFTABLE_CALLOC_ARRAY(tabs, n);
|
||||
REFTABLE_CALLOC_ARRAY(*readers, n);
|
||||
REFTABLE_CALLOC_ARRAY(*source, n);
|
||||
|
||||
|
@ -286,10 +280,9 @@ merged_table_from_log_records(struct reftable_log_record **logs,
|
|||
err = reftable_new_reader(&(*readers)[i], &(*source)[i],
|
||||
"name");
|
||||
check(!err);
|
||||
reftable_table_from_reader(&tabs[i], (*readers)[i]);
|
||||
}
|
||||
|
||||
err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
|
||||
err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID);
|
||||
check(!err);
|
||||
return mt;
|
||||
}
|
||||
|
@ -418,7 +411,6 @@ static void t_default_write_opts(void)
|
|||
};
|
||||
int err;
|
||||
struct reftable_block_source source = { 0 };
|
||||
struct reftable_table *tab = reftable_calloc(1, sizeof(*tab));
|
||||
uint32_t hash_id;
|
||||
struct reftable_reader *rd = NULL;
|
||||
struct reftable_merged_table *merged = NULL;
|
||||
|
@ -440,10 +432,9 @@ static void t_default_write_opts(void)
|
|||
hash_id = reftable_reader_hash_id(rd);
|
||||
check_int(hash_id, ==, GIT_SHA1_FORMAT_ID);
|
||||
|
||||
reftable_table_from_reader(&tab[0], rd);
|
||||
err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA256_FORMAT_ID);
|
||||
err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA256_FORMAT_ID);
|
||||
check_int(err, ==, REFTABLE_FORMAT_ERROR);
|
||||
err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA1_FORMAT_ID);
|
||||
err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA1_FORMAT_ID);
|
||||
check(!err);
|
||||
|
||||
reftable_reader_free(rd);
|
||||
|
|
Loading…
Reference in New Issue