Skip to content

Commit 4592e60

Browse files
pcloudsgitster
authored andcommitted
cache-tree: verify valid cache-tree in the test suite
This makes sure that cache-tree is consistent with the index. The main purpose is to catch potential problems by saving the index in unpack_trees() but the line in write_index() would also help spot missing invalidation in other code. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5697ca9 commit 4592e60

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed

cache-tree.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "tree-walk.h"
55
#include "cache-tree.h"
66
#include "object-store.h"
7+
#include "replace-object.h"
78

89
#ifndef DEBUG
910
#define DEBUG 0
@@ -732,3 +733,80 @@ int update_main_cache_tree(int flags)
732733
the_index.cache_tree = cache_tree();
733734
return cache_tree_update(&the_index, flags);
734735
}
736+
737+
static void verify_one(struct index_state *istate,
738+
struct cache_tree *it,
739+
struct strbuf *path)
740+
{
741+
int i, pos, len = path->len;
742+
struct strbuf tree_buf = STRBUF_INIT;
743+
struct object_id new_oid;
744+
745+
for (i = 0; i < it->subtree_nr; i++) {
746+
strbuf_addf(path, "%s/", it->down[i]->name);
747+
verify_one(istate, it->down[i]->cache_tree, path);
748+
strbuf_setlen(path, len);
749+
}
750+
751+
if (it->entry_count < 0 ||
752+
/* no verification on tests (t7003) that replace trees */
753+
lookup_replace_object(the_repository, &it->oid) != &it->oid)
754+
return;
755+
756+
if (path->len) {
757+
pos = index_name_pos(istate, path->buf, path->len);
758+
pos = -pos - 1;
759+
} else {
760+
pos = 0;
761+
}
762+
763+
i = 0;
764+
while (i < it->entry_count) {
765+
struct cache_entry *ce = istate->cache[pos + i];
766+
const char *slash;
767+
struct cache_tree_sub *sub = NULL;
768+
const struct object_id *oid;
769+
const char *name;
770+
unsigned mode;
771+
int entlen;
772+
773+
if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE))
774+
BUG("%s with flags 0x%x should not be in cache-tree",
775+
ce->name, ce->ce_flags);
776+
name = ce->name + path->len;
777+
slash = strchr(name, '/');
778+
if (slash) {
779+
entlen = slash - name;
780+
sub = find_subtree(it, ce->name + path->len, entlen, 0);
781+
if (!sub || sub->cache_tree->entry_count < 0)
782+
BUG("bad subtree '%.*s'", entlen, name);
783+
oid = &sub->cache_tree->oid;
784+
mode = S_IFDIR;
785+
i += sub->cache_tree->entry_count;
786+
} else {
787+
oid = &ce->oid;
788+
mode = ce->ce_mode;
789+
entlen = ce_namelen(ce) - path->len;
790+
i++;
791+
}
792+
strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0');
793+
strbuf_add(&tree_buf, oid->hash, the_hash_algo->rawsz);
794+
}
795+
hash_object_file(tree_buf.buf, tree_buf.len, tree_type, &new_oid);
796+
if (oidcmp(&new_oid, &it->oid))
797+
BUG("cache-tree for path %.*s does not match. "
798+
"Expected %s got %s", len, path->buf,
799+
oid_to_hex(&new_oid), oid_to_hex(&it->oid));
800+
strbuf_setlen(path, len);
801+
strbuf_release(&tree_buf);
802+
}
803+
804+
void cache_tree_verify(struct index_state *istate)
805+
{
806+
struct strbuf path = STRBUF_INIT;
807+
808+
if (!istate->cache_tree)
809+
return;
810+
verify_one(istate, istate->cache_tree, &path);
811+
strbuf_release(&path);
812+
}

cache-tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
3232

3333
int cache_tree_fully_valid(struct cache_tree *);
3434
int cache_tree_update(struct index_state *, int);
35+
void cache_tree_verify(struct index_state *);
3536

3637
int update_main_cache_tree(int);
3738

read-cache.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,6 +2744,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
27442744
int new_shared_index, ret;
27452745
struct split_index *si = istate->split_index;
27462746

2747+
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
2748+
cache_tree_verify(istate);
2749+
27472750
if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
27482751
if (flags & COMMIT_LOCK)
27492752
rollback_lock_file(lock);

t/test-lib.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,12 @@ else
10831083
test_set_prereq C_LOCALE_OUTPUT
10841084
fi
10851085

1086+
if test -z "$GIT_TEST_CHECK_CACHE_TREE"
1087+
then
1088+
GIT_TEST_CHECK_CACHE_TREE=true
1089+
export GIT_TEST_CHECK_CACHE_TREE
1090+
fi
1091+
10861092
test_lazy_prereq PIPE '
10871093
# test whether the filesystem supports FIFOs
10881094
test_have_prereq !MINGW,!CYGWIN &&

unpack-trees.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
15781578
if (o->dst_index) {
15791579
move_index_extensions(&o->result, o->src_index);
15801580
if (!ret) {
1581+
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
1582+
cache_tree_verify(&o->result);
15811583
if (!o->result.cache_tree)
15821584
o->result.cache_tree = cache_tree();
15831585
if (!cache_tree_fully_valid(o->result.cache_tree))

0 commit comments

Comments
 (0)