git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 12/20] ref-cache: use a callback function to fill the cache

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Apr 16, 2017, 06:41 UTC
Message-ID
<2e1a785f6a6227eb99af0e60d12ecaa0af63e1fb.1492323985.git.mhagger@alum.mit.edu>
In-Reply-To
<cover.1492323985.git.mhagger@alum.mit.edu>

It is a leveling violation for `ref_cache` to know about `files_ref_store` or that it should call `read_loose_refs()` to lazily fill cache directories. So instead, have its constructor take as an argument a callback function that it should use for lazy-filling, and change `files_ref_store` to supply a pointer to function `read_loose_refs` (renamed to `loose_fill_ref_dir`) when creating the ref cache for its loose refs.

This means that we can generify the type of the back-pointer in `struct ref_cache` from `files_ref_store` to `ref_store`.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 refs/files-backend.c | 10 ++++++----
 refs/ref-cache.c     | 12 +++++++-----
 refs/ref-cache.h     | 29 +++++++++++++++++++++++++----
 3 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 1ed3a30d82..ff9251b9cd 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -386,7 +386,7 @@ static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *ref
 
 		refs->packed = xcalloc(1, sizeof(*refs->packed));
 		acquire_packed_ref_cache(refs->packed);
-		refs->packed->cache = create_ref_cache(refs);
+		refs->packed->cache = create_ref_cache(&refs->base, NULL);
 		refs->packed->cache->root->flag &= ~REF_INCOMPLETE;
 		f = fopen(packed_refs_file, "r");
 		if (f) {
@@ -430,9 +430,11 @@ static void add_packed_ref(struct files_ref_store *refs,
  * (without recursing).  dirname must end with '/'.  dir must be the
  * directory entry corresponding to dirname.
  */
-void read_loose_refs(const char *dirname, struct ref_dir *dir)
+static void loose_fill_ref_dir(struct ref_store *ref_store,
+			       struct ref_dir *dir, const char *dirname)
 {
-	struct files_ref_store *refs = dir->cache->ref_store;
+	struct files_ref_store *refs =
+		files_downcast(ref_store, REF_STORE_READ, "fill_ref_dir");
 	DIR *d;
 	struct dirent *de;
 	int dirnamelen = strlen(dirname);
@@ -515,7 +517,7 @@ static struct ref_dir *get_loose_refs(struct files_ref_store *refs)
 		 * are about to read the only subdirectory that can
 		 * hold references:
 		 */
-		refs->loose = create_ref_cache(refs);
+		refs->loose = create_ref_cache(&refs->base, loose_fill_ref_dir);
 
 		/* We're going to fill the top level ourselves: */
 		refs->loose->root->flag &= ~REF_INCOMPLETE;
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 96da094788..7f247b9170 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -4,9 +4,6 @@
 #include "ref-cache.h"
 #include "../iterator.h"
 
-/* FIXME: This declaration shouldn't be here */
-void read_loose_refs(const char *dirname, struct ref_dir *dir);
-
 void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry)
 {
 	ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);
@@ -25,7 +22,10 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
 	assert(entry->flag & REF_DIR);
 	dir = &entry->u.subdir;
 	if (entry->flag & REF_INCOMPLETE) {
-		read_loose_refs(entry->name, dir);
+		if (!dir->cache->fill_ref_dir)
+			die("BUG: incomplete ref_store without fill_ref_dir function");
+
+		dir->cache->fill_ref_dir(dir->cache->ref_store, dir, entry->name);
 
 		/*
 		 * Manually add refs/bisect, which, being
@@ -63,11 +63,13 @@ struct ref_entry *create_ref_entry(const char *refname,
 	return ref;
 }
 
-struct ref_cache *create_ref_cache(struct files_ref_store *refs)
+struct ref_cache *create_ref_cache(struct ref_store *refs,
+				   fill_ref_dir_fn *fill_ref_dir)
 {
 	struct ref_cache *ret = xcalloc(1, sizeof(*ret));
 
 	ret->ref_store = refs;
+	ret->fill_ref_dir = fill_ref_dir;
 	ret->root = create_dir_entry(ret, "", 0, 1);
 	return ret;
 }
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 83051854ff..ed51e80d88 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -1,11 +1,27 @@
 #ifndef REFS_REF_CACHE_H
 #define REFS_REF_CACHE_H
 
+struct ref_dir;
+
+/*
+ * If this ref_cache is filled lazily, this function is used to load
+ * information into the specified ref_dir (shallow or deep, at the
+ * option of the ref_store). dirname includes a trailing slash.
+ */
+typedef void fill_ref_dir_fn(struct ref_store *ref_store,
+			     struct ref_dir *dir, const char *dirname);
+
 struct ref_cache {
 	struct ref_entry *root;
 
-	/* A pointer to the files_ref_store whose cache this is: */
-	struct files_ref_store *ref_store;
+	/* A pointer to the ref_store whose cache this is: */
+	struct ref_store *ref_store;
+
+	/*
+	 * Function used (if necessary) to lazily-fill cache. May be
+	 * NULL.
+	 */
+	fill_ref_dir_fn *fill_ref_dir;
 };
 
 /*
@@ -174,9 +190,14 @@ struct ref_entry *create_ref_entry(const char *refname,
 
 /*
  * Return a pointer to a new `ref_cache`. Its top-level starts out
- * marked incomplete.
+ * marked incomplete. If `fill_ref_dir` is non-NULL, it is the
+ * function called to fill in incomplete directories in the
+ * `ref_cache` when they are accessed. If it is NULL, then the whole
+ * `ref_cache` must be filled (including clearing its directories'
+ * `REF_INCOMPLETE` bits) before it is used.
  */
-struct ref_cache *create_ref_cache(struct files_ref_store *refs);
+struct ref_cache *create_ref_cache(struct ref_store *refs,
+				   fill_ref_dir_fn *fill_ref_dir);
 
 /*
  * Free the `ref_cache` and all of its associated data.
-- 
2.11.0
Previous: Michael HaggertyNext: Michael Haggerty
Message 10 of 21 in “Separate `ref_cache` into a separate module”
  1. 00/20 Separate `ref_cache` into a separate moduleMichael Haggerty, Apr 16, 2017
  2. 01/20 get_ref_dir(): don't call read_loose_refs() for "refs/bisect"Michael Haggerty, Apr 16, 2017
  3. 02/20 refs_read_raw_ref(): new functionMichael Haggerty, Apr 16, 2017
  4. 04/20 refs_verify_refname_available(): implement once for all backendsMichael Haggerty, Apr 16, 2017
  5. 05/20 refs_verify_refname_available(): use function in more placesMichael Haggerty, Apr 16, 2017
  6. 03/20 refs_ref_iterator_begin(): new functionMichael Haggerty, Apr 16, 2017
  7. 07/20 ref-cache: rename `find_ref()` to `find_ref_entry()`Michael Haggerty, Apr 16, 2017
  8. 06/20 ref-cache: rename `add_ref()` to `add_ref_entry()`Michael Haggerty, Apr 16, 2017
  9. 10/20 ref-cache: introduce a new type, ref_cacheMichael Haggerty, Apr 16, 2017
  10. 12/20 ref-cache: use a callback function to fill the cacheMichael Haggerty, Apr 16, 2017
  11. 13/20 refs: handle "refs/bisect/" in `loose_fill_ref_dir()`Michael Haggerty, Apr 16, 2017
  12. 08/20 ref-cache: rename `remove_entry()` to `remove_entry_from_dir()`Michael Haggerty, Apr 16, 2017
  13. 14/20 do_for_each_entry_in_dir(): eliminate `offset` argumentMichael Haggerty, Apr 16, 2017
  14. 15/20 get_loose_ref_dir(): function renamed from get_loose_refs()Michael Haggerty, Apr 16, 2017
  15. 16/20 get_loose_ref_cache(): new functionMichael Haggerty, Apr 16, 2017
  16. 11/20 refs: record the ref_store in ref_cache, not ref_dirMichael Haggerty, Apr 16, 2017
  17. 20/20 do_for_each_entry_in_dir(): delete functionMichael Haggerty, Apr 16, 2017
  18. 19/20 files_pack_refs(): use reference iterationMichael Haggerty, Apr 16, 2017
  19. 18/20 commit_packed_refs(): use reference iterationMichael Haggerty, Apr 16, 2017
  20. 17/20 cache_ref_iterator_begin(): make function smarterMichael Haggerty, Apr 16, 2017
  21. 09/20 refs: split `ref_cache` code into separate filesMichael Haggerty, Apr 16, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.