{"thread":{"id":"44001","subject":"[PATCH v2 06/38] add_packed_ref(): add a files_ref_store argument","startedAt":"2016-09-04T16:10:18Z","lastAt":"2016-09-08T21:45:39Z","messageCount":49,"participants":["Michael Haggerty","David Turner","Stefan Beller","Jakub Narębski","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":38},"messages":[{"id":"300990","messageId":"e97937c1bc45f9bf0d9fc5464d84cee514512e7d.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 06/38] add_packed_ref(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:12Z","receivedAt":"2016-09-04T16:10:18Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 439c500..c544de8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1192,10 +1192,9 @@ static struct ref_dir *get_packed_refs(struct files_ref_store *refs)\n  * lock_packed_refs()).  To actually write the packed-refs file, call\n  * commit_packed_refs().\n  */\n-static void add_packed_ref(const char *refname, const unsigned char *sha1)\n+static void add_packed_ref(struct files_ref_store *refs,\n+\t\t\t   const char *refname, const unsigned char *sha1)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"add_packed_ref\");\n \tstruct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);\n \n \tif (!packed_ref_cache->lock)\n@@ -3879,6 +3878,8 @@ static int ref_present(const char *refname,\n int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t\t   struct strbuf *err)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"initial_ref_transaction_commit\");\n \tint ret = 0, i;\n \tstruct string_list affected_refnames = STRING_LIST_INIT_NODUP;\n \n@@ -3938,7 +3939,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \n \t\tif ((update->flags & REF_HAVE_NEW) &&\n \t\t    !is_null_sha1(update->new_sha1))\n-\t\t\tadd_packed_ref(update->refname, update->new_sha1);\n+\t\t\tadd_packed_ref(refs, update->refname, update->new_sha1);\n \t}\n \n \tif (commit_packed_refs()) {\n-- \n2.9.3\n\n"},{"id":"300991","messageId":"f89d56ef0841a3cc35689436c0b9473c6773d22d.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 02/38] rename_ref_available(): add docstring","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:08Z","receivedAt":"2016-09-04T16:10:23Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nAnd improve the internal variable names.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 12 ++++++------\n refs/refs-internal.h | 12 +++++++++++-\n 2 files changed, 17 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex b4e7cac..4c609df 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1081,20 +1081,20 @@ const char *find_descendant_ref(const char *dirname,\n \treturn NULL;\n }\n \n-int rename_ref_available(const char *oldname, const char *newname)\n+int rename_ref_available(const char *old_refname, const char *new_refname)\n {\n \tstruct string_list skip = STRING_LIST_INIT_NODUP;\n \tstruct strbuf err = STRBUF_INIT;\n-\tint ret;\n+\tint ok;\n \n-\tstring_list_insert(&skip, oldname);\n-\tret = !verify_refname_available(newname, NULL, &skip, &err);\n-\tif (!ret)\n+\tstring_list_insert(&skip, old_refname);\n+\tok = !verify_refname_available(new_refname, NULL, &skip, &err);\n+\tif (!ok)\n \t\terror(\"%s\", err.buf);\n \n \tstring_list_clear(&skip, 0);\n \tstrbuf_release(&err);\n-\treturn ret;\n+\treturn ok;\n }\n \n int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex efe5847..0206e2b 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -240,7 +240,17 @@ const char *find_descendant_ref(const char *dirname,\n \t\t\t\tconst struct string_list *extras,\n \t\t\t\tconst struct string_list *skip);\n \n-int rename_ref_available(const char *oldname, const char *newname);\n+/*\n+ * Check whether an attempt to rename old_refname to new_refname would\n+ * cause a D/F conflict with any existing reference (other than\n+ * possibly old_refname). If there would be a conflict, emit an error\n+ * message and return false; otherwise, return true.\n+ *\n+ * Note that this function is not safe against all races with other\n+ * processes (though rename_ref() catches some races that might get by\n+ * this check).\n+ */\n+int rename_ref_available(const char *old_refname, const char *new_refname);\n \n /* We allow \"recursive\" symbolic refs. Only within reason, though */\n #define SYMREF_MAXDEPTH 5\n-- \n2.9.3\n\n"},{"id":"300992","messageId":"fbd7038a70da3306ba684d636302cb43d1fa4742.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 01/38] resolve_gitlink_ref(): eliminate temporary variable","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:07Z","receivedAt":"2016-09-04T16:10:26Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 12290d2..74c2c47 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1387,7 +1387,7 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,\n \n int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n {\n-\tint len = strlen(path), retval;\n+\tint len = strlen(path);\n \tstruct strbuf submodule = STRBUF_INIT;\n \tstruct ref_cache *refs;\n \n@@ -1404,8 +1404,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n \t}\n \tstrbuf_release(&submodule);\n \n-\tretval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);\n-\treturn retval;\n+\treturn resolve_gitlink_ref_recursive(refs, refname, sha1, 0);\n }\n \n /*\n-- \n2.9.3\n\n"},{"id":"300993","messageId":"4da46c8dfa4b7ec13927ca8597b64ffff7de4430.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 04/38] refs: add a backend method structure","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:10Z","receivedAt":"2016-09-04T16:10:27Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nAdd a `struct ref_storage_be` to represent types of reference stores. In\nOO notation, this is the class, and will soon hold some class\nmethods (e.g., a factory to create new ref_store instances) and will\nalso serve as the vtable for ref_store instances of that type.\n\nAs yet, the backends cannot do anything.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 19 +++++++++++++++++++\n refs.h               |  2 ++\n refs/files-backend.c |  5 +++++\n refs/refs-internal.h |  8 ++++++++\n 4 files changed, 34 insertions(+)\n\ndiff --git a/refs.c b/refs.c\nindex 4c609df..d2a29bb 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -10,6 +10,25 @@\n #include \"tag.h\"\n \n /*\n+ * List of all available backends\n+ */\n+static struct ref_storage_be *refs_backends = &refs_be_files;\n+\n+static struct ref_storage_be *find_ref_storage_backend(const char *name)\n+{\n+\tstruct ref_storage_be *be;\n+\tfor (be = refs_backends; be; be = be->next)\n+\t\tif (!strcmp(be->name, name))\n+\t\t\treturn be;\n+\treturn NULL;\n+}\n+\n+int ref_storage_backend_exists(const char *name)\n+{\n+\treturn find_ref_storage_backend(name) != NULL;\n+}\n+\n+/*\n  * How to handle various characters in refnames:\n  * 0: An acceptable character for refs\n  * 1: End-of-component\ndiff --git a/refs.h b/refs.h\nindex 1b02043..9a29f1b 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -544,4 +544,6 @@ int reflog_expire(const char *refname, const unsigned char *sha1,\n \t\t  reflog_expiry_cleanup_fn cleanup_fn,\n \t\t  void *policy_cb_data);\n \n+int ref_storage_backend_exists(const char *name);\n+\n #endif /* REFS_H */\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex aa09586..ecf66e6 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -4076,3 +4076,8 @@ int reflog_expire(const char *refname, const unsigned char *sha1,\n \tunlock_ref(lock);\n \treturn -1;\n }\n+\n+struct ref_storage_be refs_be_files = {\n+\tNULL,\n+\t\"files\"\n+};\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 0206e2b..2c9d134 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -525,4 +525,12 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,\n int read_raw_ref(const char *refname, unsigned char *sha1,\n \t\t struct strbuf *referent, unsigned int *type);\n \n+/* refs backends */\n+struct ref_storage_be {\n+\tstruct ref_storage_be *next;\n+\tconst char *name;\n+};\n+\n+extern struct ref_storage_be refs_be_files;\n+\n #endif /* REFS_REFS_INTERNAL_H */\n-- \n2.9.3\n\n"},{"id":"300994","messageId":"9745c19acb6fc673bfa09c4fec4f8f5833a02429.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 07/38] get_packed_ref(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:13Z","receivedAt":"2016-09-04T16:10:30Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 16 +++++++++-------\n 1 file changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex c544de8..2fc8ec9 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1403,11 +1403,9 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n  * Return the ref_entry for the given refname from the packed\n  * references.  If it does not exist, return NULL.\n  */\n-static struct ref_entry *get_packed_ref(const char *refname)\n+static struct ref_entry *get_packed_ref(struct files_ref_store *refs,\n+\t\t\t\t\tconst char *refname)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"get_packed_ref\");\n-\n \treturn find_ref(get_packed_refs(refs), refname);\n }\n \n@@ -1418,13 +1416,16 @@ static int resolve_missing_loose_ref(const char *refname,\n \t\t\t\t     unsigned char *sha1,\n \t\t\t\t     unsigned int *flags)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"resolve_missing_loose_ref\");\n+\n \tstruct ref_entry *entry;\n \n \t/*\n \t * The loose reference file does not exist; check for a packed\n \t * reference.\n \t */\n-\tentry = get_packed_ref(refname);\n+\tentry = get_packed_ref(refs, refname);\n \tif (entry) {\n \t\thashcpy(sha1, entry->u.value.oid.hash);\n \t\t*flags |= REF_ISPACKED;\n@@ -1836,6 +1837,7 @@ static enum peel_status peel_entry(struct ref_entry *entry, int repeel)\n \n int peel_ref(const char *refname, unsigned char *sha1)\n {\n+\tstruct files_ref_store *refs = get_files_ref_store(NULL, \"peel_ref\");\n \tint flag;\n \tunsigned char base[20];\n \n@@ -1860,7 +1862,7 @@ int peel_ref(const char *refname, unsigned char *sha1)\n \t * have REF_KNOWS_PEELED.\n \t */\n \tif (flag & REF_ISPACKED) {\n-\t\tstruct ref_entry *r = get_packed_ref(refname);\n+\t\tstruct ref_entry *r = get_packed_ref(refs, refname);\n \t\tif (r) {\n \t\t\tif (peel_entry(r, 0))\n \t\t\t\treturn -1;\n@@ -2469,7 +2471,7 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)\n \n \t/* Look for a packed ref */\n \tfor_each_string_list_item(refname, refnames) {\n-\t\tif (get_packed_ref(refname->string)) {\n+\t\tif (get_packed_ref(refs, refname->string)) {\n \t\t\tneeds_repacking = 1;\n \t\t\tbreak;\n \t\t}\n-- \n2.9.3\n\n"},{"id":"300995","messageId":"7bebb0f31efc5fe78fab9d31e055a7ce91898c81.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 14/38] read_raw_ref(): take a (struct ref_store *) argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:20Z","receivedAt":"2016-09-04T16:10:33Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"And make the function work for submodules.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               |  4 +++-\n refs/files-backend.c | 18 +++++++++++++-----\n refs/refs-internal.h |  9 ++++++---\n 3 files changed, 22 insertions(+), 9 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 9475844..9e6b005 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1222,6 +1222,7 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \tstatic struct strbuf sb_refname = STRBUF_INIT;\n \tint unused_flags;\n \tint symref_count;\n+\tstruct ref_store *refs = get_ref_store(NULL);\n \n \tif (!flags)\n \t\tflags = &unused_flags;\n@@ -1249,7 +1250,8 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \tfor (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) {\n \t\tunsigned int read_flags = 0;\n \n-\t\tif (read_raw_ref(refname, sha1, &sb_refname, &read_flags)) {\n+\t\tif (read_raw_ref(refs, refname,\n+\t\t\t\t sha1, &sb_refname, &read_flags)) {\n \t\t\t*flags |= read_flags;\n \t\t\tif (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))\n \t\t\t\treturn NULL;\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 3b0c837..ce6fe94 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1349,11 +1349,12 @@ static int resolve_packed_ref(struct files_ref_store *refs,\n \treturn -1;\n }\n \n-int read_raw_ref(const char *refname, unsigned char *sha1,\n+int read_raw_ref(struct ref_store *ref_store,\n+\t\t const char *refname, unsigned char *sha1,\n \t\t struct strbuf *referent, unsigned int *type)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"read_raw_ref\");\n+\t\tfiles_downcast(ref_store, 1, \"read_raw_ref\");\n \tstruct strbuf sb_contents = STRBUF_INIT;\n \tstruct strbuf sb_path = STRBUF_INIT;\n \tconst char *path;\n@@ -1365,7 +1366,12 @@ int read_raw_ref(const char *refname, unsigned char *sha1,\n \n \t*type = 0;\n \tstrbuf_reset(&sb_path);\n-\tstrbuf_git_path(&sb_path, \"%s\", refname);\n+\n+\tif (*refs->base.submodule)\n+\t\tstrbuf_git_path_submodule(&sb_path, refs->base.submodule, \"%s\", refname);\n+\telse\n+\t\tstrbuf_git_path(&sb_path, \"%s\", refname);\n+\n \tpath = sb_path.buf;\n \n stat_ref:\n@@ -1592,8 +1598,9 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t\t\tunsigned int *type,\n \t\t\tstruct strbuf *err)\n {\n+\tstruct ref_store *ref_store = get_ref_store(NULL);\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"lock_raw_ref\");\n+\t\tfiles_downcast(ref_store, 0, \"lock_raw_ref\");\n \tstruct ref_lock *lock;\n \tstruct strbuf ref_file = STRBUF_INIT;\n \tint attempts_remaining = 3;\n@@ -1683,7 +1690,8 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t * fear that its value will change.\n \t */\n \n-\tif (read_raw_ref(refname, lock->old_oid.hash, referent, type)) {\n+\tif (read_raw_ref(ref_store, refname,\n+\t\t\t lock->old_oid.hash, referent, type)) {\n \t\tif (errno == ENOENT) {\n \t\t\tif (mustexist) {\n \t\t\t\t/* Garden variety missing reference. */\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex b7367ab..fa41d51 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -484,9 +484,11 @@ extern struct ref_iterator *current_ref_iter;\n int do_for_each_ref_iterator(struct ref_iterator *iter,\n \t\t\t     each_ref_fn fn, void *cb_data);\n \n+struct ref_store;\n+\n /*\n- * Read the specified reference from the filesystem or packed refs\n- * file, non-recursively. Set type to describe the reference, and:\n+ * Read a reference from the specified reference store, non-recursively.\n+ * Set type to describe the reference, and:\n  *\n  * - If refname is the name of a normal reference, fill in sha1\n  *   (leaving referent unchanged).\n@@ -522,7 +524,8 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,\n  * - in all other cases, referent will be untouched, and therefore\n  *   refname will still be valid and unchanged.\n  */\n-int read_raw_ref(const char *refname, unsigned char *sha1,\n+int read_raw_ref(struct ref_store *ref_store,\n+\t\t const char *refname, unsigned char *sha1,\n \t\t struct strbuf *referent, unsigned int *type);\n \n /* refs backends */\n-- \n2.9.3\n\n"},{"id":"300996","messageId":"3265523aca57d95a47120e8886b728fdbabbd768.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 10/38] refs: add a transaction_commit() method","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:16Z","receivedAt":"2016-09-04T16:10:37Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: Ronnie Sahlberg <sahlberg@google.com>\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               |  9 +++++++++\n refs/files-backend.c | 10 ++++++----\n refs/refs-internal.h |  5 +++++\n 3 files changed, 20 insertions(+), 4 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 9d6bcb1..9475844 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1377,3 +1377,12 @@ void assert_main_repository(struct ref_store *refs, const char *caller)\n \tif (*refs->submodule)\n \t\tdie(\"BUG: %s called for a submodule\", caller);\n }\n+\n+/* backend functions */\n+int ref_transaction_commit(struct ref_transaction *transaction,\n+\t\t\t   struct strbuf *err)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->transaction_commit(refs, transaction, err);\n+}\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 6913d45..d896052 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3710,11 +3710,12 @@ static int lock_ref_for_update(struct ref_update *update,\n \treturn 0;\n }\n \n-int ref_transaction_commit(struct ref_transaction *transaction,\n-\t\t\t   struct strbuf *err)\n+static int files_transaction_commit(struct ref_store *ref_store,\n+\t\t\t\t    struct ref_transaction *transaction,\n+\t\t\t\t    struct strbuf *err)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"ref_transaction_commit\");\n+\t\tfiles_downcast(ref_store, 0, \"ref_transaction_commit\");\n \tint ret = 0, i;\n \tstruct string_list refs_to_delete = STRING_LIST_INIT_NODUP;\n \tstruct string_list_item *ref_to_delete;\n@@ -4103,5 +4104,6 @@ int reflog_expire(const char *refname, const unsigned char *sha1,\n struct ref_storage_be refs_be_files = {\n \tNULL,\n \t\"files\",\n-\tfiles_ref_store_create\n+\tfiles_ref_store_create,\n+\tfiles_transaction_commit\n };\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex b952038..b7367ab 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -535,10 +535,15 @@ int read_raw_ref(const char *refname, unsigned char *sha1,\n  */\n typedef struct ref_store *ref_store_init_fn(const char *submodule);\n \n+typedef int ref_transaction_commit_fn(struct ref_store *refs,\n+\t\t\t\t      struct ref_transaction *transaction,\n+\t\t\t\t      struct strbuf *err);\n+\n struct ref_storage_be {\n \tstruct ref_storage_be *next;\n \tconst char *name;\n \tref_store_init_fn *init;\n+\tref_transaction_commit_fn *transaction_commit;\n };\n \n extern struct ref_storage_be refs_be_files;\n-- \n2.9.3\n\n"},{"id":"300997","messageId":"df4bcb99055ecaaadd7091403815f8a134a6a262.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 03/38] refs: rename struct ref_cache to files_ref_store","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:09Z","receivedAt":"2016-09-04T16:10:44Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"The greater goal of this patch series is to develop the concept of a\nreference store, which is a place that references, their values, and\ntheir reflogs are stored, and to virtualize the reference interface so\nthat different types of ref_stores can be implemented. We will then, for\nexample, use ref_store instances to access submodule references and\nworktree references.\n\nCurrently, we keep a ref_cache for each submodule that has had its\nreferences iterated over. It is a far cry from a ref_store, but they are\nstored the way we will want to store ref_stores, and ref_stores will\neventually have to hold the reference caches. So let's treat ref_caches\nas embryo ref_stores, and build them out from there.\n\nAs the first step, simply rename `ref_cache` to `files_ref_store`, and\nrename some functions and attributes correspondingly.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 126 +++++++++++++++++++++++++--------------------------\n 1 file changed, 63 insertions(+), 63 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 74c2c47..aa09586 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -39,7 +39,7 @@ struct ref_value {\n \tstruct object_id peeled;\n };\n \n-struct ref_cache;\n+struct files_ref_store;\n \n /*\n  * Information used (along with the information in ref_entry) to\n@@ -78,8 +78,8 @@ struct ref_dir {\n \t */\n \tint sorted;\n \n-\t/* A pointer to the ref_cache that contains this ref_dir. */\n-\tstruct ref_cache *ref_cache;\n+\t/* A pointer to the files_ref_store that contains this ref_dir. */\n+\tstruct files_ref_store *ref_store;\n \n \tstruct ref_entry **entries;\n };\n@@ -161,7 +161,7 @@ struct ref_entry {\n \n static void read_loose_refs(const char *dirname, struct ref_dir *dir);\n static int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len);\n-static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n+static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store,\n \t\t\t\t\t  const char *dirname, size_t len,\n \t\t\t\t\t  int incomplete);\n static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry);\n@@ -183,7 +183,7 @@ static struct ref_dir *get_ref_dir(struct ref_entry *entry)\n \t\t\tint pos = search_ref_dir(dir, \"refs/bisect/\", 12);\n \t\t\tif (pos < 0) {\n \t\t\t\tstruct ref_entry *child_entry;\n-\t\t\t\tchild_entry = create_dir_entry(dir->ref_cache,\n+\t\t\t\tchild_entry = create_dir_entry(dir->ref_store,\n \t\t\t\t\t\t\t       \"refs/bisect/\",\n \t\t\t\t\t\t\t       12, 1);\n \t\t\t\tadd_entry_to_dir(dir, child_entry);\n@@ -261,13 +261,13 @@ static void clear_ref_dir(struct ref_dir *dir)\n  * dirname is the name of the directory with a trailing slash (e.g.,\n  * \"refs/heads/\") or \"\" for the top-level directory.\n  */\n-static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,\n+static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store,\n \t\t\t\t\t  const char *dirname, size_t len,\n \t\t\t\t\t  int incomplete)\n {\n \tstruct ref_entry *direntry;\n \tFLEX_ALLOC_MEM(direntry, name, dirname, len);\n-\tdirentry->u.subdir.ref_cache = ref_cache;\n+\tdirentry->u.subdir.ref_store = ref_store;\n \tdirentry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);\n \treturn direntry;\n }\n@@ -343,7 +343,7 @@ static struct ref_dir *search_for_subdir(struct ref_dir *dir,\n \t\t * therefore, create an empty record for it but mark\n \t\t * the record complete.\n \t\t */\n-\t\tentry = create_dir_entry(dir->ref_cache, subdirname, len, 0);\n+\t\tentry = create_dir_entry(dir->ref_store, subdirname, len, 0);\n \t\tadd_entry_to_dir(dir, entry);\n \t} else {\n \t\tentry = dir->entries[entry_index];\n@@ -887,9 +887,9 @@ struct packed_ref_cache {\n \n \t/*\n \t * Count of references to the data structure in this instance,\n-\t * including the pointer from ref_cache::packed if any.  The\n-\t * data will not be freed as long as the reference count is\n-\t * nonzero.\n+\t * including the pointer from files_ref_store::packed if any.\n+\t * The data will not be freed as long as the reference count\n+\t * is nonzero.\n \t */\n \tunsigned int referrers;\n \n@@ -910,17 +910,17 @@ struct packed_ref_cache {\n  * Future: need to be in \"struct repository\"\n  * when doing a full libification.\n  */\n-static struct ref_cache {\n-\tstruct ref_cache *next;\n+static struct files_ref_store {\n+\tstruct files_ref_store *next;\n \tstruct ref_entry *loose;\n \tstruct packed_ref_cache *packed;\n \t/*\n-\t * The submodule name, or \"\" for the main repo.  We allocate\n-\t * length 1 rather than FLEX_ARRAY so that the main ref_cache\n-\t * is initialized correctly.\n+\t * The submodule name, or \"\" for the main repo. We allocate\n+\t * length 1 rather than FLEX_ARRAY so that the main\n+\t * files_ref_store is initialized correctly.\n \t */\n \tchar name[1];\n-} ref_cache, *submodule_ref_caches;\n+} ref_store, *submodule_ref_stores;\n \n /* Lock used for the main packed-refs file: */\n static struct lock_file packlock;\n@@ -949,7 +949,7 @@ static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)\n \t}\n }\n \n-static void clear_packed_ref_cache(struct ref_cache *refs)\n+static void clear_packed_ref_cache(struct files_ref_store *refs)\n {\n \tif (refs->packed) {\n \t\tstruct packed_ref_cache *packed_refs = refs->packed;\n@@ -961,7 +961,7 @@ static void clear_packed_ref_cache(struct ref_cache *refs)\n \t}\n }\n \n-static void clear_loose_ref_cache(struct ref_cache *refs)\n+static void clear_loose_ref_cache(struct files_ref_store *refs)\n {\n \tif (refs->loose) {\n \t\tfree_ref_entry(refs->loose);\n@@ -973,32 +973,32 @@ static void clear_loose_ref_cache(struct ref_cache *refs)\n  * Create a new submodule ref cache and add it to the internal\n  * set of caches.\n  */\n-static struct ref_cache *create_ref_cache(const char *submodule)\n+static struct files_ref_store *create_ref_store(const char *submodule)\n {\n-\tstruct ref_cache *refs;\n+\tstruct files_ref_store *refs;\n \tif (!submodule)\n \t\tsubmodule = \"\";\n \tFLEX_ALLOC_STR(refs, name, submodule);\n-\trefs->next = submodule_ref_caches;\n-\tsubmodule_ref_caches = refs;\n+\trefs->next = submodule_ref_stores;\n+\tsubmodule_ref_stores = refs;\n \treturn refs;\n }\n \n-static struct ref_cache *lookup_ref_cache(const char *submodule)\n+static struct files_ref_store *lookup_ref_store(const char *submodule)\n {\n-\tstruct ref_cache *refs;\n+\tstruct files_ref_store *refs;\n \n \tif (!submodule || !*submodule)\n-\t\treturn &ref_cache;\n+\t\treturn &ref_store;\n \n-\tfor (refs = submodule_ref_caches; refs; refs = refs->next)\n+\tfor (refs = submodule_ref_stores; refs; refs = refs->next)\n \t\tif (!strcmp(submodule, refs->name))\n \t\t\treturn refs;\n \treturn NULL;\n }\n \n /*\n- * Return a pointer to a ref_cache for the specified submodule. For\n+ * Return a pointer to a files_ref_store for the specified submodule. For\n  * the main repository, use submodule==NULL; such a call cannot fail.\n  * For a submodule, the submodule must exist and be a nonbare\n  * repository, otherwise return NULL.\n@@ -1006,16 +1006,16 @@ static struct ref_cache *lookup_ref_cache(const char *submodule)\n  * The returned structure will be allocated and initialized but not\n  * necessarily populated; it should not be freed.\n  */\n-static struct ref_cache *get_ref_cache(const char *submodule)\n+static struct files_ref_store *get_ref_store(const char *submodule)\n {\n-\tstruct ref_cache *refs = lookup_ref_cache(submodule);\n+\tstruct files_ref_store *refs = lookup_ref_store(submodule);\n \n \tif (!refs) {\n \t\tstruct strbuf submodule_sb = STRBUF_INIT;\n \n \t\tstrbuf_addstr(&submodule_sb, submodule);\n \t\tif (is_nonbare_repository_dir(&submodule_sb))\n-\t\t\trefs = create_ref_cache(submodule);\n+\t\t\trefs = create_ref_store(submodule);\n \t\tstrbuf_release(&submodule_sb);\n \t}\n \n@@ -1151,10 +1151,10 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)\n }\n \n /*\n- * Get the packed_ref_cache for the specified ref_cache, creating it\n- * if necessary.\n+ * Get the packed_ref_cache for the specified files_ref_store,\n+ * creating it if necessary.\n  */\n-static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)\n+static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *refs)\n {\n \tchar *packed_refs_file;\n \n@@ -1189,7 +1189,7 @@ static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache *packed_ref_ca\n \treturn get_ref_dir(packed_ref_cache->root);\n }\n \n-static struct ref_dir *get_packed_refs(struct ref_cache *refs)\n+static struct ref_dir *get_packed_refs(struct files_ref_store *refs)\n {\n \treturn get_packed_ref_dir(get_packed_ref_cache(refs));\n }\n@@ -1203,7 +1203,7 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)\n static void add_packed_ref(const char *refname, const unsigned char *sha1)\n {\n \tstruct packed_ref_cache *packed_ref_cache =\n-\t\tget_packed_ref_cache(&ref_cache);\n+\t\tget_packed_ref_cache(&ref_store);\n \n \tif (!packed_ref_cache->lock)\n \t\tdie(\"internal error: packed refs not locked\");\n@@ -1218,7 +1218,7 @@ static void add_packed_ref(const char *refname, const unsigned char *sha1)\n  */\n static void read_loose_refs(const char *dirname, struct ref_dir *dir)\n {\n-\tstruct ref_cache *refs = dir->ref_cache;\n+\tstruct files_ref_store *refs = dir->ref_store;\n \tDIR *d;\n \tstruct dirent *de;\n \tint dirnamelen = strlen(dirname);\n@@ -1306,7 +1306,7 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)\n \tclosedir(d);\n }\n \n-static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n+static struct ref_dir *get_loose_refs(struct files_ref_store *refs)\n {\n \tif (!refs->loose) {\n \t\t/*\n@@ -1328,10 +1328,10 @@ static struct ref_dir *get_loose_refs(struct ref_cache *refs)\n \n /*\n  * Called by resolve_gitlink_ref_recursive() after it failed to read\n- * from the loose refs in ref_cache refs. Find <refname> in the\n- * packed-refs file for the submodule.\n+ * from the loose refs in refs. Find <refname> in the packed-refs file\n+ * for the submodule.\n  */\n-static int resolve_gitlink_packed_ref(struct ref_cache *refs,\n+static int resolve_gitlink_packed_ref(struct files_ref_store *refs,\n \t\t\t\t      const char *refname, unsigned char *sha1)\n {\n \tstruct ref_entry *ref;\n@@ -1345,7 +1345,7 @@ static int resolve_gitlink_packed_ref(struct ref_cache *refs,\n \treturn 0;\n }\n \n-static int resolve_gitlink_ref_recursive(struct ref_cache *refs,\n+static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,\n \t\t\t\t\t const char *refname, unsigned char *sha1,\n \t\t\t\t\t int recursion)\n {\n@@ -1389,7 +1389,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n {\n \tint len = strlen(path);\n \tstruct strbuf submodule = STRBUF_INIT;\n-\tstruct ref_cache *refs;\n+\tstruct files_ref_store *refs;\n \n \twhile (len && path[len-1] == '/')\n \t\tlen--;\n@@ -1397,7 +1397,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n \t\treturn -1;\n \n \tstrbuf_add(&submodule, path, len);\n-\trefs = get_ref_cache(submodule.buf);\n+\trefs = get_ref_store(submodule.buf);\n \tif (!refs) {\n \t\tstrbuf_release(&submodule);\n \t\treturn -1;\n@@ -1413,7 +1413,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n  */\n static struct ref_entry *get_packed_ref(const char *refname)\n {\n-\treturn find_ref(get_packed_refs(&ref_cache), refname);\n+\treturn find_ref(get_packed_refs(&ref_store), refname);\n }\n \n /*\n@@ -1745,7 +1745,7 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t\t\t\t\t\t\t  REMOVE_DIR_EMPTY_ONLY)) {\n \t\t\t\tif (verify_refname_available_dir(\n \t\t\t\t\t\t    refname, extras, skip,\n-\t\t\t\t\t\t    get_loose_refs(&ref_cache),\n+\t\t\t\t\t\t    get_loose_refs(&ref_store),\n \t\t\t\t\t\t    err)) {\n \t\t\t\t\t/*\n \t\t\t\t\t * The error message set by\n@@ -1784,7 +1784,7 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t\t */\n \t\tif (verify_refname_available_dir(\n \t\t\t\t    refname, extras, skip,\n-\t\t\t\t    get_packed_refs(&ref_cache),\n+\t\t\t\t    get_packed_refs(&ref_store),\n \t\t\t\t    err)) {\n \t\t\tgoto error_return;\n \t\t}\n@@ -1942,7 +1942,7 @@ struct ref_iterator *files_ref_iterator_begin(\n \t\tconst char *submodule,\n \t\tconst char *prefix, unsigned int flags)\n {\n-\tstruct ref_cache *refs = get_ref_cache(submodule);\n+\tstruct files_ref_store *refs = get_ref_store(submodule);\n \tstruct ref_dir *loose_dir, *packed_dir;\n \tstruct ref_iterator *loose_iter, *packed_iter;\n \tstruct files_ref_iterator *iter;\n@@ -2096,7 +2096,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t\tif (remove_empty_directories(&ref_file)) {\n \t\t\tlast_errno = errno;\n \t\t\tif (!verify_refname_available_dir(refname, extras, skip,\n-\t\t\t\t\t\t\t  get_loose_refs(&ref_cache), err))\n+\t\t\t\t\t\t\t  get_loose_refs(&ref_store), err))\n \t\t\t\tstrbuf_addf(err, \"there are still refs under '%s'\",\n \t\t\t\t\t    refname);\n \t\t\tgoto error_return;\n@@ -2108,7 +2108,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t\tlast_errno = errno;\n \t\tif (last_errno != ENOTDIR ||\n \t\t    !verify_refname_available_dir(refname, extras, skip,\n-\t\t\t\t\t\t  get_loose_refs(&ref_cache), err))\n+\t\t\t\t\t\t  get_loose_refs(&ref_store), err))\n \t\t\tstrbuf_addf(err, \"unable to resolve reference '%s': %s\",\n \t\t\t\t    refname, strerror(last_errno));\n \n@@ -2123,7 +2123,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t */\n \tif (is_null_oid(&lock->old_oid) &&\n \t    verify_refname_available_dir(refname, extras, skip,\n-\t\t\t\t\t get_packed_refs(&ref_cache), err)) {\n+\t\t\t\t\t get_packed_refs(&ref_store), err)) {\n \t\tlast_errno = ENOTDIR;\n \t\tgoto error_return;\n \t}\n@@ -2232,7 +2232,7 @@ static int lock_packed_refs(int flags)\n \t * this will automatically invalidate the cache and re-read\n \t * the packed-refs file.\n \t */\n-\tpacked_ref_cache = get_packed_ref_cache(&ref_cache);\n+\tpacked_ref_cache = get_packed_ref_cache(&ref_store);\n \tpacked_ref_cache->lock = &packlock;\n \t/* Increment the reference count to prevent it from being freed: */\n \tacquire_packed_ref_cache(packed_ref_cache);\n@@ -2248,7 +2248,7 @@ static int lock_packed_refs(int flags)\n static int commit_packed_refs(void)\n {\n \tstruct packed_ref_cache *packed_ref_cache =\n-\t\tget_packed_ref_cache(&ref_cache);\n+\t\tget_packed_ref_cache(&ref_store);\n \tint error = 0;\n \tint save_errno = 0;\n \tFILE *out;\n@@ -2282,14 +2282,14 @@ static int commit_packed_refs(void)\n static void rollback_packed_refs(void)\n {\n \tstruct packed_ref_cache *packed_ref_cache =\n-\t\tget_packed_ref_cache(&ref_cache);\n+\t\tget_packed_ref_cache(&ref_store);\n \n \tif (!packed_ref_cache->lock)\n \t\tdie(\"internal error: packed-refs not locked\");\n \trollback_lock_file(packed_ref_cache->lock);\n \tpacked_ref_cache->lock = NULL;\n \trelease_packed_ref_cache(packed_ref_cache);\n-\tclear_packed_ref_cache(&ref_cache);\n+\tclear_packed_ref_cache(&ref_store);\n }\n \n struct ref_to_prune {\n@@ -2428,9 +2428,9 @@ int pack_refs(unsigned int flags)\n \tcbdata.flags = flags;\n \n \tlock_packed_refs(LOCK_DIE_ON_ERROR);\n-\tcbdata.packed_refs = get_packed_refs(&ref_cache);\n+\tcbdata.packed_refs = get_packed_refs(&ref_store);\n \n-\tdo_for_each_entry_in_dir(get_loose_refs(&ref_cache), 0,\n+\tdo_for_each_entry_in_dir(get_loose_refs(&ref_store), 0,\n \t\t\t\t pack_if_possible_fn, &cbdata);\n \n \tif (commit_packed_refs())\n@@ -2471,7 +2471,7 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)\n \t\tunable_to_lock_message(git_path(\"packed-refs\"), errno, err);\n \t\treturn -1;\n \t}\n-\tpacked = get_packed_refs(&ref_cache);\n+\tpacked = get_packed_refs(&ref_store);\n \n \t/* Remove refnames from the cache */\n \tfor_each_string_list_item(refname, refnames)\n@@ -2616,8 +2616,8 @@ int verify_refname_available(const char *newname,\n \t\t\t     const struct string_list *skip,\n \t\t\t     struct strbuf *err)\n {\n-\tstruct ref_dir *packed_refs = get_packed_refs(&ref_cache);\n-\tstruct ref_dir *loose_refs = get_loose_refs(&ref_cache);\n+\tstruct ref_dir *packed_refs = get_packed_refs(&ref_store);\n+\tstruct ref_dir *loose_refs = get_loose_refs(&ref_store);\n \n \tif (verify_refname_available_dir(newname, extras, skip,\n \t\t\t\t\t packed_refs, err) ||\n@@ -2968,7 +2968,7 @@ static int commit_ref_update(struct ref_lock *lock,\n \t\t\t     const unsigned char *sha1, const char *logmsg,\n \t\t\t     struct strbuf *err)\n {\n-\tclear_loose_ref_cache(&ref_cache);\n+\tclear_loose_ref_cache(&ref_store);\n \tif (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, 0, err)) {\n \t\tchar *old_msg = strbuf_detach(err, NULL);\n \t\tstrbuf_addf(err, \"cannot update the ref '%s': %s\",\n@@ -3800,7 +3800,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t}\n \t\t}\n \t\tif (update->flags & REF_NEEDS_COMMIT) {\n-\t\t\tclear_loose_ref_cache(&ref_cache);\n+\t\t\tclear_loose_ref_cache(&ref_store);\n \t\t\tif (commit_ref(lock)) {\n \t\t\t\tstrbuf_addf(err, \"couldn't set '%s'\", lock->ref_name);\n \t\t\t\tunlock_ref(lock);\n@@ -3833,7 +3833,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \t}\n \tfor_each_string_list_item(ref_to_delete, &refs_to_delete)\n \t\tunlink_or_warn(git_path(\"logs/%s\", ref_to_delete->string));\n-\tclear_loose_ref_cache(&ref_cache);\n+\tclear_loose_ref_cache(&ref_store);\n \n cleanup:\n \ttransaction->state = REF_TRANSACTION_CLOSED;\n-- \n2.9.3\n\n"},{"id":"300998","messageId":"cover.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":null,"subject":"[PATCH v2 00/38] Virtualization of the refs API","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:06Z","receivedAt":"2016-09-04T16:10:47Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"This is v2 of the patch series to virtualize the references API\n(though earlier patch series similar in spirit were submitted by\nRonnie Sahlberg and David Turner). Thanks to Junio, Eric, and Ramsay\nfor their comments about v1 [1].\n\nNobody pointed out any fundamental problems with v1, but this version\nincludes the following improvements:\n\n* In \"rename_ref_available(): add docstring\":\n\n  * Improve docstring as suggested by Junio.\n\n* In \"refs: create a base class \"ref_store\" for files_ref_store\":\n\n  * Let main_ref_store and submodule_ref_stores be initialized\n    implicitly rather than initializing them explicitly to NULL.\n\n  * Add docstrings for those two variables.\n\n  * Eliminate a temporary variable in `files_downcast()`.\n\n* In \"resolve_gitlink_ref(): avoid memory allocation in many cases\":\n\n  * Instead of keeping track of `orig_len`, after stripping off any\n    trailing slashes check whether `path[len - 1]` is NUL.\n\n* In \"refs: add methods for reflog\":\n\n  * Don't export `files_reflog_iterator_begin()` (suggested by\n    Ramsay).\n\nIn addition, given that v1 was pretty old, I have rebased the patch\nseries against the current upstream master. (The rebase was\nunproblematic.)\n\nThis patch series is also available from my GitHub fork [2] as branch\n\"ref-store\".\n\nMichael\n\n[1] http://public-inbox.org/git/cover.1464983301.git.mhagger@alum.mit.edu/t/\n[2] https://github.com/mhagger/git\n\nDavid Turner (8):\n  rename_ref_available(): add docstring\n  refs: add methods for reflog\n  refs: add method for initial ref transaction commit\n  refs: make delete_refs() virtual\n  refs: add methods to init refs db\n  refs: add method to rename refs\n  refs: make lock generic\n  refs: implement iteration over only per-worktree refs\n\nMichael Haggerty (28):\n  resolve_gitlink_ref(): eliminate temporary variable\n  refs: rename struct ref_cache to files_ref_store\n  refs: create a base class \"ref_store\" for files_ref_store\n  add_packed_ref(): add a files_ref_store argument\n  get_packed_ref(): add a files_ref_store argument\n  resolve_missing_loose_ref(): add a files_ref_store argument\n  {lock,commit,rollback}_packed_refs(): add files_ref_store arguments\n  refs: reorder definitions\n  resolve_packed_ref(): rename function from resolve_missing_loose_ref()\n  resolve_gitlink_packed_ref(): remove function\n  read_raw_ref(): take a (struct ref_store *) argument\n  resolve_ref_recursively(): new function\n  resolve_gitlink_ref(): implement using resolve_ref_recursively()\n  resolve_gitlink_ref(): avoid memory allocation in many cases\n  resolve_gitlink_ref(): rename path parameter to submodule\n  refs: make read_raw_ref() virtual\n  refs: make verify_refname_available() virtual\n  refs: make pack_refs() virtual\n  refs: make create_symref() virtual\n  refs: make peel_ref() virtual\n  repack_without_refs(): add a files_ref_store argument\n  lock_raw_ref(): add a files_ref_store argument\n  commit_ref_update(): add a files_ref_store argument\n  lock_ref_for_update(): add a files_ref_store argument\n  lock_ref_sha1_basic(): add a files_ref_store argument\n  split_symref_update(): add a files_ref_store argument\n  files_ref_iterator_begin(): take a ref_store argument\n  refs: add method iterator_begin\n\nRonnie Sahlberg (2):\n  refs: add a backend method structure\n  refs: add a transaction_commit() method\n\n builtin/init-db.c    |  21 +-\n refs.c               | 309 +++++++++++++++++++++++++++-\n refs.h               |  13 +-\n refs/files-backend.c | 566 +++++++++++++++++++++++++++------------------------\n refs/refs-internal.h | 220 +++++++++++++++++---\n 5 files changed, 812 insertions(+), 317 deletions(-)\n\n-- \n2.9.3\n\n"},{"id":"300999","messageId":"1e7e45a2a96e1ae7d45a1072c3c965bc7c02105c.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 16/38] resolve_gitlink_ref(): implement using resolve_ref_recursively()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:22Z","receivedAt":"2016-09-04T16:10:49Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"resolve_ref_recursively() can handle references in arbitrary files\nreference stores, so use it to resolve \"gitlink\" (i.e., submodule)\nreferences. Aside from removing redundant code, this allows submodule\nlookups to benefit from the much more robust code that we use for\nreading non-submodule references. And, since the code is now agnostic\nabout reference backends, it will work for any future references\nbackend (so move its definition to refs.c).\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 24 +++++++++++++++++++\n refs/files-backend.c | 67 ----------------------------------------------------\n 2 files changed, 24 insertions(+), 67 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 3723169..647ead5 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1299,6 +1299,30 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \t\t\t\t       resolve_flags, sha1, flags);\n }\n \n+int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n+{\n+\tint len = strlen(path);\n+\tstruct strbuf submodule = STRBUF_INIT;\n+\tstruct ref_store *refs;\n+\tint flags;\n+\n+\twhile (len && path[len-1] == '/')\n+\t\tlen--;\n+\tif (!len)\n+\t\treturn -1;\n+\n+\tstrbuf_add(&submodule, path, len);\n+\trefs = get_ref_store(submodule.buf);\n+\tstrbuf_release(&submodule);\n+\tif (!refs)\n+\t\treturn -1;\n+\n+\tif (!resolve_ref_recursively(refs, refname, 0, sha1, &flags) ||\n+\t    is_null_sha1(sha1))\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n /* A pointer to the ref_store for the main repository: */\n static struct ref_store *main_ref_store;\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ce6fe94..6382c6b 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1494,73 +1494,6 @@ static void unlock_ref(struct ref_lock *lock)\n \tfree(lock);\n }\n \n-#define MAXREFLEN (1024)\n-\n-static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,\n-\t\t\t\t\t const char *refname, unsigned char *sha1,\n-\t\t\t\t\t int recursion)\n-{\n-\tint fd, len;\n-\tchar buffer[128], *p;\n-\tchar *path;\n-\n-\tif (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)\n-\t\treturn -1;\n-\tpath = *refs->base.submodule\n-\t\t? git_pathdup_submodule(refs->base.submodule, \"%s\", refname)\n-\t\t: git_pathdup(\"%s\", refname);\n-\tfd = open(path, O_RDONLY);\n-\tfree(path);\n-\tif (fd < 0) {\n-\t\tunsigned int flags;\n-\n-\t\treturn resolve_packed_ref(refs, refname, sha1, &flags);\n-\t}\n-\n-\tlen = read(fd, buffer, sizeof(buffer)-1);\n-\tclose(fd);\n-\tif (len < 0)\n-\t\treturn -1;\n-\twhile (len && isspace(buffer[len-1]))\n-\t\tlen--;\n-\tbuffer[len] = 0;\n-\n-\t/* Was it a detached head or an old-fashioned symlink? */\n-\tif (!get_sha1_hex(buffer, sha1))\n-\t\treturn 0;\n-\n-\t/* Symref? */\n-\tif (strncmp(buffer, \"ref:\", 4))\n-\t\treturn -1;\n-\tp = buffer + 4;\n-\twhile (isspace(*p))\n-\t\tp++;\n-\n-\treturn resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1);\n-}\n-\n-int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n-{\n-\tint len = strlen(path);\n-\tstruct strbuf submodule = STRBUF_INIT;\n-\tstruct files_ref_store *refs;\n-\n-\twhile (len && path[len-1] == '/')\n-\t\tlen--;\n-\tif (!len)\n-\t\treturn -1;\n-\n-\tstrbuf_add(&submodule, path, len);\n-\trefs = get_files_ref_store(submodule.buf, \"resolve_gitlink_ref\");\n-\tif (!refs) {\n-\t\tstrbuf_release(&submodule);\n-\t\treturn -1;\n-\t}\n-\tstrbuf_release(&submodule);\n-\n-\treturn resolve_gitlink_ref_recursive(refs, refname, sha1, 0);\n-}\n-\n /*\n  * Lock refname, without following symrefs, and set *lock_p to point\n  * at a newly-allocated lock object. Fill in lock->old_oid, referent,\n-- \n2.9.3\n\n"},{"id":"301000","messageId":"1f8eae1b5920dbe464bb52cc4b54bc26b7f0ec2d.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 18/38] resolve_gitlink_ref(): rename path parameter to submodule","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:24Z","receivedAt":"2016-09-04T16:10:50Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c | 13 +++++++------\n refs.h |  9 +++++----\n 2 files changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 34c0c5e..e881874 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1299,26 +1299,27 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \t\t\t\t       resolve_flags, sha1, flags);\n }\n \n-int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n+int resolve_gitlink_ref(const char *submodule, const char *refname,\n+\t\t\tunsigned char *sha1)\n {\n-\tsize_t len = strlen(path);\n+\tsize_t len = strlen(submodule);\n \tstruct ref_store *refs;\n \tint flags;\n \n-\twhile (len && path[len - 1] == '/')\n+\twhile (len && submodule[len - 1] == '/')\n \t\tlen--;\n \n \tif (!len)\n \t\treturn -1;\n \n-\tif (path[len]) {\n+\tif (submodule[len]) {\n \t\t/* We need to strip off one or more trailing slashes */\n-\t\tchar *stripped = xmemdupz(path, len);\n+\t\tchar *stripped = xmemdupz(submodule, len);\n \n \t\trefs = get_ref_store(stripped);\n \t\tfree(stripped);\n \t} else {\n-\t\trefs = get_ref_store(path);\n+\t\trefs = get_ref_store(submodule);\n \t}\n \n \tif (!refs)\ndiff --git a/refs.h b/refs.h\nindex 9a29f1b..17e8cfb 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -77,11 +77,12 @@ int is_branch(const char *refname);\n int peel_ref(const char *refname, unsigned char *sha1);\n \n /**\n- * Resolve refname in the nested \"gitlink\" repository that is located\n- * at path.  If the resolution is successful, return 0 and set sha1 to\n- * the name of the object; otherwise, return a non-zero value.\n+ * Resolve refname in the nested \"gitlink\" repository in the specified\n+ * submodule (which must be non-NULL). If the resolution is\n+ * successful, return 0 and set sha1 to the name of the object;\n+ * otherwise, return a non-zero value.\n  */\n-int resolve_gitlink_ref(const char *path, const char *refname,\n+int resolve_gitlink_ref(const char *submodule, const char *refname,\n \t\t\tunsigned char *sha1);\n \n /*\n-- \n2.9.3\n\n"},{"id":"301001","messageId":"abc7326c53a018854d4e9cddf2fec9e0922d9787.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 08/38] resolve_missing_loose_ref(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:14Z","receivedAt":"2016-09-04T16:10:52Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 2fc8ec9..0c92ace 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1412,13 +1412,11 @@ static struct ref_entry *get_packed_ref(struct files_ref_store *refs,\n /*\n  * A loose ref file doesn't exist; check for a packed ref.\n  */\n-static int resolve_missing_loose_ref(const char *refname,\n+static int resolve_missing_loose_ref(struct files_ref_store *refs,\n+\t\t\t\t     const char *refname,\n \t\t\t\t     unsigned char *sha1,\n \t\t\t\t     unsigned int *flags)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"resolve_missing_loose_ref\");\n-\n \tstruct ref_entry *entry;\n \n \t/*\n@@ -1438,6 +1436,8 @@ static int resolve_missing_loose_ref(const char *refname,\n int read_raw_ref(const char *refname, unsigned char *sha1,\n \t\t struct strbuf *referent, unsigned int *type)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"read_raw_ref\");\n \tstruct strbuf sb_contents = STRBUF_INIT;\n \tstruct strbuf sb_path = STRBUF_INIT;\n \tconst char *path;\n@@ -1466,7 +1466,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,\n \tif (lstat(path, &st) < 0) {\n \t\tif (errno != ENOENT)\n \t\t\tgoto out;\n-\t\tif (resolve_missing_loose_ref(refname, sha1, type)) {\n+\t\tif (resolve_missing_loose_ref(refs, refname, sha1, type)) {\n \t\t\terrno = ENOENT;\n \t\t\tgoto out;\n \t\t}\n@@ -1500,7 +1500,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,\n \t\t * ref is supposed to be, there could still be a\n \t\t * packed ref:\n \t\t */\n-\t\tif (resolve_missing_loose_ref(refname, sha1, type)) {\n+\t\tif (resolve_missing_loose_ref(refs, refname, sha1, type)) {\n \t\t\terrno = EISDIR;\n \t\t\tgoto out;\n \t\t}\n-- \n2.9.3\n\n"},{"id":"301002","messageId":"61aae94372a352f6048ea22132ec78d5891f41a0.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 31/38] refs: add method iterator_begin","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:37Z","receivedAt":"2016-09-04T16:11:54Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               |  2 +-\n refs/files-backend.c |  3 ++-\n refs/refs-internal.h | 24 ++++++++++++------------\n 3 files changed, 15 insertions(+), 14 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex d00126b..798b08a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1157,7 +1157,7 @@ static int do_for_each_ref(const char *submodule, const char *prefix,\n \tif (!refs)\n \t\treturn 0;\n \n-\titer = files_ref_iterator_begin(refs, prefix, flags);\n+\titer = refs->be->iterator_begin(refs, prefix, flags);\n \titer = prefix_ref_iterator_begin(iter, prefix, trim);\n \n \treturn do_for_each_ref_iterator(iter, fn, cb_data);\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex f521b5d..4451e13 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1862,7 +1862,7 @@ static struct ref_iterator_vtable files_ref_iterator_vtable = {\n \tfiles_ref_iterator_abort\n };\n \n-struct ref_iterator *files_ref_iterator_begin(\n+static struct ref_iterator *files_ref_iterator_begin(\n \t\tstruct ref_store *ref_store,\n \t\tconst char *prefix, unsigned int flags)\n {\n@@ -4054,6 +4054,7 @@ struct ref_storage_be refs_be_files = {\n \tfiles_peel_ref,\n \tfiles_create_symref,\n \n+\tfiles_ref_iterator_begin,\n \tfiles_read_raw_ref,\n \tfiles_verify_refname_available\n };\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 0af1079..5be62a2 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -404,18 +404,6 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,\n \t\t\t\t\t       const char *prefix,\n \t\t\t\t\t       int trim);\n \n-struct ref_store;\n-\n-/*\n- * Iterate over the packed and loose references in the specified\n- * ref_store that are within find_containing_dir(prefix). If prefix is\n- * NULL or the empty string, iterate over all references in the\n- * submodule.\n- */\n-struct ref_iterator *files_ref_iterator_begin(struct ref_store *ref_store,\n-\t\t\t\t\t      const char *prefix,\n-\t\t\t\t\t      unsigned int flags);\n-\n /*\n  * Iterate over the references in the main ref_store that have a\n  * reflog. The paths within a directory are iterated over in arbitrary\n@@ -488,6 +476,8 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,\n \n /* refs backends */\n \n+struct ref_store;\n+\n /*\n  * Initialize the ref_store for the specified submodule, or for the\n  * main repository if submodule == NULL. These functions should call\n@@ -509,6 +499,15 @@ typedef int create_symref_fn(struct ref_store *ref_store,\n \t\t\t     const char *logmsg);\n \n /*\n+ * Iterate over the references in the specified ref_store that are\n+ * within find_containing_dir(prefix). If prefix is NULL or the empty\n+ * string, iterate over all references in the submodule.\n+ */\n+typedef struct ref_iterator *ref_iterator_begin_fn(\n+\t\tstruct ref_store *ref_store,\n+\t\tconst char *prefix, unsigned int flags);\n+\n+/*\n  * Read a reference from the specified reference store, non-recursively.\n  * Set type to describe the reference, and:\n  *\n@@ -566,6 +565,7 @@ struct ref_storage_be {\n \tpeel_ref_fn *peel_ref;\n \tcreate_symref_fn *create_symref;\n \n+\tref_iterator_begin_fn *iterator_begin;\n \tread_raw_ref_fn *read_raw_ref;\n \tverify_refname_available_fn *verify_refname_available;\n };\n-- \n2.9.3\n\n"},{"id":"301003","messageId":"2bf161a94fa06317c95c5336ec384c7a7d262741.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 35/38] refs: add methods to init refs db","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:41Z","receivedAt":"2016-09-04T16:12:04Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nAlternate refs backends might not need the refs/heads directory and so\non, so we make ref db initialization part of the backend.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/init-db.c    | 21 +++++++++++----------\n refs.c               |  8 ++++++++\n refs.h               |  2 ++\n refs/files-backend.c | 18 ++++++++++++++++++\n refs/refs-internal.h |  3 +++\n 5 files changed, 42 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex 3a45f0b..80192f6 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -180,13 +180,7 @@ static int create_default_files(const char *template_path)\n \tchar junk[2];\n \tint reinit;\n \tint filemode;\n-\n-\t/*\n-\t * Create .git/refs/{heads,tags}\n-\t */\n-\tsafe_create_dir(git_path_buf(&buf, \"refs\"), 1);\n-\tsafe_create_dir(git_path_buf(&buf, \"refs/heads\"), 1);\n-\tsafe_create_dir(git_path_buf(&buf, \"refs/tags\"), 1);\n+\tstruct strbuf err = STRBUF_INIT;\n \n \t/* Just look for `init.templatedir` */\n \tgit_config(git_init_db_config, NULL);\n@@ -210,12 +204,19 @@ static int create_default_files(const char *template_path)\n \t */\n \tif (get_shared_repository()) {\n \t\tadjust_shared_perm(get_git_dir());\n-\t\tadjust_shared_perm(git_path_buf(&buf, \"refs\"));\n-\t\tadjust_shared_perm(git_path_buf(&buf, \"refs/heads\"));\n-\t\tadjust_shared_perm(git_path_buf(&buf, \"refs/tags\"));\n \t}\n \n \t/*\n+\t * We need to create a \"refs\" dir in any case so that older\n+\t * versions of git can tell that this is a repository.\n+\t */\n+\tsafe_create_dir(git_path(\"refs\"), 1);\n+\tadjust_shared_perm(git_path(\"refs\"));\n+\n+\tif (refs_init_db(&err))\n+\t\tdie(\"failed to set up refs db: %s\", err.buf);\n+\n+\t/*\n \t * Create the default symlink from \".git/HEAD\" to the \"master\"\n \t * branch, if it does not exist yet.\n \t */\ndiff --git a/refs.c b/refs.c\nindex 6efa859..fcaf3ba 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1292,6 +1292,14 @@ static const char *resolve_ref_recursively(struct ref_store *refs,\n \treturn NULL;\n }\n \n+/* backend functions */\n+int refs_init_db(struct strbuf *err)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->init_db(refs, err);\n+}\n+\n const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \t\t\t       unsigned char *sha1, int *flags)\n {\ndiff --git a/refs.h b/refs.h\nindex 17e8cfb..d42458c 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -66,6 +66,8 @@ int ref_exists(const char *refname);\n \n int is_branch(const char *refname);\n \n+extern int refs_init_db(struct strbuf *err);\n+\n /*\n  * If refname is a non-symbolic reference that refers to a tag object,\n  * and the tag can be (recursively) dereferenced to a non-tag object,\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex bcaa958..56397af 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -4068,10 +4068,28 @@ static int files_reflog_expire(struct ref_store *ref_store,\n \treturn -1;\n }\n \n+static int files_init_db(struct ref_store *ref_store, struct strbuf *err)\n+{\n+\t/* Check validity (but we don't need the result): */\n+\tfiles_downcast(ref_store, 0, \"init_db\");\n+\n+\t/*\n+\t * Create .git/refs/{heads,tags}\n+\t */\n+\tsafe_create_dir(git_path(\"refs/heads\"), 1);\n+\tsafe_create_dir(git_path(\"refs/tags\"), 1);\n+\tif (get_shared_repository()) {\n+\t\tadjust_shared_perm(git_path(\"refs/heads\"));\n+\t\tadjust_shared_perm(git_path(\"refs/tags\"));\n+\t}\n+\treturn 0;\n+}\n+\n struct ref_storage_be refs_be_files = {\n \tNULL,\n \t\"files\",\n \tfiles_ref_store_create,\n+\tfiles_init_db,\n \tfiles_transaction_commit,\n \tfiles_initial_transaction_commit,\n \ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex ade6501..b3a2095 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -479,6 +479,8 @@ struct ref_store;\n  */\n typedef struct ref_store *ref_store_init_fn(const char *submodule);\n \n+typedef int ref_init_db_fn(struct ref_store *refs, struct strbuf *err);\n+\n typedef int ref_transaction_commit_fn(struct ref_store *refs,\n \t\t\t\t      struct ref_transaction *transaction,\n \t\t\t\t      struct strbuf *err);\n@@ -583,6 +585,7 @@ struct ref_storage_be {\n \tstruct ref_storage_be *next;\n \tconst char *name;\n \tref_store_init_fn *init;\n+\tref_init_db_fn *init_db;\n \tref_transaction_commit_fn *transaction_commit;\n \tref_transaction_commit_fn *initial_transaction_commit;\n \n-- \n2.9.3\n\n"},{"id":"301004","messageId":"d4e799241de9186f05187d820707c103bc5b4e8e.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 38/38] refs: implement iteration over only per-worktree refs","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:44Z","receivedAt":"2016-09-04T16:12:07Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nAlternate refs backends might still use files to store per-worktree\nrefs. So provide a way to iterate over only the per-worktree references\nin a ref_store. The other backend can set up a files ref_store and\niterate using the new DO_FOR_EACH_PER_WORKTREE_ONLY flag when iterating.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c |  4 ++++\n refs/refs-internal.h | 10 +++++++++-\n 2 files changed, 13 insertions(+), 1 deletion(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 0714c3f..2644792 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1798,6 +1798,10 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)\n \tint ok;\n \n \twhile ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {\n+\t\tif (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&\n+\t\t    ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)\n+\t\t\tcontinue;\n+\n \t\tif (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&\n \t\t    !ref_resolves_to_object(iter->iter0->refname,\n \t\t\t\t\t    iter->iter0->oid,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 681982b..708b260 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -467,10 +467,18 @@ extern struct ref_iterator *current_ref_iter;\n int do_for_each_ref_iterator(struct ref_iterator *iter,\n \t\t\t     each_ref_fn fn, void *cb_data);\n \n-/* refs backends */\n+/*\n+ * Only include per-worktree refs in a do_for_each_ref*() iteration.\n+ * Normally this will be used with a files ref_store, since that's\n+ * where all reference backends will presumably store their\n+ * per-worktree refs.\n+ */\n+#define DO_FOR_EACH_PER_WORKTREE_ONLY 0x02\n \n struct ref_store;\n \n+/* refs backends */\n+\n /*\n  * Initialize the ref_store for the specified submodule, or for the\n  * main repository if submodule == NULL. These functions should call\n-- \n2.9.3\n\n"},{"id":"301005","messageId":"8b427ea913f4456869ff7bfeede887386f27e118.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 32/38] refs: add methods for reflog","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:38Z","receivedAt":"2016-09-04T16:12:17Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nIn the file-based backend, the reflog piggybacks on the ref lock.\nSince other backends won't have the same sort of ref lock, ref backends\nmust also handle reflogs.\n\nSigned-off-by: Ronnie Sahlberg <rsahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 63 ++++++++++++++++++++++++++++++++++++++++++++++\n refs/files-backend.c | 70 +++++++++++++++++++++++++++++++++++++---------------\n refs/refs-internal.h | 44 +++++++++++++++++++++++++++------\n 3 files changed, 150 insertions(+), 27 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 798b08a..cb9d805 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1461,3 +1461,66 @@ int verify_refname_available(const char *refname,\n \n \treturn refs->be->verify_refname_available(refs, refname, extra, skip, err);\n }\n+\n+int for_each_reflog(each_ref_fn fn, void *cb_data)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\tstruct ref_iterator *iter;\n+\n+\titer = refs->be->reflog_iterator_begin(refs);\n+\n+\treturn do_for_each_ref_iterator(iter, fn, cb_data);\n+}\n+\n+int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn,\n+\t\t\t\tvoid *cb_data)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->for_each_reflog_ent_reverse(refs, refname,\n+\t\t\t\t\t\t     fn, cb_data);\n+}\n+\n+int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn,\n+\t\t\tvoid *cb_data)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->for_each_reflog_ent(refs, refname, fn, cb_data);\n+}\n+\n+int reflog_exists(const char *refname)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->reflog_exists(refs, refname);\n+}\n+\n+int safe_create_reflog(const char *refname, int force_create,\n+\t\t       struct strbuf *err)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->create_reflog(refs, refname, force_create, err);\n+}\n+\n+int delete_reflog(const char *refname)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->delete_reflog(refs, refname);\n+}\n+\n+int reflog_expire(const char *refname, const unsigned char *sha1,\n+\t\t  unsigned int flags,\n+\t\t  reflog_expiry_prepare_fn prepare_fn,\n+\t\t  reflog_expiry_should_prune_fn should_prune_fn,\n+\t\t  reflog_expiry_cleanup_fn cleanup_fn,\n+\t\t  void *policy_cb_data)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->reflog_expire(refs, refname, sha1, flags,\n+\t\t\t\t       prepare_fn, should_prune_fn,\n+\t\t\t\t       cleanup_fn, policy_cb_data);\n+}\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4451e13..a810dfa 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2777,11 +2777,16 @@ static int log_ref_setup(const char *refname, struct strbuf *logfile, struct str\n }\n \n \n-int safe_create_reflog(const char *refname, int force_create, struct strbuf *err)\n+static int files_create_reflog(struct ref_store *ref_store,\n+\t\t\t       const char *refname, int force_create,\n+\t\t\t       struct strbuf *err)\n {\n \tint ret;\n \tstruct strbuf sb = STRBUF_INIT;\n \n+\t/* Check validity (but we don't need the result): */\n+\tfiles_downcast(ref_store, 0, \"create_reflog\");\n+\n \tret = log_ref_setup(refname, &sb, err, force_create);\n \tstrbuf_release(&sb);\n \treturn ret;\n@@ -3075,16 +3080,24 @@ int set_worktree_head_symref(const char *gitdir, const char *target)\n \treturn ret;\n }\n \n-int reflog_exists(const char *refname)\n+static int files_reflog_exists(struct ref_store *ref_store,\n+\t\t\t       const char *refname)\n {\n \tstruct stat st;\n \n+\t/* Check validity (but we don't need the result): */\n+\tfiles_downcast(ref_store, 0, \"reflog_exists\");\n+\n \treturn !lstat(git_path(\"logs/%s\", refname), &st) &&\n \t\tS_ISREG(st.st_mode);\n }\n \n-int delete_reflog(const char *refname)\n+static int files_delete_reflog(struct ref_store *ref_store,\n+\t\t\t       const char *refname)\n {\n+\t/* Check validity (but we don't need the result): */\n+\tfiles_downcast(ref_store, 0, \"delete_reflog\");\n+\n \treturn remove_path(git_path(\"logs/%s\", refname));\n }\n \n@@ -3127,13 +3140,19 @@ static char *find_beginning_of_line(char *bob, char *scan)\n \treturn scan;\n }\n \n-int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data)\n+static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,\n+\t\t\t\t\t     const char *refname,\n+\t\t\t\t\t     each_reflog_ent_fn fn,\n+\t\t\t\t\t     void *cb_data)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tFILE *logfp;\n \tlong pos;\n \tint ret = 0, at_tail = 1;\n \n+\t/* Check validity (but we don't need the result): */\n+\tfiles_downcast(ref_store, 0, \"for_each_reflog_ent_reverse\");\n+\n \tlogfp = fopen(git_path(\"logs/%s\", refname), \"r\");\n \tif (!logfp)\n \t\treturn -1;\n@@ -3229,12 +3248,17 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void\n \treturn ret;\n }\n \n-int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data)\n+static int files_for_each_reflog_ent(struct ref_store *ref_store,\n+\t\t\t\t     const char *refname,\n+\t\t\t\t     each_reflog_ent_fn fn, void *cb_data)\n {\n \tFILE *logfp;\n \tstruct strbuf sb = STRBUF_INIT;\n \tint ret = 0;\n \n+\t/* Check validity (but we don't need the result): */\n+\tfiles_downcast(ref_store, 0, \"for_each_reflog_ent\");\n+\n \tlogfp = fopen(git_path(\"logs/%s\", refname), \"r\");\n \tif (!logfp)\n \t\treturn -1;\n@@ -3313,22 +3337,19 @@ static struct ref_iterator_vtable files_reflog_iterator_vtable = {\n \tfiles_reflog_iterator_abort\n };\n \n-struct ref_iterator *files_reflog_iterator_begin(void)\n+static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)\n {\n \tstruct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));\n \tstruct ref_iterator *ref_iterator = &iter->base;\n \n+\t/* Check validity (but we don't need the result): */\n+\tfiles_downcast(ref_store, 0, \"reflog_iterator_begin\");\n+\n \tbase_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);\n \titer->dir_iterator = dir_iterator_begin(git_path(\"logs\"));\n \treturn ref_iterator;\n }\n \n-int for_each_reflog(each_ref_fn fn, void *cb_data)\n-{\n-\treturn do_for_each_ref_iterator(files_reflog_iterator_begin(),\n-\t\t\t\t\tfn, cb_data);\n-}\n-\n static int ref_update_reject_duplicates(struct string_list *refnames,\n \t\t\t\t\tstruct strbuf *err)\n {\n@@ -3935,15 +3956,16 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n \treturn 0;\n }\n \n-int reflog_expire(const char *refname, const unsigned char *sha1,\n-\t\t unsigned int flags,\n-\t\t reflog_expiry_prepare_fn prepare_fn,\n-\t\t reflog_expiry_should_prune_fn should_prune_fn,\n-\t\t reflog_expiry_cleanup_fn cleanup_fn,\n-\t\t void *policy_cb_data)\n+static int files_reflog_expire(struct ref_store *ref_store,\n+\t\t\t       const char *refname, const unsigned char *sha1,\n+\t\t\t       unsigned int flags,\n+\t\t\t       reflog_expiry_prepare_fn prepare_fn,\n+\t\t\t       reflog_expiry_should_prune_fn should_prune_fn,\n+\t\t\t       reflog_expiry_cleanup_fn cleanup_fn,\n+\t\t\t       void *policy_cb_data)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"reflog_expire\");\n+\t\tfiles_downcast(ref_store, 0, \"reflog_expire\");\n \tstatic struct lock_file reflog_lock;\n \tstruct expire_reflog_cb cb;\n \tstruct ref_lock *lock;\n@@ -4056,5 +4078,13 @@ struct ref_storage_be refs_be_files = {\n \n \tfiles_ref_iterator_begin,\n \tfiles_read_raw_ref,\n-\tfiles_verify_refname_available\n+\tfiles_verify_refname_available,\n+\n+\tfiles_reflog_iterator_begin,\n+\tfiles_for_each_reflog_ent,\n+\tfiles_for_each_reflog_ent_reverse,\n+\tfiles_reflog_exists,\n+\tfiles_create_reflog,\n+\tfiles_delete_reflog,\n+\tfiles_reflog_expire\n };\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 5be62a2..a20b622 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -404,13 +404,6 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,\n \t\t\t\t\t       const char *prefix,\n \t\t\t\t\t       int trim);\n \n-/*\n- * Iterate over the references in the main ref_store that have a\n- * reflog. The paths within a directory are iterated over in arbitrary\n- * order.\n- */\n-struct ref_iterator *files_reflog_iterator_begin(void);\n-\n /* Internal implementation of reference iteration: */\n \n /*\n@@ -507,6 +500,35 @@ typedef struct ref_iterator *ref_iterator_begin_fn(\n \t\tstruct ref_store *ref_store,\n \t\tconst char *prefix, unsigned int flags);\n \n+/* reflog functions */\n+\n+/*\n+ * Iterate over the references in the specified ref_store that have a\n+ * reflog. The refs are iterated over in arbitrary order.\n+ */\n+typedef struct ref_iterator *reflog_iterator_begin_fn(\n+\t\tstruct ref_store *ref_store);\n+\n+typedef int for_each_reflog_ent_fn(struct ref_store *ref_store,\n+\t\t\t\t   const char *refname,\n+\t\t\t\t   each_reflog_ent_fn fn,\n+\t\t\t\t   void *cb_data);\n+typedef int for_each_reflog_ent_reverse_fn(struct ref_store *ref_store,\n+\t\t\t\t\t   const char *refname,\n+\t\t\t\t\t   each_reflog_ent_fn fn,\n+\t\t\t\t\t   void *cb_data);\n+typedef int reflog_exists_fn(struct ref_store *ref_store, const char *refname);\n+typedef int create_reflog_fn(struct ref_store *ref_store, const char *refname,\n+\t\t\t     int force_create, struct strbuf *err);\n+typedef int delete_reflog_fn(struct ref_store *ref_store, const char *refname);\n+typedef int reflog_expire_fn(struct ref_store *ref_store,\n+\t\t\t     const char *refname, const unsigned char *sha1,\n+\t\t\t     unsigned int flags,\n+\t\t\t     reflog_expiry_prepare_fn prepare_fn,\n+\t\t\t     reflog_expiry_should_prune_fn should_prune_fn,\n+\t\t\t     reflog_expiry_cleanup_fn cleanup_fn,\n+\t\t\t     void *policy_cb_data);\n+\n /*\n  * Read a reference from the specified reference store, non-recursively.\n  * Set type to describe the reference, and:\n@@ -568,6 +590,14 @@ struct ref_storage_be {\n \tref_iterator_begin_fn *iterator_begin;\n \tread_raw_ref_fn *read_raw_ref;\n \tverify_refname_available_fn *verify_refname_available;\n+\n+\treflog_iterator_begin_fn *reflog_iterator_begin;\n+\tfor_each_reflog_ent_fn *for_each_reflog_ent;\n+\tfor_each_reflog_ent_reverse_fn *for_each_reflog_ent_reverse;\n+\treflog_exists_fn *reflog_exists;\n+\tcreate_reflog_fn *create_reflog;\n+\tdelete_reflog_fn *delete_reflog;\n+\treflog_expire_fn *reflog_expire;\n };\n \n extern struct ref_storage_be refs_be_files;\n-- \n2.9.3\n\n"},{"id":"301006","messageId":"fe062b480d491f9c374d4184797f3523716ee681.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 33/38] refs: add method for initial ref transaction commit","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:39Z","receivedAt":"2016-09-04T16:12:20Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nSigned-off-by: Ronnie Sahlberg <rsahlberg@google.com>\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 8 ++++++++\n refs/files-backend.c | 8 +++++---\n refs/refs-internal.h | 1 +\n 3 files changed, 14 insertions(+), 3 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex cb9d805..3830918 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1524,3 +1524,11 @@ int reflog_expire(const char *refname, const unsigned char *sha1,\n \t\t\t\t       prepare_fn, should_prune_fn,\n \t\t\t\t       cleanup_fn, policy_cb_data);\n }\n+\n+int initial_ref_transaction_commit(struct ref_transaction *transaction,\n+\t\t\t\t   struct strbuf *err)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->initial_transaction_commit(refs, transaction, err);\n+}\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex a810dfa..81008d7 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3839,11 +3839,12 @@ static int ref_present(const char *refname,\n \treturn string_list_has_string(affected_refnames, refname);\n }\n \n-int initial_ref_transaction_commit(struct ref_transaction *transaction,\n-\t\t\t\t   struct strbuf *err)\n+static int files_initial_transaction_commit(struct ref_store *ref_store,\n+\t\t\t\t\t    struct ref_transaction *transaction,\n+\t\t\t\t\t    struct strbuf *err)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"initial_ref_transaction_commit\");\n+\t\tfiles_downcast(ref_store, 0, \"initial_ref_transaction_commit\");\n \tint ret = 0, i;\n \tstruct string_list affected_refnames = STRING_LIST_INIT_NODUP;\n \n@@ -4071,6 +4072,7 @@ struct ref_storage_be refs_be_files = {\n \t\"files\",\n \tfiles_ref_store_create,\n \tfiles_transaction_commit,\n+\tfiles_initial_transaction_commit,\n \n \tfiles_pack_refs,\n \tfiles_peel_ref,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex a20b622..08c8586 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -582,6 +582,7 @@ struct ref_storage_be {\n \tconst char *name;\n \tref_store_init_fn *init;\n \tref_transaction_commit_fn *transaction_commit;\n+\tref_transaction_commit_fn *initial_transaction_commit;\n \n \tpack_refs_fn *pack_refs;\n \tpeel_ref_fn *peel_ref;\n-- \n2.9.3\n\n"},{"id":"301007","messageId":"c83131a4e0776271ec15265b0b712de16a0fb513.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 29/38] split_symref_update(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:35Z","receivedAt":"2016-09-04T16:12:21Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ab2c1de..3a0db5a 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3401,7 +3401,8 @@ static int split_head_update(struct ref_update *update,\n  * Note that the new update will itself be subject to splitting when\n  * the iteration gets to it.\n  */\n-static int split_symref_update(struct ref_update *update,\n+static int split_symref_update(struct files_ref_store *refs,\n+\t\t\t       struct ref_update *update,\n \t\t\t       const char *referent,\n \t\t\t       struct ref_transaction *transaction,\n \t\t\t       struct string_list *affected_refnames,\n@@ -3583,7 +3584,8 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\t\t * of processing the split-off update, so we\n \t\t\t * don't have to do it here.\n \t\t\t */\n-\t\t\tret = split_symref_update(update, referent.buf, transaction,\n+\t\t\tret = split_symref_update(refs, update,\n+\t\t\t\t\t\t  referent.buf, transaction,\n \t\t\t\t\t\t  affected_refnames, err);\n \t\t\tif (ret)\n \t\t\t\treturn ret;\n-- \n2.9.3\n\n"},{"id":"301008","messageId":"21555b1c09974a58972940745c5778a119b0a0fa.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 37/38] refs: make lock generic","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:43Z","receivedAt":"2016-09-04T16:12:22Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nInstead of including a files-backend-specific struct ref_lock, change\nthe generic ref_update struct to include a void pointer that backends\ncan use for their own arbitrary data.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 25 +++++++++++++------------\n refs/refs-internal.h |  2 +-\n 2 files changed, 14 insertions(+), 13 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 7cc4191..0714c3f 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3552,9 +3552,8 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \n \tret = lock_raw_ref(refs, update->refname, mustexist,\n \t\t\t   affected_refnames, NULL,\n-\t\t\t   &update->lock, &referent,\n+\t\t\t   &lock, &referent,\n \t\t\t   &update->type, err);\n-\n \tif (ret) {\n \t\tchar *reason;\n \n@@ -3565,7 +3564,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\treturn ret;\n \t}\n \n-\tlock = update->lock;\n+\tupdate->backend_data = lock;\n \n \tif (update->type & REF_ISSYMREF) {\n \t\tif (update->flags & REF_NODEREF) {\n@@ -3613,7 +3612,8 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\tfor (parent_update = update->parent_update;\n \t\t     parent_update;\n \t\t     parent_update = parent_update->parent_update) {\n-\t\t\toidcpy(&parent_update->lock->old_oid, &lock->old_oid);\n+\t\t\tstruct ref_lock *parent_lock = parent_update->backend_data;\n+\t\t\toidcpy(&parent_lock->old_oid, &lock->old_oid);\n \t\t}\n \t}\n \n@@ -3634,7 +3634,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,\n \t\t\t * The lock was freed upon failure of\n \t\t\t * write_ref_to_lockfile():\n \t\t\t */\n-\t\t\tupdate->lock = NULL;\n+\t\t\tupdate->backend_data = NULL;\n \t\t\tstrbuf_addf(err,\n \t\t\t\t    \"cannot update ref '%s': %s\",\n \t\t\t\t    update->refname, write_err);\n@@ -3752,7 +3752,7 @@ static int files_transaction_commit(struct ref_store *ref_store,\n \t/* Perform updates first so live commits remain referenced */\n \tfor (i = 0; i < transaction->nr; i++) {\n \t\tstruct ref_update *update = transaction->updates[i];\n-\t\tstruct ref_lock *lock = update->lock;\n+\t\tstruct ref_lock *lock = update->backend_data;\n \n \t\tif (update->flags & REF_NEEDS_COMMIT ||\n \t\t    update->flags & REF_LOG_ONLY) {\n@@ -3765,7 +3765,7 @@ static int files_transaction_commit(struct ref_store *ref_store,\n \t\t\t\t\t    lock->ref_name, old_msg);\n \t\t\t\tfree(old_msg);\n \t\t\t\tunlock_ref(lock);\n-\t\t\t\tupdate->lock = NULL;\n+\t\t\t\tupdate->backend_data = NULL;\n \t\t\t\tret = TRANSACTION_GENERIC_ERROR;\n \t\t\t\tgoto cleanup;\n \t\t\t}\n@@ -3775,7 +3775,7 @@ static int files_transaction_commit(struct ref_store *ref_store,\n \t\t\tif (commit_ref(lock)) {\n \t\t\t\tstrbuf_addf(err, \"couldn't set '%s'\", lock->ref_name);\n \t\t\t\tunlock_ref(lock);\n-\t\t\t\tupdate->lock = NULL;\n+\t\t\t\tupdate->backend_data = NULL;\n \t\t\t\tret = TRANSACTION_GENERIC_ERROR;\n \t\t\t\tgoto cleanup;\n \t\t\t}\n@@ -3784,17 +3784,18 @@ static int files_transaction_commit(struct ref_store *ref_store,\n \t/* Perform deletes now that updates are safely completed */\n \tfor (i = 0; i < transaction->nr; i++) {\n \t\tstruct ref_update *update = transaction->updates[i];\n+\t\tstruct ref_lock *lock = update->backend_data;\n \n \t\tif (update->flags & REF_DELETING &&\n \t\t    !(update->flags & REF_LOG_ONLY)) {\n-\t\t\tif (delete_ref_loose(update->lock, update->type, err)) {\n+\t\t\tif (delete_ref_loose(lock, update->type, err)) {\n \t\t\t\tret = TRANSACTION_GENERIC_ERROR;\n \t\t\t\tgoto cleanup;\n \t\t\t}\n \n \t\t\tif (!(update->flags & REF_ISPRUNING))\n \t\t\t\tstring_list_append(&refs_to_delete,\n-\t\t\t\t\t\t   update->lock->ref_name);\n+\t\t\t\t\t\t   lock->ref_name);\n \t\t}\n \t}\n \n@@ -3810,8 +3811,8 @@ static int files_transaction_commit(struct ref_store *ref_store,\n \ttransaction->state = REF_TRANSACTION_CLOSED;\n \n \tfor (i = 0; i < transaction->nr; i++)\n-\t\tif (transaction->updates[i]->lock)\n-\t\t\tunlock_ref(transaction->updates[i]->lock);\n+\t\tif (transaction->updates[i]->backend_data)\n+\t\t\tunlock_ref(transaction->updates[i]->backend_data);\n \tstring_list_clear(&refs_to_delete, 0);\n \tfree(head_ref);\n \tstring_list_clear(&affected_refnames, 0);\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex c598cb1..681982b 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -162,7 +162,7 @@ struct ref_update {\n \t */\n \tunsigned int flags;\n \n-\tstruct ref_lock *lock;\n+\tvoid *backend_data;\n \tunsigned int type;\n \tchar *msg;\n \n-- \n2.9.3\n\n"},{"id":"301009","messageId":"0437f726a01114dce8e4d6871d51458277356b32.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 30/38] files_ref_iterator_begin(): take a ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:36Z","receivedAt":"2016-09-04T16:12:23Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 2 +-\n refs/files-backend.c | 4 ++--\n refs/refs-internal.h | 8 ++++----\n 3 files changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex f10f86a..d00126b 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1157,7 +1157,7 @@ static int do_for_each_ref(const char *submodule, const char *prefix,\n \tif (!refs)\n \t\treturn 0;\n \n-\titer = files_ref_iterator_begin(submodule, prefix, flags);\n+\titer = files_ref_iterator_begin(refs, prefix, flags);\n \titer = prefix_ref_iterator_begin(iter, prefix, trim);\n \n \treturn do_for_each_ref_iterator(iter, fn, cb_data);\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 3a0db5a..f521b5d 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1863,11 +1863,11 @@ static struct ref_iterator_vtable files_ref_iterator_vtable = {\n };\n \n struct ref_iterator *files_ref_iterator_begin(\n-\t\tconst char *submodule,\n+\t\tstruct ref_store *ref_store,\n \t\tconst char *prefix, unsigned int flags)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(submodule, \"ref_iterator_begin\");\n+\t\tfiles_downcast(ref_store, 1, \"ref_iterator_begin\");\n \tstruct ref_dir *loose_dir, *packed_dir;\n \tstruct ref_iterator *loose_iter, *packed_iter;\n \tstruct files_ref_iterator *iter;\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 84c81ad..0af1079 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -404,13 +404,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,\n \t\t\t\t\t       const char *prefix,\n \t\t\t\t\t       int trim);\n \n+struct ref_store;\n+\n /*\n  * Iterate over the packed and loose references in the specified\n- * submodule that are within find_containing_dir(prefix). If prefix is\n+ * ref_store that are within find_containing_dir(prefix). If prefix is\n  * NULL or the empty string, iterate over all references in the\n  * submodule.\n  */\n-struct ref_iterator *files_ref_iterator_begin(const char *submodule,\n+struct ref_iterator *files_ref_iterator_begin(struct ref_store *ref_store,\n \t\t\t\t\t      const char *prefix,\n \t\t\t\t\t      unsigned int flags);\n \n@@ -484,8 +486,6 @@ extern struct ref_iterator *current_ref_iter;\n int do_for_each_ref_iterator(struct ref_iterator *iter,\n \t\t\t     each_ref_fn fn, void *cb_data);\n \n-struct ref_store;\n-\n /* refs backends */\n \n /*\n-- \n2.9.3\n\n"},{"id":"301010","messageId":"b7399efde555f056c736bcc1c07a685290bc796e.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 22/38] refs: make create_symref() virtual","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:28Z","receivedAt":"2016-09-04T16:12:24Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 9 +++++++++\n refs/files-backend.c | 7 ++++++-\n refs/refs-internal.h | 5 +++++\n 3 files changed, 20 insertions(+), 1 deletion(-)\n\ndiff --git a/refs.c b/refs.c\nindex 961927a..74874e5 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1428,6 +1428,15 @@ int pack_refs(unsigned int flags)\n \treturn refs->be->pack_refs(refs, flags);\n }\n \n+int create_symref(const char *ref_target, const char *refs_heads_master,\n+\t\t  const char *logmsg)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->create_symref(refs, ref_target, refs_heads_master,\n+\t\t\t\t       logmsg);\n+}\n+\n int ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t   struct strbuf *err)\n {\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 7ad8821..bf53670 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3011,12 +3011,16 @@ static int create_symref_locked(struct ref_lock *lock, const char *refname,\n \treturn 0;\n }\n \n-int create_symref(const char *refname, const char *target, const char *logmsg)\n+static int files_create_symref(struct ref_store *ref_store,\n+\t\t\t       const char *refname, const char *target,\n+\t\t\t       const char *logmsg)\n {\n \tstruct strbuf err = STRBUF_INIT;\n \tstruct ref_lock *lock;\n \tint ret;\n \n+\tfiles_downcast(ref_store, 0, \"create_symref\");\n+\n \tlock = lock_ref_sha1_basic(refname, NULL, NULL, NULL, REF_NODEREF, NULL,\n \t\t\t\t   &err);\n \tif (!lock) {\n@@ -4033,6 +4037,7 @@ struct ref_storage_be refs_be_files = {\n \tfiles_transaction_commit,\n \n \tfiles_pack_refs,\n+\tfiles_create_symref,\n \n \tfiles_read_raw_ref,\n \tfiles_verify_refname_available\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 256f7f5..bf96503 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -501,6 +501,10 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,\n \t\t\t\t      struct strbuf *err);\n \n typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags);\n+typedef int create_symref_fn(struct ref_store *ref_store,\n+\t\t\t     const char *ref_target,\n+\t\t\t     const char *refs_heads_master,\n+\t\t\t     const char *logmsg);\n \n /*\n  * Read a reference from the specified reference store, non-recursively.\n@@ -557,6 +561,7 @@ struct ref_storage_be {\n \tref_transaction_commit_fn *transaction_commit;\n \n \tpack_refs_fn *pack_refs;\n+\tcreate_symref_fn *create_symref;\n \n \tread_raw_ref_fn *read_raw_ref;\n \tverify_refname_available_fn *verify_refname_available;\n-- \n2.9.3\n\n"},{"id":"301011","messageId":"ee72c2f9d2019a5348748964e715c2037c3d05e5.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 15/38] resolve_ref_recursively(): new function","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:21Z","receivedAt":"2016-09-04T16:12:27Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Add a new function, resolve_ref_recursively(), which is basically like\nthe old resolve_ref_unsafe() except that it takes a (ref_store *)\nargument and also works for submodules.\n\nRe-implement resolve_ref_unsafe() as a thin wrapper around\nresolve_ref_recursively().\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c | 14 +++++++++++---\n 1 file changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 9e6b005..3723169 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1216,13 +1216,14 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)\n }\n \n /* This function needs to return a meaningful errno on failure */\n-const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n-\t\t\t       unsigned char *sha1, int *flags)\n+static const char *resolve_ref_recursively(struct ref_store *refs,\n+\t\t\t\t\t   const char *refname,\n+\t\t\t\t\t   int resolve_flags,\n+\t\t\t\t\t   unsigned char *sha1, int *flags)\n {\n \tstatic struct strbuf sb_refname = STRBUF_INIT;\n \tint unused_flags;\n \tint symref_count;\n-\tstruct ref_store *refs = get_ref_store(NULL);\n \n \tif (!flags)\n \t\tflags = &unused_flags;\n@@ -1291,6 +1292,13 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \treturn NULL;\n }\n \n+const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n+\t\t\t       unsigned char *sha1, int *flags)\n+{\n+\treturn resolve_ref_recursively(get_ref_store(NULL), refname,\n+\t\t\t\t       resolve_flags, sha1, flags);\n+}\n+\n /* A pointer to the ref_store for the main repository: */\n static struct ref_store *main_ref_store;\n \n-- \n2.9.3\n\n"},{"id":"301012","messageId":"4083413a38a52f9f8db6b9fb009dd522ad75a8df.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 27/38] lock_ref_for_update(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:33Z","receivedAt":"2016-09-04T16:12:28Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 11 ++++++-----\n 1 file changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 001b8ef..2f8eb54 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3514,20 +3514,21 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,\n  * - If it is an update of head_ref, add a corresponding REF_LOG_ONLY\n  *   update of HEAD.\n  */\n-static int lock_ref_for_update(struct ref_update *update,\n+static int lock_ref_for_update(struct files_ref_store *refs,\n+\t\t\t       struct ref_update *update,\n \t\t\t       struct ref_transaction *transaction,\n \t\t\t       const char *head_ref,\n \t\t\t       struct string_list *affected_refnames,\n \t\t\t       struct strbuf *err)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"lock_ref_for_update\");\n \tstruct strbuf referent = STRBUF_INIT;\n \tint mustexist = (update->flags & REF_HAVE_OLD) &&\n \t\t!is_null_sha1(update->old_sha1);\n \tint ret;\n \tstruct ref_lock *lock;\n \n+\tassert_main_repository(&refs->base, \"lock_ref_for_update\");\n+\n \tif ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))\n \t\tupdate->flags |= REF_DELETING;\n \n@@ -3730,8 +3731,8 @@ static int files_transaction_commit(struct ref_store *ref_store,\n \tfor (i = 0; i < transaction->nr; i++) {\n \t\tstruct ref_update *update = transaction->updates[i];\n \n-\t\tret = lock_ref_for_update(update, transaction, head_ref,\n-\t\t\t\t\t  &affected_refnames, err);\n+\t\tret = lock_ref_for_update(refs, update, transaction,\n+\t\t\t\t\t  head_ref, &affected_refnames, err);\n \t\tif (ret)\n \t\t\tgoto cleanup;\n \t}\n-- \n2.9.3\n\n"},{"id":"301013","messageId":"596373545ace1cf29cc4f2c76db9299dc99deb9e.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 36/38] refs: add method to rename refs","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:42Z","receivedAt":"2016-09-04T16:12:30Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nThis removes the last caller of function get_files_ref_store(), so\nremove it.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               |  7 +++++++\n refs/files-backend.c | 24 ++++++------------------\n refs/refs-internal.h |  4 ++++\n 3 files changed, 17 insertions(+), 18 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex fcaf3ba..113e3c8 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1547,3 +1547,10 @@ int delete_refs(struct string_list *refnames, unsigned int flags)\n \n \treturn refs->be->delete_refs(refs, refnames, flags);\n }\n+\n+int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->rename_ref(refs, oldref, newref, logmsg);\n+}\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 56397af..7cc4191 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -997,22 +997,6 @@ static struct files_ref_store *files_downcast(\n \treturn (struct files_ref_store *)ref_store;\n }\n \n-/*\n- * Return a pointer to the reference store for the specified\n- * submodule. For the main repository, use submodule==NULL; such a\n- * call cannot fail. For a submodule, the submodule must exist and be\n- * a nonbare repository, otherwise return NULL. Verify that the\n- * reference store is a files_ref_store, and cast it to that type\n- * before returning it.\n- */\n-static struct files_ref_store *get_files_ref_store(const char *submodule,\n-\t\t\t\t\t\t   const char *caller)\n-{\n-\tstruct ref_store *refs = get_ref_store(submodule);\n-\n-\treturn refs ? files_downcast(refs, 1, caller) : NULL;\n-}\n-\n /* The length of a peeled reference line in packed-refs, including EOL: */\n #define PEELED_LINE_LENGTH 42\n \n@@ -2580,9 +2564,12 @@ static int commit_ref_update(struct files_ref_store *refs,\n \t\t\t     const unsigned char *sha1, const char *logmsg,\n \t\t\t     struct strbuf *err);\n \n-int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)\n+static int files_rename_ref(struct ref_store *ref_store,\n+\t\t\t    const char *oldrefname, const char *newrefname,\n+\t\t\t    const char *logmsg)\n {\n-\tstruct files_ref_store *refs = get_files_ref_store(NULL, \"rename_ref\");\n+\tstruct files_ref_store *refs =\n+\t\tfiles_downcast(ref_store, 0, \"rename_ref\");\n \tunsigned char sha1[20], orig_sha1[20];\n \tint flag = 0, logmoved = 0;\n \tstruct ref_lock *lock;\n@@ -4097,6 +4084,7 @@ struct ref_storage_be refs_be_files = {\n \tfiles_peel_ref,\n \tfiles_create_symref,\n \tfiles_delete_refs,\n+\tfiles_rename_ref,\n \n \tfiles_ref_iterator_begin,\n \tfiles_read_raw_ref,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex b3a2095..c598cb1 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -494,6 +494,9 @@ typedef int create_symref_fn(struct ref_store *ref_store,\n \t\t\t     const char *logmsg);\n typedef int delete_refs_fn(struct ref_store *ref_store,\n \t\t\t   struct string_list *refnames, unsigned int flags);\n+typedef int rename_ref_fn(struct ref_store *ref_store,\n+\t\t\t  const char *oldref, const char *newref,\n+\t\t\t  const char *logmsg);\n \n /*\n  * Iterate over the references in the specified ref_store that are\n@@ -593,6 +596,7 @@ struct ref_storage_be {\n \tpeel_ref_fn *peel_ref;\n \tcreate_symref_fn *create_symref;\n \tdelete_refs_fn *delete_refs;\n+\trename_ref_fn *rename_ref;\n \n \tref_iterator_begin_fn *iterator_begin;\n \tread_raw_ref_fn *read_raw_ref;\n-- \n2.9.3\n\n"},{"id":"301014","messageId":"832c66fc96bb474df73169819938ccc827f810d0.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 26/38] commit_ref_update(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:32Z","receivedAt":"2016-09-04T16:12:31Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ae425c5..001b8ef 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2574,12 +2574,14 @@ static int files_verify_refname_available(struct ref_store *ref_store,\n \n static int write_ref_to_lockfile(struct ref_lock *lock,\n \t\t\t\t const unsigned char *sha1, struct strbuf *err);\n-static int commit_ref_update(struct ref_lock *lock,\n+static int commit_ref_update(struct files_ref_store *refs,\n+\t\t\t     struct ref_lock *lock,\n \t\t\t     const unsigned char *sha1, const char *logmsg,\n \t\t\t     struct strbuf *err);\n \n int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)\n {\n+\tstruct files_ref_store *refs = get_files_ref_store(NULL, \"rename_ref\");\n \tunsigned char sha1[20], orig_sha1[20];\n \tint flag = 0, logmoved = 0;\n \tstruct ref_lock *lock;\n@@ -2652,7 +2654,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \thashcpy(lock->old_oid.hash, orig_sha1);\n \n \tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n-\t    commit_ref_update(lock, orig_sha1, logmsg, &err)) {\n+\t    commit_ref_update(refs, lock, orig_sha1, logmsg, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n \t\tstrbuf_release(&err);\n \t\tgoto rollback;\n@@ -2672,7 +2674,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = 0;\n \tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n-\t    commit_ref_update(lock, orig_sha1, NULL, &err)) {\n+\t    commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n \t}\n@@ -2908,12 +2910,12 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n  * to the loose reference lockfile. Also update the reflogs if\n  * necessary, using the specified lockmsg (which can be NULL).\n  */\n-static int commit_ref_update(struct ref_lock *lock,\n+static int commit_ref_update(struct files_ref_store *refs,\n+\t\t\t     struct ref_lock *lock,\n \t\t\t     const unsigned char *sha1, const char *logmsg,\n \t\t\t     struct strbuf *err)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"commit_ref_update\");\n+\tassert_main_repository(&refs->base, \"commit_ref_update\");\n \n \tclear_loose_ref_cache(refs);\n \tif (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, 0, err)) {\n-- \n2.9.3\n\n"},{"id":"301015","messageId":"d32ff64a4c27afe0e238cdef82dc1e1268f63057.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 28/38] lock_ref_sha1_basic(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:34Z","receivedAt":"2016-09-04T16:12:32Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 26 +++++++++++++++-----------\n 1 file changed, 15 insertions(+), 11 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 2f8eb54..ab2c1de 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1983,15 +1983,14 @@ static int remove_empty_directories(struct strbuf *path)\n  * Locks a ref returning the lock on success and NULL on failure.\n  * On failure errno is set to something meaningful.\n  */\n-static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n+static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,\n+\t\t\t\t\t    const char *refname,\n \t\t\t\t\t    const unsigned char *old_sha1,\n \t\t\t\t\t    const struct string_list *extras,\n \t\t\t\t\t    const struct string_list *skip,\n \t\t\t\t\t    unsigned int flags, int *type,\n \t\t\t\t\t    struct strbuf *err)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"lock_ref_sha1_basic\");\n \tstruct strbuf ref_file = STRBUF_INIT;\n \tstruct ref_lock *lock;\n \tint last_errno = 0;\n@@ -2001,6 +2000,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \tint attempts_remaining = 3;\n \tint resolved;\n \n+\tassert_main_repository(&refs->base, \"lock_ref_sha1_basic\");\n \tassert(err);\n \n \tlock = xcalloc(1, sizeof(struct ref_lock));\n@@ -2644,8 +2644,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \n \tlogmoved = log;\n \n-\tlock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, REF_NODEREF,\n-\t\t\t\t   NULL, &err);\n+\tlock = lock_ref_sha1_basic(refs, newrefname, NULL, NULL, NULL,\n+\t\t\t\t   REF_NODEREF, NULL, &err);\n \tif (!lock) {\n \t\terror(\"unable to rename '%s' to '%s': %s\", oldrefname, newrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -2663,8 +2663,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \treturn 0;\n \n  rollback:\n-\tlock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, REF_NODEREF,\n-\t\t\t\t   NULL, &err);\n+\tlock = lock_ref_sha1_basic(refs, oldrefname, NULL, NULL, NULL,\n+\t\t\t\t   REF_NODEREF, NULL, &err);\n \tif (!lock) {\n \t\terror(\"unable to lock %s for rollback: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n@@ -3020,13 +3020,14 @@ static int files_create_symref(struct ref_store *ref_store,\n \t\t\t       const char *refname, const char *target,\n \t\t\t       const char *logmsg)\n {\n+\tstruct files_ref_store *refs =\n+\t\tfiles_downcast(ref_store, 0, \"create_symref\");\n \tstruct strbuf err = STRBUF_INIT;\n \tstruct ref_lock *lock;\n \tint ret;\n \n-\tfiles_downcast(ref_store, 0, \"create_symref\");\n-\n-\tlock = lock_ref_sha1_basic(refname, NULL, NULL, NULL, REF_NODEREF, NULL,\n+\tlock = lock_ref_sha1_basic(refs, refname, NULL,\n+\t\t\t\t   NULL, NULL, REF_NODEREF, NULL,\n \t\t\t\t   &err);\n \tif (!lock) {\n \t\terror(\"%s\", err.buf);\n@@ -3939,6 +3940,8 @@ int reflog_expire(const char *refname, const unsigned char *sha1,\n \t\t reflog_expiry_cleanup_fn cleanup_fn,\n \t\t void *policy_cb_data)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"reflog_expire\");\n \tstatic struct lock_file reflog_lock;\n \tstruct expire_reflog_cb cb;\n \tstruct ref_lock *lock;\n@@ -3957,7 +3960,8 @@ int reflog_expire(const char *refname, const unsigned char *sha1,\n \t * reference itself, plus we might need to update the\n \t * reference if --updateref was specified:\n \t */\n-\tlock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, REF_NODEREF,\n+\tlock = lock_ref_sha1_basic(refs, refname, sha1,\n+\t\t\t\t   NULL, NULL, REF_NODEREF,\n \t\t\t\t   &type, &err);\n \tif (!lock) {\n \t\terror(\"cannot lock ref '%s': %s\", refname, err.buf);\n-- \n2.9.3\n\n"},{"id":"301016","messageId":"dabafdf7ac61460fd0b0edbaf40e655b1f60a222.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 34/38] refs: make delete_refs() virtual","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:40Z","receivedAt":"2016-09-04T16:12:35Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"From: David Turner <dturner@twopensource.com>\n\nIn the file-based backend, delete_refs has some special optimization\nto deal with packed refs.  In other backends, we might be able to make\nref deletion faster by putting all deletions into a single\ntransaction.  So we need a special backend function for this.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 7 +++++++\n refs/files-backend.c | 6 ++++--\n refs/refs-internal.h | 3 +++\n 3 files changed, 14 insertions(+), 2 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 3830918..6efa859 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1532,3 +1532,10 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \n \treturn refs->be->initial_transaction_commit(refs, transaction, err);\n }\n+\n+int delete_refs(struct string_list *refnames, unsigned int flags)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->delete_refs(refs, refnames, flags);\n+}\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 81008d7..bcaa958 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2451,10 +2451,11 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)\n \treturn 0;\n }\n \n-int delete_refs(struct string_list *refnames, unsigned int flags)\n+static int files_delete_refs(struct ref_store *ref_store,\n+\t\t\t     struct string_list *refnames, unsigned int flags)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"delete_refs\");\n+\t\tfiles_downcast(ref_store, 0, \"delete_refs\");\n \tstruct strbuf err = STRBUF_INIT;\n \tint i, result = 0;\n \n@@ -4077,6 +4078,7 @@ struct ref_storage_be refs_be_files = {\n \tfiles_pack_refs,\n \tfiles_peel_ref,\n \tfiles_create_symref,\n+\tfiles_delete_refs,\n \n \tfiles_ref_iterator_begin,\n \tfiles_read_raw_ref,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 08c8586..ade6501 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -490,6 +490,8 @@ typedef int create_symref_fn(struct ref_store *ref_store,\n \t\t\t     const char *ref_target,\n \t\t\t     const char *refs_heads_master,\n \t\t\t     const char *logmsg);\n+typedef int delete_refs_fn(struct ref_store *ref_store,\n+\t\t\t   struct string_list *refnames, unsigned int flags);\n \n /*\n  * Iterate over the references in the specified ref_store that are\n@@ -587,6 +589,7 @@ struct ref_storage_be {\n \tpack_refs_fn *pack_refs;\n \tpeel_ref_fn *peel_ref;\n \tcreate_symref_fn *create_symref;\n+\tdelete_refs_fn *delete_refs;\n \n \tref_iterator_begin_fn *iterator_begin;\n \tread_raw_ref_fn *read_raw_ref;\n-- \n2.9.3\n\n"},{"id":"301017","messageId":"ddf220e2f0a79cef2642c05209d87fbd7d135912.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 12/38] resolve_packed_ref(): rename function from resolve_missing_loose_ref()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:18Z","receivedAt":"2016-09-04T16:13:06Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 11 +++++------\n 1 file changed, 5 insertions(+), 6 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 7673342..32ca5ff 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1329,10 +1329,9 @@ static struct ref_entry *get_packed_ref(struct files_ref_store *refs,\n /*\n  * A loose ref file doesn't exist; check for a packed ref.\n  */\n-static int resolve_missing_loose_ref(struct files_ref_store *refs,\n-\t\t\t\t     const char *refname,\n-\t\t\t\t     unsigned char *sha1,\n-\t\t\t\t     unsigned int *flags)\n+static int resolve_packed_ref(struct files_ref_store *refs,\n+\t\t\t      const char *refname,\n+\t\t\t      unsigned char *sha1, unsigned int *flags)\n {\n \tstruct ref_entry *entry;\n \n@@ -1383,7 +1382,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,\n \tif (lstat(path, &st) < 0) {\n \t\tif (errno != ENOENT)\n \t\t\tgoto out;\n-\t\tif (resolve_missing_loose_ref(refs, refname, sha1, type)) {\n+\t\tif (resolve_packed_ref(refs, refname, sha1, type)) {\n \t\t\terrno = ENOENT;\n \t\t\tgoto out;\n \t\t}\n@@ -1417,7 +1416,7 @@ int read_raw_ref(const char *refname, unsigned char *sha1,\n \t\t * ref is supposed to be, there could still be a\n \t\t * packed ref:\n \t\t */\n-\t\tif (resolve_missing_loose_ref(refs, refname, sha1, type)) {\n+\t\tif (resolve_packed_ref(refs, refname, sha1, type)) {\n \t\t\terrno = EISDIR;\n \t\t\tgoto out;\n \t\t}\n-- \n2.9.3\n\n"},{"id":"301018","messageId":"9b5862009f45ae8ca8b14133ea0fcf0054901d70.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 13/38] resolve_gitlink_packed_ref(): remove function","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:19Z","receivedAt":"2016-09-04T16:13:09Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Now that resolve_packed_ref() can work with an arbitrary\nfiles_ref_store, there is no need to have a separate\nresolve_gitlink_packed_ref() function.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 26 +++++---------------------\n 1 file changed, 5 insertions(+), 21 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 32ca5ff..3b0c837 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1490,25 +1490,6 @@ static void unlock_ref(struct ref_lock *lock)\n \n #define MAXREFLEN (1024)\n \n-/*\n- * Called by resolve_gitlink_ref_recursive() after it failed to read\n- * from the loose refs in refs. Find <refname> in the packed-refs file\n- * for the submodule.\n- */\n-static int resolve_gitlink_packed_ref(struct files_ref_store *refs,\n-\t\t\t\t      const char *refname, unsigned char *sha1)\n-{\n-\tstruct ref_entry *ref;\n-\tstruct ref_dir *dir = get_packed_refs(refs);\n-\n-\tref = find_ref(dir, refname);\n-\tif (ref == NULL)\n-\t\treturn -1;\n-\n-\thashcpy(sha1, ref->u.value.oid.hash);\n-\treturn 0;\n-}\n-\n static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,\n \t\t\t\t\t const char *refname, unsigned char *sha1,\n \t\t\t\t\t int recursion)\n@@ -1524,8 +1505,11 @@ static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,\n \t\t: git_pathdup(\"%s\", refname);\n \tfd = open(path, O_RDONLY);\n \tfree(path);\n-\tif (fd < 0)\n-\t\treturn resolve_gitlink_packed_ref(refs, refname, sha1);\n+\tif (fd < 0) {\n+\t\tunsigned int flags;\n+\n+\t\treturn resolve_packed_ref(refs, refname, sha1, &flags);\n+\t}\n \n \tlen = read(fd, buffer, sizeof(buffer)-1);\n \tclose(fd);\n-- \n2.9.3\n\n"},{"id":"301019","messageId":"87a96792de01dcabfbd5adbf521d9110751c4987.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 19/38] refs: make read_raw_ref() virtual","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:25Z","receivedAt":"2016-09-04T16:13:12Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Reference backends will be able to customize this function to implement\nreference reading.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               |  4 ++--\n refs/files-backend.c | 14 ++++++++------\n refs/refs-internal.h | 36 +++++++++++++++++++-----------------\n 3 files changed, 29 insertions(+), 25 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex e881874..7a7adeb 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1251,8 +1251,8 @@ static const char *resolve_ref_recursively(struct ref_store *refs,\n \tfor (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) {\n \t\tunsigned int read_flags = 0;\n \n-\t\tif (read_raw_ref(refs, refname,\n-\t\t\t\t sha1, &sb_refname, &read_flags)) {\n+\t\tif (refs->be->read_raw_ref(refs, refname,\n+\t\t\t\t\t   sha1, &sb_refname, &read_flags)) {\n \t\t\t*flags |= read_flags;\n \t\t\tif (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))\n \t\t\t\treturn NULL;\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 6382c6b..ff11a51 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1349,9 +1349,9 @@ static int resolve_packed_ref(struct files_ref_store *refs,\n \treturn -1;\n }\n \n-int read_raw_ref(struct ref_store *ref_store,\n-\t\t const char *refname, unsigned char *sha1,\n-\t\t struct strbuf *referent, unsigned int *type)\n+static int files_read_raw_ref(struct ref_store *ref_store,\n+\t\t\t      const char *refname, unsigned char *sha1,\n+\t\t\t      struct strbuf *referent, unsigned int *type)\n {\n \tstruct files_ref_store *refs =\n \t\tfiles_downcast(ref_store, 1, \"read_raw_ref\");\n@@ -1623,8 +1623,8 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t * fear that its value will change.\n \t */\n \n-\tif (read_raw_ref(ref_store, refname,\n-\t\t\t lock->old_oid.hash, referent, type)) {\n+\tif (files_read_raw_ref(ref_store, refname,\n+\t\t\t       lock->old_oid.hash, referent, type)) {\n \t\tif (errno == ENOENT) {\n \t\t\tif (mustexist) {\n \t\t\t\t/* Garden variety missing reference. */\n@@ -4029,5 +4029,7 @@ struct ref_storage_be refs_be_files = {\n \tNULL,\n \t\"files\",\n \tfiles_ref_store_create,\n-\tfiles_transaction_commit\n+\tfiles_transaction_commit,\n+\n+\tfiles_read_raw_ref\n };\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex fa41d51..19cb6e1 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -486,6 +486,20 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,\n \n struct ref_store;\n \n+/* refs backends */\n+\n+/*\n+ * Initialize the ref_store for the specified submodule, or for the\n+ * main repository if submodule == NULL. These functions should call\n+ * base_ref_store_init() to initialize the shared part of the\n+ * ref_store and to record the ref_store for later lookup.\n+ */\n+typedef struct ref_store *ref_store_init_fn(const char *submodule);\n+\n+typedef int ref_transaction_commit_fn(struct ref_store *refs,\n+\t\t\t\t      struct ref_transaction *transaction,\n+\t\t\t\t      struct strbuf *err);\n+\n /*\n  * Read a reference from the specified reference store, non-recursively.\n  * Set type to describe the reference, and:\n@@ -524,29 +538,17 @@ struct ref_store;\n  * - in all other cases, referent will be untouched, and therefore\n  *   refname will still be valid and unchanged.\n  */\n-int read_raw_ref(struct ref_store *ref_store,\n-\t\t const char *refname, unsigned char *sha1,\n-\t\t struct strbuf *referent, unsigned int *type);\n-\n-/* refs backends */\n-\n-/*\n- * Initialize the ref_store for the specified submodule, or for the\n- * main repository if submodule == NULL. These functions should call\n- * base_ref_store_init() to initialize the shared part of the\n- * ref_store and to record the ref_store for later lookup.\n- */\n-typedef struct ref_store *ref_store_init_fn(const char *submodule);\n-\n-typedef int ref_transaction_commit_fn(struct ref_store *refs,\n-\t\t\t\t      struct ref_transaction *transaction,\n-\t\t\t\t      struct strbuf *err);\n+typedef int read_raw_ref_fn(struct ref_store *ref_store,\n+\t\t\t    const char *refname, unsigned char *sha1,\n+\t\t\t    struct strbuf *referent, unsigned int *type);\n \n struct ref_storage_be {\n \tstruct ref_storage_be *next;\n \tconst char *name;\n \tref_store_init_fn *init;\n \tref_transaction_commit_fn *transaction_commit;\n+\n+\tread_raw_ref_fn *read_raw_ref;\n };\n \n extern struct ref_storage_be refs_be_files;\n-- \n2.9.3\n\n"},{"id":"301020","messageId":"12edfade1c59ad1eac43761a7ba9466c1d00e924.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 25/38] lock_raw_ref(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:31Z","receivedAt":"2016-09-04T16:13:15Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 363f306..ae425c5 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1523,7 +1523,8 @@ static void unlock_ref(struct ref_lock *lock)\n  *   avoided, namely if we were successfully able to read the ref\n  * - Generate informative error messages in the case of failure\n  */\n-static int lock_raw_ref(const char *refname, int mustexist,\n+static int lock_raw_ref(struct files_ref_store *refs,\n+\t\t\tconst char *refname, int mustexist,\n \t\t\tconst struct string_list *extras,\n \t\t\tconst struct string_list *skip,\n \t\t\tstruct ref_lock **lock_p,\n@@ -1531,15 +1532,14 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t\t\tunsigned int *type,\n \t\t\tstruct strbuf *err)\n {\n-\tstruct ref_store *ref_store = get_ref_store(NULL);\n-\tstruct files_ref_store *refs =\n-\t\tfiles_downcast(ref_store, 0, \"lock_raw_ref\");\n \tstruct ref_lock *lock;\n \tstruct strbuf ref_file = STRBUF_INIT;\n \tint attempts_remaining = 3;\n \tint ret = TRANSACTION_GENERIC_ERROR;\n \n \tassert(err);\n+\tassert_main_repository(&refs->base, \"lock_raw_ref\");\n+\n \t*type = 0;\n \n \t/* First lock the file so it can't change out from under us. */\n@@ -1623,7 +1623,7 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t * fear that its value will change.\n \t */\n \n-\tif (files_read_raw_ref(ref_store, refname,\n+\tif (files_read_raw_ref(&refs->base, refname,\n \t\t\t       lock->old_oid.hash, referent, type)) {\n \t\tif (errno == ENOENT) {\n \t\t\tif (mustexist) {\n@@ -3518,6 +3518,8 @@ static int lock_ref_for_update(struct ref_update *update,\n \t\t\t       struct string_list *affected_refnames,\n \t\t\t       struct strbuf *err)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"lock_ref_for_update\");\n \tstruct strbuf referent = STRBUF_INIT;\n \tint mustexist = (update->flags & REF_HAVE_OLD) &&\n \t\t!is_null_sha1(update->old_sha1);\n@@ -3534,7 +3536,7 @@ static int lock_ref_for_update(struct ref_update *update,\n \t\t\treturn ret;\n \t}\n \n-\tret = lock_raw_ref(update->refname, mustexist,\n+\tret = lock_raw_ref(refs, update->refname, mustexist,\n \t\t\t   affected_refnames, NULL,\n \t\t\t   &update->lock, &referent,\n \t\t\t   &update->type, err);\n-- \n2.9.3\n\n"},{"id":"301021","messageId":"1c1421e8f0bf4dd1bcaf3b7bb63a2d102d4fadae.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 11/38] refs: reorder definitions","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:17Z","receivedAt":"2016-09-04T16:13:18Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Move resolve_gitlink_ref() and related functions lower in the file to\navoid the need for forward declarations in the next step.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 166 +++++++++++++++++++++++++--------------------------\n 1 file changed, 83 insertions(+), 83 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex d896052..7673342 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1316,89 +1316,6 @@ static struct ref_dir *get_loose_refs(struct files_ref_store *refs)\n \treturn get_ref_dir(refs->loose);\n }\n \n-#define MAXREFLEN (1024)\n-\n-/*\n- * Called by resolve_gitlink_ref_recursive() after it failed to read\n- * from the loose refs in refs. Find <refname> in the packed-refs file\n- * for the submodule.\n- */\n-static int resolve_gitlink_packed_ref(struct files_ref_store *refs,\n-\t\t\t\t      const char *refname, unsigned char *sha1)\n-{\n-\tstruct ref_entry *ref;\n-\tstruct ref_dir *dir = get_packed_refs(refs);\n-\n-\tref = find_ref(dir, refname);\n-\tif (ref == NULL)\n-\t\treturn -1;\n-\n-\thashcpy(sha1, ref->u.value.oid.hash);\n-\treturn 0;\n-}\n-\n-static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,\n-\t\t\t\t\t const char *refname, unsigned char *sha1,\n-\t\t\t\t\t int recursion)\n-{\n-\tint fd, len;\n-\tchar buffer[128], *p;\n-\tchar *path;\n-\n-\tif (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)\n-\t\treturn -1;\n-\tpath = *refs->base.submodule\n-\t\t? git_pathdup_submodule(refs->base.submodule, \"%s\", refname)\n-\t\t: git_pathdup(\"%s\", refname);\n-\tfd = open(path, O_RDONLY);\n-\tfree(path);\n-\tif (fd < 0)\n-\t\treturn resolve_gitlink_packed_ref(refs, refname, sha1);\n-\n-\tlen = read(fd, buffer, sizeof(buffer)-1);\n-\tclose(fd);\n-\tif (len < 0)\n-\t\treturn -1;\n-\twhile (len && isspace(buffer[len-1]))\n-\t\tlen--;\n-\tbuffer[len] = 0;\n-\n-\t/* Was it a detached head or an old-fashioned symlink? */\n-\tif (!get_sha1_hex(buffer, sha1))\n-\t\treturn 0;\n-\n-\t/* Symref? */\n-\tif (strncmp(buffer, \"ref:\", 4))\n-\t\treturn -1;\n-\tp = buffer + 4;\n-\twhile (isspace(*p))\n-\t\tp++;\n-\n-\treturn resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1);\n-}\n-\n-int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n-{\n-\tint len = strlen(path);\n-\tstruct strbuf submodule = STRBUF_INIT;\n-\tstruct files_ref_store *refs;\n-\n-\twhile (len && path[len-1] == '/')\n-\t\tlen--;\n-\tif (!len)\n-\t\treturn -1;\n-\n-\tstrbuf_add(&submodule, path, len);\n-\trefs = get_files_ref_store(submodule.buf, \"resolve_gitlink_ref\");\n-\tif (!refs) {\n-\t\tstrbuf_release(&submodule);\n-\t\treturn -1;\n-\t}\n-\tstrbuf_release(&submodule);\n-\n-\treturn resolve_gitlink_ref_recursive(refs, refname, sha1, 0);\n-}\n-\n /*\n  * Return the ref_entry for the given refname from the packed\n  * references.  If it does not exist, return NULL.\n@@ -1572,6 +1489,89 @@ static void unlock_ref(struct ref_lock *lock)\n \tfree(lock);\n }\n \n+#define MAXREFLEN (1024)\n+\n+/*\n+ * Called by resolve_gitlink_ref_recursive() after it failed to read\n+ * from the loose refs in refs. Find <refname> in the packed-refs file\n+ * for the submodule.\n+ */\n+static int resolve_gitlink_packed_ref(struct files_ref_store *refs,\n+\t\t\t\t      const char *refname, unsigned char *sha1)\n+{\n+\tstruct ref_entry *ref;\n+\tstruct ref_dir *dir = get_packed_refs(refs);\n+\n+\tref = find_ref(dir, refname);\n+\tif (ref == NULL)\n+\t\treturn -1;\n+\n+\thashcpy(sha1, ref->u.value.oid.hash);\n+\treturn 0;\n+}\n+\n+static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,\n+\t\t\t\t\t const char *refname, unsigned char *sha1,\n+\t\t\t\t\t int recursion)\n+{\n+\tint fd, len;\n+\tchar buffer[128], *p;\n+\tchar *path;\n+\n+\tif (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)\n+\t\treturn -1;\n+\tpath = *refs->base.submodule\n+\t\t? git_pathdup_submodule(refs->base.submodule, \"%s\", refname)\n+\t\t: git_pathdup(\"%s\", refname);\n+\tfd = open(path, O_RDONLY);\n+\tfree(path);\n+\tif (fd < 0)\n+\t\treturn resolve_gitlink_packed_ref(refs, refname, sha1);\n+\n+\tlen = read(fd, buffer, sizeof(buffer)-1);\n+\tclose(fd);\n+\tif (len < 0)\n+\t\treturn -1;\n+\twhile (len && isspace(buffer[len-1]))\n+\t\tlen--;\n+\tbuffer[len] = 0;\n+\n+\t/* Was it a detached head or an old-fashioned symlink? */\n+\tif (!get_sha1_hex(buffer, sha1))\n+\t\treturn 0;\n+\n+\t/* Symref? */\n+\tif (strncmp(buffer, \"ref:\", 4))\n+\t\treturn -1;\n+\tp = buffer + 4;\n+\twhile (isspace(*p))\n+\t\tp++;\n+\n+\treturn resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1);\n+}\n+\n+int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n+{\n+\tint len = strlen(path);\n+\tstruct strbuf submodule = STRBUF_INIT;\n+\tstruct files_ref_store *refs;\n+\n+\twhile (len && path[len-1] == '/')\n+\t\tlen--;\n+\tif (!len)\n+\t\treturn -1;\n+\n+\tstrbuf_add(&submodule, path, len);\n+\trefs = get_files_ref_store(submodule.buf, \"resolve_gitlink_ref\");\n+\tif (!refs) {\n+\t\tstrbuf_release(&submodule);\n+\t\treturn -1;\n+\t}\n+\tstrbuf_release(&submodule);\n+\n+\treturn resolve_gitlink_ref_recursive(refs, refname, sha1, 0);\n+}\n+\n /*\n  * Lock refname, without following symrefs, and set *lock_p to point\n  * at a newly-allocated lock object. Fill in lock->old_oid, referent,\n-- \n2.9.3\n\n"},{"id":"301022","messageId":"bc87063e6a1b203cf7345b30e060caae245a3ca6.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 17/38] resolve_gitlink_ref(): avoid memory allocation in many cases","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:23Z","receivedAt":"2016-09-04T16:13:20Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"If we don't have to strip trailing '/' from the submodule path, then\ndon't allocate and copy the submodule name.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c | 19 +++++++++++++------\n 1 file changed, 13 insertions(+), 6 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 647ead5..34c0c5e 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1301,19 +1301,26 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \n int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)\n {\n-\tint len = strlen(path);\n-\tstruct strbuf submodule = STRBUF_INIT;\n+\tsize_t len = strlen(path);\n \tstruct ref_store *refs;\n \tint flags;\n \n-\twhile (len && path[len-1] == '/')\n+\twhile (len && path[len - 1] == '/')\n \t\tlen--;\n+\n \tif (!len)\n \t\treturn -1;\n \n-\tstrbuf_add(&submodule, path, len);\n-\trefs = get_ref_store(submodule.buf);\n-\tstrbuf_release(&submodule);\n+\tif (path[len]) {\n+\t\t/* We need to strip off one or more trailing slashes */\n+\t\tchar *stripped = xmemdupz(path, len);\n+\n+\t\trefs = get_ref_store(stripped);\n+\t\tfree(stripped);\n+\t} else {\n+\t\trefs = get_ref_store(path);\n+\t}\n+\n \tif (!refs)\n \t\treturn -1;\n \n-- \n2.9.3\n\n"},{"id":"301023","messageId":"9aa0bb261d5e583fe2e2ea4cfeb4815c5267ee06.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 24/38] repack_without_refs(): add a files_ref_store argument","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:30Z","receivedAt":"2016-09-04T16:13:23Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 8d43e0b..363f306 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2384,14 +2384,14 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)\n  *\n  * The refs in 'refnames' needn't be sorted. `err` must not be NULL.\n  */\n-static int repack_without_refs(struct string_list *refnames, struct strbuf *err)\n+static int repack_without_refs(struct files_ref_store *refs,\n+\t\t\t       struct string_list *refnames, struct strbuf *err)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"repack_without_refs\");\n \tstruct ref_dir *packed;\n \tstruct string_list_item *refname;\n \tint ret, needs_repacking = 0, removed = 0;\n \n+\tassert_main_repository(&refs->base, \"repack_without_refs\");\n \tassert(err);\n \n \t/* Look for a packed ref */\n@@ -2453,13 +2453,15 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)\n \n int delete_refs(struct string_list *refnames, unsigned int flags)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"delete_refs\");\n \tstruct strbuf err = STRBUF_INIT;\n \tint i, result = 0;\n \n \tif (!refnames->nr)\n \t\treturn 0;\n \n-\tresult = repack_without_refs(refnames, &err);\n+\tresult = repack_without_refs(refs, refnames, &err);\n \tif (result) {\n \t\t/*\n \t\t * If we failed to rewrite the packed-refs file, then\n@@ -3779,7 +3781,7 @@ static int files_transaction_commit(struct ref_store *ref_store,\n \t\t}\n \t}\n \n-\tif (repack_without_refs(&refs_to_delete, err)) {\n+\tif (repack_without_refs(refs, &refs_to_delete, err)) {\n \t\tret = TRANSACTION_GENERIC_ERROR;\n \t\tgoto cleanup;\n \t}\n-- \n2.9.3\n\n"},{"id":"301024","messageId":"016e25dc60b86d4b2312963a913ecd512e2e75b9.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 20/38] refs: make verify_refname_available() virtual","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:26Z","receivedAt":"2016-09-04T16:13:26Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 10 ++++++++++\n refs/files-backend.c | 14 ++++++++------\n refs/refs-internal.h |  7 +++++++\n 3 files changed, 25 insertions(+), 6 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 7a7adeb..662c417 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1428,3 +1428,13 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \n \treturn refs->be->transaction_commit(refs, transaction, err);\n }\n+\n+int verify_refname_available(const char *refname,\n+\t\t\t     const struct string_list *extra,\n+\t\t\t     const struct string_list *skip,\n+\t\t\t     struct strbuf *err)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->verify_refname_available(refs, refname, extra, skip, err);\n+}\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ff11a51..4e1d431 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2549,13 +2549,14 @@ static int rename_tmp_log(const char *newrefname)\n \treturn ret;\n }\n \n-int verify_refname_available(const char *newname,\n-\t\t\t     const struct string_list *extras,\n-\t\t\t     const struct string_list *skip,\n-\t\t\t     struct strbuf *err)\n+static int files_verify_refname_available(struct ref_store *ref_store,\n+\t\t\t\t\t  const char *newname,\n+\t\t\t\t\t  const struct string_list *extras,\n+\t\t\t\t\t  const struct string_list *skip,\n+\t\t\t\t\t  struct strbuf *err)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"verify_refname_available\");\n+\t\tfiles_downcast(ref_store, 1, \"verify_refname_available\");\n \tstruct ref_dir *packed_refs = get_packed_refs(refs);\n \tstruct ref_dir *loose_refs = get_loose_refs(refs);\n \n@@ -4031,5 +4032,6 @@ struct ref_storage_be refs_be_files = {\n \tfiles_ref_store_create,\n \tfiles_transaction_commit,\n \n-\tfiles_read_raw_ref\n+\tfiles_read_raw_ref,\n+\tfiles_verify_refname_available\n };\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 19cb6e1..6c698f4 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -542,6 +542,12 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store,\n \t\t\t    const char *refname, unsigned char *sha1,\n \t\t\t    struct strbuf *referent, unsigned int *type);\n \n+typedef int verify_refname_available_fn(struct ref_store *ref_store,\n+\t\t\t\t\tconst char *newname,\n+\t\t\t\t\tconst struct string_list *extras,\n+\t\t\t\t\tconst struct string_list *skip,\n+\t\t\t\t\tstruct strbuf *err);\n+\n struct ref_storage_be {\n \tstruct ref_storage_be *next;\n \tconst char *name;\n@@ -549,6 +555,7 @@ struct ref_storage_be {\n \tref_transaction_commit_fn *transaction_commit;\n \n \tread_raw_ref_fn *read_raw_ref;\n+\tverify_refname_available_fn *verify_refname_available;\n };\n \n extern struct ref_storage_be refs_be_files;\n-- \n2.9.3\n\n"},{"id":"301025","messageId":"39277c75122a374b360057d6e1f6d889a90f6fb4.1473003902.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 05/38] refs: create a base class \"ref_store\" for files_ref_store","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:11Z","receivedAt":"2016-09-04T16:13:29Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"We want ref_stores to be polymorphic, so invent a base class of which\nfiles_ref_store is a derived class. For now there is exactly one\nref_store for the main repository and one for any submodules whose\nreferences have been accessed.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               |  93 +++++++++++++++++++++++++++\n refs/files-backend.c | 177 ++++++++++++++++++++++++++++-----------------------\n refs/refs-internal.h |  78 +++++++++++++++++++++++\n 3 files changed, 270 insertions(+), 78 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex d2a29bb..9d6bcb1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1151,8 +1151,12 @@ int head_ref(each_ref_fn fn, void *cb_data)\n static int do_for_each_ref(const char *submodule, const char *prefix,\n \t\t\t   each_ref_fn fn, int trim, int flags, void *cb_data)\n {\n+\tstruct ref_store *refs = get_ref_store(submodule);\n \tstruct ref_iterator *iter;\n \n+\tif (!refs)\n+\t\treturn 0;\n+\n \titer = files_ref_iterator_begin(submodule, prefix, flags);\n \titer = prefix_ref_iterator_begin(iter, prefix, trim);\n \n@@ -1284,3 +1288,92 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n \terrno = ELOOP;\n \treturn NULL;\n }\n+\n+/* A pointer to the ref_store for the main repository: */\n+static struct ref_store *main_ref_store;\n+\n+/* A linked list of ref_stores for submodules: */\n+static struct ref_store *submodule_ref_stores;\n+\n+void base_ref_store_init(struct ref_store *refs,\n+\t\t\t const struct ref_storage_be *be,\n+\t\t\t const char *submodule)\n+{\n+\trefs->be = be;\n+\tif (!submodule) {\n+\t\tif (main_ref_store)\n+\t\t\tdie(\"BUG: main_ref_store initialized twice\");\n+\n+\t\trefs->submodule = \"\";\n+\t\trefs->next = NULL;\n+\t\tmain_ref_store = refs;\n+\t} else {\n+\t\tif (lookup_ref_store(submodule))\n+\t\t\tdie(\"BUG: ref_store for submodule '%s' initialized twice\",\n+\t\t\t    submodule);\n+\n+\t\trefs->submodule = xstrdup(submodule);\n+\t\trefs->next = submodule_ref_stores;\n+\t\tsubmodule_ref_stores = refs;\n+\t}\n+}\n+\n+struct ref_store *ref_store_init(const char *submodule)\n+{\n+\tconst char *be_name = \"files\";\n+\tstruct ref_storage_be *be = find_ref_storage_backend(be_name);\n+\n+\tif (!be)\n+\t\tdie(\"BUG: reference backend %s is unknown\", be_name);\n+\n+\tif (!submodule || !*submodule)\n+\t\treturn be->init(NULL);\n+\telse\n+\t\treturn be->init(submodule);\n+}\n+\n+struct ref_store *lookup_ref_store(const char *submodule)\n+{\n+\tstruct ref_store *refs;\n+\n+\tif (!submodule || !*submodule)\n+\t\treturn main_ref_store;\n+\n+\tfor (refs = submodule_ref_stores; refs; refs = refs->next) {\n+\t\tif (!strcmp(submodule, refs->submodule))\n+\t\t\treturn refs;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+struct ref_store *get_ref_store(const char *submodule)\n+{\n+\tstruct ref_store *refs;\n+\n+\tif (!submodule || !*submodule) {\n+\t\trefs = lookup_ref_store(NULL);\n+\n+\t\tif (!refs)\n+\t\t\trefs = ref_store_init(NULL);\n+\t} else {\n+\t\trefs = lookup_ref_store(submodule);\n+\n+\t\tif (!refs) {\n+\t\t\tstruct strbuf submodule_sb = STRBUF_INIT;\n+\n+\t\t\tstrbuf_addstr(&submodule_sb, submodule);\n+\t\t\tif (is_nonbare_repository_dir(&submodule_sb))\n+\t\t\t\trefs = ref_store_init(submodule);\n+\t\t\tstrbuf_release(&submodule_sb);\n+\t\t}\n+\t}\n+\n+\treturn refs;\n+}\n+\n+void assert_main_repository(struct ref_store *refs, const char *caller)\n+{\n+\tif (*refs->submodule)\n+\t\tdie(\"BUG: %s called for a submodule\", caller);\n+}\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ecf66e6..439c500 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -910,17 +910,11 @@ struct packed_ref_cache {\n  * Future: need to be in \"struct repository\"\n  * when doing a full libification.\n  */\n-static struct files_ref_store {\n-\tstruct files_ref_store *next;\n+struct files_ref_store {\n+\tstruct ref_store base;\n \tstruct ref_entry *loose;\n \tstruct packed_ref_cache *packed;\n-\t/*\n-\t * The submodule name, or \"\" for the main repo. We allocate\n-\t * length 1 rather than FLEX_ARRAY so that the main\n-\t * files_ref_store is initialized correctly.\n-\t */\n-\tchar name[1];\n-} ref_store, *submodule_ref_stores;\n+};\n \n /* Lock used for the main packed-refs file: */\n static struct lock_file packlock;\n@@ -973,53 +967,50 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)\n  * Create a new submodule ref cache and add it to the internal\n  * set of caches.\n  */\n-static struct files_ref_store *create_ref_store(const char *submodule)\n+static struct ref_store *files_ref_store_create(const char *submodule)\n {\n-\tstruct files_ref_store *refs;\n-\tif (!submodule)\n-\t\tsubmodule = \"\";\n-\tFLEX_ALLOC_STR(refs, name, submodule);\n-\trefs->next = submodule_ref_stores;\n-\tsubmodule_ref_stores = refs;\n-\treturn refs;\n+\tstruct files_ref_store *refs = xcalloc(1, sizeof(*refs));\n+\tstruct ref_store *ref_store = (struct ref_store *)refs;\n+\n+\tbase_ref_store_init(ref_store, &refs_be_files, submodule);\n+\n+\treturn ref_store;\n }\n \n-static struct files_ref_store *lookup_ref_store(const char *submodule)\n+/*\n+ * Downcast ref_store to files_ref_store. Die if ref_store is not a\n+ * files_ref_store. If submodule_allowed is not true, then also die if\n+ * files_ref_store is for a submodule (i.e., not for the main\n+ * repository). caller is used in any necessary error messages.\n+ */\n+static struct files_ref_store *files_downcast(\n+\t\tstruct ref_store *ref_store, int submodule_allowed,\n+\t\tconst char *caller)\n {\n-\tstruct files_ref_store *refs;\n+\tif (ref_store->be != &refs_be_files)\n+\t\tdie(\"BUG: ref_store is type \\\"%s\\\" not \\\"files\\\" in %s\",\n+\t\t    ref_store->be->name, caller);\n \n-\tif (!submodule || !*submodule)\n-\t\treturn &ref_store;\n+\tif (!submodule_allowed)\n+\t\tassert_main_repository(ref_store, caller);\n \n-\tfor (refs = submodule_ref_stores; refs; refs = refs->next)\n-\t\tif (!strcmp(submodule, refs->name))\n-\t\t\treturn refs;\n-\treturn NULL;\n+\treturn (struct files_ref_store *)ref_store;\n }\n \n /*\n- * Return a pointer to a files_ref_store for the specified submodule. For\n- * the main repository, use submodule==NULL; such a call cannot fail.\n- * For a submodule, the submodule must exist and be a nonbare\n- * repository, otherwise return NULL.\n- *\n- * The returned structure will be allocated and initialized but not\n- * necessarily populated; it should not be freed.\n+ * Return a pointer to the reference store for the specified\n+ * submodule. For the main repository, use submodule==NULL; such a\n+ * call cannot fail. For a submodule, the submodule must exist and be\n+ * a nonbare repository, otherwise return NULL. Verify that the\n+ * reference store is a files_ref_store, and cast it to that type\n+ * before returning it.\n  */\n-static struct files_ref_store *get_ref_store(const char *submodule)\n+static struct files_ref_store *get_files_ref_store(const char *submodule,\n+\t\t\t\t\t\t   const char *caller)\n {\n-\tstruct files_ref_store *refs = lookup_ref_store(submodule);\n+\tstruct ref_store *refs = get_ref_store(submodule);\n \n-\tif (!refs) {\n-\t\tstruct strbuf submodule_sb = STRBUF_INIT;\n-\n-\t\tstrbuf_addstr(&submodule_sb, submodule);\n-\t\tif (is_nonbare_repository_dir(&submodule_sb))\n-\t\t\trefs = create_ref_store(submodule);\n-\t\tstrbuf_release(&submodule_sb);\n-\t}\n-\n-\treturn refs;\n+\treturn refs ? files_downcast(refs, 1, caller) : NULL;\n }\n \n /* The length of a peeled reference line in packed-refs, including EOL: */\n@@ -1158,8 +1149,9 @@ static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *ref\n {\n \tchar *packed_refs_file;\n \n-\tif (*refs->name)\n-\t\tpacked_refs_file = git_pathdup_submodule(refs->name, \"packed-refs\");\n+\tif (*refs->base.submodule)\n+\t\tpacked_refs_file = git_pathdup_submodule(refs->base.submodule,\n+\t\t\t\t\t\t\t \"packed-refs\");\n \telse\n \t\tpacked_refs_file = git_pathdup(\"packed-refs\");\n \n@@ -1202,8 +1194,9 @@ static struct ref_dir *get_packed_refs(struct files_ref_store *refs)\n  */\n static void add_packed_ref(const char *refname, const unsigned char *sha1)\n {\n-\tstruct packed_ref_cache *packed_ref_cache =\n-\t\tget_packed_ref_cache(&ref_store);\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"add_packed_ref\");\n+\tstruct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);\n \n \tif (!packed_ref_cache->lock)\n \t\tdie(\"internal error: packed refs not locked\");\n@@ -1226,8 +1219,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)\n \tstruct strbuf path = STRBUF_INIT;\n \tsize_t path_baselen;\n \n-\tif (*refs->name)\n-\t\tstrbuf_git_path_submodule(&path, refs->name, \"%s\", dirname);\n+\tif (*refs->base.submodule)\n+\t\tstrbuf_git_path_submodule(&path, refs->base.submodule, \"%s\", dirname);\n \telse\n \t\tstrbuf_git_path(&path, \"%s\", dirname);\n \tpath_baselen = path.len;\n@@ -1262,10 +1255,10 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)\n \t\t} else {\n \t\t\tint read_ok;\n \n-\t\t\tif (*refs->name) {\n+\t\t\tif (*refs->base.submodule) {\n \t\t\t\thashclr(sha1);\n \t\t\t\tflag = 0;\n-\t\t\t\tread_ok = !resolve_gitlink_ref(refs->name,\n+\t\t\t\tread_ok = !resolve_gitlink_ref(refs->base.submodule,\n \t\t\t\t\t\t\t       refname.buf, sha1);\n \t\t\t} else {\n \t\t\t\tread_ok = !read_ref_full(refname.buf,\n@@ -1355,8 +1348,8 @@ static int resolve_gitlink_ref_recursive(struct files_ref_store *refs,\n \n \tif (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)\n \t\treturn -1;\n-\tpath = *refs->name\n-\t\t? git_pathdup_submodule(refs->name, \"%s\", refname)\n+\tpath = *refs->base.submodule\n+\t\t? git_pathdup_submodule(refs->base.submodule, \"%s\", refname)\n \t\t: git_pathdup(\"%s\", refname);\n \tfd = open(path, O_RDONLY);\n \tfree(path);\n@@ -1397,7 +1390,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n \t\treturn -1;\n \n \tstrbuf_add(&submodule, path, len);\n-\trefs = get_ref_store(submodule.buf);\n+\trefs = get_files_ref_store(submodule.buf, \"resolve_gitlink_ref\");\n \tif (!refs) {\n \t\tstrbuf_release(&submodule);\n \t\treturn -1;\n@@ -1413,7 +1406,10 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sh\n  */\n static struct ref_entry *get_packed_ref(const char *refname)\n {\n-\treturn find_ref(get_packed_refs(&ref_store), refname);\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"get_packed_ref\");\n+\n+\treturn find_ref(get_packed_refs(refs), refname);\n }\n \n /*\n@@ -1613,6 +1609,8 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t\t\tunsigned int *type,\n \t\t\tstruct strbuf *err)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"lock_raw_ref\");\n \tstruct ref_lock *lock;\n \tstruct strbuf ref_file = STRBUF_INIT;\n \tint attempts_remaining = 3;\n@@ -1745,7 +1743,7 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t\t\t\t\t\t\t  REMOVE_DIR_EMPTY_ONLY)) {\n \t\t\t\tif (verify_refname_available_dir(\n \t\t\t\t\t\t    refname, extras, skip,\n-\t\t\t\t\t\t    get_loose_refs(&ref_store),\n+\t\t\t\t\t\t    get_loose_refs(refs),\n \t\t\t\t\t\t    err)) {\n \t\t\t\t\t/*\n \t\t\t\t\t * The error message set by\n@@ -1784,7 +1782,7 @@ static int lock_raw_ref(const char *refname, int mustexist,\n \t\t */\n \t\tif (verify_refname_available_dir(\n \t\t\t\t    refname, extras, skip,\n-\t\t\t\t    get_packed_refs(&ref_store),\n+\t\t\t\t    get_packed_refs(refs),\n \t\t\t\t    err)) {\n \t\t\tgoto error_return;\n \t\t}\n@@ -1942,7 +1940,8 @@ struct ref_iterator *files_ref_iterator_begin(\n \t\tconst char *submodule,\n \t\tconst char *prefix, unsigned int flags)\n {\n-\tstruct files_ref_store *refs = get_ref_store(submodule);\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(submodule, \"ref_iterator_begin\");\n \tstruct ref_dir *loose_dir, *packed_dir;\n \tstruct ref_iterator *loose_iter, *packed_iter;\n \tstruct files_ref_iterator *iter;\n@@ -2065,6 +2064,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t\t\t\t\t    unsigned int flags, int *type,\n \t\t\t\t\t    struct strbuf *err)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"lock_ref_sha1_basic\");\n \tstruct strbuf ref_file = STRBUF_INIT;\n \tstruct ref_lock *lock;\n \tint last_errno = 0;\n@@ -2095,8 +2096,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t\t */\n \t\tif (remove_empty_directories(&ref_file)) {\n \t\t\tlast_errno = errno;\n-\t\t\tif (!verify_refname_available_dir(refname, extras, skip,\n-\t\t\t\t\t\t\t  get_loose_refs(&ref_store), err))\n+\t\t\tif (!verify_refname_available_dir(\n+\t\t\t\t\t    refname, extras, skip,\n+\t\t\t\t\t    get_loose_refs(refs), err))\n \t\t\t\tstrbuf_addf(err, \"there are still refs under '%s'\",\n \t\t\t\t\t    refname);\n \t\t\tgoto error_return;\n@@ -2107,8 +2109,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \tif (!resolved) {\n \t\tlast_errno = errno;\n \t\tif (last_errno != ENOTDIR ||\n-\t\t    !verify_refname_available_dir(refname, extras, skip,\n-\t\t\t\t\t\t  get_loose_refs(&ref_store), err))\n+\t\t    !verify_refname_available_dir(\n+\t\t\t\t    refname, extras, skip,\n+\t\t\t\t    get_loose_refs(refs), err))\n \t\t\tstrbuf_addf(err, \"unable to resolve reference '%s': %s\",\n \t\t\t\t    refname, strerror(last_errno));\n \n@@ -2123,7 +2126,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,\n \t */\n \tif (is_null_oid(&lock->old_oid) &&\n \t    verify_refname_available_dir(refname, extras, skip,\n-\t\t\t\t\t get_packed_refs(&ref_store), err)) {\n+\t\t\t\t\t get_packed_refs(refs),\n+\t\t\t\t\t err)) {\n \t\tlast_errno = ENOTDIR;\n \t\tgoto error_return;\n \t}\n@@ -2212,9 +2216,10 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)\n  */\n static int lock_packed_refs(int flags)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"lock_packed_refs\");\n \tstatic int timeout_configured = 0;\n \tstatic int timeout_value = 1000;\n-\n \tstruct packed_ref_cache *packed_ref_cache;\n \n \tif (!timeout_configured) {\n@@ -2232,7 +2237,7 @@ static int lock_packed_refs(int flags)\n \t * this will automatically invalidate the cache and re-read\n \t * the packed-refs file.\n \t */\n-\tpacked_ref_cache = get_packed_ref_cache(&ref_store);\n+\tpacked_ref_cache = get_packed_ref_cache(refs);\n \tpacked_ref_cache->lock = &packlock;\n \t/* Increment the reference count to prevent it from being freed: */\n \tacquire_packed_ref_cache(packed_ref_cache);\n@@ -2247,8 +2252,10 @@ static int lock_packed_refs(int flags)\n  */\n static int commit_packed_refs(void)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"commit_packed_refs\");\n \tstruct packed_ref_cache *packed_ref_cache =\n-\t\tget_packed_ref_cache(&ref_store);\n+\t\tget_packed_ref_cache(refs);\n \tint error = 0;\n \tint save_errno = 0;\n \tFILE *out;\n@@ -2281,15 +2288,17 @@ static int commit_packed_refs(void)\n  */\n static void rollback_packed_refs(void)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"rollback_packed_refs\");\n \tstruct packed_ref_cache *packed_ref_cache =\n-\t\tget_packed_ref_cache(&ref_store);\n+\t\tget_packed_ref_cache(refs);\n \n \tif (!packed_ref_cache->lock)\n \t\tdie(\"internal error: packed-refs not locked\");\n \trollback_lock_file(packed_ref_cache->lock);\n \tpacked_ref_cache->lock = NULL;\n \trelease_packed_ref_cache(packed_ref_cache);\n-\tclear_packed_ref_cache(&ref_store);\n+\tclear_packed_ref_cache(refs);\n }\n \n struct ref_to_prune {\n@@ -2422,15 +2431,17 @@ static void prune_refs(struct ref_to_prune *r)\n \n int pack_refs(unsigned int flags)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"pack_refs\");\n \tstruct pack_refs_cb_data cbdata;\n \n \tmemset(&cbdata, 0, sizeof(cbdata));\n \tcbdata.flags = flags;\n \n \tlock_packed_refs(LOCK_DIE_ON_ERROR);\n-\tcbdata.packed_refs = get_packed_refs(&ref_store);\n+\tcbdata.packed_refs = get_packed_refs(refs);\n \n-\tdo_for_each_entry_in_dir(get_loose_refs(&ref_store), 0,\n+\tdo_for_each_entry_in_dir(get_loose_refs(refs), 0,\n \t\t\t\t pack_if_possible_fn, &cbdata);\n \n \tif (commit_packed_refs())\n@@ -2449,6 +2460,8 @@ int pack_refs(unsigned int flags)\n  */\n static int repack_without_refs(struct string_list *refnames, struct strbuf *err)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"repack_without_refs\");\n \tstruct ref_dir *packed;\n \tstruct string_list_item *refname;\n \tint ret, needs_repacking = 0, removed = 0;\n@@ -2471,7 +2484,7 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)\n \t\tunable_to_lock_message(git_path(\"packed-refs\"), errno, err);\n \t\treturn -1;\n \t}\n-\tpacked = get_packed_refs(&ref_store);\n+\tpacked = get_packed_refs(refs);\n \n \t/* Remove refnames from the cache */\n \tfor_each_string_list_item(refname, refnames)\n@@ -2616,8 +2629,10 @@ int verify_refname_available(const char *newname,\n \t\t\t     const struct string_list *skip,\n \t\t\t     struct strbuf *err)\n {\n-\tstruct ref_dir *packed_refs = get_packed_refs(&ref_store);\n-\tstruct ref_dir *loose_refs = get_loose_refs(&ref_store);\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"verify_refname_available\");\n+\tstruct ref_dir *packed_refs = get_packed_refs(refs);\n+\tstruct ref_dir *loose_refs = get_loose_refs(refs);\n \n \tif (verify_refname_available_dir(newname, extras, skip,\n \t\t\t\t\t packed_refs, err) ||\n@@ -2968,7 +2983,10 @@ static int commit_ref_update(struct ref_lock *lock,\n \t\t\t     const unsigned char *sha1, const char *logmsg,\n \t\t\t     struct strbuf *err)\n {\n-\tclear_loose_ref_cache(&ref_store);\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"commit_ref_update\");\n+\n+\tclear_loose_ref_cache(refs);\n \tif (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, 0, err)) {\n \t\tchar *old_msg = strbuf_detach(err, NULL);\n \t\tstrbuf_addf(err, \"cannot update the ref '%s': %s\",\n@@ -3694,6 +3712,8 @@ static int lock_ref_for_update(struct ref_update *update,\n int ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t   struct strbuf *err)\n {\n+\tstruct files_ref_store *refs =\n+\t\tget_files_ref_store(NULL, \"ref_transaction_commit\");\n \tint ret = 0, i;\n \tstruct string_list refs_to_delete = STRING_LIST_INIT_NODUP;\n \tstruct string_list_item *ref_to_delete;\n@@ -3800,7 +3820,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t}\n \t\t}\n \t\tif (update->flags & REF_NEEDS_COMMIT) {\n-\t\t\tclear_loose_ref_cache(&ref_store);\n+\t\t\tclear_loose_ref_cache(refs);\n \t\t\tif (commit_ref(lock)) {\n \t\t\t\tstrbuf_addf(err, \"couldn't set '%s'\", lock->ref_name);\n \t\t\t\tunlock_ref(lock);\n@@ -3833,7 +3853,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \t}\n \tfor_each_string_list_item(ref_to_delete, &refs_to_delete)\n \t\tunlink_or_warn(git_path(\"logs/%s\", ref_to_delete->string));\n-\tclear_loose_ref_cache(&ref_store);\n+\tclear_loose_ref_cache(refs);\n \n cleanup:\n \ttransaction->state = REF_TRANSACTION_CLOSED;\n@@ -4079,5 +4099,6 @@ int reflog_expire(const char *refname, const unsigned char *sha1,\n \n struct ref_storage_be refs_be_files = {\n \tNULL,\n-\t\"files\"\n+\t\"files\",\n+\tfiles_ref_store_create\n };\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 2c9d134..b952038 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -526,11 +526,89 @@ int read_raw_ref(const char *refname, unsigned char *sha1,\n \t\t struct strbuf *referent, unsigned int *type);\n \n /* refs backends */\n+\n+/*\n+ * Initialize the ref_store for the specified submodule, or for the\n+ * main repository if submodule == NULL. These functions should call\n+ * base_ref_store_init() to initialize the shared part of the\n+ * ref_store and to record the ref_store for later lookup.\n+ */\n+typedef struct ref_store *ref_store_init_fn(const char *submodule);\n+\n struct ref_storage_be {\n \tstruct ref_storage_be *next;\n \tconst char *name;\n+\tref_store_init_fn *init;\n };\n \n extern struct ref_storage_be refs_be_files;\n \n+/*\n+ * A representation of the reference store for the main repository or\n+ * a submodule. The ref_store instances for submodules are kept in a\n+ * linked list.\n+ */\n+struct ref_store {\n+\t/* The backend describing this ref_store's storage scheme: */\n+\tconst struct ref_storage_be *be;\n+\n+\t/*\n+\t * The name of the submodule represented by this object, or\n+\t * the empty string if it represents the main repository's\n+\t * reference store:\n+\t */\n+\tconst char *submodule;\n+\n+\t/*\n+\t * Submodule reference store instances are stored in a linked\n+\t * list using this pointer.\n+\t */\n+\tstruct ref_store *next;\n+};\n+\n+/*\n+ * Fill in the generic part of refs for the specified submodule and\n+ * add it to our collection of reference stores.\n+ */\n+void base_ref_store_init(struct ref_store *refs,\n+\t\t\t const struct ref_storage_be *be,\n+\t\t\t const char *submodule);\n+\n+/*\n+ * Create, record, and return a ref_store instance for the specified\n+ * submodule (or the main repository if submodule is NULL).\n+ *\n+ * For backwards compatibility, submodule==\"\" is treated the same as\n+ * submodule==NULL.\n+ */\n+struct ref_store *ref_store_init(const char *submodule);\n+\n+/*\n+ * Return the ref_store instance for the specified submodule (or the\n+ * main repository if submodule is NULL). If that ref_store hasn't\n+ * been initialized yet, return NULL.\n+ *\n+ * For backwards compatibility, submodule==\"\" is treated the same as\n+ * submodule==NULL.\n+ */\n+struct ref_store *lookup_ref_store(const char *submodule);\n+\n+/*\n+ * Return the ref_store instance for the specified submodule. For the\n+ * main repository, use submodule==NULL; such a call cannot fail. For\n+ * a submodule, the submodule must exist and be a nonbare repository,\n+ * otherwise return NULL. If the requested reference store has not yet\n+ * been initialized, initialize it first.\n+ *\n+ * For backwards compatibility, submodule==\"\" is treated the same as\n+ * submodule==NULL.\n+ */\n+struct ref_store *get_ref_store(const char *submodule);\n+\n+/*\n+ * Die if refs is for a submodule (i.e., not for the main repository).\n+ * caller is used in any necessary error messages.\n+ */\n+void assert_main_repository(struct ref_store *refs, const char *caller);\n+\n #endif /* REFS_REFS_INTERNAL_H */\n-- \n2.9.3\n\n"},{"id":"301026","messageId":"d4f623a7fde1ccc7d3ab49f8f8bed8b1dddf1933.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 09/38] {lock,commit,rollback}_packed_refs(): add files_ref_store arguments","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:15Z","receivedAt":"2016-09-04T16:13:32Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"These functions currently only work in the main repository, so add an\nassert_main_repository() check to each function.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs/files-backend.c | 32 ++++++++++++++++----------------\n 1 file changed, 16 insertions(+), 16 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 0c92ace..6913d45 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2215,14 +2215,14 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)\n  * hold_lock_file_for_update(). Return 0 on success. On errors, set\n  * errno appropriately and return a nonzero value.\n  */\n-static int lock_packed_refs(int flags)\n+static int lock_packed_refs(struct files_ref_store *refs, int flags)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"lock_packed_refs\");\n \tstatic int timeout_configured = 0;\n \tstatic int timeout_value = 1000;\n \tstruct packed_ref_cache *packed_ref_cache;\n \n+\tassert_main_repository(&refs->base, \"lock_packed_refs\");\n+\n \tif (!timeout_configured) {\n \t\tgit_config_get_int(\"core.packedrefstimeout\", &timeout_value);\n \t\ttimeout_configured = 1;\n@@ -2251,16 +2251,16 @@ static int lock_packed_refs(int flags)\n  * lock_packed_refs()). Return zero on success. On errors, set errno\n  * and return a nonzero value\n  */\n-static int commit_packed_refs(void)\n+static int commit_packed_refs(struct files_ref_store *refs)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"commit_packed_refs\");\n \tstruct packed_ref_cache *packed_ref_cache =\n \t\tget_packed_ref_cache(refs);\n \tint error = 0;\n \tint save_errno = 0;\n \tFILE *out;\n \n+\tassert_main_repository(&refs->base, \"commit_packed_refs\");\n+\n \tif (!packed_ref_cache->lock)\n \t\tdie(\"internal error: packed-refs not locked\");\n \n@@ -2287,13 +2287,13 @@ static int commit_packed_refs(void)\n  * in-memory packed reference cache.  (The packed-refs file will be\n  * read anew if it is needed again after this function is called.)\n  */\n-static void rollback_packed_refs(void)\n+static void rollback_packed_refs(struct files_ref_store *refs)\n {\n-\tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"rollback_packed_refs\");\n \tstruct packed_ref_cache *packed_ref_cache =\n \t\tget_packed_ref_cache(refs);\n \n+\tassert_main_repository(&refs->base, \"rollback_packed_refs\");\n+\n \tif (!packed_ref_cache->lock)\n \t\tdie(\"internal error: packed-refs not locked\");\n \trollback_lock_file(packed_ref_cache->lock);\n@@ -2439,13 +2439,13 @@ int pack_refs(unsigned int flags)\n \tmemset(&cbdata, 0, sizeof(cbdata));\n \tcbdata.flags = flags;\n \n-\tlock_packed_refs(LOCK_DIE_ON_ERROR);\n+\tlock_packed_refs(refs, LOCK_DIE_ON_ERROR);\n \tcbdata.packed_refs = get_packed_refs(refs);\n \n \tdo_for_each_entry_in_dir(get_loose_refs(refs), 0,\n \t\t\t\t pack_if_possible_fn, &cbdata);\n \n-\tif (commit_packed_refs())\n+\tif (commit_packed_refs(refs))\n \t\tdie_errno(\"unable to overwrite old ref-pack file\");\n \n \tprune_refs(cbdata.ref_to_prune);\n@@ -2481,7 +2481,7 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)\n \tif (!needs_repacking)\n \t\treturn 0; /* no refname exists in packed refs */\n \n-\tif (lock_packed_refs(0)) {\n+\tif (lock_packed_refs(refs, 0)) {\n \t\tunable_to_lock_message(git_path(\"packed-refs\"), errno, err);\n \t\treturn -1;\n \t}\n@@ -2496,12 +2496,12 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)\n \t\t * All packed entries disappeared while we were\n \t\t * acquiring the lock.\n \t\t */\n-\t\trollback_packed_refs();\n+\t\trollback_packed_refs(refs);\n \t\treturn 0;\n \t}\n \n \t/* Write what remains */\n-\tret = commit_packed_refs();\n+\tret = commit_packed_refs(refs);\n \tif (ret)\n \t\tstrbuf_addf(err, \"unable to overwrite old ref-pack file: %s\",\n \t\t\t    strerror(errno));\n@@ -3929,7 +3929,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \t\t}\n \t}\n \n-\tif (lock_packed_refs(0)) {\n+\tif (lock_packed_refs(refs, 0)) {\n \t\tstrbuf_addf(err, \"unable to lock packed-refs file: %s\",\n \t\t\t    strerror(errno));\n \t\tret = TRANSACTION_GENERIC_ERROR;\n@@ -3944,7 +3944,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\tadd_packed_ref(refs, update->refname, update->new_sha1);\n \t}\n \n-\tif (commit_packed_refs()) {\n+\tif (commit_packed_refs(refs)) {\n \t\tstrbuf_addf(err, \"unable to commit packed-refs file: %s\",\n \t\t\t    strerror(errno));\n \t\tret = TRANSACTION_GENERIC_ERROR;\n-- \n2.9.3\n\n"},{"id":"301027","messageId":"a46ef6f70f2ed1e7f9c688e7c5a5845ec05bef40.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 21/38] refs: make pack_refs() virtual","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:27Z","receivedAt":"2016-09-04T16:13:35Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 7 +++++++\n refs/files-backend.c | 6 ++++--\n refs/refs-internal.h | 4 ++++\n 3 files changed, 15 insertions(+), 2 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 662c417..961927a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1421,6 +1421,13 @@ void assert_main_repository(struct ref_store *refs, const char *caller)\n }\n \n /* backend functions */\n+int pack_refs(unsigned int flags)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->pack_refs(refs, flags);\n+}\n+\n int ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t   struct strbuf *err)\n {\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4e1d431..7ad8821 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -2354,10 +2354,10 @@ static void prune_refs(struct ref_to_prune *r)\n \t}\n }\n \n-int pack_refs(unsigned int flags)\n+static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)\n {\n \tstruct files_ref_store *refs =\n-\t\tget_files_ref_store(NULL, \"pack_refs\");\n+\t\tfiles_downcast(ref_store, 0, \"pack_refs\");\n \tstruct pack_refs_cb_data cbdata;\n \n \tmemset(&cbdata, 0, sizeof(cbdata));\n@@ -4032,6 +4032,8 @@ struct ref_storage_be refs_be_files = {\n \tfiles_ref_store_create,\n \tfiles_transaction_commit,\n \n+\tfiles_pack_refs,\n+\n \tfiles_read_raw_ref,\n \tfiles_verify_refname_available\n };\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex 6c698f4..256f7f5 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -500,6 +500,8 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,\n \t\t\t\t      struct ref_transaction *transaction,\n \t\t\t\t      struct strbuf *err);\n \n+typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags);\n+\n /*\n  * Read a reference from the specified reference store, non-recursively.\n  * Set type to describe the reference, and:\n@@ -554,6 +556,8 @@ struct ref_storage_be {\n \tref_store_init_fn *init;\n \tref_transaction_commit_fn *transaction_commit;\n \n+\tpack_refs_fn *pack_refs;\n+\n \tread_raw_ref_fn *read_raw_ref;\n \tverify_refname_available_fn *verify_refname_available;\n };\n-- \n2.9.3\n\n"},{"id":"301028","messageId":"c1b265f4d4476a4dd9ce85aabbfb02b154fee094.1473003903.git.mhagger@alum.mit.edu","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"[PATCH v2 23/38] refs: make peel_ref() virtual","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-04T16:08:29Z","receivedAt":"2016-09-04T16:13:53Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"For now it only supports the main reference store.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c               | 7 +++++++\n refs/files-backend.c | 6 ++++--\n refs/refs-internal.h | 3 +++\n 3 files changed, 14 insertions(+), 2 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 74874e5..f10f86a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1428,6 +1428,13 @@ int pack_refs(unsigned int flags)\n \treturn refs->be->pack_refs(refs, flags);\n }\n \n+int peel_ref(const char *refname, unsigned char *sha1)\n+{\n+\tstruct ref_store *refs = get_ref_store(NULL);\n+\n+\treturn refs->be->peel_ref(refs, refname, sha1);\n+}\n+\n int create_symref(const char *ref_target, const char *refs_heads_master,\n \t\t  const char *logmsg)\n {\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex bf53670..8d43e0b 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1759,9 +1759,10 @@ static enum peel_status peel_entry(struct ref_entry *entry, int repeel)\n \treturn status;\n }\n \n-int peel_ref(const char *refname, unsigned char *sha1)\n+static int files_peel_ref(struct ref_store *ref_store,\n+\t\t\t  const char *refname, unsigned char *sha1)\n {\n-\tstruct files_ref_store *refs = get_files_ref_store(NULL, \"peel_ref\");\n+\tstruct files_ref_store *refs = files_downcast(ref_store, 0, \"peel_ref\");\n \tint flag;\n \tunsigned char base[20];\n \n@@ -4037,6 +4038,7 @@ struct ref_storage_be refs_be_files = {\n \tfiles_transaction_commit,\n \n \tfiles_pack_refs,\n+\tfiles_peel_ref,\n \tfiles_create_symref,\n \n \tfiles_read_raw_ref,\ndiff --git a/refs/refs-internal.h b/refs/refs-internal.h\nindex bf96503..84c81ad 100644\n--- a/refs/refs-internal.h\n+++ b/refs/refs-internal.h\n@@ -501,6 +501,8 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,\n \t\t\t\t      struct strbuf *err);\n \n typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags);\n+typedef int peel_ref_fn(struct ref_store *ref_store,\n+\t\t\tconst char *refname, unsigned char *sha1);\n typedef int create_symref_fn(struct ref_store *ref_store,\n \t\t\t     const char *ref_target,\n \t\t\t     const char *refs_heads_master,\n@@ -561,6 +563,7 @@ struct ref_storage_be {\n \tref_transaction_commit_fn *transaction_commit;\n \n \tpack_refs_fn *pack_refs;\n+\tpeel_ref_fn *peel_ref;\n \tcreate_symref_fn *create_symref;\n \n \tread_raw_ref_fn *read_raw_ref;\n-- \n2.9.3\n\n"},{"id":"301032","messageId":"1473018200.6035.18.camel@frank","threadId":"44001","inReplyTo":"4da46c8dfa4b7ec13927ca8597b64ffff7de4430.1473003902.git.mhagger@alum.mit.edu","subject":"Re: [PATCH v2 04/38] refs: add a backend method structure","fromName":"David Turner","fromEmail":"novalis@novalis.org","sentAt":"2016-09-04T19:43:20Z","receivedAt":"2016-09-04T19:43:36Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Sun, 2016-09-04 at 18:08 +0200, Michael Haggerty wrote:\n> From: Ronnie Sahlberg <sahlberg@google.com>\n> \n> Add a `struct ref_storage_be` to represent types of reference stores. In\n> OO notation, this is the class, and will soon hold some class\n> methods (e.g., a factory to create new ref_store instances) and will\n> also serve as the vtable for ref_store instances of that type.\n> \n> As yet, the backends cannot do anything.\n> \n> Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Jeff King <peff@peff.net>\n> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\n\nnit: duplicate Sign-off from Junio.\n\n\n\n"},{"id":"301075","messageId":"1473021637.6035.27.camel@frank","threadId":"44001","inReplyTo":"39277c75122a374b360057d6e1f6d889a90f6fb4.1473003902.git.mhagger@alum.mit.edu","subject":"Re: [PATCH v2 05/38] refs: create a base class \"ref_store\" for files_ref_store","fromName":"David Turner","fromEmail":"novalis@novalis.org","sentAt":"2016-09-04T20:40:37Z","receivedAt":"2016-09-04T20:40:46Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Sun, 2016-09-04 at 18:08 +0200, Michael Haggerty wrote:\n\n> +/* A linked list of ref_stores for submodules: */\n> +static struct ref_store *submodule_ref_stores;\n\nI don't like the per-submodule stores being in a linked list, which\nrequires a linear search.  Stefan has, I think, been doing a bunch of\nwork to scale git to support on the order of thousands of submodules,\nwhich this potentially breaks.  What about a hashmap?\n\n\n"},{"id":"301078","messageId":"c6ae77bf-e2e2-c108-648d-75b5164b7ba2@alum.mit.edu","threadId":"44001","inReplyTo":"1473021637.6035.27.camel@frank","subject":"Re: [PATCH v2 05/38] refs: create a base class \"ref_store\" for files_ref_store","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-05T03:53:46Z","receivedAt":"2016-09-05T03:54:27Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 09/04/2016 10:40 PM, David Turner wrote:\n> On Sun, 2016-09-04 at 18:08 +0200, Michael Haggerty wrote:\n> \n>> +/* A linked list of ref_stores for submodules: */\n>> +static struct ref_store *submodule_ref_stores;\n> \n> I don't like the per-submodule stores being in a linked list, which\n> requires a linear search.  Stefan has, I think, been doing a bunch of\n> work to scale git to support on the order of thousands of submodules,\n> which this potentially breaks.  What about a hashmap?\n\nI agree it's not ideal, but this linked list is not new. Before this\npatch the same code was in `files-backend.c`, and before patch [03/38]\nessentially the same linked list was stored as `submodule_ref_caches`.\nSo this is not a regression, and I'd rather not address it in this patch\nseries.\n\nCC Stefan in case he'd like to put it on his radar. Honestly, I've never\nchecked how often the submodule reference cache is used in real life.\n\nMichael\n\n"},{"id":"301080","messageId":"d04e8a6c-15c8-a39a-2200-ef20b0cd3a42@gmail.com","threadId":"44001","inReplyTo":"c6ae77bf-e2e2-c108-648d-75b5164b7ba2@alum.mit.edu","subject":"Re: [PATCH v2 05/38] refs: create a base class \"ref_store\" for files_ref_store","fromName":"Stefan Beller","fromEmail":"stefanbeller@gmail.com","sentAt":"2016-09-05T05:17:53Z","receivedAt":"2016-09-05T05:18:00Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On 04.09.2016 20:53, Michael Haggerty wrote:\n> On 09/04/2016 10:40 PM, David Turner wrote:\n>> On Sun, 2016-09-04 at 18:08 +0200, Michael Haggerty wrote:\n>>\n>>> +/* A linked list of ref_stores for submodules: */\n>>> +static struct ref_store *submodule_ref_stores;\n>>\n>> I don't like the per-submodule stores being in a linked list, which\n>> requires a linear search.  Stefan has, I think, been doing a bunch of\n>> work to scale git to support on the order of thousands of submodules,\n>> which this potentially breaks.  What about a hashmap?\n\nWell I did mostly usability up to this point, not efficiency in terms\nof fast execution.\n\n> \n> I agree it's not ideal, but this linked list is not new. Before this\n> patch the same code was in `files-backend.c`, and before patch [03/38]\n> essentially the same linked list was stored as `submodule_ref_caches`.\n> So this is not a regression, and I'd rather not address it in this patch\n> series.\n> \n> CC Stefan in case he'd like to put it on his radar. Honestly, I've never\n> checked how often the submodule reference cache is used in real life.\n\nI think I need to spend some time on the data structures eventually.\n\nThanks for cc'ing\n\nStefan\n\n\n> \n> Michael\n> \n\n"},{"id":"301103","messageId":"1473092212.6035.30.camel@frank","threadId":"44001","inReplyTo":"c6ae77bf-e2e2-c108-648d-75b5164b7ba2@alum.mit.edu","subject":"Re: [PATCH v2 05/38] refs: create a base class \"ref_store\" for files_ref_store","fromName":"David Turner","fromEmail":"novalis@novalis.org","sentAt":"2016-09-05T16:16:52Z","receivedAt":"2016-09-05T16:17:01Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Mon, 2016-09-05 at 05:53 +0200, Michael Haggerty wrote:\n> On 09/04/2016 10:40 PM, David Turner wrote:\n> > On Sun, 2016-09-04 at 18:08 +0200, Michael Haggerty wrote:\n> > \n> >> +/* A linked list of ref_stores for submodules: */\n> >> +static struct ref_store *submodule_ref_stores;\n> > \n> > I don't like the per-submodule stores being in a linked list, which\n> > requires a linear search.  Stefan has, I think, been doing a bunch of\n> > work to scale git to support on the order of thousands of submodules,\n> > which this potentially breaks.  What about a hashmap?\n> \n> I agree it's not ideal, but this linked list is not new. Before this\n> patch the same code was in `files-backend.c`, and before patch [03/38]\n> essentially the same linked list was stored as `submodule_ref_caches`.\n> So this is not a regression, and I'd rather not address it in this patch\n> series.\n\nFair enough!\n\n"},{"id":"301192","messageId":"236a95a0-59d4-3788-9104-5ca299119e66@gmail.com","threadId":"44001","inReplyTo":"f89d56ef0841a3cc35689436c0b9473c6773d22d.1473003902.git.mhagger@alum.mit.edu","subject":"Re: [PATCH v2 02/38] rename_ref_available(): add docstring","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2016-09-06T14:25:38Z","receivedAt":"2016-09-06T14:25:59Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 04.09.2016 o 18:08, Michael Haggerty pisze:\n\n> +/*\n> + * Check whether an attempt to rename old_refname to new_refname would\n> + * cause a D/F conflict with any existing reference (other than\n> + * possibly old_refname). If there would be a conflict, emit an error\n> + * message and return false; otherwise, return true.\n> + *\n> + * Note that this function is not safe against all races with other\n> + * processes (though rename_ref() catches some races that might get by\n> + * this check).\n> + */\n> +int rename_ref_available(const char *old_refname, const char *new_refname);\n\nJust a sidenote: does Git have a naming convention for query functions\nreturning a boolean, for example using is_* as a prefix?  That is, shouldn't\nit be\n\n  int is_rename_ref_available(const char *old_refname, const char *new_refname);\n\nI'm sorry if this is too nitpicky\n-- \nJakub Narębski\n\n"},{"id":"301238","messageId":"8a13500c-55a0-a069-4b69-a651c218ded5@alum.mit.edu","threadId":"44001","inReplyTo":"236a95a0-59d4-3788-9104-5ca299119e66@gmail.com","subject":"Re: [PATCH v2 02/38] rename_ref_available(): add docstring","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-07T04:32:03Z","receivedAt":"2016-09-07T04:32:18Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 09/06/2016 04:25 PM, Jakub Narębski wrote:\n> W dniu 04.09.2016 o 18:08, Michael Haggerty pisze:\n> \n>> +/*\n>> + * Check whether an attempt to rename old_refname to new_refname would\n>> + * cause a D/F conflict with any existing reference (other than\n>> + * possibly old_refname). If there would be a conflict, emit an error\n>> + * message and return false; otherwise, return true.\n>> + *\n>> + * Note that this function is not safe against all races with other\n>> + * processes (though rename_ref() catches some races that might get by\n>> + * this check).\n>> + */\n>> +int rename_ref_available(const char *old_refname, const char *new_refname);\n> \n> Just a sidenote: does Git have a naming convention for query functions\n> returning a boolean, for example using is_* as a prefix?\n\nI've never heard of an official convention like that, and don't see it\ndocumented anywhere. But there are a lot of functions (and variables)\nwhose names start with `is_`, and it seems like a reasonable idea.\n\n> That is, shouldn't it be\n> \n>   int is_rename_ref_available(const char *old_refname, const char *new_refname);\n\nI agree, that would be a better name.\n\nBut that naming change is orthogonal to this patch series, which only\nadds a docstring to the function. I don't think it's worth rerolling\nthis 38-patch series to add it. So I suggest that we keep your idea in\nmind for the next time this code is touched (or feel free to submit a\npatch yourself, preferably on top of this patch series to avoid conflicts).\n\nThanks,\nMichael\n\n"},{"id":"301317","messageId":"xmqqmvjjldp2.fsf@gitster.mtv.corp.google.com","threadId":"44001","inReplyTo":"cover.1473003902.git.mhagger@alum.mit.edu","subject":"Re: [PATCH v2 00/38] Virtualization of the refs API","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-09-07T19:20:09Z","receivedAt":"2016-09-07T19:20:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> This is v2 of the patch series to virtualize the references API\n> (though earlier patch series similar in spirit were submitted by\n> Ronnie Sahlberg and David Turner). Thanks to Junio, Eric, and Ramsay\n> for their comments about v1 [1].\n>\n> Nobody pointed out any fundamental problems with v1, but this version\n> includes the following improvements:\n\nCuriously, many of these improvements were already in 'pu'.\n\n> * In \"rename_ref_available(): add docstring\":\n>\n>   * Improve docstring as suggested by Junio.\n\nI might have squashed that in myself; it is a long time ago so I\ndon't quite remember.\n\n> * In \"refs: create a base class \"ref_store\" for files_ref_store\":\n>\n>   * Let main_ref_store and submodule_ref_stores be initialized\n>     implicitly rather than initializing them explicitly to NULL.\n>\n>   * Add docstrings for those two variables.\n>\n>   * Eliminate a temporary variable in `files_downcast()`.\n\nThis was already in what has been in 'pu'.\n\n> * In \"resolve_gitlink_ref(): avoid memory allocation in many cases\":\n>\n>   * Instead of keeping track of `orig_len`, after stripping off any\n>     trailing slashes check whether `path[len - 1]` is NUL.\n\nThis was already in what has been in 'pu'.\n\n> * In \"refs: add methods for reflog\":\n>\n>   * Don't export `files_reflog_iterator_begin()` (suggested by\n>     Ramsay).\n\nThis I can see was missing in what has been in 'pu'.\n"},{"id":"301367","messageId":"7aac9c43-b8fc-c6fa-6311-4ff7a5495464@alum.mit.edu","threadId":"44001","inReplyTo":"xmqqmvjjldp2.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 00/38] Virtualization of the refs API","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2016-09-08T06:42:08Z","receivedAt":"2016-09-08T06:42:21Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 09/07/2016 09:20 PM, Junio C Hamano wrote:\n> Michael Haggerty <mhagger@alum.mit.edu> writes:\n> \n>> This is v2 of the patch series to virtualize the references API\n>> (though earlier patch series similar in spirit were submitted by\n>> Ronnie Sahlberg and David Turner). Thanks to Junio, Eric, and Ramsay\n>> for their comments about v1 [1].\n>>\n>> Nobody pointed out any fundamental problems with v1, but this version\n>> includes the following improvements:\n> \n> Curiously, many of these improvements were already in 'pu'.\n\nI pushed some of these changes to GitHub a while ago and mentioned that\nfact on the mailing list [1]; I assume you fetched from there. But I was\nwaiting for the dust to settle from the earlier patch series and the\n2.10 release before sending them to the mailing list again.\n\n>> * In \"refs: add methods for reflog\":\n>>\n>>   * Don't export `files_reflog_iterator_begin()` (suggested by\n>>     Ramsay).\n> \n> This I can see was missing in what has been in 'pu'.\n\nAnd according to your \"What's cooking\", you were waiting on this change\nbefore proceeding.\n\nFYI: I haven't done significant work on any next steps, which IMO could\ngo in many possible directions:\n\n* Splitting loose and packed refs storage into two separate ref_store\nsubclasses that are joined together using some kind of\noverlay_ref_store. This is not necessarily a blocker for the following\nideas, but the overlay_ref_store would make it easier to construct other\nhybrid ref-stores, as for example the ubiquitous \"most references are\nstored in main repo; per-worktree refs are stored in worktree\".\n\n* Implementing reference caching as a ref_store that \"writes through\"\nchanges to a backing reference store. This is also not a blocker for\nother ideas, but it would allow reference caching easily to be turned\non/off for other reference stores (or even disabled for packed/loose\nreference storage during command invocations that know they won't have\nto iterate over references more than once).\n\n* A variant of loose reference storage that encodes the reference names\nsomehow before turning them into filenames (1) to make refnames\nindependent of filesystem path-name encoding issues, and (2) to\neliminate D/F conflicts, thereby allowing reflogs to be retained after a\nreference is deleted.\n\n* A reference backend based on LMDB (or any other key-value store).\n\n* A reference backend based on Shawn Pearce's RefTree proposal or\nsomething like it [2].\n\nIt's uncertain when I'll next have a chunk of time to work on any of these.\n\nMichael\n\n[1] http://public-inbox.org/git/575990FB.5000908@alum.mit.edu/\n[2]\nhttp://public-inbox.org/git/CAJo=hJvnAPNAdDcAAwAvU9C4RVeQdoS3Ev9WTguHx4fD0V_nOg@mail.gmail.com/t\n\n"},{"id":"301458","messageId":"1473371131.9503.5.camel@frank","threadId":"44001","inReplyTo":"d4e799241de9186f05187d820707c103bc5b4e8e.1473003903.git.mhagger@alum.mit.edu","subject":"Re: [PATCH v2 38/38] refs: implement iteration over only per-worktree refs","fromName":"David Turner","fromEmail":"novalis@novalis.org","sentAt":"2016-09-08T21:45:31Z","receivedAt":"2016-09-08T21:45:39Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Other than the duplicated sign-offs, this series looks good to me\n(\"Don't act surprised, you guys, cuz I wrote 'em\").\n\nKind of a funny place to cut it off, but I guess it makes sense.\n\nOn Sun, 2016-09-04 at 18:08 +0200, Michael Haggerty wrote:\n> From: David Turner <dturner@twopensource.com>\n> \n> Alternate refs backends might still use files to store per-worktree\n> refs. So provide a way to iterate over only the per-worktree references\n> in a ref_store. The other backend can set up a files ref_store and\n> iterate using the new DO_FOR_EACH_PER_WORKTREE_ONLY flag when iterating.\n\n\n"}]}