struct object_entry *delta; /* delta base object */
struct packed_git *in_pack; /* already in pack */
unsigned int in_pack_offset;
- struct object_entry *delta_child; /* delitified objects who bases me */
+ struct object_entry *delta_child; /* deltified objects who bases me */
struct object_entry *delta_sibling; /* other deltified objects who
* uses the same base as me
*/
};
/*
- * Objects we are going to pack are colected in objects array (dynamically
+ * Objects we are going to pack are collected in objects array (dynamically
* expanded). nr_objects & nr_alloc controls this array. They are stored
* in the order we see -- typically rev-list --objects order that gives us
* nice "minimum seek" order.
static unsigned char pack_file_sha1[20];
static int progress = 1;
static volatile sig_atomic_t progress_update = 0;
+static int window = 10;
/*
* The object names in objects array are hashed with this hashtable,
rix->revindex = xmalloc(sizeof(unsigned long) * (num_ent + 1));
for (i = 0; i < num_ent; i++) {
- unsigned int hl = *((unsigned int *)(index + 24 * i));
+ unsigned int hl = *((unsigned int *)((char *) index + 24*i));
rix->revindex[i] = ntohl(hl);
}
/* This knows the pack format -- the 20-byte trailer
use_packed_git(p);
datalen = find_packed_object_size(p, entry->in_pack_offset);
- buf = p->pack_base + entry->in_pack_offset;
+ buf = (char *) p->pack_base + entry->in_pack_offset;
sha1write(f, buf, datalen);
unuse_packed_git(p);
hdrlen = 0; /* not really */
}
}
-struct name_path {
- struct name_path *up;
- const char *elem;
- int len;
-};
-
-#define DIRBITS 12
-
-static unsigned name_hash(struct name_path *path, const char *name)
+static unsigned name_hash(const char *name)
{
- struct name_path *p = path;
- const char *n = name + strlen(name);
- unsigned hash = 0, name_hash = 0, name_done = 0;
-
- if (n != name && n[-1] == '\n')
- n--;
- while (name <= --n) {
- unsigned char c = *n;
- if (c == '/' && !name_done) {
- name_hash = hash;
- name_done = 1;
- hash = 0;
- }
- hash = hash * 11 + c;
- }
- if (!name_done) {
- name_hash = hash;
- hash = 0;
- }
- for (p = path; p; p = p->up) {
- hash = hash * 11 + '/';
- n = p->elem + p->len;
- while (p->elem <= --n) {
- unsigned char c = *n;
- hash = hash * 11 + c;
- }
- }
+ unsigned char c;
+ unsigned hash = 0;
+
/*
- * Make sure "Makefile" and "t/Makefile" are hashed separately
- * but close enough.
+ * This effectively just creates a sortable number from the
+ * last sixteen non-whitespace characters. Last characters
+ * count "most", so things that end in ".c" sort together.
*/
- hash = (name_hash<<DIRBITS) | (hash & ((1U<<DIRBITS )-1));
+ while ((c = *name++) != 0) {
+ if (isspace(c))
+ continue;
+ hash = (hash >> 2) + (c << 24);
+ }
return hash;
}
}
static void add_pbase_object(struct tree_desc *tree,
- struct name_path *up,
const char *name,
- int cmplen)
+ int cmplen,
+ const char *fullname)
{
struct name_entry entry;
sha1_object_info(entry.sha1, type, &size))
continue;
if (name[cmplen] != '/') {
- unsigned hash = name_hash(up, name);
+ unsigned hash = name_hash(fullname);
add_object_entry(entry.sha1, hash, 1);
return;
}
if (!strcmp(type, tree_type)) {
struct tree_desc sub;
- struct name_path me;
struct pbase_tree_cache *tree;
const char *down = name+cmplen+1;
int downlen = name_cmp_len(down);
sub.buf = tree->tree_data;
sub.size = tree->tree_size;
- me.up = up;
- me.elem = entry.path;
- me.len = entry.pathlen;
- add_pbase_object(&sub, &me, down, downlen);
+ add_pbase_object(&sub, down, downlen, fullname);
pbase_tree_put(tree);
}
}
for (it = pbase_tree; it; it = it->next) {
if (cmplen == 0) {
- hash = name_hash(NULL, "");
+ hash = name_hash("");
add_object_entry(it->pcache.sha1, hash, 1);
}
else {
struct tree_desc tree;
tree.buf = it->pcache.tree_data;
tree.size = it->pcache.tree_size;
- add_pbase_object(&tree, NULL, name, cmplen);
+ add_pbase_object(&tree, name, cmplen, name);
}
}
}
* one.
*/
static int try_delta(struct unpacked *trg, struct unpacked *src,
- struct delta_index *src_index, unsigned max_depth)
+ unsigned max_depth)
{
struct object_entry *trg_entry = trg->entry;
struct object_entry *src_entry = src->entry;
- unsigned long size, src_size, delta_size, sizediff, max_size;
+ unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;
+ char type[10];
void *delta_buf;
/* Don't bother doing diffs between different types */
if (trg_entry->preferred_base)
return -1;
+ /*
+ * We do not bother to try a delta that we discarded
+ * on an earlier try, but only when reusing delta data.
+ */
+ if (!no_reuse_delta && trg_entry->in_pack &&
+ trg_entry->in_pack == src_entry->in_pack)
+ return 0;
+
/*
* If the current object is at pack edge, take the depth the
* objects that depend on the current object into account --
return 0;
/* Now some size filtering heuristics. */
- size = trg_entry->size;
- max_size = size/2 - 20;
+ trg_size = trg_entry->size;
+ max_size = trg_size/2 - 20;
max_size = max_size * (max_depth - src_entry->depth) / max_depth;
if (max_size == 0)
return 0;
if (trg_entry->delta && trg_entry->delta_size <= max_size)
max_size = trg_entry->delta_size-1;
src_size = src_entry->size;
- sizediff = src_size < size ? size - src_size : 0;
+ sizediff = src_size < trg_size ? trg_size - src_size : 0;
if (sizediff >= max_size)
return 0;
- delta_buf = create_delta(src_index, trg->data, size, &delta_size, max_size);
+ /* Load data if not already done */
+ if (!trg->data) {
+ trg->data = read_sha1_file(trg_entry->sha1, type, &sz);
+ if (sz != trg_size)
+ die("object %s inconsistent object length (%lu vs %lu)",
+ sha1_to_hex(trg_entry->sha1), sz, trg_size);
+ }
+ if (!src->data) {
+ src->data = read_sha1_file(src_entry->sha1, type, &sz);
+ if (sz != src_size)
+ die("object %s inconsistent object length (%lu vs %lu)",
+ sha1_to_hex(src_entry->sha1), sz, src_size);
+ }
+ if (!src->index) {
+ src->index = create_delta_index(src->data, src_size);
+ if (!src->index)
+ die("out of memory");
+ }
+
+ delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
if (!delta_buf)
return 0;
while (--i >= 0) {
struct object_entry *entry = list[i];
struct unpacked *n = array + idx;
- unsigned long size;
- char type[10];
int j;
if (!entry->preferred_base)
free_delta_index(n->index);
n->index = NULL;
free(n->data);
+ n->data = NULL;
n->entry = entry;
- n->data = read_sha1_file(entry->sha1, type, &size);
- if (size != entry->size)
- die("object %s inconsistent object length (%lu vs %lu)",
- sha1_to_hex(entry->sha1), size, entry->size);
j = window;
while (--j > 0) {
m = array + other_idx;
if (!m->entry)
break;
- if (try_delta(n, m, m->index, depth) < 0)
+ if (try_delta(n, m, depth) < 0)
break;
}
/* if we made n a delta, and if n is already at max
if (entry->delta && depth <= entry->depth)
continue;
- n->index = create_delta_index(n->data, size);
- if (!n->index)
- die("out of memory");
-
idx++;
if (idx >= window)
idx = 0;
setitimer(ITIMER_REAL, &v, NULL);
}
+static int git_pack_config(const char *k, const char *v)
+{
+ if(!strcmp(k, "pack.window")) {
+ window = git_config_int(k, v);
+ return 0;
+ }
+ return git_default_config(k, v);
+}
+
int main(int argc, char **argv)
{
SHA_CTX ctx;
char line[40 + 1 + PATH_MAX + 2];
- int window = 10, depth = 10, pack_to_stdout = 0;
+ int depth = 10, pack_to_stdout = 0;
struct object_entry **list;
int num_preferred_base = 0;
int i;
setup_git_directory();
+ git_config(git_pack_config);
progress = isatty(2);
for (i = 1; i < argc; i++) {
local = 1;
continue;
}
+ if (!strcmp("--progress", arg)) {
+ progress = 1;
+ continue;
+ }
if (!strcmp("--incremental", arg)) {
incremental = 1;
continue;
}
if (get_sha1_hex(line, sha1))
die("expected sha1, got garbage:\n %s", line);
- hash = name_hash(NULL, line+41);
+ hash = name_hash(line+41);
add_preferred_base_object(line+41, hash);
add_object_entry(sha1, hash, 0);
}