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 <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Aug 18, 2018 at 16:41 UTC
4592e6080ff0f9eb0218162be0e40b2d6abc979a
5 files changed
+90
cache-tree.c
+78
@@ -4,6 +4,7 @@
4
#include "tree-walk.h"
5
#include "cache-tree.h"
6
#include "object-store.h"
7
+#include "replace-object.h"
8
9
#ifndef DEBUG
10
#define DEBUG 0
@@ -732,3 +733,80 @@ int update_main_cache_tree(int flags)
733
the_index.cache_tree = cache_tree();
734
return cache_tree_update(&the_index, flags);
735
}
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
+1
@@ -32,6 +32,7 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
32
33
int cache_tree_fully_valid(struct cache_tree *);
34
int cache_tree_update(struct index_state *, int);
35
+void cache_tree_verify(struct index_state *);
36
37
int update_main_cache_tree(int);
38
read-cache.c
+3
@@ -2744,6 +2744,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
2744
int new_shared_index, ret;
2745
struct split_index *si = istate->split_index;
2746
2747
+ if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
2748
+ cache_tree_verify(istate);
2749
+
2750
if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
2751
if (flags & COMMIT_LOCK)
2752
rollback_lock_file(lock);
t/test-lib.sh
+6
@@ -1083,6 +1083,12 @@ else
1083
test_set_prereq C_LOCALE_OUTPUT
1084
fi
1085
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
+
1092
test_lazy_prereq PIPE '
1093
# test whether the filesystem supports FIFOs
1094
test_have_prereq !MINGW,!CYGWIN &&
unpack-trees.c
+2
@@ -1578,6 +1578,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
1578
if (o->dst_index) {
1579
move_index_extensions(&o->result, o->src_index);
1580
if (!ret) {
1581
+ if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
1582
+ cache_tree_verify(&o->result);
1583
if (!o->result.cache_tree)
1584
o->result.cache_tree = cache_tree();
1585
if (!cache_tree_fully_valid(o->result.cache_tree))