From 8738a8a4df9ee50112b5f5a757c58988166974d3 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 13 Sep 2017 19:15:55 +0200 Subject: ref_iterator: keep track of whether the iterator output is ordered References are iterated over in order by refname, but reflogs are not. Some consumers of reference iteration care about the difference. Teach each `ref_iterator` to keep track of whether its output is ordered. `overlay_ref_iterator` is one of the picky consumers. Add a sanity check in `overlay_ref_iterator_begin()` to verify that its inputs are ordered. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- refs/refs-internal.h | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'refs/refs-internal.h') diff --git a/refs/refs-internal.h b/refs/refs-internal.h index d7d344de73..d7f233beba 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -329,6 +329,13 @@ int refs_rename_ref_available(struct ref_store *refs, */ struct ref_iterator { struct ref_iterator_vtable *vtable; + + /* + * Does this `ref_iterator` iterate over references in order + * by refname? + */ + unsigned int ordered : 1; + const char *refname; const struct object_id *oid; unsigned int flags; @@ -374,7 +381,7 @@ int is_empty_ref_iterator(struct ref_iterator *ref_iterator); * which the refname begins with prefix. If trim is non-zero, then * trim that many characters off the beginning of each refname. flags * can be DO_FOR_EACH_INCLUDE_BROKEN to include broken references in - * the iteration. + * the iteration. The output is ordered by refname. */ struct ref_iterator *refs_ref_iterator_begin( struct ref_store *refs, @@ -400,9 +407,11 @@ typedef enum iterator_selection ref_iterator_select_fn( * Iterate over the entries from iter0 and iter1, with the values * interleaved as directed by the select function. The iterator takes * ownership of iter0 and iter1 and frees them when the iteration is - * over. + * over. A derived class should set `ordered` to 1 or 0 based on + * whether it generates its output in order by reference name. */ struct ref_iterator *merge_ref_iterator_begin( + int ordered, struct ref_iterator *iter0, struct ref_iterator *iter1, ref_iterator_select_fn *select, void *cb_data); @@ -431,6 +440,8 @@ struct ref_iterator *overlay_ref_iterator_begin( * As an convenience to callers, if prefix is the empty string and * trim is zero, this function returns iter0 directly, without * wrapping it. + * + * The resulting ref_iterator is ordered if iter0 is. */ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0, const char *prefix, @@ -441,11 +452,14 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0, /* * Base class constructor for ref_iterators. Initialize the * ref_iterator part of iter, setting its vtable pointer as specified. + * `ordered` should be set to 1 if the iterator will iterate over + * references in order by refname; otherwise it should be set to 0. * This is meant to be called only by the initializers of derived * classes. */ void base_ref_iterator_init(struct ref_iterator *iter, - struct ref_iterator_vtable *vtable); + struct ref_iterator_vtable *vtable, + int ordered); /* * Base class destructor for ref_iterators. Destroy the ref_iterator @@ -564,7 +578,8 @@ typedef int rename_ref_fn(struct ref_store *ref_store, * Iterate over the references in `ref_store` whose names start with * `prefix`. `prefix` is matched as a literal string, without regard * for path separators. If prefix is NULL or the empty string, iterate - * over all references in `ref_store`. + * over all references in `ref_store`. The output is ordered by + * refname. */ typedef struct ref_iterator *ref_iterator_begin_fn( struct ref_store *ref_store, -- cgit v1.3-5-g9baa From ba1c052fa616eb93a654375e8b9d59daa47c28a8 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Mon, 25 Sep 2017 10:00:14 +0200 Subject: ref_store: implement `refs_peel_ref()` generically We're about to stop storing packed refs in a `ref_cache`. That means that the only way we have left to optimize `peel_ref()` is by checking whether the reference being peeled is the one currently being iterated over (in `current_ref_iter`), and if so, using `ref_iterator_peel()`. But this can be done generically; it doesn't have to be implemented per-backend. So implement `refs_peel_ref()` in `refs.c` and remove the `peel_ref()` method from the refs API. This removes the last callers of a couple of functions, so delete them. More cleanup to come... Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- refs.c | 18 +++++++++++++++++- refs/files-backend.c | 38 -------------------------------------- refs/packed-backend.c | 36 ------------------------------------ refs/refs-internal.h | 3 --- 4 files changed, 17 insertions(+), 78 deletions(-) (limited to 'refs/refs-internal.h') diff --git a/refs.c b/refs.c index 101c107ee8..c5e6f79c77 100644 --- a/refs.c +++ b/refs.c @@ -1735,7 +1735,23 @@ int refs_pack_refs(struct ref_store *refs, unsigned int flags) int refs_peel_ref(struct ref_store *refs, const char *refname, unsigned char *sha1) { - return refs->be->peel_ref(refs, refname, sha1); + int flag; + unsigned char base[20]; + + if (current_ref_iter && current_ref_iter->refname == refname) { + struct object_id peeled; + + if (ref_iterator_peel(current_ref_iter, &peeled)) + return -1; + hashcpy(sha1, peeled.hash); + return 0; + } + + if (refs_read_ref_full(refs, refname, + RESOLVE_REF_READING, base, &flag)) + return -1; + + return peel_object(base, sha1); } int peel_ref(const char *refname, unsigned char *sha1) diff --git a/refs/files-backend.c b/refs/files-backend.c index 35648c89fc..7d12de88d0 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -655,43 +655,6 @@ out: return ret; } -static int files_peel_ref(struct ref_store *ref_store, - const char *refname, unsigned char *sha1) -{ - struct files_ref_store *refs = - files_downcast(ref_store, REF_STORE_READ | REF_STORE_ODB, - "peel_ref"); - int flag; - unsigned char base[20]; - - if (current_ref_iter && current_ref_iter->refname == refname) { - struct object_id peeled; - - if (ref_iterator_peel(current_ref_iter, &peeled)) - return -1; - hashcpy(sha1, peeled.hash); - return 0; - } - - if (refs_read_ref_full(ref_store, refname, - RESOLVE_REF_READING, base, &flag)) - return -1; - - /* - * If the reference is packed, read its ref_entry from the - * cache in the hope that we already know its peeled value. - * We only try this optimization on packed references because - * (a) forcing the filling of the loose reference cache could - * be expensive and (b) loose references anyway usually do not - * have REF_KNOWS_PEELED. - */ - if (flag & REF_ISPACKED && - !refs_peel_ref(refs->packed_ref_store, refname, sha1)) - return 0; - - return peel_object(base, sha1); -} - struct files_ref_iterator { struct ref_iterator base; @@ -3012,7 +2975,6 @@ struct ref_storage_be refs_be_files = { files_initial_transaction_commit, files_pack_refs, - files_peel_ref, files_create_symref, files_delete_refs, files_rename_ref, diff --git a/refs/packed-backend.c b/refs/packed-backend.c index be614e79f5..dbbba45502 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -850,26 +850,6 @@ static struct packed_ref_cache *get_packed_ref_cache(struct packed_ref_store *re return refs->cache; } -static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache *packed_ref_cache) -{ - return get_ref_dir(packed_ref_cache->cache->root); -} - -static struct ref_dir *get_packed_refs(struct packed_ref_store *refs) -{ - return get_packed_ref_dir(get_packed_ref_cache(refs)); -} - -/* - * Return the ref_entry for the given refname from the packed - * references. If it does not exist, return NULL. - */ -static struct ref_entry *get_packed_ref(struct packed_ref_store *refs, - const char *refname) -{ - return find_ref_entry(get_packed_refs(refs), refname); -} - static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname, unsigned char *sha1, struct strbuf *referent, unsigned int *type) @@ -896,21 +876,6 @@ static int packed_read_raw_ref(struct ref_store *ref_store, return 0; } -static int packed_peel_ref(struct ref_store *ref_store, - const char *refname, unsigned char *sha1) -{ - struct packed_ref_store *refs = - packed_downcast(ref_store, REF_STORE_READ | REF_STORE_ODB, - "peel_ref"); - struct ref_entry *r = get_packed_ref(refs, refname); - - if (!r || peel_entry(r, 0)) - return -1; - - hashcpy(sha1, r->u.value.peeled.hash); - return 0; -} - struct packed_ref_iterator { struct ref_iterator base; @@ -1597,7 +1562,6 @@ struct ref_storage_be refs_be_packed = { packed_initial_transaction_commit, packed_pack_refs, - packed_peel_ref, packed_create_symref, packed_delete_refs, packed_rename_ref, diff --git a/refs/refs-internal.h b/refs/refs-internal.h index d7f233beba..cc6c373f59 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -562,8 +562,6 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs, struct strbuf *err); typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags); -typedef int peel_ref_fn(struct ref_store *ref_store, - const char *refname, unsigned char *sha1); typedef int create_symref_fn(struct ref_store *ref_store, const char *ref_target, const char *refs_heads_master, @@ -668,7 +666,6 @@ struct ref_storage_be { ref_transaction_commit_fn *initial_transaction_commit; pack_refs_fn *pack_refs; - peel_ref_fn *peel_ref; create_symref_fn *create_symref; delete_refs_fn *delete_refs; rename_ref_fn *rename_ref; -- cgit v1.3-5-g9baa