always start looking up objects in the last used pack first
[gitweb.git] / builtin-pack-objects.c
index 930b57a34bf83f1570604af3c5a76e872faa7210..e52332df99d4fc7c3d4643a682147a7397ebb568 100644 (file)
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "attr.h"
 #include "object.h"
 #include "blob.h"
 #include "commit.h"
@@ -40,9 +41,10 @@ struct object_entry {
        enum object_type in_pack_type;  /* could be delta */
        unsigned char in_pack_header_size;
        unsigned char preferred_base; /* we do not pack this, but is available
-                                      * to be used as the base objectto delta
+                                      * to be used as the base object to delta
                                       * objects against.
                                       */
+       unsigned char no_try_delta;
 };
 
 /*
@@ -677,6 +679,12 @@ static void write_pack_file(void)
                stop_progress(&progress_state);
        if (written != nr_result)
                die("wrote %u objects while expecting %u", written, nr_result);
+       /*
+        * We have scanned through [0 ... i).  Since we have written
+        * the correct number of objects,  the remaining [i ... nr_objects)
+        * items must be either already written (due to out-of-order delta base)
+        * or a preferred base.  Count those which are neither and complain if any.
+        */
        for (j = 0; i < nr_objects; i++) {
                struct object_entry *e = objects + i;
                j += !e->offset && !e->preferred_base;
@@ -854,6 +862,9 @@ static unsigned name_hash(const char *name)
        unsigned char c;
        unsigned hash = 0;
 
+       if (!name)
+               return 0;
+
        /*
         * This effectively just creates a sortable number from the
         * last sixteen non-whitespace characters. Last characters
@@ -867,13 +878,36 @@ static unsigned name_hash(const char *name)
        return hash;
 }
 
+static void setup_delta_attr_check(struct git_attr_check *check)
+{
+       static struct git_attr *attr_delta;
+
+       if (!attr_delta)
+               attr_delta = git_attr("delta", 5);
+
+       check[0].attr = attr_delta;
+}
+
+static int no_try_delta(const char *path)
+{
+       struct git_attr_check check[1];
+
+       setup_delta_attr_check(check);
+       if (git_checkattr(path, ARRAY_SIZE(check), check))
+               return 0;
+       if (ATTR_FALSE(check->value))
+               return 1;
+       return 0;
+}
+
 static int add_object_entry(const unsigned char *sha1, enum object_type type,
-                           unsigned hash, int exclude)
+                           const char *name, int exclude)
 {
        struct object_entry *entry;
        struct packed_git *p, *found_pack = NULL;
        off_t found_offset = 0;
        int ix;
+       unsigned hash = name_hash(name);
 
        ix = nr_objects ? locate_object_entry_hash(sha1) : -1;
        if (ix >= 0) {
@@ -930,6 +964,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
        if (progress)
                display_progress(&progress_state, nr_objects);
 
+       if (name && no_try_delta(name))
+               entry->no_try_delta = 1;
+
        return 1;
 }
 
@@ -1062,10 +1099,9 @@ static void add_pbase_object(struct tree_desc *tree,
                if (cmp < 0)
                        return;
                if (name[cmplen] != '/') {
-                       unsigned hash = name_hash(fullname);
                        add_object_entry(entry.sha1,
                                         S_ISDIR(entry.mode) ? OBJ_TREE : OBJ_BLOB,
-                                        hash, 1);
+                                        fullname, 1);
                        return;
                }
                if (S_ISDIR(entry.mode)) {
@@ -1125,10 +1161,11 @@ static int check_pbase_path(unsigned hash)
        return 0;
 }
 
-static void add_preferred_base_object(const char *name, unsigned hash)
+static void add_preferred_base_object(const char *name)
 {
        struct pbase_tree *it;
        int cmplen;
+       unsigned hash = name_hash(name);
 
        if (!num_preferred_base || check_pbase_path(hash))
                return;
@@ -1136,7 +1173,7 @@ static void add_preferred_base_object(const char *name, unsigned hash)
        cmplen = name_cmp_len(name);
        for (it = pbase_tree; it; it = it->next) {
                if (cmplen == 0) {
-                       add_object_entry(it->pcache.sha1, OBJ_TREE, 0, 1);
+                       add_object_entry(it->pcache.sha1, OBJ_TREE, NULL, 1);
                }
                else {
                        struct tree_desc tree;
@@ -1478,6 +1515,10 @@ static void find_deltas(struct object_entry **list, int window, int depth)
 
                if (entry->size < 50)
                        continue;
+
+               if (entry->no_try_delta)
+                       continue;
+
                free_delta_index(n->index);
                n->index = NULL;
                free(n->data);
@@ -1577,7 +1618,6 @@ static void read_object_list_from_stdin(void)
 {
        char line[40 + 1 + PATH_MAX + 2];
        unsigned char sha1[20];
-       unsigned hash;
 
        for (;;) {
                if (!fgets(line, sizeof(line), stdin)) {
@@ -1600,22 +1640,20 @@ static void read_object_list_from_stdin(void)
                if (get_sha1_hex(line, sha1))
                        die("expected sha1, got garbage:\n %s", line);
 
-               hash = name_hash(line+41);
-               add_preferred_base_object(line+41, hash);
-               add_object_entry(sha1, 0, hash, 0);
+               add_preferred_base_object(line+41);
+               add_object_entry(sha1, 0, line+41, 0);
        }
 }
 
 static void show_commit(struct commit *commit)
 {
-       add_object_entry(commit->object.sha1, OBJ_COMMIT, 0, 0);
+       add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
 }
 
 static void show_object(struct object_array_entry *p)
 {
-       unsigned hash = name_hash(p->name);
-       add_preferred_base_object(p->name, hash);
-       add_object_entry(p->item->sha1, p->item->type, hash, 0);
+       add_preferred_base_object(p->name);
+       add_object_entry(p->item->sha1, p->item->type, p->name, 0);
 }
 
 static void show_edge(struct commit *commit)
@@ -1818,6 +1856,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (pack_to_stdout != !base_name)
                usage(pack_usage);
 
+       if (pack_to_stdout && pack_size_limit)
+               die("--max-pack-size cannot be used to build a pack for transfer.");
+
        if (!pack_to_stdout && thin)
                die("--thin cannot be used to build an indexable pack.");