aboutsummaryrefslogtreecommitdiffstats
path: root/refs
diff options
context:
space:
mode:
Diffstat (limited to 'refs')
-rw-r--r--refs/debug.c11
-rw-r--r--refs/files-backend.c269
-rw-r--r--refs/iterator.c4
-rw-r--r--refs/packed-backend.c38
-rw-r--r--refs/packed-backend.h7
-rw-r--r--refs/ref-cache.c5
-rw-r--r--refs/ref-cache.h2
-rw-r--r--refs/refs-internal.h10
-rw-r--r--refs/reftable-backend.c283
9 files changed, 533 insertions, 96 deletions
diff --git a/refs/debug.c b/refs/debug.c
index 547d9245b9..45e2e784a0 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -419,6 +419,15 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
return res;
}
+static int debug_fsck(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
+ int res = drefs->refs->be->fsck(drefs->refs, o);
+ trace_printf_key(&trace_refs, "fsck: %d\n", res);
+ return res;
+}
+
struct ref_storage_be refs_be_debug = {
.name = "debug",
.init = NULL,
@@ -451,4 +460,6 @@ struct ref_storage_be refs_be_debug = {
.create_reflog = debug_create_reflog,
.delete_reflog = debug_delete_reflog,
.reflog_expire = debug_reflog_expire,
+
+ .fsck = debug_fsck,
};
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 11551de8f8..0824c0b8a9 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1,12 +1,15 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "../git-compat-util.h"
+#include "../config.h"
#include "../copy.h"
#include "../environment.h"
#include "../gettext.h"
#include "../hash.h"
#include "../hex.h"
+#include "../fsck.h"
#include "../refs.h"
+#include "../repo-settings.h"
#include "refs-internal.h"
#include "ref-cache.h"
#include "packed-backend.h"
@@ -73,6 +76,8 @@ struct files_ref_store {
unsigned int store_flags;
char *gitcommondir;
+ enum log_refs_config log_all_ref_updates;
+ int prefer_symlink_refs;
struct ref_cache *loose;
@@ -105,6 +110,8 @@ static struct ref_store *files_ref_store_init(struct repository *repo,
refs->gitcommondir = strbuf_detach(&sb, NULL);
refs->packed_ref_store =
packed_ref_store_init(repo, refs->gitcommondir, flags);
+ refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
+ repo_config_get_bool(repo, "core.prefersymlinkrefs", &refs->prefer_symlink_refs);
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
@@ -246,10 +253,13 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
{
struct object_id oid;
int flag;
+ const char *referent = refs_resolve_ref_unsafe(&refs->base,
+ refname,
+ RESOLVE_REF_READING,
+ &oid, &flag);
- if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING,
- &oid, &flag)) {
- oidclr(&oid, the_repository->hash_algo);
+ if (!referent) {
+ oidclr(&oid, refs->base.repo->hash_algo);
flag |= REF_ISBROKEN;
} else if (is_null_oid(&oid)) {
/*
@@ -266,10 +276,14 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
if (!refname_is_safe(refname))
die("loose refname is dangerous: %s", refname);
- oidclr(&oid, the_repository->hash_algo);
+ oidclr(&oid, refs->base.repo->hash_algo);
flag |= REF_BAD_NAME | REF_ISBROKEN;
}
- add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag));
+
+ if (!(flag & REF_ISSYMREF))
+ referent = NULL;
+
+ add_entry_to_dir(dir, create_ref_entry(refname, referent, &oid, flag));
}
/*
@@ -553,7 +567,8 @@ stat_ref:
strbuf_rtrim(&sb_contents);
buf = sb_contents.buf;
- ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr);
+ ret = parse_loose_ref_contents(ref_store->repo->hash_algo, buf,
+ oid, referent, type, &myerr);
out:
if (ret && !myerr)
@@ -587,7 +602,8 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn
return !(type & REF_ISSYMREF);
}
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+ const char *buf, struct object_id *oid,
struct strbuf *referent, unsigned int *type,
int *failure_errno)
{
@@ -605,7 +621,7 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,
/*
* FETCH_HEAD has additional data after the sha.
*/
- if (parse_oid_hex(buf, oid, &p) ||
+ if (parse_oid_hex_algop(buf, oid, &p, algop) ||
(*p != '\0' && !isspace(*p))) {
*type |= REF_ISBROKEN;
*failure_errno = EINVAL;
@@ -887,6 +903,8 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
iter->base.refname = iter->iter0->refname;
iter->base.oid = iter->iter0->oid;
iter->base.flags = iter->iter0->flags;
+ iter->base.referent = iter->iter0->referent;
+
return ITER_OK;
}
@@ -1153,7 +1171,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0,
&lock->old_oid, NULL))
- oidclr(&lock->old_oid, the_repository->hash_algo);
+ oidclr(&lock->old_oid, refs->base.repo->hash_algo);
goto out;
error_return:
@@ -1301,6 +1319,68 @@ static int should_pack_ref(struct files_ref_store *refs,
return 0;
}
+static int should_pack_refs(struct files_ref_store *refs,
+ struct pack_refs_opts *opts)
+{
+ struct ref_iterator *iter;
+ size_t packed_size;
+ size_t refcount = 0;
+ size_t limit;
+ int ret;
+
+ if (!(opts->flags & PACK_REFS_AUTO))
+ return 1;
+
+ ret = packed_refs_size(refs->packed_ref_store, &packed_size);
+ if (ret < 0)
+ die("cannot determine packed-refs size");
+
+ /*
+ * Packing loose references into the packed-refs file scales with the
+ * number of references we're about to write. We thus decide whether we
+ * repack refs by weighing the current size of the packed-refs file
+ * against the number of loose references. This is done such that we do
+ * not repack too often on repositories with a huge number of
+ * references, where we can expect a lot of churn in the number of
+ * references.
+ *
+ * As a heuristic, we repack if the number of loose references in the
+ * repository exceeds `log2(nr_packed_refs) * 5`, where we estimate
+ * `nr_packed_refs = packed_size / 100`, which scales as following:
+ *
+ * - 1kB ~ 10 packed refs: 16 refs
+ * - 10kB ~ 100 packed refs: 33 refs
+ * - 100kB ~ 1k packed refs: 49 refs
+ * - 1MB ~ 10k packed refs: 66 refs
+ * - 10MB ~ 100k packed refs: 82 refs
+ * - 100MB ~ 1m packed refs: 99 refs
+ *
+ * We thus allow roughly 16 additional loose refs per factor of ten of
+ * packed refs. This heuristic may be tweaked in the future, but should
+ * serve as a sufficiently good first iteration.
+ */
+ limit = log2u(packed_size / 100) * 5;
+ if (limit < 16)
+ limit = 16;
+
+ iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
+ refs->base.repo, 0);
+ while ((ret = ref_iterator_advance(iter)) == ITER_OK) {
+ if (should_pack_ref(refs, iter->refname, iter->oid,
+ iter->flags, opts))
+ refcount++;
+ if (refcount >= limit) {
+ ref_iterator_abort(iter);
+ return 1;
+ }
+ }
+
+ if (ret != ITER_DONE)
+ die("error while iterating over references");
+
+ return 0;
+}
+
static int files_pack_refs(struct ref_store *ref_store,
struct pack_refs_opts *opts)
{
@@ -1313,6 +1393,9 @@ static int files_pack_refs(struct ref_store *ref_store,
struct strbuf err = STRBUF_INIT;
struct ref_transaction *transaction;
+ if (!should_pack_refs(refs, opts))
+ return 0;
+
transaction = ref_store_transaction_begin(refs->packed_ref_store, &err);
if (!transaction)
return -1;
@@ -1431,6 +1514,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,
static int commit_ref_update(struct files_ref_store *refs,
struct ref_lock *lock,
const struct object_id *oid, const char *logmsg,
+ int flags,
struct strbuf *err);
/*
@@ -1574,7 +1658,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
oidcpy(&lock->old_oid, &orig_oid);
if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
- commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
+ commit_ref_update(refs, lock, &orig_oid, logmsg, 0, &err)) {
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
strbuf_release(&err);
goto rollback;
@@ -1591,14 +1675,11 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
goto rollbacklog;
}
- flag = log_all_ref_updates;
- log_all_ref_updates = LOG_REFS_NONE;
if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
- commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
+ commit_ref_update(refs, lock, &orig_oid, NULL, REF_SKIP_CREATE_REFLOG, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
}
- log_all_ref_updates = flag;
rollbacklog:
if (logmoved && rename(sb_newref.buf, sb_oldref.buf))
@@ -1693,13 +1774,17 @@ static int log_ref_setup(struct files_ref_store *refs,
const char *refname, int force_create,
int *logfd, struct strbuf *err)
{
+ enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
struct strbuf logfile_sb = STRBUF_INIT;
char *logfile;
+ if (log_refs_cfg == LOG_REFS_UNSET)
+ log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+
files_reflog_path(refs, &logfile_sb, refname);
logfile = strbuf_detach(&logfile_sb, NULL);
- if (force_create || should_autocreate_reflog(refname)) {
+ if (force_create || should_autocreate_reflog(log_refs_cfg, refname)) {
if (raceproof_create_file(logfile, open_or_create_logfile, logfd)) {
if (errno == ENOENT)
strbuf_addf(err, "unable to create directory for '%s': "
@@ -1788,9 +1873,6 @@ static int files_log_ref_write(struct files_ref_store *refs,
if (flags & REF_SKIP_CREATE_REFLOG)
return 0;
- if (log_all_ref_updates == LOG_REFS_UNSET)
- log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
-
result = log_ref_setup(refs, refname,
flags & REF_FORCE_CREATE_REFLOG,
&logfd, err);
@@ -1879,6 +1961,7 @@ static int write_ref_to_lockfile(struct files_ref_store *refs,
static int commit_ref_update(struct files_ref_store *refs,
struct ref_lock *lock,
const struct object_id *oid, const char *logmsg,
+ int flags,
struct strbuf *err)
{
files_assert_main_repository(refs, "commit_ref_update");
@@ -1886,7 +1969,7 @@ static int commit_ref_update(struct files_ref_store *refs,
clear_loose_ref_cache(refs);
if (files_log_ref_write(refs, lock->ref_name,
&lock->old_oid, oid,
- logmsg, 0, err)) {
+ logmsg, flags, err)) {
char *old_msg = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot update the ref '%s': %s",
lock->ref_name, old_msg);
@@ -1919,7 +2002,7 @@ static int commit_ref_update(struct files_ref_store *refs,
struct strbuf log_err = STRBUF_INIT;
if (files_log_ref_write(refs, "HEAD",
&lock->old_oid, oid,
- logmsg, 0, &log_err)) {
+ logmsg, flags, &log_err)) {
error("%s", log_err.buf);
strbuf_release(&log_err);
}
@@ -1936,10 +2019,13 @@ static int commit_ref_update(struct files_ref_store *refs,
return 0;
}
+#ifdef NO_SYMLINK_HEAD
+#define create_ref_symlink(a, b) (-1)
+#else
static int create_ref_symlink(struct ref_lock *lock, const char *target)
{
int ret = -1;
-#ifndef NO_SYMLINK_HEAD
+
char *ref_path = get_locked_file_path(&lock->lk);
unlink(ref_path);
ret = symlink(target, ref_path);
@@ -1947,13 +2033,12 @@ static int create_ref_symlink(struct ref_lock *lock, const char *target)
if (ret)
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
-#endif
return ret;
}
+#endif
-static int create_symref_lock(struct files_ref_store *refs,
- struct ref_lock *lock, const char *refname,
- const char *target, struct strbuf *err)
+static int create_symref_lock(struct ref_lock *lock, const char *target,
+ struct strbuf *err)
{
if (!fdopen_lock_file(&lock->lk, "w")) {
strbuf_addf(err, "unable to fdopen %s: %s",
@@ -1999,7 +2084,8 @@ static int files_delete_reflog(struct ref_store *ref_store,
return ret;
}
-static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data)
+static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb,
+ each_reflog_ent_fn fn, void *cb_data)
{
struct object_id ooid, noid;
char *email_end, *message;
@@ -2009,8 +2095,8 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c
/* old SP new SP name <email> SP time TAB msg LF */
if (!sb->len || sb->buf[sb->len - 1] != '\n' ||
- parse_oid_hex(p, &ooid, &p) || *p++ != ' ' ||
- parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||
+ parse_oid_hex_algop(p, &ooid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
+ parse_oid_hex_algop(p, &noid, &p, refs->base.repo->hash_algo) || *p++ != ' ' ||
!(email_end = strchr(p, '>')) ||
email_end[1] != ' ' ||
!(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||
@@ -2109,7 +2195,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
strbuf_reset(&sb);
if (ret)
break;
@@ -2121,7 +2207,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
* Process it, and we can end the loop.
*/
strbuf_splice(&sb, 0, 0, buf, endp - buf);
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
strbuf_reset(&sb);
break;
}
@@ -2171,7 +2257,7 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store,
return -1;
while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
fclose(logfp);
strbuf_release(&sb);
return ret;
@@ -2568,8 +2654,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
}
if (update->new_target && !(update->flags & REF_LOG_ONLY)) {
- if (create_symref_lock(refs, lock, update->refname,
- update->new_target, err)) {
+ if (create_symref_lock(lock, update->new_target, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
@@ -2928,7 +3013,7 @@ static int files_transaction_finish(struct ref_store *ref_store,
* We try creating a symlink, if that succeeds we continue to the
* next update. If not, we try and create a regular symref.
*/
- if (update->new_target && prefer_symlink_refs)
+ if (update->new_target && refs->prefer_symlink_refs)
if (!create_ref_symlink(lock, update->new_target))
continue;
@@ -3036,7 +3121,7 @@ static int files_transaction_abort(struct ref_store *ref_store,
return 0;
}
-static int ref_present(const char *refname,
+static int ref_present(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED,
void *cb_data)
@@ -3409,6 +3494,116 @@ static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
return ret;
}
+/*
+ * For refs and reflogs, they share a unified interface when scanning
+ * the whole directory. This function is used as the callback for each
+ * regular file or symlink in the directory.
+ */
+typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *refs_check_dir,
+ struct dir_iterator *iter);
+
+static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
+ struct fsck_options *o,
+ const char *refs_check_dir,
+ struct dir_iterator *iter)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ /*
+ * Ignore the files ending with ".lock" as they may be lock files
+ * However, do not allow bare ".lock" files.
+ */
+ if (iter->basename[0] != '.' && ends_with(iter->basename, ".lock"))
+ goto cleanup;
+
+ if (check_refname_format(iter->basename, REFNAME_ALLOW_ONELEVEL)) {
+ struct fsck_ref_report report = { .path = NULL };
+
+ strbuf_addf(&sb, "%s/%s", refs_check_dir, iter->relative_path);
+ report.path = sb.buf;
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_NAME,
+ "invalid refname format");
+ }
+
+cleanup:
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int files_fsck_refs_dir(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *refs_check_dir,
+ files_fsck_refs_fn *fsck_refs_fn)
+{
+ struct strbuf sb = STRBUF_INIT;
+ struct dir_iterator *iter;
+ int iter_status;
+ int ret = 0;
+
+ strbuf_addf(&sb, "%s/%s", ref_store->gitdir, refs_check_dir);
+
+ iter = dir_iterator_begin(sb.buf, 0);
+ if (!iter) {
+ ret = error_errno(_("cannot open directory %s"), sb.buf);
+ goto out;
+ }
+
+ while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
+ if (S_ISDIR(iter->st.st_mode)) {
+ continue;
+ } else if (S_ISREG(iter->st.st_mode) ||
+ S_ISLNK(iter->st.st_mode)) {
+ if (o->verbose)
+ fprintf_ln(stderr, "Checking %s/%s",
+ refs_check_dir, iter->relative_path);
+ for (size_t i = 0; fsck_refs_fn[i]; i++) {
+ if (fsck_refs_fn[i](ref_store, o, refs_check_dir, iter))
+ ret = -1;
+ }
+ } else {
+ struct fsck_ref_report report = { .path = iter->basename };
+ if (fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_FILETYPE,
+ "unexpected file type"))
+ ret = -1;
+ }
+ }
+
+ if (iter_status != ITER_DONE)
+ ret = error(_("failed to iterate over '%s'"), sb.buf);
+
+out:
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int files_fsck_refs(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ files_fsck_refs_fn fsck_refs_fn[]= {
+ files_fsck_refs_name,
+ NULL,
+ };
+
+ if (o->verbose)
+ fprintf_ln(stderr, _("Checking references consistency"));
+ return files_fsck_refs_dir(ref_store, o, "refs", fsck_refs_fn);
+}
+
+static int files_fsck(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_READ, "fsck");
+
+ return files_fsck_refs(ref_store, o) |
+ refs->packed_ref_store->be->fsck(refs->packed_ref_store, o);
+}
+
struct ref_storage_be refs_be_files = {
.name = "files",
.init = files_ref_store_init,
@@ -3435,5 +3630,7 @@ struct ref_storage_be refs_be_files = {
.reflog_exists = files_reflog_exists,
.create_reflog = files_create_reflog,
.delete_reflog = files_delete_reflog,
- .reflog_expire = files_reflog_expire
+ .reflog_expire = files_reflog_expire,
+
+ .fsck = files_fsck,
};
diff --git a/refs/iterator.c b/refs/iterator.c
index d355ebf0d5..8e999d81fc 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -29,6 +29,7 @@ void base_ref_iterator_init(struct ref_iterator *iter,
{
iter->vtable = vtable;
iter->refname = NULL;
+ iter->referent = NULL;
iter->oid = NULL;
iter->flags = 0;
}
@@ -199,6 +200,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
if (selection & ITER_YIELD_CURRENT) {
+ iter->base.referent = (*iter->current)->referent;
iter->base.refname = (*iter->current)->refname;
iter->base.oid = (*iter->current)->oid;
iter->base.flags = (*iter->current)->flags;
@@ -448,7 +450,7 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,
current_ref_iter = iter;
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
- retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
+ retval = fn(iter->refname, iter->referent, iter->oid, iter->flags, cb_data);
if (retval) {
/*
* If ref_iterator_abort() returns ITER_ERROR,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index a0666407cd..07c57fd541 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -794,7 +794,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname,
return -1;
}
- if (get_oid_hex(rec, oid))
+ if (get_oid_hex_algop(rec, oid, ref_store->repo->hash_algo))
die_invalid_line(refs->path, rec, snapshot->eof - rec);
*type = REF_ISPACKED;
@@ -879,7 +879,7 @@ static int next_record(struct packed_ref_iterator *iter)
p = iter->pos;
if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 ||
- parse_oid_hex(p, &iter->oid, &p) ||
+ parse_oid_hex_algop(p, &iter->oid, &p, iter->repo->hash_algo) ||
!isspace(*p++))
die_invalid_line(iter->snapshot->refs->path,
iter->pos, iter->eof - iter->pos);
@@ -896,7 +896,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (!refname_is_safe(iter->base.refname))
die("packed refname is dangerous: %s",
iter->base.refname);
- oidclr(&iter->oid, the_repository->hash_algo);
+ oidclr(&iter->oid, iter->repo->hash_algo);
iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN;
}
if (iter->snapshot->peeled == PEELED_FULLY ||
@@ -909,7 +909,7 @@ static int next_record(struct packed_ref_iterator *iter)
if (iter->pos < iter->eof && *iter->pos == '^') {
p = iter->pos + 1;
if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 1 ||
- parse_oid_hex(p, &iter->peeled, &p) ||
+ parse_oid_hex_algop(p, &iter->peeled, &p, iter->repo->hash_algo) ||
*p++ != '\n')
die_invalid_line(iter->snapshot->refs->path,
iter->pos, iter->eof - iter->pos);
@@ -921,13 +921,13 @@ static int next_record(struct packed_ref_iterator *iter)
* we suppress it if the reference is broken:
*/
if ((iter->base.flags & REF_ISBROKEN)) {
- oidclr(&iter->peeled, the_repository->hash_algo);
+ oidclr(&iter->peeled, iter->repo->hash_algo);
iter->base.flags &= ~REF_KNOWS_PEELED;
} else {
iter->base.flags |= REF_KNOWS_PEELED;
}
} else {
- oidclr(&iter->peeled, the_repository->hash_algo);
+ oidclr(&iter->peeled, iter->repo->hash_algo);
}
return ITER_OK;
@@ -1250,6 +1250,24 @@ int packed_refs_is_locked(struct ref_store *ref_store)
return is_lock_file_locked(&refs->lock);
}
+int packed_refs_size(struct ref_store *ref_store,
+ size_t *out)
+{
+ struct packed_ref_store *refs = packed_downcast(ref_store, REF_STORE_READ,
+ "packed_refs_size");
+ struct stat st;
+
+ if (stat(refs->path, &st) < 0) {
+ if (errno != ENOENT)
+ return -1;
+ *out = 0;
+ return 0;
+ }
+
+ *out = st.st_size;
+ return 0;
+}
+
/*
* The packed-refs header line that we write out. Perhaps other traits
* will be added later.
@@ -1735,6 +1753,12 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
return empty_ref_iterator_begin();
}
+static int packed_fsck(struct ref_store *ref_store UNUSED,
+ struct fsck_options *o UNUSED)
+{
+ return 0;
+}
+
struct ref_storage_be refs_be_packed = {
.name = "packed",
.init = packed_ref_store_init,
@@ -1762,4 +1786,6 @@ struct ref_storage_be refs_be_packed = {
.create_reflog = NULL,
.delete_reflog = NULL,
.reflog_expire = NULL,
+
+ .fsck = packed_fsck,
};
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index 09437ad13b..9481d5e7c2 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -28,6 +28,13 @@ void packed_refs_unlock(struct ref_store *ref_store);
int packed_refs_is_locked(struct ref_store *ref_store);
/*
+ * Obtain the size of the `packed-refs` file. Reports `0` as size in case there
+ * is no packed-refs file. Returns 0 on success, negative otherwise.
+ */
+int packed_refs_size(struct ref_store *ref_store,
+ size_t *out);
+
+/*
* Return true if `transaction` really needs to be carried out against
* the specified packed_ref_store, or false if it can be skipped
* (i.e., because it is an obvious NOOP). `ref_store` must be locked
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 4ce519bbc8..35bae7e05d 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -34,6 +34,7 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
}
struct ref_entry *create_ref_entry(const char *refname,
+ const char *referent,
const struct object_id *oid, int flag)
{
struct ref_entry *ref;
@@ -41,6 +42,8 @@ struct ref_entry *create_ref_entry(const char *refname,
FLEX_ALLOC_STR(ref, name, refname);
oidcpy(&ref->u.value.oid, oid);
ref->flag = flag;
+ ref->u.value.referent = xstrdup_or_null(referent);
+
return ref;
}
@@ -66,6 +69,7 @@ static void free_ref_entry(struct ref_entry *entry)
*/
clear_ref_dir(&entry->u.subdir);
}
+ free(entry->u.value.referent);
free(entry);
}
@@ -431,6 +435,7 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
level->index = -1;
} else {
iter->base.refname = entry->name;
+ iter->base.referent = entry->u.value.referent;
iter->base.oid = &entry->u.value.oid;
iter->base.flags = entry->flag;
return ITER_OK;
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 31ebe24f6c..5f04e518c3 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -42,6 +42,7 @@ struct ref_value {
* referred to by the last reference in the symlink chain.
*/
struct object_id oid;
+ char *referent;
};
/*
@@ -173,6 +174,7 @@ struct ref_entry *create_dir_entry(struct ref_cache *cache,
const char *dirname, size_t len);
struct ref_entry *create_ref_entry(const char *refname,
+ const char *referent,
const struct object_id *oid, int flag);
/*
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index fa975d69aa..2313c830d8 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -4,6 +4,7 @@
#include "refs.h"
#include "iterator.h"
+struct fsck_options;
struct ref_transaction;
/*
@@ -299,6 +300,7 @@ enum do_for_each_ref_flags {
struct ref_iterator {
struct ref_iterator_vtable *vtable;
const char *refname;
+ const char *referent;
const struct object_id *oid;
unsigned int flags;
};
@@ -650,6 +652,9 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refname,
struct strbuf *referent);
+typedef int fsck_fn(struct ref_store *ref_store,
+ struct fsck_options *o);
+
struct ref_storage_be {
const char *name;
ref_store_init_fn *init;
@@ -677,6 +682,8 @@ struct ref_storage_be {
create_reflog_fn *create_reflog;
delete_reflog_fn *delete_reflog;
reflog_expire_fn *reflog_expire;
+
+ fsck_fn *fsck;
};
extern struct ref_storage_be refs_be_files;
@@ -705,7 +712,8 @@ struct ref_store {
* Parse contents of a loose ref file. *failure_errno maybe be set to EINVAL for
* invalid contents.
*/
-int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+int parse_loose_ref_contents(const struct git_hash_algo *algop,
+ const char *buf, struct object_id *oid,
struct strbuf *referent, unsigned int *type,
int *failure_errno);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index fbe74c239d..3c6107c7ce 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -19,8 +19,10 @@
#include "../reftable/reftable-record.h"
#include "../reftable/reftable-error.h"
#include "../reftable/reftable-iterator.h"
+#include "../repo-settings.h"
#include "../setup.h"
#include "../strmap.h"
+#include "../trace2.h"
#include "parse.h"
#include "refs-internal.h"
@@ -51,6 +53,7 @@ struct reftable_ref_store {
struct reftable_write_options write_options;
unsigned int store_flags;
+ enum log_refs_config log_all_ref_updates;
int err;
};
@@ -156,22 +159,23 @@ static struct reftable_stack *stack_for(struct reftable_ref_store *store,
}
}
-static int should_write_log(struct ref_store *refs, const char *refname)
+static int should_write_log(struct reftable_ref_store *refs, const char *refname)
{
- if (log_all_ref_updates == LOG_REFS_UNSET)
- log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+ enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
+ if (log_refs_cfg == LOG_REFS_UNSET)
+ log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
- switch (log_all_ref_updates) {
+ switch (log_refs_cfg) {
case LOG_REFS_NONE:
- return refs_reflog_exists(refs, refname);
+ return refs_reflog_exists(&refs->base, refname);
case LOG_REFS_ALWAYS:
return 1;
case LOG_REFS_NORMAL:
- if (should_autocreate_reflog(refname))
+ if (should_autocreate_reflog(log_refs_cfg, refname))
return 1;
- return refs_reflog_exists(refs, refname);
+ return refs_reflog_exists(&refs->base, refname);
default:
- BUG("unhandled core.logAllRefUpdates value %d", log_all_ref_updates);
+ BUG("unhandled core.logAllRefUpdates value %d", log_refs_cfg);
}
}
@@ -201,7 +205,8 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru
log->value.update.tz_offset = sign * atoi(tz_begin);
}
-static int read_ref_without_reload(struct reftable_stack *stack,
+static int read_ref_without_reload(struct reftable_ref_store *refs,
+ struct reftable_stack *stack,
const char *refname,
struct object_id *oid,
struct strbuf *referent,
@@ -220,7 +225,7 @@ static int read_ref_without_reload(struct reftable_stack *stack,
*type |= REF_ISSYMREF;
} else if (reftable_ref_record_val1(&ref)) {
oidread(oid, reftable_ref_record_val1(&ref),
- the_repository->hash_algo);
+ refs->base.repo->hash_algo);
} else {
/* We got a tombstone, which should not happen. */
BUG("unhandled reference value type %d", ref.value_type);
@@ -255,6 +260,13 @@ static int reftable_be_config(const char *var, const char *value,
if (factor > UINT8_MAX)
die("reftable geometric factor cannot exceed %u", (unsigned)UINT8_MAX);
opts->auto_compaction_factor = factor;
+ } else if (!strcmp(var, "reftable.locktimeout")) {
+ int64_t lock_timeout = git_config_int64(var, value, ctx->kvi);
+ if (lock_timeout > LONG_MAX)
+ die("reftable lock timeout cannot exceed %"PRIdMAX, (intmax_t)LONG_MAX);
+ if (lock_timeout < 0 && lock_timeout != -1)
+ die("reftable lock timeout does not support negative values other than -1");
+ opts->lock_timeout_ms = lock_timeout;
}
return 0;
@@ -275,11 +287,13 @@ static struct ref_store *reftable_be_init(struct repository *repo,
base_ref_store_init(&refs->base, repo, gitdir, &refs_be_reftable);
strmap_init(&refs->worktree_stacks);
refs->store_flags = store_flags;
+ refs->log_all_ref_updates = repo_settings_get_log_all_ref_updates(repo);
refs->write_options.hash_id = repo->hash_algo->format_id;
refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask);
refs->write_options.disable_auto_compact =
!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
+ refs->write_options.lock_timeout_ms = 100;
git_config(reftable_be_config, &refs->write_options);
@@ -446,15 +460,87 @@ struct reftable_ref_iterator {
const char *prefix;
size_t prefix_len;
+ char **exclude_patterns;
+ size_t exclude_patterns_index;
+ size_t exclude_patterns_strlen;
unsigned int flags;
int err;
};
+/*
+ * Handle exclude patterns. Returns either `1`, which tells the caller that the
+ * current reference shall not be shown. Or `0`, which indicates that it should
+ * be shown.
+ */
+static int should_exclude_current_ref(struct reftable_ref_iterator *iter)
+{
+ while (iter->exclude_patterns[iter->exclude_patterns_index]) {
+ const char *pattern = iter->exclude_patterns[iter->exclude_patterns_index];
+ char *ref_after_pattern;
+ int cmp;
+
+ /*
+ * Lazily cache the pattern length so that we don't have to
+ * recompute it every time this function is called.
+ */
+ if (!iter->exclude_patterns_strlen)
+ iter->exclude_patterns_strlen = strlen(pattern);
+
+ /*
+ * When the reference name is lexicographically bigger than the
+ * current exclude pattern we know that it won't ever match any
+ * of the following references, either. We thus advance to the
+ * next pattern and re-check whether it matches.
+ *
+ * Otherwise, if it's smaller, then we do not have a match and
+ * thus want to show the current reference.
+ */
+ cmp = strncmp(iter->ref.refname, pattern,
+ iter->exclude_patterns_strlen);
+ if (cmp > 0) {
+ iter->exclude_patterns_index++;
+ iter->exclude_patterns_strlen = 0;
+ continue;
+ }
+ if (cmp < 0)
+ return 0;
+
+ /*
+ * The reference shares a prefix with the exclude pattern and
+ * shall thus be omitted. We skip all references that match the
+ * pattern by seeking to the first reference after the block of
+ * matches.
+ *
+ * This is done by appending the highest possible character to
+ * the pattern. Consequently, all references that have the
+ * pattern as prefix and whose suffix starts with anything in
+ * the range [0x00, 0xfe] are skipped. And given that 0xff is a
+ * non-printable character that shouldn't ever be in a ref name,
+ * we'd not yield any such record, either.
+ *
+ * Note that the seeked-to reference may also be excluded. This
+ * is not handled here though, but the caller is expected to
+ * loop and re-verify the next reference for us.
+ */
+ ref_after_pattern = xstrfmt("%s%c", pattern, 0xff);
+ iter->err = reftable_iterator_seek_ref(&iter->iter, ref_after_pattern);
+ iter->exclude_patterns_index++;
+ iter->exclude_patterns_strlen = 0;
+ trace2_counter_add(TRACE2_COUNTER_ID_REFTABLE_RESEEKS, 1);
+
+ free(ref_after_pattern);
+ return 1;
+ }
+
+ return 0;
+}
+
static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
{
struct reftable_ref_iterator *iter =
(struct reftable_ref_iterator *)ref_iterator;
struct reftable_ref_store *refs = iter->refs;
+ const char *referent = NULL;
while (!iter->err) {
int flags = 0;
@@ -479,6 +565,9 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
break;
}
+ if (iter->exclude_patterns && should_exclude_current_ref(iter))
+ continue;
+
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
parse_worktree_ref(iter->ref.refname, NULL, NULL, NULL) !=
REF_WORKTREE_CURRENT)
@@ -487,16 +576,19 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
switch (iter->ref.value_type) {
case REFTABLE_REF_VAL1:
oidread(&iter->oid, iter->ref.value.val1,
- the_repository->hash_algo);
+ refs->base.repo->hash_algo);
break;
case REFTABLE_REF_VAL2:
oidread(&iter->oid, iter->ref.value.val2.value,
- the_repository->hash_algo);
+ refs->base.repo->hash_algo);
break;
case REFTABLE_REF_SYMREF:
- if (!refs_resolve_ref_unsafe(&iter->refs->base, iter->ref.refname,
- RESOLVE_REF_READING, &iter->oid, &flags))
- oidclr(&iter->oid, the_repository->hash_algo);
+ referent = refs_resolve_ref_unsafe(&iter->refs->base,
+ iter->ref.refname,
+ RESOLVE_REF_READING,
+ &iter->oid, &flags);
+ if (!referent)
+ oidclr(&iter->oid, refs->base.repo->hash_algo);
break;
default:
BUG("unhandled reference value type %d", iter->ref.value_type);
@@ -508,7 +600,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
if (check_refname_format(iter->ref.refname, REFNAME_ALLOW_ONELEVEL)) {
if (!refname_is_safe(iter->ref.refname))
die(_("refname is dangerous: %s"), iter->ref.refname);
- oidclr(&iter->oid, the_repository->hash_algo);
+ oidclr(&iter->oid, refs->base.repo->hash_algo);
flags |= REF_BAD_NAME | REF_ISBROKEN;
}
@@ -523,6 +615,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
continue;
iter->base.refname = iter->ref.refname;
+ iter->base.referent = referent;
iter->base.oid = &iter->oid;
iter->base.flags = flags;
@@ -551,7 +644,7 @@ static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator,
if (iter->ref.value_type == REFTABLE_REF_VAL2) {
oidread(peeled, iter->ref.value.val2.target_value,
- the_repository->hash_algo);
+ iter->refs->base.repo->hash_algo);
return 0;
}
@@ -564,6 +657,11 @@ static int reftable_ref_iterator_abort(struct ref_iterator *ref_iterator)
(struct reftable_ref_iterator *)ref_iterator;
reftable_ref_record_release(&iter->ref);
reftable_iterator_destroy(&iter->iter);
+ if (iter->exclude_patterns) {
+ for (size_t i = 0; iter->exclude_patterns[i]; i++)
+ free(iter->exclude_patterns[i]);
+ free(iter->exclude_patterns);
+ }
free(iter);
return ITER_DONE;
}
@@ -574,9 +672,53 @@ static struct ref_iterator_vtable reftable_ref_iterator_vtable = {
.abort = reftable_ref_iterator_abort
};
+static int qsort_strcmp(const void *va, const void *vb)
+{
+ const char *a = *(const char **)va;
+ const char *b = *(const char **)vb;
+ return strcmp(a, b);
+}
+
+static char **filter_exclude_patterns(const char **exclude_patterns)
+{
+ size_t filtered_size = 0, filtered_alloc = 0;
+ char **filtered = NULL;
+
+ if (!exclude_patterns)
+ return NULL;
+
+ for (size_t i = 0; ; i++) {
+ const char *exclude_pattern = exclude_patterns[i];
+ int has_glob = 0;
+
+ if (!exclude_pattern)
+ break;
+
+ for (const char *p = exclude_pattern; *p; p++) {
+ has_glob = is_glob_special(*p);
+ if (has_glob)
+ break;
+ }
+ if (has_glob)
+ continue;
+
+ ALLOC_GROW(filtered, filtered_size + 1, filtered_alloc);
+ filtered[filtered_size++] = xstrdup(exclude_pattern);
+ }
+
+ if (filtered_size) {
+ QSORT(filtered, filtered_size, qsort_strcmp);
+ ALLOC_GROW(filtered, filtered_size + 1, filtered_alloc);
+ filtered[filtered_size++] = NULL;
+ }
+
+ return filtered;
+}
+
static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_store *refs,
struct reftable_stack *stack,
const char *prefix,
+ const char **exclude_patterns,
int flags)
{
struct reftable_ref_iterator *iter;
@@ -589,6 +731,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
iter->base.oid = &iter->oid;
iter->flags = flags;
iter->refs = refs;
+ iter->exclude_patterns = filter_exclude_patterns(exclude_patterns);
ret = refs->err;
if (ret)
@@ -621,7 +764,8 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
required_flags |= REF_STORE_ODB;
refs = reftable_be_downcast(ref_store, required_flags, "ref_iterator_begin");
- main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix, flags);
+ main_iter = ref_iterator_for_stack(refs, refs->main_stack, prefix,
+ exclude_patterns, flags);
/*
* The worktree stack is only set when we're in an actual worktree
@@ -635,7 +779,8 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
* Otherwise we merge both the common and the per-worktree refs into a
* single iterator.
*/
- worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix, flags);
+ worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix,
+ exclude_patterns, flags);
return merge_ref_iterator_begin(&worktree_iter->base, &main_iter->base,
ref_iterator_select, NULL);
}
@@ -659,7 +804,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store,
if (ret)
return ret;
- ret = read_ref_without_reload(stack, refname, oid, referent, type);
+ ret = read_ref_without_reload(refs, stack, refname, oid, referent, type);
if (ret < 0)
return ret;
if (ret > 0) {
@@ -756,7 +901,8 @@ static int prepare_transaction_update(struct write_transaction_table_arg **out,
if (ret)
return ret;
- ret = reftable_stack_new_addition(&addition, stack);
+ ret = reftable_stack_new_addition(&addition, stack,
+ REFTABLE_STACK_NEW_ADDITION_RELOAD);
if (ret) {
if (ret == REFTABLE_LOCK_ERROR)
strbuf_addstr(err, "cannot lock references");
@@ -868,8 +1014,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
goto done;
}
- ret = read_ref_without_reload(stack_for(refs, "HEAD", NULL), "HEAD", &head_oid,
- &head_referent, &head_type);
+ ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD",
+ &head_oid, &head_referent, &head_type);
if (ret < 0)
goto done;
ret = 0;
@@ -936,7 +1082,7 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store,
string_list_insert(&affected_refnames, new_update->refname);
}
- ret = read_ref_without_reload(stack, rewritten_ref,
+ ret = read_ref_without_reload(refs, stack, rewritten_ref,
&current_oid, &referent, &u->type);
if (ret < 0)
goto done;
@@ -1119,9 +1265,9 @@ done:
return ret;
}
-static int reftable_be_transaction_abort(struct ref_store *ref_store,
+static int reftable_be_transaction_abort(struct ref_store *ref_store UNUSED,
struct ref_transaction *transaction,
- struct strbuf *err)
+ struct strbuf *err UNUSED)
{
struct reftable_transaction_data *tx_data = transaction->backend_data;
free_transaction_data(tx_data);
@@ -1174,7 +1320,9 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
struct reftable_log_record log = {0};
struct reftable_iterator it = {0};
- reftable_stack_init_log_iterator(arg->stack, &it);
+ ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ if (ret < 0)
+ goto done;
/*
* When deleting refs we also delete all reflog entries
@@ -1212,7 +1360,7 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data
} else if (!(u->flags & REF_SKIP_CREATE_REFLOG) &&
(u->flags & REF_HAVE_NEW) &&
(u->flags & REF_FORCE_CREATE_REFLOG ||
- should_write_log(&arg->refs->base, u->refname))) {
+ should_write_log(arg->refs, u->refname))) {
struct reftable_log_record *log;
int create_reflog = 1;
@@ -1311,7 +1459,7 @@ done:
return ret;
}
-static int reftable_be_transaction_finish(struct ref_store *ref_store,
+static int reftable_be_transaction_finish(struct ref_store *ref_store UNUSED,
struct ref_transaction *transaction,
struct strbuf *err)
{
@@ -1500,7 +1648,8 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ);
logs_nr++;
- ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid, &head_referent, &head_type);
+ ret = read_ref_without_reload(arg->refs, arg->stack, "HEAD", &head_oid,
+ &head_referent, &head_type);
if (ret < 0)
goto done;
append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname);
@@ -1543,7 +1692,10 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data)
* copy over all log entries from the old reflog. Last but not least,
* when renaming we also have to delete all the old reflog entries.
*/
- reftable_stack_init_log_iterator(arg->stack, &it);
+ ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ if (ret < 0)
+ goto done;
+
ret = reftable_iterator_seek_log(&it, arg->oldname);
if (ret < 0)
goto done;
@@ -1721,8 +1873,8 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
return ITER_OK;
}
-static int reftable_reflog_iterator_peel(struct ref_iterator *ref_iterator,
- struct object_id *peeled)
+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;
@@ -1764,7 +1916,10 @@ static struct reftable_reflog_iterator *reflog_iterator_for_stack(struct reftabl
if (ret < 0)
goto done;
- reftable_stack_init_log_iterator(stack, &iter->iter);
+ ret = reftable_stack_init_log_iterator(stack, &iter->iter);
+ if (ret < 0)
+ goto done;
+
ret = reftable_iterator_seek_log(&iter->iter, "");
if (ret < 0)
goto done;
@@ -1790,15 +1945,16 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store *
ref_iterator_select, NULL);
}
-static int yield_log_record(struct reftable_log_record *log,
+static int yield_log_record(struct reftable_ref_store *refs,
+ struct reftable_log_record *log,
each_reflog_ent_fn fn,
void *cb_data)
{
struct object_id old_oid, new_oid;
const char *full_committer;
- oidread(&old_oid, log->value.update.old_hash, the_repository->hash_algo);
- oidread(&new_oid, log->value.update.new_hash, the_repository->hash_algo);
+ oidread(&old_oid, log->value.update.old_hash, refs->base.repo->hash_algo);
+ oidread(&new_oid, log->value.update.new_hash, refs->base.repo->hash_algo);
/*
* When both the old object ID and the new object ID are null
@@ -1830,7 +1986,10 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
if (refs->err < 0)
return refs->err;
- reftable_stack_init_log_iterator(stack, &it);
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
+
ret = reftable_iterator_seek_log(&it, refname);
while (!ret) {
ret = reftable_iterator_next_log(&it, &log);
@@ -1841,11 +2000,12 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store,
break;
}
- ret = yield_log_record(&log, fn, cb_data);
+ ret = yield_log_record(refs, &log, fn, cb_data);
if (ret)
break;
}
+done:
reftable_log_record_release(&log);
reftable_iterator_destroy(&it);
return ret;
@@ -1867,7 +2027,10 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
if (refs->err < 0)
return refs->err;
- reftable_stack_init_log_iterator(stack, &it);
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
+
ret = reftable_iterator_seek_log(&it, refname);
while (!ret) {
struct reftable_log_record log = {0};
@@ -1886,7 +2049,7 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store,
}
for (i = logs_nr; i--;) {
- ret = yield_log_record(&logs[i], fn, cb_data);
+ ret = yield_log_record(refs, &logs[i], fn, cb_data);
if (ret)
goto done;
}
@@ -1917,7 +2080,10 @@ static int reftable_be_reflog_exists(struct ref_store *ref_store,
if (ret < 0)
goto done;
- reftable_stack_init_log_iterator(stack, &it);
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
+
ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0)
goto done;
@@ -1982,7 +2148,7 @@ done:
static int reftable_be_create_reflog(struct ref_store *ref_store,
const char *refname,
- struct strbuf *errmsg)
+ struct strbuf *errmsg UNUSED)
{
struct reftable_ref_store *refs =
reftable_be_downcast(ref_store, REF_STORE_WRITE, "create_reflog");
@@ -2023,7 +2189,9 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
reftable_writer_set_limits(writer, ts, ts);
- reftable_stack_init_log_iterator(arg->stack, &it);
+ ret = reftable_stack_init_log_iterator(arg->stack, &it);
+ if (ret < 0)
+ goto out;
/*
* In order to delete a table we need to delete all reflog entries one
@@ -2047,6 +2215,7 @@ static int write_reflog_delete_table(struct reftable_writer *writer, void *cb_da
ret = reftable_writer_add_log(writer, &tombstone);
}
+out:
reftable_log_record_release(&log);
reftable_iterator_destroy(&it);
return ret;
@@ -2185,13 +2354,15 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (ret < 0)
goto done;
- reftable_stack_init_log_iterator(stack, &it);
+ ret = reftable_stack_init_log_iterator(stack, &it);
+ if (ret < 0)
+ goto done;
ret = reftable_iterator_seek_log(&it, refname);
if (ret < 0)
goto done;
- ret = reftable_stack_new_addition(&add, stack);
+ ret = reftable_stack_new_addition(&add, stack, 0);
if (ret < 0)
goto done;
@@ -2200,7 +2371,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
goto done;
if (reftable_ref_record_val1(&ref_record))
oidread(&oid, reftable_ref_record_val1(&ref_record),
- the_repository->hash_algo);
+ ref_store->repo->hash_algo);
prepare_fn(refname, &oid, policy_cb_data);
while (1) {
@@ -2216,9 +2387,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
}
oidread(&old_oid, log.value.update.old_hash,
- the_repository->hash_algo);
+ ref_store->repo->hash_algo);
oidread(&new_oid, log.value.update.new_hash,
- the_repository->hash_algo);
+ ref_store->repo->hash_algo);
/*
* Skip over the reflog existence marker. We will add it back
@@ -2250,9 +2421,9 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
*dest = logs[i];
oidread(&old_oid, logs[i].value.update.old_hash,
- the_repository->hash_algo);
+ ref_store->repo->hash_algo);
oidread(&new_oid, logs[i].value.update.new_hash,
- the_repository->hash_algo);
+ ref_store->repo->hash_algo);
if (should_prune_fn(&old_oid, &new_oid, logs[i].value.update.email,
(timestamp_t)logs[i].value.update.time,
@@ -2269,7 +2440,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash &&
reftable_ref_record_val1(&ref_record))
- oidread(&arg.update_oid, last_hash, the_repository->hash_algo);
+ oidread(&arg.update_oid, last_hash, ref_store->repo->hash_algo);
arg.refs = refs;
arg.records = rewritten;
@@ -2303,6 +2474,12 @@ done:
return ret;
}
+static int reftable_be_fsck(struct ref_store *ref_store UNUSED,
+ struct fsck_options *o UNUSED)
+{
+ return 0;
+}
+
struct ref_storage_be refs_be_reftable = {
.name = "reftable",
.init = reftable_be_init,
@@ -2330,4 +2507,6 @@ struct ref_storage_be refs_be_reftable = {
.create_reflog = reftable_be_create_reflog,
.delete_reflog = reftable_be_delete_reflog,
.reflog_expire = reftable_be_reflog_expire,
+
+ .fsck = reftable_be_fsck,
};