aboutsummaryrefslogtreecommitdiffstats
path: root/refs/reftable-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'refs/reftable-backend.c')
-rw-r--r--refs/reftable-backend.c170
1 files changed, 112 insertions, 58 deletions
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index c0440b4bd0..c23c45f3bf 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -6,20 +6,21 @@
#include "../config.h"
#include "../dir.h"
#include "../environment.h"
+#include "../fsck.h"
#include "../gettext.h"
#include "../hash.h"
#include "../hex.h"
#include "../iterator.h"
#include "../ident.h"
-#include "../lockfile.h"
#include "../object.h"
#include "../path.h"
#include "../refs.h"
#include "../reftable/reftable-basics.h"
-#include "../reftable/reftable-stack.h"
-#include "../reftable/reftable-record.h"
#include "../reftable/reftable-error.h"
+#include "../reftable/reftable-fsck.h"
#include "../reftable/reftable-iterator.h"
+#include "../reftable/reftable-record.h"
+#include "../reftable/reftable-stack.h"
#include "../repo-settings.h"
#include "../setup.h"
#include "../strmap.h"
@@ -546,6 +547,7 @@ struct reftable_ref_iterator {
struct reftable_iterator iter;
struct reftable_ref_record ref;
struct object_id oid;
+ struct object_id peeled_oid;
char *prefix;
size_t prefix_len;
@@ -670,6 +672,8 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
case REFTABLE_REF_VAL2:
oidread(&iter->oid, iter->ref.value.val2.value,
refs->base.repo->hash_algo);
+ oidread(&iter->peeled_oid, iter->ref.value.val2.target_value,
+ refs->base.repo->hash_algo);
break;
case REFTABLE_REF_SYMREF:
referent = refs_resolve_ref_unsafe(&iter->refs->base,
@@ -703,10 +707,13 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
&iter->oid, flags))
continue;
- iter->base.refname = iter->ref.refname;
- iter->base.referent = referent;
- iter->base.oid = &iter->oid;
- iter->base.flags = flags;
+ memset(&iter->base.ref, 0, sizeof(iter->base.ref));
+ iter->base.ref.name = iter->ref.refname;
+ iter->base.ref.target = referent;
+ iter->base.ref.oid = &iter->oid;
+ if (iter->ref.value_type == REFTABLE_REF_VAL2)
+ iter->base.ref.peeled_oid = &iter->peeled_oid;
+ iter->base.ref.flags = flags;
break;
}
@@ -737,21 +744,6 @@ static int reftable_ref_iterator_seek(struct ref_iterator *ref_iterator,
return iter->err;
}
-static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
- struct object_id *peeled)
-{
- struct reftable_ref_iterator *iter =
- (struct reftable_ref_iterator *)ref_iterator;
-
- if (iter->ref.value_type == REFTABLE_REF_VAL2) {
- oidread(peeled, iter->ref.value.val2.target_value,
- iter->refs->base.repo->hash_algo);
- return 0;
- }
-
- return -1;
-}
-
static void reftable_ref_iterator_release(struct ref_iterator *ref_iterator)
{
struct reftable_ref_iterator *iter =
@@ -769,7 +761,6 @@ static void reftable_ref_iterator_release(struct ref_iterator *ref_iterator)
static struct ref_iterator_vtable reftable_ref_iterator_vtable = {
.advance = reftable_ref_iterator_advance,
.seek = reftable_ref_iterator_seek,
- .peel = reftable_ref_iterator_peel,
.release = reftable_ref_iterator_release,
};
@@ -827,7 +818,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
iter = xcalloc(1, sizeof(*iter));
base_ref_iterator_init(&iter->base, &reftable_ref_iterator_vtable);
- iter->base.oid = &iter->oid;
+ iter->base.ref.oid = &iter->oid;
iter->flags = flags;
iter->refs = refs;
iter->exclude_patterns = filter_exclude_patterns(exclude_patterns);
@@ -1012,10 +1003,6 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
if (!arg) {
struct reftable_addition *addition;
- ret = reftable_stack_reload(be->stack);
- if (ret)
- return ret;
-
ret = reftable_stack_new_addition(&addition, be->stack,
REFTABLE_STACK_NEW_ADDITION_RELOAD);
if (ret) {
@@ -1278,9 +1265,33 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
ret = ref_update_check_old_target(referent->buf, u, err);
if (ret)
return ret;
- } else if ((u->flags & (REF_LOG_ONLY | REF_HAVE_OLD)) == REF_HAVE_OLD &&
- !oideq(&current_oid, &u->old_oid)) {
- if (is_null_oid(&u->old_oid)) {
+ } else if ((u->flags & (REF_LOG_ONLY | REF_HAVE_OLD)) == REF_HAVE_OLD) {
+ if (oideq(&current_oid, &u->old_oid)) {
+ /*
+ * Normally matching the expected old oid is enough. Either we
+ * found the ref at the expected state, or we are creating and
+ * expect the null oid (and likewise found nothing).
+ *
+ * But there is one exception for the null oid: if we found a
+ * symref pointing to nothing we'll also get the null oid. In
+ * regular recursive mode, that's good (we'll write to what the
+ * symref points to, which doesn't exist). But in no-deref
+ * mode, it means we'll clobber the symref, even though the
+ * caller asked for this to be a creation event. So flag
+ * that case to preserve the dangling symref.
+ *
+ * Everything else is OK and we can fall through to the
+ * end of the conditional chain.
+ */
+ if ((u->flags & REF_NO_DEREF) &&
+ referent->len &&
+ is_null_oid(&u->old_oid)) {
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "dangling symref already exists"),
+ ref_update_original_update_refname(u));
+ return REF_TRANSACTION_ERROR_CREATE_EXISTS;
+ }
+ } else if (is_null_oid(&u->old_oid)) {
strbuf_addf(err, _("cannot lock ref '%s': "
"reference already exists"),
ref_update_original_update_refname(u));
@@ -1621,7 +1632,8 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
ref.refname = (char *)u->refname;
ref.update_index = ts;
- peel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled);
+ peel_error = peel_object(arg->refs->base.repo, &u->new_oid, &peeled,
+ PEEL_OBJECT_VERIFY_OBJECT_TYPE);
if (!peel_error) {
ref.value_type = REFTABLE_REF_VAL2;
memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
@@ -1688,11 +1700,11 @@ done:
return ret;
}
-static int reftable_be_pack_refs(struct ref_store *ref_store,
- struct pack_refs_opts *opts)
+static int reftable_be_optimize(struct ref_store *ref_store,
+ struct refs_optimize_opts *opts)
{
struct reftable_ref_store *refs =
- reftable_be_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB, "pack_refs");
+ reftable_be_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB, "optimize_refs");
struct reftable_stack *stack;
int ret;
@@ -1703,7 +1715,7 @@ static int reftable_be_pack_refs(struct ref_store *ref_store,
if (!stack)
stack = refs->main_backend.stack;
- if (opts->flags & PACK_REFS_AUTO)
+ if (opts->flags & REFS_OPTIMIZE_AUTO)
ret = reftable_stack_auto_compact(stack);
else
ret = reftable_stack_compact_all(stack, NULL);
@@ -1974,7 +1986,8 @@ static int reftable_be_rename_ref(struct ref_store *ref_store,
ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
if (ret)
goto done;
- ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
+ ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
+ REFTABLE_STACK_NEW_ADDITION_RELOAD);
done:
assert(ret != REFTABLE_API_ERROR);
@@ -2003,7 +2016,8 @@ static int reftable_be_copy_ref(struct ref_store *ref_store,
ret = backend_for(&arg.be, refs, newrefname, &newrefname, 1);
if (ret)
goto done;
- ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg);
+ ret = reftable_stack_add(arg.be->stack, &write_copy_table, &arg,
+ REFTABLE_STACK_NEW_ADDITION_RELOAD);
done:
assert(ret != REFTABLE_API_ERROR);
@@ -2043,7 +2057,7 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
strbuf_reset(&iter->last_name);
strbuf_addstr(&iter->last_name, iter->log.refname);
- iter->base.refname = iter->log.refname;
+ iter->base.ref.name = iter->log.refname;
break;
}
@@ -2063,13 +2077,6 @@ static int reftable_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSE
return -1;
}
-static int reftable_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
- struct object_id *peeled UNUSED)
-{
- BUG("reftable reflog iterator cannot be peeled");
- return -1;
-}
-
static void reftable_reflog_iterator_release(struct ref_iterator *ref_iterator)
{
struct reftable_reflog_iterator *iter =
@@ -2082,7 +2089,6 @@ static void reftable_reflog_iterator_release(struct ref_iterator *ref_iterator)
static struct ref_iterator_vtable reftable_reflog_iterator_vtable = {
.advance = reftable_reflog_iterator_advance,
.seek = reftable_reflog_iterator_seek,
- .peel = reftable_reflog_iterator_peel,
.release = reftable_reflog_iterator_release,
};
@@ -2155,7 +2161,7 @@ static int yield_log_record(struct reftable_ref_store *refs,
full_committer = fmt_ident(log->value.update.name, log->value.update.email,
WANT_COMMITTER_IDENT, NULL, IDENT_NO_DATE);
- return fn(&old_oid, &new_oid, full_committer,
+ return fn(log->refname, &old_oid, &new_oid, full_committer,
log->value.update.time, log->value.update.tz_offset,
log->value.update.message, cb_data);
}
@@ -2375,7 +2381,8 @@ static int reftable_be_create_reflog(struct ref_store *ref_store,
goto done;
arg.stack = be->stack;
- ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg);
+ ret = reftable_stack_add(be->stack, &write_reflog_existence_table, &arg,
+ REFTABLE_STACK_NEW_ADDITION_RELOAD);
done:
return ret;
@@ -2446,7 +2453,8 @@ static int reftable_be_delete_reflog(struct ref_store *ref_store,
return ret;
arg.stack = be->stack;
- ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg);
+ ret = reftable_stack_add(be->stack, &write_reflog_delete_table, &arg,
+ REFTABLE_STACK_NEW_ADDITION_RELOAD);
assert(ret != REFTABLE_API_ERROR);
return ret;
@@ -2484,7 +2492,7 @@ static int write_reflog_expiry_table(struct reftable_writer *writer, void *cb_da
ref.refname = (char *)arg->refname;
ref.update_index = ts;
- if (!peel_object(arg->refs->base.repo, &arg->update_oid, &peeled)) {
+ if (!peel_object(arg->refs->base.repo, &arg->update_oid, &peeled, 0)) {
ref.value_type = REFTABLE_REF_VAL2;
memcpy(ref.value.val2.target_value, peeled.hash, GIT_MAX_RAWSZ);
memcpy(ref.value.val2.value, arg->update_oid.hash, GIT_MAX_RAWSZ);
@@ -2567,15 +2575,16 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0)
goto done;
- ret = reftable_stack_init_log_iterator(be->stack, &it);
+ ret = reftable_stack_new_addition(&add, be->stack,
+ REFTABLE_STACK_NEW_ADDITION_RELOAD);
if (ret < 0)
goto done;
- ret = reftable_iterator_seek_log(&it, refname);
+ ret = reftable_stack_init_log_iterator(be->stack, &it);
if (ret < 0)
goto done;
- ret = reftable_stack_new_addition(&add, be->stack, 0);
+ ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0)
goto done;
@@ -2683,11 +2692,56 @@ done:
return ret;
}
-static int reftable_be_fsck(struct ref_store *ref_store UNUSED,
- struct fsck_options *o UNUSED,
+static void reftable_fsck_verbose_handler(const char *msg, void *cb_data)
+{
+ struct fsck_options *o = cb_data;
+
+ if (o->verbose)
+ fprintf_ln(stderr, "%s", msg);
+}
+
+static const enum fsck_msg_id fsck_msg_id_map[] = {
+ [REFTABLE_FSCK_ERROR_TABLE_NAME] = FSCK_MSG_BAD_REFTABLE_TABLE_NAME,
+};
+
+static int reftable_fsck_error_handler(struct reftable_fsck_info *info,
+ void *cb_data)
+{
+ struct fsck_ref_report report = { .path = info->path };
+ struct fsck_options *o = cb_data;
+ enum fsck_msg_id msg_id;
+
+ if (info->error < 0 || info->error >= REFTABLE_FSCK_MAX_VALUE)
+ BUG("unknown fsck error: %d", (int)info->error);
+
+ msg_id = fsck_msg_id_map[info->error];
+
+ if (!msg_id)
+ BUG("fsck_msg_id value missing for reftable error: %d", (int)info->error);
+
+ return fsck_report_ref(o, &report, msg_id, "%s", info->msg);
+}
+
+static int reftable_be_fsck(struct ref_store *ref_store, struct fsck_options *o,
struct worktree *wt UNUSED)
{
- return 0;
+ struct reftable_ref_store *refs;
+ struct strmap_entry *entry;
+ struct hashmap_iter iter;
+ int ret = 0;
+
+ refs = reftable_be_downcast(ref_store, REF_STORE_READ, "fsck");
+
+ ret |= reftable_fsck_check(refs->main_backend.stack, reftable_fsck_error_handler,
+ reftable_fsck_verbose_handler, o);
+
+ strmap_for_each_entry(&refs->worktree_backends, &iter, entry) {
+ struct reftable_backend *b = (struct reftable_backend *)entry->value;
+ ret |= reftable_fsck_check(b->stack, reftable_fsck_error_handler,
+ reftable_fsck_verbose_handler, o);
+ }
+
+ return ret;
}
struct ref_storage_be refs_be_reftable = {
@@ -2701,7 +2755,7 @@ struct ref_storage_be refs_be_reftable = {
.transaction_finish = reftable_be_transaction_finish,
.transaction_abort = reftable_be_transaction_abort,
- .pack_refs = reftable_be_pack_refs,
+ .optimize = reftable_be_optimize,
.rename_ref = reftable_be_rename_ref,
.copy_ref = reftable_be_copy_ref,