From 54edbb9871ad543baefc62310512719fc70539be Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 7 Feb 2014 16:48:27 -0800 Subject: [PATCH] Add index snapshot and use it for iterator --- src/index.c | 42 +++++++++++++++++++++++++++++++++--------- src/index.h | 12 ++++++++++++ src/iterator.c | 35 ++++++++++++++++++++++------------- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/index.c b/src/index.c index 8bc5cb13c..58b359bfe 100644 --- a/src/index.c +++ b/src/index.c @@ -1056,21 +1056,26 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage) return error; } -int git_index__find( - size_t *out, git_index *index, const char *path, size_t path_len, int stage) +int git_index__find_in_entries( + size_t *out, git_vector *entries, git_vector_cmp entry_cmp, + const char *path, size_t path_len, int stage) { struct entry_srch_key srch_key; - - assert(path); - - git_vector_sort(&index->entries); - srch_key.path = path; srch_key.path_len = !path_len ? strlen(path) : path_len; srch_key.stage = stage; + return git_vector_bsearch2(out, entries, entry_cmp, &srch_key); +} - return git_vector_bsearch2( - out, &index->entries, index->entries_search, &srch_key); +int git_index__find( + size_t *out, git_index *index, const char *path, size_t path_len, int stage) +{ + assert(index && path); + + git_vector_sort(&index->entries); + + return git_index__find_in_entries( + out, &index->entries, index->entries_search, path, path_len, stage); } int git_index_find(size_t *at_pos, git_index *index, const char *path) @@ -2442,3 +2447,22 @@ int git_index_update_all( return error; } + +int git_index__snapshot(git_vector *entries, git_index *index) +{ + int error; + + GIT_REFCOUNT_INC(index); + git_vector_sort(&index->entries); + error = git_vector_dup(entries, &index->entries, index->entries._cmp); + + if (error < 0) + git_index_free(index); + + return error; +} + +void git_index__release_snapshot(git_index *index) +{ + git_index_free(index); +} diff --git a/src/index.h b/src/index.h index cabdbca30..2b6f5c98b 100644 --- a/src/index.h +++ b/src/index.h @@ -71,4 +71,16 @@ GIT_INLINE(const git_futils_filestamp *) git_index__filestamp(git_index *index) extern int git_index__changed_relative_to(git_index *index, const git_futils_filestamp *fs); +/* Copy the current entries vector *and* increment the index refcount. + * Call `git_index__release_snapshot` when done. + */ +extern int git_index__snapshot(git_vector *entries, git_index *index); +extern void git_index__release_snapshot(git_index *index); + +/* Allow searching in a snapshot; entries must already be sorted! */ +extern int git_index__find_in_entries( + size_t *at_pos, + git_vector *entries, git_vector_cmp entry_cmp, + const char *path, size_t path_len, int stage); + #endif diff --git a/src/iterator.c b/src/iterator.c index 45655254c..a84f4d3db 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -644,6 +644,8 @@ typedef struct { git_iterator base; git_iterator_callbacks cb; git_index *index; + git_vector entries; + git_vector_cmp entry_srch; size_t current; /* when not in autoexpand mode, use these to represent "tree" state */ git_buf partial; @@ -654,10 +656,10 @@ typedef struct { static const git_index_entry *index_iterator__index_entry(index_iterator *ii) { - const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); + const git_index_entry *ie = git_vector_get(&ii->entries, ii->current); if (ie != NULL && iterator__past_end(ii, ie->path)) { - ii->current = git_index_entrycount(ii->index); + ii->current = git_vector_length(&ii->entries); ie = NULL; } @@ -726,7 +728,7 @@ static int index_iterator__current( const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; - const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); + const git_index_entry *ie = git_vector_get(&ii->entries, ii->current); if (ie != NULL && index_iterator__at_tree(ii)) { ii->tree_entry.path = ii->partial.ptr; @@ -744,14 +746,14 @@ static int index_iterator__current( static int index_iterator__at_end(git_iterator *self) { index_iterator *ii = (index_iterator *)self; - return (ii->current >= git_index_entrycount(ii->index)); + return (ii->current >= git_vector_length(&ii->entries)); } static int index_iterator__advance( const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; - size_t entrycount = git_index_entrycount(ii->index); + size_t entrycount = git_vector_length(&ii->entries); const git_index_entry *ie; if (!iterator__has_been_accessed(ii)) @@ -766,7 +768,7 @@ static int index_iterator__advance( while (ii->current < entrycount) { ii->current++; - if (!(ie = git_index_get_byindex(ii->index, ii->current)) || + if (!(ie = git_vector_get(&ii->entries, ii->current)) || ii->base.prefixcomp(ie->path, ii->partial.ptr) != 0) break; } @@ -789,7 +791,7 @@ static int index_iterator__advance_into( const git_index_entry **entry, git_iterator *self) { index_iterator *ii = (index_iterator *)self; - const git_index_entry *ie = git_index_get_byindex(ii->index, ii->current); + const git_index_entry *ie = git_vector_get(&ii->entries, ii->current); if (ie != NULL && index_iterator__at_tree(ii)) { if (ii->restore_terminator) @@ -818,7 +820,8 @@ static int index_iterator__reset( ii->current = 0; if (ii->base.start) - git_index__find(&ii->current, ii->index, ii->base.start, 0, 0); + git_index__find_in_entries( + &ii->current, &ii->entries, ii->entry_srch, ii->base.start, 0, 0); if ((ie = index_iterator__skip_conflicts(ii)) == NULL) return 0; @@ -843,9 +846,9 @@ static int index_iterator__reset( static void index_iterator__free(git_iterator *self) { index_iterator *ii = (index_iterator *)self; - git_index_free(ii->index); + git_index__release_snapshot(ii->index); ii->index = NULL; - + git_vector_free(&ii->entries); git_buf_free(&ii->partial); } @@ -856,9 +859,17 @@ int git_iterator_for_index( const char *start, const char *end) { + int error = 0; index_iterator *ii = git__calloc(1, sizeof(index_iterator)); GITERR_CHECK_ALLOC(ii); + if ((error = git_index__snapshot(&ii->entries, index)) < 0) { + git__free(ii); + return error; + } + ii->index = index; + ii->entry_srch = index->entries_search; + ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index)); if (index->ignore_case) { @@ -866,8 +877,7 @@ int git_iterator_for_index( ii->base.prefixcomp = git__prefixcmp_icase; } - ii->index = index; - GIT_REFCOUNT_INC(index); + /* TODO: resort entries to match desired ignore_case behavior */ git_buf_init(&ii->partial, 0); ii->tree_entry.mode = GIT_FILEMODE_TREE; @@ -875,7 +885,6 @@ int git_iterator_for_index( index_iterator__reset((git_iterator *)ii, NULL, NULL); *iter = (git_iterator *)ii; - return 0; }