From: Junio C Hamano Date: Mon, 17 Sep 2018 20:53:53 +0000 (-0700) Subject: Merge branch 'nd/unpack-trees-with-cache-tree' X-Git-Tag: v2.20.0-rc0~245 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/7e794d0a3f7ad4a37541539b823d5b9afdc10ce3 Merge branch 'nd/unpack-trees-with-cache-tree' The unpack_trees() API used in checking out a branch and merging walks one or more trees along with the index. When the cache-tree in the index tells us that we are walking a tree whose flattened contents is known (i.e. matches a span in the index), as linearly scanning a span in the index is much more efficient than having to open tree objects recursively and listing their entries, the walk can be optimized, which is done in this topic. * nd/unpack-trees-with-cache-tree: Document update for nd/unpack-trees-with-cache-tree cache-tree: verify valid cache-tree in the test suite unpack-trees: add missing cache invalidation unpack-trees: reuse (still valid) cache-tree from src_index unpack-trees: reduce malloc in cache-tree walk unpack-trees: optimize walking same trees with cache-tree unpack-trees: add performance tracing trace.h: support nested performance tracing --- 7e794d0a3f7ad4a37541539b823d5b9afdc10ce3 diff --cc cache-tree.c index 16ea022c46,c3c206427c..490a25adf0 --- a/cache-tree.c +++ b/cache-tree.c @@@ -718,3 -726,87 +721,80 @@@ int cache_tree_matches_traversal(struc return it->entry_count; return 0; } + -int update_main_cache_tree(int flags) -{ - if (!the_index.cache_tree) - the_index.cache_tree = cache_tree(); - return cache_tree_update(&the_index, flags); -} - + static void verify_one(struct index_state *istate, + struct cache_tree *it, + struct strbuf *path) + { + int i, pos, len = path->len; + struct strbuf tree_buf = STRBUF_INIT; + struct object_id new_oid; + + for (i = 0; i < it->subtree_nr; i++) { + strbuf_addf(path, "%s/", it->down[i]->name); + verify_one(istate, it->down[i]->cache_tree, path); + strbuf_setlen(path, len); + } + + if (it->entry_count < 0 || + /* no verification on tests (t7003) that replace trees */ + lookup_replace_object(the_repository, &it->oid) != &it->oid) + return; + + if (path->len) { + pos = index_name_pos(istate, path->buf, path->len); + pos = -pos - 1; + } else { + pos = 0; + } + + i = 0; + while (i < it->entry_count) { + struct cache_entry *ce = istate->cache[pos + i]; + const char *slash; + struct cache_tree_sub *sub = NULL; + const struct object_id *oid; + const char *name; + unsigned mode; + int entlen; + + if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE)) + BUG("%s with flags 0x%x should not be in cache-tree", + ce->name, ce->ce_flags); + name = ce->name + path->len; + slash = strchr(name, '/'); + if (slash) { + entlen = slash - name; + sub = find_subtree(it, ce->name + path->len, entlen, 0); + if (!sub || sub->cache_tree->entry_count < 0) + BUG("bad subtree '%.*s'", entlen, name); + oid = &sub->cache_tree->oid; + mode = S_IFDIR; + i += sub->cache_tree->entry_count; + } else { + oid = &ce->oid; + mode = ce->ce_mode; + entlen = ce_namelen(ce) - path->len; + i++; + } + strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0'); + strbuf_add(&tree_buf, oid->hash, the_hash_algo->rawsz); + } + hash_object_file(tree_buf.buf, tree_buf.len, tree_type, &new_oid); + if (oidcmp(&new_oid, &it->oid)) + BUG("cache-tree for path %.*s does not match. " + "Expected %s got %s", len, path->buf, + oid_to_hex(&new_oid), oid_to_hex(&it->oid)); + strbuf_setlen(path, len); + strbuf_release(&tree_buf); + } + + void cache_tree_verify(struct index_state *istate) + { + struct strbuf path = STRBUF_INIT; + + if (!istate->cache_tree) + return; + verify_one(istate, istate->cache_tree, &path); + strbuf_release(&path); + } diff --cc cache-tree.h index fc0c842e77,c1fde531f9..0ab6784ffe --- a/cache-tree.h +++ b/cache-tree.h @@@ -32,7 -32,10 +32,8 @@@ struct cache_tree *cache_tree_read(cons int cache_tree_fully_valid(struct cache_tree *); int cache_tree_update(struct index_state *, int); + void cache_tree_verify(struct index_state *); -int update_main_cache_tree(int); - /* bitmasks to write_cache_as_tree flags */ #define WRITE_TREE_MISSING_OK 1 #define WRITE_TREE_IGNORE_CACHE_TREE 2 diff --cc t/README index 9028b47d92,0e7cc23734..204b9f4cc5 --- a/t/README +++ b/t/README @@@ -315,10 -315,10 +315,14 @@@ packs on demand. This normally only hap over 2GB. This variable forces the code path on any object larger than bytes. +GIT_TEST_OE_DELTA_SIZE= exercises the uncomon pack-objects code +path where deltas larger than this limit require extra memory +allocation for bookkeeping. + + GIT_TEST_VALIDATE_INDEX_CACHE_ENTRIES= checks that cache-tree + records are valid when the index is written out or after a merge. This + is mostly to catch missing invalidation. Default is true. + Naming Tests ------------ diff --cc unpack-trees.c index cfa88bb6ec,515c374373..55f864ac57 --- a/unpack-trees.c +++ b/unpack-trees.c @@@ -456,11 -414,8 +457,12 @@@ static int check_updates(struct unpack_ stop_progress(&progress); errs |= finish_delayed_checkout(&state); if (o->update) - git_attr_set_direction(GIT_ATTR_CHECKIN, NULL); + git_attr_set_direction(GIT_ATTR_CHECKIN); + + if (o->clone) + report_collided_checkout(index); + + trace_performance_leave("check_updates"); return errs != 0; }