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>
This commit is contained in:
Nguyễn Thái Ngọc Duy 2018-08-18 16:41:28 +02:00 коммит произвёл Junio C Hamano
Родитель 5697ca9aa5
Коммит 4592e6080f
5 изменённых файлов: 90 добавлений и 0 удалений

Просмотреть файл

@ -4,6 +4,7 @@
#include "tree-walk.h"
#include "cache-tree.h"
#include "object-store.h"
#include "replace-object.h"
#ifndef DEBUG
#define DEBUG 0
@ -732,3 +733,80 @@ int update_main_cache_tree(int flags)
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);
}

Просмотреть файл

@ -32,6 +32,7 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
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);

Просмотреть файл

@ -2744,6 +2744,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
int new_shared_index, ret;
struct split_index *si = istate->split_index;
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
cache_tree_verify(istate);
if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
if (flags & COMMIT_LOCK)
rollback_lock_file(lock);

Просмотреть файл

@ -1083,6 +1083,12 @@ else
test_set_prereq C_LOCALE_OUTPUT
fi
if test -z "$GIT_TEST_CHECK_CACHE_TREE"
then
GIT_TEST_CHECK_CACHE_TREE=true
export GIT_TEST_CHECK_CACHE_TREE
fi
test_lazy_prereq PIPE '
# test whether the filesystem supports FIFOs
test_have_prereq !MINGW,!CYGWIN &&

Просмотреть файл

@ -1578,6 +1578,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (o->dst_index) {
move_index_extensions(&o->result, o->src_index);
if (!ret) {
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
cache_tree_verify(&o->result);
if (!o->result.cache_tree)
o->result.cache_tree = cache_tree();
if (!cache_tree_fully_valid(o->result.cache_tree))