diff options
Diffstat (limited to 'refs')
| -rw-r--r-- | refs/debug.c | 11 | ||||
| -rw-r--r-- | refs/files-backend.c | 269 | ||||
| -rw-r--r-- | refs/iterator.c | 4 | ||||
| -rw-r--r-- | refs/packed-backend.c | 38 | ||||
| -rw-r--r-- | refs/packed-backend.h | 7 | ||||
| -rw-r--r-- | refs/ref-cache.c | 5 | ||||
| -rw-r--r-- | refs/ref-cache.h | 2 | ||||
| -rw-r--r-- | refs/refs-internal.h | 10 | ||||
| -rw-r--r-- | refs/reftable-backend.c | 283 |
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, ¤t_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, }; |
