Merge branch 'mh/submodule-hash'

Code and design clean-up for the refs API.

* mh/submodule-hash:
  read_loose_refs(): read refs using resolve_ref_recursively()
  files_ref_store::submodule: use NULL for the main repository
  base_ref_store_init(): remove submodule argument
  refs: push the submodule attribute down
  refs: store submodule ref stores in a hashmap
  register_ref_store(): new function
  refs: remove some unnecessary handling of submodule == ""
  refs: make some ref_store lookup functions private
  refs: reorder some function definitions
This commit is contained in:
Junio C Hamano 2017-02-27 13:57:15 -08:00
commit 466be3e1de
3 changed files with 135 additions and 113 deletions

113
refs.c
View File

@ -3,6 +3,7 @@
*/ */
#include "cache.h" #include "cache.h"
#include "hashmap.h"
#include "lockfile.h" #include "lockfile.h"
#include "refs.h" #include "refs.h"
#include "refs/refs-internal.h" #include "refs/refs-internal.h"
@ -1234,7 +1235,7 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
} }
/* This function needs to return a meaningful errno on failure */ /* This function needs to return a meaningful errno on failure */
static const char *resolve_ref_recursively(struct ref_store *refs, const char *resolve_ref_recursively(struct ref_store *refs,
const char *refname, const char *refname,
int resolve_flags, int resolve_flags,
unsigned char *sha1, int *flags) unsigned char *sha1, int *flags)
@ -1357,64 +1358,104 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
return 0; return 0;
} }
struct submodule_hash_entry
{
struct hashmap_entry ent; /* must be the first member! */
struct ref_store *refs;
/* NUL-terminated name of submodule: */
char submodule[FLEX_ARRAY];
};
static int submodule_hash_cmp(const void *entry, const void *entry_or_key,
const void *keydata)
{
const struct submodule_hash_entry *e1 = entry, *e2 = entry_or_key;
const char *submodule = keydata ? keydata : e2->submodule;
return strcmp(e1->submodule, submodule);
}
static struct submodule_hash_entry *alloc_submodule_hash_entry(
const char *submodule, struct ref_store *refs)
{
struct submodule_hash_entry *entry;
FLEX_ALLOC_STR(entry, submodule, submodule);
hashmap_entry_init(entry, strhash(submodule));
entry->refs = refs;
return entry;
}
/* A pointer to the ref_store for the main repository: */ /* A pointer to the ref_store for the main repository: */
static struct ref_store *main_ref_store; static struct ref_store *main_ref_store;
/* A linked list of ref_stores for submodules: */ /* A hashmap of ref_stores, stored by submodule name: */
static struct ref_store *submodule_ref_stores; static struct hashmap submodule_ref_stores;
void base_ref_store_init(struct ref_store *refs, /*
const struct ref_storage_be *be, * Return the ref_store instance for the specified submodule (or the
const char *submodule) * main repository if submodule is NULL). If that ref_store hasn't
* been initialized yet, return NULL.
*/
static struct ref_store *lookup_ref_store(const char *submodule)
{
struct submodule_hash_entry *entry;
if (!submodule)
return main_ref_store;
if (!submodule_ref_stores.tablesize)
/* It's initialized on demand in register_ref_store(). */
return NULL;
entry = hashmap_get_from_hash(&submodule_ref_stores,
strhash(submodule), submodule);
return entry ? entry->refs : NULL;
}
/*
* Register the specified ref_store to be the one that should be used
* for submodule (or the main repository if submodule is NULL). It is
* a fatal error to call this function twice for the same submodule.
*/
static void register_ref_store(struct ref_store *refs, const char *submodule)
{ {
refs->be = be;
if (!submodule) { if (!submodule) {
if (main_ref_store) if (main_ref_store)
die("BUG: main_ref_store initialized twice"); die("BUG: main_ref_store initialized twice");
refs->submodule = "";
refs->next = NULL;
main_ref_store = refs; main_ref_store = refs;
} else { } else {
if (lookup_ref_store(submodule)) if (!submodule_ref_stores.tablesize)
hashmap_init(&submodule_ref_stores, submodule_hash_cmp, 0);
if (hashmap_put(&submodule_ref_stores,
alloc_submodule_hash_entry(submodule, refs)))
die("BUG: ref_store for submodule '%s' initialized twice", die("BUG: ref_store for submodule '%s' initialized twice",
submodule); submodule);
refs->submodule = xstrdup(submodule);
refs->next = submodule_ref_stores;
submodule_ref_stores = refs;
} }
} }
struct ref_store *ref_store_init(const char *submodule) /*
* Create, record, and return a ref_store instance for the specified
* submodule (or the main repository if submodule is NULL).
*/
static struct ref_store *ref_store_init(const char *submodule)
{ {
const char *be_name = "files"; const char *be_name = "files";
struct ref_storage_be *be = find_ref_storage_backend(be_name); struct ref_storage_be *be = find_ref_storage_backend(be_name);
struct ref_store *refs;
if (!be) if (!be)
die("BUG: reference backend %s is unknown", be_name); die("BUG: reference backend %s is unknown", be_name);
if (!submodule || !*submodule) refs = be->init(submodule);
return be->init(NULL); register_ref_store(refs, submodule);
else
return be->init(submodule);
}
struct ref_store *lookup_ref_store(const char *submodule)
{
struct ref_store *refs;
if (!submodule || !*submodule)
return main_ref_store;
for (refs = submodule_ref_stores; refs; refs = refs->next) {
if (!strcmp(submodule, refs->submodule))
return refs; return refs;
} }
return NULL;
}
struct ref_store *get_ref_store(const char *submodule) struct ref_store *get_ref_store(const char *submodule)
{ {
struct ref_store *refs; struct ref_store *refs;
@ -1440,10 +1481,10 @@ struct ref_store *get_ref_store(const char *submodule)
return refs; return refs;
} }
void assert_main_repository(struct ref_store *refs, const char *caller) void base_ref_store_init(struct ref_store *refs,
const struct ref_storage_be *be)
{ {
if (*refs->submodule) refs->be = be;
die("BUG: %s called for a submodule", caller);
} }
/* backend functions */ /* backend functions */

View File

@ -912,6 +912,14 @@ struct packed_ref_cache {
*/ */
struct files_ref_store { struct files_ref_store {
struct ref_store base; struct ref_store base;
/*
* The name of the submodule represented by this object, or
* NULL if it represents the main repository's reference
* store:
*/
const char *submodule;
struct ref_entry *loose; struct ref_entry *loose;
struct packed_ref_cache *packed; struct packed_ref_cache *packed;
}; };
@ -972,11 +980,24 @@ static struct ref_store *files_ref_store_create(const char *submodule)
struct files_ref_store *refs = xcalloc(1, sizeof(*refs)); struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs; struct ref_store *ref_store = (struct ref_store *)refs;
base_ref_store_init(ref_store, &refs_be_files, submodule); base_ref_store_init(ref_store, &refs_be_files);
refs->submodule = xstrdup_or_null(submodule);
return ref_store; return ref_store;
} }
/*
* Die if refs is for a submodule (i.e., not for the main repository).
* caller is used in any necessary error messages.
*/
static void files_assert_main_repository(struct files_ref_store *refs,
const char *caller)
{
if (refs->submodule)
die("BUG: %s called for a submodule", caller);
}
/* /*
* Downcast ref_store to files_ref_store. Die if ref_store is not a * Downcast ref_store to files_ref_store. Die if ref_store is not a
* files_ref_store. If submodule_allowed is not true, then also die if * files_ref_store. If submodule_allowed is not true, then also die if
@ -987,14 +1008,18 @@ static struct files_ref_store *files_downcast(
struct ref_store *ref_store, int submodule_allowed, struct ref_store *ref_store, int submodule_allowed,
const char *caller) const char *caller)
{ {
struct files_ref_store *refs;
if (ref_store->be != &refs_be_files) if (ref_store->be != &refs_be_files)
die("BUG: ref_store is type \"%s\" not \"files\" in %s", die("BUG: ref_store is type \"%s\" not \"files\" in %s",
ref_store->be->name, caller); ref_store->be->name, caller);
if (!submodule_allowed) refs = (struct files_ref_store *)ref_store;
assert_main_repository(ref_store, caller);
return (struct files_ref_store *)ref_store; if (!submodule_allowed)
files_assert_main_repository(refs, caller);
return refs;
} }
/* The length of a peeled reference line in packed-refs, including EOL: */ /* The length of a peeled reference line in packed-refs, including EOL: */
@ -1133,8 +1158,8 @@ static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *ref
{ {
char *packed_refs_file; char *packed_refs_file;
if (*refs->base.submodule) if (refs->submodule)
packed_refs_file = git_pathdup_submodule(refs->base.submodule, packed_refs_file = git_pathdup_submodule(refs->submodule,
"packed-refs"); "packed-refs");
else else
packed_refs_file = git_pathdup("packed-refs"); packed_refs_file = git_pathdup("packed-refs");
@ -1203,8 +1228,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
size_t path_baselen; size_t path_baselen;
int err = 0; int err = 0;
if (*refs->base.submodule) if (refs->submodule)
err = strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname); err = strbuf_git_path_submodule(&path, refs->submodule, "%s", dirname);
else else
strbuf_git_path(&path, "%s", dirname); strbuf_git_path(&path, "%s", dirname);
path_baselen = path.len; path_baselen = path.len;
@ -1242,20 +1267,10 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
create_dir_entry(refs, refname.buf, create_dir_entry(refs, refname.buf,
refname.len, 1)); refname.len, 1));
} else { } else {
int read_ok; if (!resolve_ref_recursively(&refs->base,
refname.buf,
if (*refs->base.submodule) {
hashclr(sha1);
flag = 0;
read_ok = !resolve_gitlink_ref(refs->base.submodule,
refname.buf, sha1);
} else {
read_ok = !read_ref_full(refname.buf,
RESOLVE_REF_READING, RESOLVE_REF_READING,
sha1, &flag); sha1, &flag)) {
}
if (!read_ok) {
hashclr(sha1); hashclr(sha1);
flag |= REF_ISBROKEN; flag |= REF_ISBROKEN;
} else if (is_null_sha1(sha1)) { } else if (is_null_sha1(sha1)) {
@ -1358,8 +1373,8 @@ static int files_read_raw_ref(struct ref_store *ref_store,
*type = 0; *type = 0;
strbuf_reset(&sb_path); strbuf_reset(&sb_path);
if (*refs->base.submodule) if (refs->submodule)
strbuf_git_path_submodule(&sb_path, refs->base.submodule, "%s", refname); strbuf_git_path_submodule(&sb_path, refs->submodule, "%s", refname);
else else
strbuf_git_path(&sb_path, "%s", refname); strbuf_git_path(&sb_path, "%s", refname);
@ -1540,7 +1555,7 @@ static int lock_raw_ref(struct files_ref_store *refs,
int ret = TRANSACTION_GENERIC_ERROR; int ret = TRANSACTION_GENERIC_ERROR;
assert(err); assert(err);
assert_main_repository(&refs->base, "lock_raw_ref"); files_assert_main_repository(refs, "lock_raw_ref");
*type = 0; *type = 0;
@ -2011,7 +2026,7 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
int resolve_flags = RESOLVE_REF_NO_RECURSE; int resolve_flags = RESOLVE_REF_NO_RECURSE;
int resolved; int resolved;
assert_main_repository(&refs->base, "lock_ref_sha1_basic"); files_assert_main_repository(refs, "lock_ref_sha1_basic");
assert(err); assert(err);
lock = xcalloc(1, sizeof(struct ref_lock)); lock = xcalloc(1, sizeof(struct ref_lock));
@ -2134,7 +2149,7 @@ static int lock_packed_refs(struct files_ref_store *refs, int flags)
static int timeout_value = 1000; static int timeout_value = 1000;
struct packed_ref_cache *packed_ref_cache; struct packed_ref_cache *packed_ref_cache;
assert_main_repository(&refs->base, "lock_packed_refs"); files_assert_main_repository(refs, "lock_packed_refs");
if (!timeout_configured) { if (!timeout_configured) {
git_config_get_int("core.packedrefstimeout", &timeout_value); git_config_get_int("core.packedrefstimeout", &timeout_value);
@ -2172,7 +2187,7 @@ static int commit_packed_refs(struct files_ref_store *refs)
int save_errno = 0; int save_errno = 0;
FILE *out; FILE *out;
assert_main_repository(&refs->base, "commit_packed_refs"); files_assert_main_repository(refs, "commit_packed_refs");
if (!packed_ref_cache->lock) if (!packed_ref_cache->lock)
die("internal error: packed-refs not locked"); die("internal error: packed-refs not locked");
@ -2205,7 +2220,7 @@ static void rollback_packed_refs(struct files_ref_store *refs)
struct packed_ref_cache *packed_ref_cache = struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(refs); get_packed_ref_cache(refs);
assert_main_repository(&refs->base, "rollback_packed_refs"); files_assert_main_repository(refs, "rollback_packed_refs");
if (!packed_ref_cache->lock) if (!packed_ref_cache->lock)
die("internal error: packed-refs not locked"); die("internal error: packed-refs not locked");
@ -2392,7 +2407,7 @@ static int repack_without_refs(struct files_ref_store *refs,
struct string_list_item *refname; struct string_list_item *refname;
int ret, needs_repacking = 0, removed = 0; int ret, needs_repacking = 0, removed = 0;
assert_main_repository(&refs->base, "repack_without_refs"); files_assert_main_repository(refs, "repack_without_refs");
assert(err); assert(err);
/* Look for a packed ref */ /* Look for a packed ref */
@ -2902,7 +2917,7 @@ static int commit_ref_update(struct files_ref_store *refs,
const unsigned char *sha1, const char *logmsg, const unsigned char *sha1, const char *logmsg,
struct strbuf *err) struct strbuf *err)
{ {
assert_main_repository(&refs->base, "commit_ref_update"); files_assert_main_repository(refs, "commit_ref_update");
clear_loose_ref_cache(refs); clear_loose_ref_cache(refs);
if (files_log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, if (files_log_ref_write(lock->ref_name, lock->old_oid.hash, sha1,
@ -3534,7 +3549,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
int ret; int ret;
struct ref_lock *lock; struct ref_lock *lock;
assert_main_repository(&refs->base, "lock_ref_for_update"); files_assert_main_repository(refs, "lock_ref_for_update");
if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
update->flags |= REF_DELETING; update->flags |= REF_DELETING;

View File

@ -635,47 +635,14 @@ extern struct ref_storage_be refs_be_files;
struct ref_store { struct ref_store {
/* The backend describing this ref_store's storage scheme: */ /* The backend describing this ref_store's storage scheme: */
const struct ref_storage_be *be; const struct ref_storage_be *be;
/*
* The name of the submodule represented by this object, or
* the empty string if it represents the main repository's
* reference store:
*/
const char *submodule;
/*
* Submodule reference store instances are stored in a linked
* list using this pointer.
*/
struct ref_store *next;
}; };
/* /*
* Fill in the generic part of refs for the specified submodule and * Fill in the generic part of refs and add it to our collection of
* add it to our collection of reference stores. * reference stores.
*/ */
void base_ref_store_init(struct ref_store *refs, void base_ref_store_init(struct ref_store *refs,
const struct ref_storage_be *be, const struct ref_storage_be *be);
const char *submodule);
/*
* Create, record, and return a ref_store instance for the specified
* submodule (or the main repository if submodule is NULL).
*
* For backwards compatibility, submodule=="" is treated the same as
* submodule==NULL.
*/
struct ref_store *ref_store_init(const char *submodule);
/*
* Return the ref_store instance for the specified submodule (or the
* main repository if submodule is NULL). If that ref_store hasn't
* been initialized yet, return NULL.
*
* For backwards compatibility, submodule=="" is treated the same as
* submodule==NULL.
*/
struct ref_store *lookup_ref_store(const char *submodule);
/* /*
* Return the ref_store instance for the specified submodule. For the * Return the ref_store instance for the specified submodule. For the
@ -689,10 +656,9 @@ struct ref_store *lookup_ref_store(const char *submodule);
*/ */
struct ref_store *get_ref_store(const char *submodule); struct ref_store *get_ref_store(const char *submodule);
/* const char *resolve_ref_recursively(struct ref_store *refs,
* Die if refs is for a submodule (i.e., not for the main repository). const char *refname,
* caller is used in any necessary error messages. int resolve_flags,
*/ unsigned char *sha1, int *flags);
void assert_main_repository(struct ref_store *refs, const char *caller);
#endif /* REFS_REFS_INTERNAL_H */ #endif /* REFS_REFS_INTERNAL_H */