Merge branch 'jc/cache-tree' into next
* jc/cache-tree: test-dump-cache-tree: report number of subtrees. cache-tree: sort the subtree entries. Teach fsck-objects about cache-tree.
This commit is contained in:
commit
a77ada62a1
92
cache-tree.c
92
cache-tree.c
@ -19,38 +19,75 @@ void cache_tree_free(struct cache_tree **it_p)
|
|||||||
if (!it)
|
if (!it)
|
||||||
return;
|
return;
|
||||||
for (i = 0; i < it->subtree_nr; i++)
|
for (i = 0; i < it->subtree_nr; i++)
|
||||||
cache_tree_free(&it->down[i]->cache_tree);
|
if (it->down[i])
|
||||||
|
cache_tree_free(&it->down[i]->cache_tree);
|
||||||
free(it->down);
|
free(it->down);
|
||||||
free(it);
|
free(it);
|
||||||
*it_p = NULL;
|
*it_p = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int subtree_name_cmp(const char *one, int onelen,
|
||||||
|
const char *two, int twolen)
|
||||||
|
{
|
||||||
|
if (onelen < twolen)
|
||||||
|
return -1;
|
||||||
|
if (twolen < onelen)
|
||||||
|
return 1;
|
||||||
|
return memcmp(one, two, onelen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int subtree_pos(struct cache_tree *it, const char *path, int pathlen)
|
||||||
|
{
|
||||||
|
struct cache_tree_sub **down = it->down;
|
||||||
|
int lo, hi;
|
||||||
|
lo = 0;
|
||||||
|
hi = it->subtree_nr;
|
||||||
|
while (lo < hi) {
|
||||||
|
int mi = (lo + hi) / 2;
|
||||||
|
struct cache_tree_sub *mdl = down[mi];
|
||||||
|
int cmp = subtree_name_cmp(path, pathlen,
|
||||||
|
mdl->name, mdl->namelen);
|
||||||
|
if (!cmp)
|
||||||
|
return mi;
|
||||||
|
if (cmp < 0)
|
||||||
|
hi = mi;
|
||||||
|
else
|
||||||
|
lo = mi + 1;
|
||||||
|
}
|
||||||
|
return -lo-1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct cache_tree_sub *find_subtree(struct cache_tree *it,
|
static struct cache_tree_sub *find_subtree(struct cache_tree *it,
|
||||||
const char *path,
|
const char *path,
|
||||||
int pathlen,
|
int pathlen,
|
||||||
int create)
|
int create)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct cache_tree_sub *down;
|
struct cache_tree_sub *down;
|
||||||
for (i = 0; i < it->subtree_nr; i++) {
|
int pos = subtree_pos(it, path, pathlen);
|
||||||
down = it->down[i];
|
if (0 <= pos)
|
||||||
if (down->namelen == pathlen &&
|
return it->down[pos];
|
||||||
!memcmp(down->name, path, pathlen))
|
|
||||||
return down;
|
|
||||||
}
|
|
||||||
if (!create)
|
if (!create)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
pos = -pos-1;
|
||||||
if (it->subtree_alloc <= it->subtree_nr) {
|
if (it->subtree_alloc <= it->subtree_nr) {
|
||||||
it->subtree_alloc = alloc_nr(it->subtree_alloc);
|
it->subtree_alloc = alloc_nr(it->subtree_alloc);
|
||||||
it->down = xrealloc(it->down, it->subtree_alloc *
|
it->down = xrealloc(it->down, it->subtree_alloc *
|
||||||
sizeof(*it->down));
|
sizeof(*it->down));
|
||||||
}
|
}
|
||||||
|
it->subtree_nr++;
|
||||||
|
|
||||||
down = xmalloc(sizeof(*down) + pathlen + 1);
|
down = xmalloc(sizeof(*down) + pathlen + 1);
|
||||||
down->cache_tree = NULL; /* cache_tree(); */
|
down->cache_tree = NULL;
|
||||||
down->namelen = pathlen;
|
down->namelen = pathlen;
|
||||||
memcpy(down->name, path, pathlen);
|
memcpy(down->name, path, pathlen);
|
||||||
down->name[pathlen] = 0; /* not strictly needed */
|
down->name[pathlen] = 0;
|
||||||
it->down[it->subtree_nr++] = down;
|
|
||||||
|
if (pos < it->subtree_nr)
|
||||||
|
memmove(it->down + pos + 1,
|
||||||
|
it->down + pos,
|
||||||
|
sizeof(down) * (it->subtree_nr - pos - 1));
|
||||||
|
it->down[pos] = down;
|
||||||
return down;
|
return down;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,25 +109,21 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path)
|
|||||||
slash = strchr(path, '/');
|
slash = strchr(path, '/');
|
||||||
it->entry_count = -1;
|
it->entry_count = -1;
|
||||||
if (!slash) {
|
if (!slash) {
|
||||||
int i;
|
int pos;
|
||||||
namelen = strlen(path);
|
namelen = strlen(path);
|
||||||
for (i = 0; i < it->subtree_nr; i++) {
|
pos = subtree_pos(it, path, namelen);
|
||||||
if (it->down[i]->namelen == namelen &&
|
if (0 <= pos) {
|
||||||
!memcmp(it->down[i]->name, path, namelen))
|
cache_tree_free(&it->down[pos]->cache_tree);
|
||||||
break;
|
free(it->down[pos]);
|
||||||
}
|
|
||||||
if (i < it->subtree_nr) {
|
|
||||||
cache_tree_free(&it->down[i]->cache_tree);
|
|
||||||
free(it->down[i]);
|
|
||||||
/* 0 1 2 3 4 5
|
/* 0 1 2 3 4 5
|
||||||
* ^ ^subtree_nr = 6
|
* ^ ^subtree_nr = 6
|
||||||
* i
|
* pos
|
||||||
* move 4 and 5 up one place (2 entries)
|
* move 4 and 5 up one place (2 entries)
|
||||||
* 2 = 6 - 3 - 1 = subtree_nr - i - 1
|
* 2 = 6 - 3 - 1 = subtree_nr - pos - 1
|
||||||
*/
|
*/
|
||||||
memmove(it->down+i, it->down+i+1,
|
memmove(it->down+pos, it->down+pos+1,
|
||||||
sizeof(struct cache_tree_sub *) *
|
sizeof(struct cache_tree_sub *) *
|
||||||
(it->subtree_nr - i - 1));
|
(it->subtree_nr - pos - 1));
|
||||||
it->subtree_nr--;
|
it->subtree_nr--;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -364,6 +397,12 @@ static void *write_one(struct cache_tree *it,
|
|||||||
}
|
}
|
||||||
for (i = 0; i < it->subtree_nr; i++) {
|
for (i = 0; i < it->subtree_nr; i++) {
|
||||||
struct cache_tree_sub *down = it->down[i];
|
struct cache_tree_sub *down = it->down[i];
|
||||||
|
if (i) {
|
||||||
|
struct cache_tree_sub *prev = it->down[i-1];
|
||||||
|
if (subtree_name_cmp(down->name, down->namelen,
|
||||||
|
prev->name, prev->namelen) <= 0)
|
||||||
|
die("fatal - unsorted cache subtree");
|
||||||
|
}
|
||||||
buffer = write_one(down->cache_tree, down->name, down->namelen,
|
buffer = write_one(down->cache_tree, down->name, down->namelen,
|
||||||
buffer, size, offset);
|
buffer, size, offset);
|
||||||
}
|
}
|
||||||
@ -435,14 +474,15 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
|
|||||||
for (i = 0; i < subtree_nr; i++) {
|
for (i = 0; i < subtree_nr; i++) {
|
||||||
/* read each subtree */
|
/* read each subtree */
|
||||||
struct cache_tree *sub;
|
struct cache_tree *sub;
|
||||||
|
struct cache_tree_sub *subtree;
|
||||||
const char *name = buf;
|
const char *name = buf;
|
||||||
int namelen;
|
int namelen;
|
||||||
sub = read_one(&buf, &size);
|
sub = read_one(&buf, &size);
|
||||||
if (!sub)
|
if (!sub)
|
||||||
goto free_return;
|
goto free_return;
|
||||||
namelen = strlen(name);
|
namelen = strlen(name);
|
||||||
it->down[i] = find_subtree(it, name, namelen, 1);
|
subtree = find_subtree(it, name, namelen, 1);
|
||||||
it->down[i]->cache_tree = sub;
|
subtree->cache_tree = sub;
|
||||||
}
|
}
|
||||||
if (subtree_nr != it->subtree_nr)
|
if (subtree_nr != it->subtree_nr)
|
||||||
die("cache-tree: internal error");
|
die("cache-tree: internal error");
|
||||||
|
@ -8,11 +8,12 @@ static void dump_cache_tree(struct cache_tree *it, const char *pfx)
|
|||||||
if (!it)
|
if (!it)
|
||||||
return;
|
return;
|
||||||
if (it->entry_count < 0)
|
if (it->entry_count < 0)
|
||||||
printf("%-40s %s\n", "invalid", pfx);
|
printf("%-40s %s (%d subtrees)\n", "invalid", pfx,
|
||||||
|
it->subtree_nr);
|
||||||
else
|
else
|
||||||
printf("%s %s (%d entries)\n",
|
printf("%s %s (%d entries, %d subtrees)\n",
|
||||||
sha1_to_hex(it->sha1),
|
sha1_to_hex(it->sha1),
|
||||||
pfx, it->entry_count);
|
pfx, it->entry_count, it->subtree_nr);
|
||||||
for (i = 0; i < it->subtree_nr; i++) {
|
for (i = 0; i < it->subtree_nr; i++) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct cache_tree_sub *down = it->down[i];
|
struct cache_tree_sub *down = it->down[i];
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "pack.h"
|
#include "pack.h"
|
||||||
|
#include "cache-tree.h"
|
||||||
|
|
||||||
#define REACHABLE 0x0001
|
#define REACHABLE 0x0001
|
||||||
|
|
||||||
@ -438,6 +439,21 @@ static int fsck_head_link(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fsck_cache_tree(struct cache_tree *it)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (0 <= it->entry_count) {
|
||||||
|
struct object *obj = parse_object(it->sha1);
|
||||||
|
if (obj->type != tree_type)
|
||||||
|
err |= objerror(obj, "non-tree in cache-tree");
|
||||||
|
}
|
||||||
|
for (i = 0; i < it->subtree_nr; i++)
|
||||||
|
err |= fsck_cache_tree(it->down[i]->cache_tree);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i, heads;
|
int i, heads;
|
||||||
@ -547,6 +563,8 @@ int main(int argc, char **argv)
|
|||||||
obj->used = 1;
|
obj->used = 1;
|
||||||
mark_reachable(obj, REACHABLE);
|
mark_reachable(obj, REACHABLE);
|
||||||
}
|
}
|
||||||
|
if (active_cache_tree)
|
||||||
|
fsck_cache_tree(active_cache_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_connectivity();
|
check_connectivity();
|
||||||
|
Loading…
Reference in New Issue
Block a user