aboutsummaryrefslogtreecommitdiffstats
path: root/cache-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'cache-tree.c')
-rw-r--r--cache-tree.c92
1 files changed, 81 insertions, 11 deletions
diff --git a/cache-tree.c b/cache-tree.c
index 79d168192d..ff794d940f 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -3,6 +3,7 @@
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
+#include "bulk-checkin.h"
#include "object-store.h"
#include "replace-object.h"
#include "promisor-remote.h"
@@ -100,6 +101,33 @@ struct cache_tree_sub *cache_tree_sub(struct cache_tree *it, const char *path)
return find_subtree(it, path, pathlen, 1);
}
+struct cache_tree *cache_tree_find_path(struct cache_tree *it, const char *path)
+{
+ const char *slash;
+ int namelen;
+ struct cache_tree_sub it_sub = {
+ .cache_tree = it,
+ };
+ struct cache_tree_sub *down = &it_sub;
+
+ while (down) {
+ slash = strchrnul(path, '/');
+ namelen = slash - path;
+ down->cache_tree->entry_count = -1;
+ if (!*slash) {
+ int pos;
+ pos = cache_tree_subtree_pos(down->cache_tree, path, namelen);
+ if (0 <= pos)
+ return down->cache_tree->down[pos]->cache_tree;
+ return NULL;
+ }
+ down = find_subtree(it, path, namelen, 0);
+ path = slash + 1;
+ }
+
+ return NULL;
+}
+
static int do_invalidate_path(struct cache_tree *it, const char *path)
{
/* a/b/c
@@ -432,15 +460,15 @@ static int update_one(struct cache_tree *it,
if (repair) {
struct object_id oid;
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
- tree_type, &oid);
+ OBJ_TREE, &oid);
if (has_object_file_with_flags(&oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
oidcpy(&it->oid, &oid);
else
to_invalidate = 1;
} else if (dryrun) {
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
- tree_type, &it->oid);
- } else if (write_object_file_flags(buffer.buf, buffer.len, tree_type,
+ OBJ_TREE, &it->oid);
+ } else if (write_object_file_flags(buffer.buf, buffer.len, OBJ_TREE,
&it->oid, flags & WRITE_TREE_SILENT
? HASH_SILENT : 0)) {
strbuf_release(&buffer);
@@ -474,8 +502,10 @@ int cache_tree_update(struct index_state *istate, int flags)
trace_performance_enter();
trace2_region_enter("cache_tree", "update", the_repository);
+ begin_odb_transaction();
i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
"", 0, &skip, flags);
+ end_odb_transaction();
trace2_region_leave("cache_tree", "update", the_repository);
trace_performance_leave("cache_tree_update");
if (i < 0)
@@ -692,14 +722,14 @@ struct tree* write_in_core_index_as_tree(struct repository *repo) {
ret = write_index_as_tree_internal(&o, index_state, was_valid, 0, NULL);
if (ret == WRITE_TREE_UNMERGED_INDEX) {
int i;
- fprintf(stderr, "BUG: There are unmerged index entries:\n");
+ bug("there are unmerged index entries:");
for (i = 0; i < index_state->cache_nr; i++) {
const struct cache_entry *ce = index_state->cache[i];
if (ce_stage(ce))
- fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce),
- (int)ce_namelen(ce), ce->name);
+ bug("%d %.*s", ce_stage(ce),
+ (int)ce_namelen(ce), ce->name);
}
- BUG("unmerged index entries when writing inmemory index");
+ BUG("unmerged index entries when writing in-core index");
}
return lookup_tree(repo, &index_state->cache_tree->oid);
@@ -741,15 +771,26 @@ out:
return ret;
}
+static void prime_cache_tree_sparse_dir(struct cache_tree *it,
+ struct tree *tree)
+{
+
+ oidcpy(&it->oid, &tree->object.oid);
+ it->entry_count = 1;
+}
+
static void prime_cache_tree_rec(struct repository *r,
struct cache_tree *it,
- struct tree *tree)
+ struct tree *tree,
+ struct strbuf *tree_path)
{
struct tree_desc desc;
struct name_entry entry;
int cnt;
+ int base_path_len = tree_path->len;
oidcpy(&it->oid, &tree->object.oid);
+
init_tree_desc(&desc, tree->buffer, tree->size);
cnt = 0;
while (tree_entry(&desc, &entry)) {
@@ -758,14 +799,40 @@ static void prime_cache_tree_rec(struct repository *r,
else {
struct cache_tree_sub *sub;
struct tree *subtree = lookup_tree(r, &entry.oid);
+
if (!subtree->object.parsed)
parse_tree(subtree);
sub = cache_tree_sub(it, entry.path);
sub->cache_tree = cache_tree();
- prime_cache_tree_rec(r, sub->cache_tree, subtree);
+
+ /*
+ * Recursively-constructed subtree path is only needed when working
+ * in a sparse index (where it's used to determine whether the
+ * subtree is a sparse directory in the index).
+ */
+ if (r->index->sparse_index) {
+ strbuf_setlen(tree_path, base_path_len);
+ strbuf_grow(tree_path, base_path_len + entry.pathlen + 1);
+ strbuf_add(tree_path, entry.path, entry.pathlen);
+ strbuf_addch(tree_path, '/');
+ }
+
+ /*
+ * If a sparse index is in use, the directory being processed may be
+ * sparse. To confirm that, we can check whether an entry with that
+ * exact name exists in the index. If it does, the created subtree
+ * should be sparse. Otherwise, cache tree expansion should continue
+ * as normal.
+ */
+ if (r->index->sparse_index &&
+ index_entry_exists(r->index, tree_path->buf, tree_path->len))
+ prime_cache_tree_sparse_dir(sub->cache_tree, subtree);
+ else
+ prime_cache_tree_rec(r, sub->cache_tree, subtree, tree_path);
cnt += sub->cache_tree->entry_count;
}
}
+
it->entry_count = cnt;
}
@@ -773,11 +840,14 @@ void prime_cache_tree(struct repository *r,
struct index_state *istate,
struct tree *tree)
{
+ struct strbuf tree_path = STRBUF_INIT;
+
trace2_region_enter("cache-tree", "prime_cache_tree", the_repository);
cache_tree_free(&istate->cache_tree);
istate->cache_tree = cache_tree();
- prime_cache_tree_rec(r, istate->cache_tree, tree);
+ prime_cache_tree_rec(r, istate->cache_tree, tree, &tree_path);
+ strbuf_release(&tree_path);
istate->cache_changed |= CACHE_TREE_CHANGED;
trace2_region_leave("cache-tree", "prime_cache_tree", the_repository);
}
@@ -908,7 +978,7 @@ static int verify_one(struct repository *r,
strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0');
strbuf_add(&tree_buf, oid->hash, r->hash_algo->rawsz);
}
- hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, tree_type,
+ hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, OBJ_TREE,
&new_oid);
if (!oideq(&new_oid, &it->oid))
BUG("cache-tree for path %.*s does not match. "