static int pack_revindex_ix(struct packed_git *p)
{
- unsigned int ui = (unsigned int) p;
+ unsigned long ui = (unsigned long)p;
int i;
ui = ui ^ (ui >> 16); /* defeat structure alignment */
}
}
-static int add_object_entry(const unsigned char *sha1, const char *name, int exclude)
+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)
+{
+ 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;
+ }
+ }
+ /*
+ * Make sure "Makefile" and "t/Makefile" are hashed separately
+ * but close enough.
+ */
+ hash = (name_hash<<DIRBITS) | (hash & ((1U<<DIRBITS )-1));
+
+ if (0) { /* debug */
+ n = name + strlen(name);
+ if (n != name && n[-1] == '\n')
+ n--;
+ while (name <= --n)
+ fputc(*n, stderr);
+ for (p = path; p; p = p->up) {
+ fputc('/', stderr);
+ n = p->elem + p->len;
+ while (p->elem <= --n)
+ fputc(*n, stderr);
+ }
+ fprintf(stderr, "\t%08x\n", hash);
+ }
+ return hash;
+}
+
+static int add_object_entry(const unsigned char *sha1, unsigned hash, int exclude)
{
- unsigned int hash = 0;
unsigned int idx = nr_objects;
struct object_entry *entry;
struct packed_git *p;
unsigned int found_offset = 0;
struct packed_git *found_pack = NULL;
- int ix;
+ int ix, status = 0;
if (!exclude) {
for (p = packed_git; p; p = p->next) {
if ((entry = locate_object_entry(sha1)) != NULL)
goto already_added;
- while (*name) {
- unsigned char c = *name++;
- if (isspace(c))
- continue;
- hash = hash * 11 + c;
- }
-
if (idx >= nr_alloc) {
unsigned int needed = (idx + 1024) * 3 / 2;
objects = xrealloc(objects, needed * sizeof(*entry));
die("internal error in object hashing.");
object_ix[-1 - ix] = idx + 1;
}
+ status = 1;
already_added:
if (progress_update) {
entry->in_pack_offset = found_offset;
}
}
- return 1;
+ return status;
}
-static void add_pbase_tree(struct tree_desc *tree)
+static void add_pbase_tree(struct tree_desc *tree, struct name_path *up)
{
while (tree->size) {
const unsigned char *sha1;
const char *name;
- unsigned mode;
+ unsigned mode, hash;
unsigned long size;
char type[20];
continue;
if (sha1_object_info(sha1, type, &size))
continue;
- add_object_entry(sha1, name, 1);
+
+ hash = name_hash(up, name);
+ if (!add_object_entry(sha1, hash, 1))
+ continue;
+
if (!strcmp(type, "tree")) {
struct tree_desc sub;
void *elem;
+ struct name_path me;
+
elem = read_sha1_file(sha1, type, &sub.size);
sub.buf = elem;
if (sub.buf) {
- add_pbase_tree(&sub);
+ me.up = up;
+ me.elem = name;
+ me.len = strlen(name);
+ add_pbase_tree(&sub, &me);
free(elem);
}
}
{
struct tree_desc tree;
void *elem;
+
elem = read_object_with_reference(sha1, "tree", &tree.size, NULL);
tree.buf = elem;
if (!tree.buf)
return;
- add_object_entry(sha1, "", 1);
- add_pbase_tree(&tree);
+ if (add_object_entry(sha1, name_hash(NULL, ""), 1))
+ add_pbase_tree(&tree, NULL);
free(elem);
}
prepare_pack_ix();
for (i = 0, entry = objects; i < nr_objects; i++, entry++)
check_object(entry);
- for (i = 0, entry = objects; i < nr_objects; i++, entry++)
- if (!entry->delta && entry->delta_child)
- entry->delta_limit =
- check_delta_limit(entry, 1);
+
+ if (nr_objects == nr_result) {
+ /*
+ * Depth of objects that depend on the entry -- this
+ * is subtracted from depth-max to break too deep
+ * delta chain because of delta data reusing.
+ * However, we loosen this restriction when we know we
+ * are creating a thin pack -- it will have to be
+ * expanded on the other end anyway, so do not
+ * artificially cut the delta chain and let it go as
+ * deep as it wants.
+ */
+ for (i = 0, entry = objects; i < nr_objects; i++, entry++)
+ if (!entry->delta && entry->delta_child)
+ entry->delta_limit =
+ check_delta_limit(entry, 1);
+ }
}
typedef int (*entry_sort_t)(const struct object_entry *, const struct object_entry *);
return memcmp(a->sha1, b->sha1, 20);
}
-static struct object_entry **create_final_object_list()
+static struct object_entry **create_final_object_list(void)
{
struct object_entry **list;
int i, j;
* already have a delta based on preferred
* one is pointless.
*/
- return 0;
+ return -1;
}
else if (!old_preferred)
max_size = cur_entry->delta_size-1;
}
if (get_sha1_hex(line, sha1))
die("expected sha1, got garbage:\n %s", line);
- add_object_entry(sha1, line+40, 0);
+ add_object_entry(sha1, name_hash(NULL, line+41), 0);
}
if (progress)
fprintf(stderr, "Done counting %d objects.\n", nr_objects);