read-cache: avoid allocating every ondisk entry when writing
[gitweb.git] / attr.c
diff --git a/attr.c b/attr.c
index 62298ec2fb4ee8368024046a3b86495a25d90696..2f49151736095cf2e2a76ea91d72743df3778a5d 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -9,6 +9,7 @@
 
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
+#include "config.h"
 #include "exec_cmd.h"
 #include "attr.h"
 #include "dir.h"
@@ -75,17 +76,20 @@ struct attr_hash_entry {
 };
 
 /* attr_hashmap comparison function */
-static int attr_hash_entry_cmp(const struct attr_hash_entry *a,
-                              const struct attr_hash_entry *b,
-                              void *unused)
+static int attr_hash_entry_cmp(const void *unused_cmp_data,
+                              const void *entry,
+                              const void *entry_or_key,
+                              const void *unused_keydata)
 {
+       const struct attr_hash_entry *a = entry;
+       const struct attr_hash_entry *b = entry_or_key;
        return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
 }
 
 /* Initialize an 'attr_hashmap' object */
 static void attr_hashmap_init(struct attr_hashmap *map)
 {
-       hashmap_init(&map->map, (hashmap_cmp_fn) attr_hash_entry_cmp, 0);
+       hashmap_init(&map->map, attr_hash_entry_cmp, NULL, 0);
 }
 
 /*
@@ -603,6 +607,23 @@ struct attr_check *attr_check_initl(const char *one, ...)
        return check;
 }
 
+struct attr_check *attr_check_dup(const struct attr_check *check)
+{
+       struct attr_check *ret;
+
+       if (!check)
+               return NULL;
+
+       ret = attr_check_alloc();
+
+       ret->nr = check->nr;
+       ret->alloc = check->alloc;
+       ALLOC_ARRAY(ret->items, ret->nr);
+       COPY_ARRAY(ret->items, check->items, ret->nr);
+
+       return ret;
+}
+
 struct attr_check_item *attr_check_append(struct attr_check *check,
                                          const struct git_attr *attr)
 {
@@ -621,13 +642,11 @@ void attr_check_reset(struct attr_check *check)
 
 void attr_check_clear(struct attr_check *check)
 {
-       free(check->items);
-       check->items = NULL;
+       FREE_AND_NULL(check->items);
        check->alloc = 0;
        check->nr = 0;
 
-       free(check->all_attrs);
-       check->all_attrs = NULL;
+       FREE_AND_NULL(check->all_attrs);
        check->all_attrs_nr = 0;
 
        drop_attr_stack(&check->stack);
@@ -677,38 +696,39 @@ static struct attr_stack *read_attr_from_array(const char **list)
 }
 
 /*
- * NEEDSWORK: these two are tricky.  The callers assume there is a
- * single, system-wide global state "where we read attributes from?"
- * and when the state is flipped by calling git_attr_set_direction(),
- * attr_stack is discarded so that subsequent attr_check will lazily
- * read from the right place.  And they do not know or care who called
- * by them uses the attribute subsystem, hence have no knowledge of
- * existing git_attr_check instances or future ones that will be
- * created).
- *
- * Probably we need a thread_local that holds these two variables,
- * and a list of git_attr_check instances (which need to be maintained
- * by hooking into git_attr_check_alloc(), git_attr_check_initl(), and
- * git_attr_check_clear().  Then git_attr_set_direction() updates the
- * fields in that thread_local for these two variables, iterate over
- * all the active git_attr_check instances and discard the attr_stack
- * they hold.  Yuck, but it sounds doable.
+ * Callers into the attribute system assume there is a single, system-wide
+ * global state where attributes are read from and when the state is flipped by
+ * calling git_attr_set_direction(), the stack frames that have been
+ * constructed need to be discarded so so that subsequent calls into the
+ * attribute system will lazily read from the right place.  Since changing
+ * direction causes a global paradigm shift, it should not ever be called while
+ * another thread could potentially be calling into the attribute system.
  */
 static enum git_attr_direction direction;
 static struct index_state *use_index;
 
+void git_attr_set_direction(enum git_attr_direction new_direction,
+                           struct index_state *istate)
+{
+       if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)
+               die("BUG: non-INDEX attr direction in a bare repo");
+
+       if (new_direction != direction)
+               drop_all_attr_stacks();
+
+       direction = new_direction;
+       use_index = istate;
+}
+
 static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
 {
-       FILE *fp = fopen(path, "r");
+       FILE *fp = fopen_or_warn(path, "r");
        struct attr_stack *res;
        char buf[2048];
        int lineno = 0;
 
-       if (!fp) {
-               if (errno != ENOENT && errno != ENOTDIR)
-                       warn_on_inaccessible(path);
+       if (!fp)
                return NULL;
-       }
        res = xcalloc(1, sizeof(*res));
        while (fgets(buf, sizeof(buf), fp)) {
                char *bufp = buf;
@@ -1148,19 +1168,6 @@ void git_all_attrs(const char *path, struct attr_check *check)
        }
 }
 
-void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
-{
-       enum git_attr_direction old = direction;
-
-       if (is_bare_repository() && new != GIT_ATTR_INDEX)
-               die("BUG: non-INDEX attr direction in a bare repo");
-
-       direction = new;
-       if (new != old)
-               drop_all_attr_stacks();
-       use_index = istate;
-}
-
 void attr_start(void)
 {
 #ifndef NO_PTHREADS