git/reftable/iter.c
Han-Wen Nienhuys 66c0dabab5 reftable: make reftable_record a tagged union
This reduces the amount of glue code, because we don't need a void
pointer or vtable within the structure.

The only snag is that reftable_index_record contain a strbuf, so it
cannot be zero-initialized. To address this, use reftable_new_record()
to return fresh instance, given a record type. Since
reftable_new_record() doesn't cause heap allocation anymore, it should
be balanced with reftable_record_release() rather than
reftable_record_destroy().

Thanks to Peff for the suggestion.

Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-01-20 11:31:53 -08:00

194 lines
4.3 KiB
C

/*
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 "iter.h"
#include "system.h"
#include "block.h"
#include "generic.h"
#include "constants.h"
#include "reader.h"
#include "reftable-error.h"
int iterator_is_null(struct reftable_iterator *it)
{
return !it->ops;
}
static void filtering_ref_iterator_close(void *iter_arg)
{
struct filtering_ref_iterator *fri = iter_arg;
strbuf_release(&fri->oid);
reftable_iterator_destroy(&fri->it);
}
static int filtering_ref_iterator_next(void *iter_arg,
struct reftable_record *rec)
{
struct filtering_ref_iterator *fri = iter_arg;
struct reftable_ref_record *ref = &rec->u.ref;
int err = 0;
while (1) {
err = reftable_iterator_next_ref(&fri->it, ref);
if (err != 0) {
break;
}
if (fri->double_check) {
struct reftable_iterator it = { NULL };
err = reftable_table_seek_ref(&fri->tab, &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) ||
!memcmp(fri->oid.buf, ref->value.val2.value,
fri->oid.len)))
return 0;
if (ref->value_type == REFTABLE_REF_VAL1 &&
!memcmp(fri->oid.buf, ref->value.val1, fri->oid.len)) {
return 0;
}
}
reftable_ref_record_release(ref);
return err;
}
static struct reftable_iterator_vtable filtering_ref_iterator_vtable = {
.next = &filtering_ref_iterator_next,
.close = &filtering_ref_iterator_close,
};
void iterator_from_filtering_ref_iterator(struct reftable_iterator *it,
struct filtering_ref_iterator *fri)
{
assert(!it->ops);
it->iter_arg = fri;
it->ops = &filtering_ref_iterator_vtable;
}
static void indexed_table_ref_iter_close(void *p)
{
struct indexed_table_ref_iter *it = p;
block_iter_close(&it->cur);
reftable_block_done(&it->block_reader.block);
reftable_free(it->offsets);
strbuf_release(&it->oid);
}
static int indexed_table_ref_iter_next_block(struct indexed_table_ref_iter *it)
{
uint64_t off;
int err = 0;
if (it->offset_idx == it->offset_len) {
it->is_finished = 1;
return 1;
}
reftable_block_done(&it->block_reader.block);
off = it->offsets[it->offset_idx++];
err = reader_init_block_reader(it->r, &it->block_reader, off,
BLOCK_TYPE_REF);
if (err < 0) {
return err;
}
if (err > 0) {
/* indexed block does not exist. */
return REFTABLE_FORMAT_ERROR;
}
block_reader_start(&it->block_reader, &it->cur);
return 0;
}
static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
{
struct indexed_table_ref_iter *it = p;
struct reftable_ref_record *ref = &rec->u.ref;
while (1) {
int err = block_iter_next(&it->cur, rec);
if (err < 0) {
return err;
}
if (err > 0) {
err = indexed_table_ref_iter_next_block(it);
if (err < 0) {
return err;
}
if (it->is_finished) {
return 1;
}
continue;
}
/* BUG */
if (!memcmp(it->oid.buf, ref->value.val2.target_value,
it->oid.len) ||
!memcmp(it->oid.buf, ref->value.val2.value, it->oid.len)) {
return 0;
}
}
}
int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
struct reftable_reader *r, uint8_t *oid,
int oid_len, uint64_t *offsets, int offset_len)
{
struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
struct indexed_table_ref_iter *itr =
reftable_calloc(sizeof(struct indexed_table_ref_iter));
int err = 0;
*itr = empty;
itr->r = r;
strbuf_add(&itr->oid, oid, oid_len);
itr->offsets = offsets;
itr->offset_len = offset_len;
err = indexed_table_ref_iter_next_block(itr);
if (err < 0) {
reftable_free(itr);
} else {
*dest = itr;
}
return err;
}
static struct reftable_iterator_vtable indexed_table_ref_iter_vtable = {
.next = &indexed_table_ref_iter_next,
.close = &indexed_table_ref_iter_close,
};
void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
struct indexed_table_ref_iter *itr)
{
assert(!it->ops);
it->iter_arg = itr;
it->ops = &indexed_table_ref_iter_vtable;
}