return 1;
}
-/*
- * Return true if the reference described by entry can be resolved to
- * an object in the database; otherwise, emit a warning and return
- * false.
- */
-static int entry_resolves_to_object(struct ref_entry *entry)
-{
- return ref_resolves_to_object(entry->name,
- &entry->u.value.oid, entry->flag);
-}
-
struct packed_ref_cache {
struct ref_cache *cache;
return refs->loose;
}
-static struct ref_dir *get_loose_ref_dir(struct files_ref_store *refs)
-{
- return get_ref_dir(get_loose_ref_cache(refs)->root);
-}
-
/*
* Return the ref_entry for the given refname from the packed
* references. If it does not exist, return NULL.
const char *prefix, unsigned int flags)
{
struct files_ref_store *refs;
- struct ref_dir *loose_dir, *packed_dir;
struct ref_iterator *loose_iter, *packed_iter;
struct files_ref_iterator *iter;
struct ref_iterator *ref_iterator;
* condition if loose refs are migrated to the packed-refs
* file by a simultaneous process, but our in-memory view is
* from before the migration. We ensure this as follows:
- * First, we call prime_ref_dir(), which pre-reads the loose
- * references for the subtree into the cache. (If they've
- * already been read, that's OK; we only need to guarantee
- * that they're read before the packed refs, not *how much*
- * before.) After that, we call get_packed_ref_cache(), which
- * internally checks whether the packed-ref cache is up to
- * date with what is on disk, and re-reads it if not.
+ * First, we call start the loose refs iteration with its
+ * `prime_ref` argument set to true. This causes the loose
+ * references in the subtree to be pre-read into the cache.
+ * (If they've already been read, that's OK; we only need to
+ * guarantee that they're read before the packed refs, not
+ * *how much* before.) After that, we call
+ * get_packed_ref_cache(), which internally checks whether the
+ * packed-ref cache is up to date with what is on disk, and
+ * re-reads it if not.
*/
- loose_dir = get_loose_ref_dir(refs);
-
- if (prefix && *prefix)
- loose_dir = find_containing_dir(loose_dir, prefix, 0);
-
- if (loose_dir) {
- prime_ref_dir(loose_dir);
- loose_iter = cache_ref_iterator_begin(loose_dir);
- } else {
- /* There's nothing to iterate over. */
- loose_iter = empty_ref_iterator_begin();
- }
+ loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
+ prefix, 1);
iter->packed_ref_cache = get_packed_ref_cache(refs);
acquire_packed_ref_cache(iter->packed_ref_cache);
- packed_dir = get_packed_ref_dir(iter->packed_ref_cache);
-
- if (prefix && *prefix)
- packed_dir = find_containing_dir(packed_dir, prefix, 0);
-
- if (packed_dir) {
- packed_iter = cache_ref_iterator_begin(packed_dir);
- } else {
- /* There's nothing to iterate over. */
- packed_iter = empty_ref_iterator_begin();
- }
+ packed_iter = cache_ref_iterator_begin(iter->packed_ref_cache->cache,
+ prefix, 0);
iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter);
iter->flags = flags;
* Write an entry to the packed-refs file for the specified refname.
* If peeled is non-NULL, write it as the entry's peeled value.
*/
-static void write_packed_entry(FILE *fh, char *refname, unsigned char *sha1,
- unsigned char *peeled)
+static void write_packed_entry(FILE *fh, const char *refname,
+ const unsigned char *sha1,
+ const unsigned char *peeled)
{
fprintf_or_die(fh, "%s %s\n", sha1_to_hex(sha1), refname);
if (peeled)
fprintf_or_die(fh, "^%s\n", sha1_to_hex(peeled));
}
-/*
- * An each_ref_entry_fn that writes the entry to a packed-refs file.
- */
-static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
-{
- enum peel_status peel_status = peel_entry(entry, 0);
-
- if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
- error("internal error: %s is not a valid packed reference!",
- entry->name);
- write_packed_entry(cb_data, entry->name, entry->u.value.oid.hash,
- peel_status == PEEL_PEELED ?
- entry->u.value.peeled.hash : NULL);
- return 0;
-}
-
/*
* Lock the packed-refs file for writing. Flags is passed to
* hold_lock_file_for_update(). Return 0 on success. On errors, set
{
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(refs);
- int error = 0;
+ int ok, error = 0;
int save_errno = 0;
FILE *out;
+ struct ref_iterator *iter;
files_assert_main_repository(refs, "commit_packed_refs");
die_errno("unable to fdopen packed-refs descriptor");
fprintf_or_die(out, "%s", PACKED_REFS_HEADER);
- do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
- write_packed_entry_fn, out);
+
+ iter = cache_ref_iterator_begin(packed_ref_cache->cache, NULL, 0);
+ while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
+ struct object_id peeled;
+ int peel_error = ref_iterator_peel(iter, &peeled);
+
+ write_packed_entry(out, iter->refname, iter->oid->hash,
+ peel_error ? NULL : peeled.hash);
+ }
+
+ if (ok != ITER_DONE)
+ die("error while iterating over references");
if (commit_lock_file(packed_ref_cache->lock)) {
save_errno = errno;
char name[FLEX_ARRAY];
};
-struct pack_refs_cb_data {
- unsigned int flags;
- struct ref_dir *packed_refs;
- struct ref_to_prune *ref_to_prune;
-};
-
-/*
- * An each_ref_entry_fn that is run over loose references only. If
- * the loose reference can be packed, add an entry in the packed ref
- * cache. If the reference should be pruned, also add it to
- * ref_to_prune in the pack_refs_cb_data.
- */
-static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)
-{
- struct pack_refs_cb_data *cb = cb_data;
- enum peel_status peel_status;
- struct ref_entry *packed_entry;
- int is_tag_ref = starts_with(entry->name, "refs/tags/");
-
- /* Do not pack per-worktree refs: */
- if (ref_type(entry->name) != REF_TYPE_NORMAL)
- return 0;
-
- /* ALWAYS pack tags */
- if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref)
- return 0;
-
- /* Do not pack symbolic or broken refs: */
- if ((entry->flag & REF_ISSYMREF) || !entry_resolves_to_object(entry))
- return 0;
-
- /* Add a packed ref cache entry equivalent to the loose entry. */
- peel_status = peel_entry(entry, 1);
- if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
- die("internal error peeling reference %s (%s)",
- entry->name, oid_to_hex(&entry->u.value.oid));
- packed_entry = find_ref_entry(cb->packed_refs, entry->name);
- if (packed_entry) {
- /* Overwrite existing packed entry with info from loose entry */
- packed_entry->flag = REF_ISPACKED | REF_KNOWS_PEELED;
- oidcpy(&packed_entry->u.value.oid, &entry->u.value.oid);
- } else {
- packed_entry = create_ref_entry(entry->name, entry->u.value.oid.hash,
- REF_ISPACKED | REF_KNOWS_PEELED, 0);
- add_ref_entry(cb->packed_refs, packed_entry);
- }
- oidcpy(&packed_entry->u.value.peeled, &entry->u.value.peeled);
-
- /* Schedule the loose reference for pruning if requested. */
- if ((cb->flags & PACK_REFS_PRUNE)) {
- struct ref_to_prune *n;
- FLEX_ALLOC_STR(n, name, entry->name);
- hashcpy(n->sha1, entry->u.value.oid.hash);
- n->next = cb->ref_to_prune;
- cb->ref_to_prune = n;
- }
- return 0;
-}
-
enum {
REMOVE_EMPTY_PARENTS_REF = 0x01,
REMOVE_EMPTY_PARENTS_REFLOG = 0x02
struct files_ref_store *refs =
files_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB,
"pack_refs");
- struct pack_refs_cb_data cbdata;
-
- memset(&cbdata, 0, sizeof(cbdata));
- cbdata.flags = flags;
+ struct ref_iterator *iter;
+ struct ref_dir *packed_refs;
+ int ok;
+ struct ref_to_prune *refs_to_prune = NULL;
lock_packed_refs(refs, LOCK_DIE_ON_ERROR);
- cbdata.packed_refs = get_packed_refs(refs);
+ packed_refs = get_packed_refs(refs);
- do_for_each_entry_in_dir(get_loose_ref_dir(refs),
- pack_if_possible_fn, &cbdata);
+ iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL, 0);
+ while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
+ /*
+ * If the loose reference can be packed, add an entry
+ * in the packed ref cache. If the reference should be
+ * pruned, also add it to refs_to_prune.
+ */
+ struct ref_entry *packed_entry;
+ int is_tag_ref = starts_with(iter->refname, "refs/tags/");
+
+ /* Do not pack per-worktree refs: */
+ if (ref_type(iter->refname) != REF_TYPE_NORMAL)
+ continue;
+
+ /* ALWAYS pack tags */
+ if (!(flags & PACK_REFS_ALL) && !is_tag_ref)
+ continue;
+
+ /* Do not pack symbolic or broken refs: */
+ if (iter->flags & REF_ISSYMREF)
+ continue;
+
+ if (!ref_resolves_to_object(iter->refname, iter->oid, iter->flags))
+ continue;
+
+ /*
+ * Create an entry in the packed-refs cache equivalent
+ * to the one from the loose ref cache, except that
+ * we don't copy the peeled status, because we want it
+ * to be re-peeled.
+ */
+ packed_entry = find_ref_entry(packed_refs, iter->refname);
+ if (packed_entry) {
+ /* Overwrite existing packed entry with info from loose entry */
+ packed_entry->flag = REF_ISPACKED;
+ oidcpy(&packed_entry->u.value.oid, iter->oid);
+ } else {
+ packed_entry = create_ref_entry(iter->refname, iter->oid->hash,
+ REF_ISPACKED, 0);
+ add_ref_entry(packed_refs, packed_entry);
+ }
+ oidclr(&packed_entry->u.value.peeled);
+
+ /* Schedule the loose reference for pruning if requested. */
+ if ((flags & PACK_REFS_PRUNE)) {
+ struct ref_to_prune *n;
+ FLEX_ALLOC_STR(n, name, iter->refname);
+ hashcpy(n->sha1, iter->oid->hash);
+ n->next = refs_to_prune;
+ refs_to_prune = n;
+ }
+ }
+ if (ok != ITER_DONE)
+ die("error while iterating over references");
if (commit_packed_refs(refs))
die_errno("unable to overwrite old ref-pack file");
- prune_refs(refs, cbdata.ref_to_prune);
+ prune_refs(refs, refs_to_prune);
return 0;
}
/* Jump to the end */
if (fseek(logfp, 0, SEEK_END) < 0)
- return error("cannot seek back reflog for %s: %s",
- refname, strerror(errno));
+ ret = error("cannot seek back reflog for %s: %s",
+ refname, strerror(errno));
pos = ftell(logfp);
while (!ret && 0 < pos) {
int cnt;
/* Fill next block from the end */
cnt = (sizeof(buf) < pos) ? sizeof(buf) : pos;
- if (fseek(logfp, pos - cnt, SEEK_SET))
- return error("cannot seek back reflog for %s: %s",
- refname, strerror(errno));
+ if (fseek(logfp, pos - cnt, SEEK_SET)) {
+ ret = error("cannot seek back reflog for %s: %s",
+ refname, strerror(errno));
+ break;
+ }
nread = fread(buf, cnt, 1, logfp);
- if (nread != 1)
- return error("cannot read %d bytes from reflog for %s: %s",
- cnt, refname, strerror(errno));
+ if (nread != 1) {
+ ret = error("cannot read %d bytes from reflog for %s: %s",
+ cnt, refname, strerror(errno));
+ break;
+ }
pos -= cnt;
scanp = endp = buf + cnt;