Merge branch 'sb/object-store-alloc'
authorJunio C Hamano <gitster@pobox.com>
Mon, 25 Jun 2018 20:22:38 +0000 (13:22 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 25 Jun 2018 20:22:38 +0000 (13:22 -0700)
The conversion to pass "the_repository" and then "a_repository"
throughout the object access API continues.

* sb/object-store-alloc:
alloc: allow arbitrary repositories for alloc functions
object: allow create_object to handle arbitrary repositories
object: allow grow_object_hash to handle arbitrary repositories
alloc: add repository argument to alloc_commit_index
alloc: add repository argument to alloc_report
alloc: add repository argument to alloc_object_node
alloc: add repository argument to alloc_tag_node
alloc: add repository argument to alloc_commit_node
alloc: add repository argument to alloc_tree_node
alloc: add repository argument to alloc_blob_node
object: add repository argument to grow_object_hash
object: add repository argument to create_object
repository: introduce parsed objects field

15 files changed:
alloc.c
alloc.h [new file with mode: 0644]
blame.c
blob.c
cache.h
commit.c
commit.h
merge-recursive.c
object.c
object.h
repository.c
repository.h
tag.c
tag.h
tree.c
diff --git a/alloc.c b/alloc.c
index e8ab14f4a12bc65eb32152192af1faf719e3423c..c2fc5d68886bf3f74a1f013a3a36c7b5dcad2258 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -4,8 +4,7 @@
  * Copyright (C) 2006 Linus Torvalds
  *
  * The standard malloc/free wastes too much space for objects, partly because
- * it maintains all the allocation infrastructure (which isn't needed, since
- * we never free an object descriptor anyway), but even more because it ends
+ * it maintains all the allocation infrastructure, but even more because it ends
  * up with maximal alignment because it doesn't know what the object alignment
  * for the new allocation is.
  */
@@ -15,6 +14,7 @@
 #include "tree.h"
 #include "commit.h"
 #include "tag.h"
+#include "alloc.h"
 
 #define BLOCKING 1024
 
@@ -30,8 +30,27 @@ struct alloc_state {
        int count; /* total number of nodes allocated */
        int nr;    /* number of nodes left in current allocation */
        void *p;   /* first free node in current allocation */
+
+       /* bookkeeping of allocations */
+       void **slabs;
+       int slab_nr, slab_alloc;
 };
 
+void *allocate_alloc_state(void)
+{
+       return xcalloc(1, sizeof(struct alloc_state));
+}
+
+void clear_alloc_state(struct alloc_state *s)
+{
+       while (s->slab_nr > 0) {
+               s->slab_nr--;
+               free(s->slabs[s->slab_nr]);
+       }
+
+       FREE_AND_NULL(s->slabs);
+}
+
 static inline void *alloc_node(struct alloc_state *s, size_t node_size)
 {
        void *ret;
@@ -39,60 +58,57 @@ static inline void *alloc_node(struct alloc_state *s, size_t node_size)
        if (!s->nr) {
                s->nr = BLOCKING;
                s->p = xmalloc(BLOCKING * node_size);
+
+               ALLOC_GROW(s->slabs, s->slab_nr + 1, s->slab_alloc);
+               s->slabs[s->slab_nr++] = s->p;
        }
        s->nr--;
        s->count++;
        ret = s->p;
        s->p = (char *)s->p + node_size;
        memset(ret, 0, node_size);
+
        return ret;
 }
 
-static struct alloc_state blob_state;
-void *alloc_blob_node(void)
+void *alloc_blob_node(struct repository *r)
 {
-       struct blob *b = alloc_node(&blob_state, sizeof(struct blob));
+       struct blob *b = alloc_node(r->parsed_objects->blob_state, sizeof(struct blob));
        b->object.type = OBJ_BLOB;
        return b;
 }
 
-static struct alloc_state tree_state;
-void *alloc_tree_node(void)
+void *alloc_tree_node(struct repository *r)
 {
-       struct tree *t = alloc_node(&tree_state, sizeof(struct tree));
+       struct tree *t = alloc_node(r->parsed_objects->tree_state, sizeof(struct tree));
        t->object.type = OBJ_TREE;
        return t;
 }
 
-static struct alloc_state tag_state;
-void *alloc_tag_node(void)
+void *alloc_tag_node(struct repository *r)
 {
-       struct tag *t = alloc_node(&tag_state, sizeof(struct tag));
+       struct tag *t = alloc_node(r->parsed_objects->tag_state, sizeof(struct tag));
        t->object.type = OBJ_TAG;
        return t;
 }
 
-static struct alloc_state object_state;
-void *alloc_object_node(void)
+void *alloc_object_node(struct repository *r)
 {
-       struct object *obj = alloc_node(&object_state, sizeof(union any_object));
+       struct object *obj = alloc_node(r->parsed_objects->object_state, sizeof(union any_object));
        obj->type = OBJ_NONE;
        return obj;
 }
 
-static struct alloc_state commit_state;
-
-unsigned int alloc_commit_index(void)
+unsigned int alloc_commit_index(struct repository *r)
 {
-       static unsigned int count;
-       return count++;
+       return r->parsed_objects->commit_count++;
 }
 
-void *alloc_commit_node(void)
+void *alloc_commit_node(struct repository *r)
 {
-       struct commit *c = alloc_node(&commit_state, sizeof(struct commit));
+       struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit));
        c->object.type = OBJ_COMMIT;
-       c->index = alloc_commit_index();
+       c->index = alloc_commit_index(r);
        c->graph_pos = COMMIT_NOT_FROM_GRAPH;
        c->generation = GENERATION_NUMBER_INFINITY;
        return c;
@@ -105,9 +121,10 @@ static void report(const char *name, unsigned int count, size_t size)
 }
 
 #define REPORT(name, type)     \
-    report(#name, name##_state.count, name##_state.count * sizeof(type) >> 10)
+    report(#name, r->parsed_objects->name##_state->count, \
+                 r->parsed_objects->name##_state->count * sizeof(type) >> 10)
 
-void alloc_report(void)
+void alloc_report(struct repository *r)
 {
        REPORT(blob, struct blob);
        REPORT(tree, struct tree);
diff --git a/alloc.h b/alloc.h
new file mode 100644 (file)
index 0000000..3e4e828
--- /dev/null
+++ b/alloc.h
@@ -0,0 +1,19 @@
+#ifndef ALLOC_H
+#define ALLOC_H
+
+struct tree;
+struct commit;
+struct tag;
+
+void *alloc_blob_node(struct repository *r);
+void *alloc_tree_node(struct repository *r);
+void *alloc_commit_node(struct repository *r);
+void *alloc_tag_node(struct repository *r);
+void *alloc_object_node(struct repository *r);
+void alloc_report(struct repository *r);
+unsigned int alloc_commit_index(struct repository *r);
+
+void *allocate_alloc_state(void);
+void clear_alloc_state(struct alloc_state *s);
+
+#endif
diff --git a/blame.c b/blame.c
index ba1b33c7f4e92c432d4cbdcb43b8d061e436f027..a5c9bd78ab09ce1d1ce40f82ccf13fcc8d973eec 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -6,6 +6,7 @@
 #include "diffcore.h"
 #include "tag.h"
 #include "blame.h"
+#include "alloc.h"
 #include "commit-slab.h"
 
 define_commit_slab(blame_suspects, struct blame_origin *);
@@ -179,7 +180,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
 
        read_cache();
        time(&now);
-       commit = alloc_commit_node();
+       commit = alloc_commit_node(the_repository);
        commit->object.parsed = 1;
        commit->date = now;
        parent_tail = &commit->parents;
diff --git a/blob.c b/blob.c
index fa2ab4f7a74e501366e1d3ceca9285ae60606165..458dafa811edf74e01e10777cf580c696bf0b1a8 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -1,5 +1,7 @@
 #include "cache.h"
 #include "blob.h"
+#include "repository.h"
+#include "alloc.h"
 
 const char *blob_type = "blob";
 
@@ -7,7 +9,8 @@ struct blob *lookup_blob(const struct object_id *oid)
 {
        struct object *obj = lookup_object(oid->hash);
        if (!obj)
-               return create_object(oid->hash, alloc_blob_node());
+               return create_object(the_repository, oid->hash,
+                                    alloc_blob_node(the_repository));
        return object_as_type(obj, OBJ_BLOB, 0);
 }
 
diff --git a/cache.h b/cache.h
index 89a107a7f79175c600eb2a9689982912541ae4e7..d49092d94d1970cc7e07ade8064793fa64d8f362 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1770,15 +1770,6 @@ extern const char *excludes_file;
 int decode_85(char *dst, const char *line, int linelen);
 void encode_85(char *buf, const unsigned char *data, int bytes);
 
-/* alloc.c */
-extern void *alloc_blob_node(void);
-extern void *alloc_tree_node(void);
-extern void *alloc_commit_node(void);
-extern void *alloc_tag_node(void);
-extern void *alloc_object_node(void);
-extern void alloc_report(void);
-extern unsigned int alloc_commit_index(void);
-
 /* pkt-line.c */
 void packet_trace_identity(const char *prog);
 
index 298ad747c6e0d8b1e800b5e643ab0fa6f67cd491..0c3b75aeffea75956adf2190e763b0d753c848c5 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -7,6 +7,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "notes.h"
+#include "alloc.h"
 #include "gpg-interface.h"
 #include "mergesort.h"
 #include "commit-slab.h"
@@ -52,7 +53,8 @@ struct commit *lookup_commit(const struct object_id *oid)
 {
        struct object *obj = lookup_object(oid->hash);
        if (!obj)
-               return create_object(oid->hash, alloc_commit_node());
+               return create_object(the_repository, oid->hash,
+                                    alloc_commit_node(the_repository));
        return object_as_type(obj, OBJ_COMMIT, 0);
 }
 
@@ -325,6 +327,17 @@ struct object_id *get_commit_tree_oid(const struct commit *commit)
        return &get_commit_tree(commit)->object.oid;
 }
 
+void release_commit_memory(struct commit *c)
+{
+       c->maybe_tree = NULL;
+       c->index = 0;
+       free_commit_buffer(c);
+       free_commit_list(c->parents);
+       /* TODO: what about commit->util? */
+
+       c->object.parsed = 0;
+}
+
 const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
 {
        struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
index cb943013d06a58f2e0427a33f5ab718df23e730f..3ad07c2e3d092a97e3bc20091566f4b967b6bc8c 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -119,6 +119,12 @@ void free_commit_buffer(struct commit *);
 struct tree *get_commit_tree(const struct commit *);
 struct object_id *get_commit_tree_oid(const struct commit *);
 
+/*
+ * Release memory related to a commit, including the parent list and
+ * any cached object buffer.
+ */
+void release_commit_memory(struct commit *c);
+
 /*
  * Disassociate any cached object buffer from the commit, but do not free it.
  * The buffer (or NULL, if none) is returned.
index 404f050cafe919023ec86d14230a0f6455714538..bed4a5be02404ef512ba5cfcd9bb33ac04a4ca47 100644 (file)
@@ -15,6 +15,7 @@
 #include "diff.h"
 #include "diffcore.h"
 #include "tag.h"
+#include "alloc.h"
 #include "unpack-trees.h"
 #include "string-list.h"
 #include "xdiff-interface.h"
@@ -160,7 +161,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
 
 static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
 {
-       struct commit *commit = alloc_commit_node();
+       struct commit *commit = alloc_commit_node(the_repository);
 
        set_merge_remote_desc(commit, comment, (struct object *)commit);
        commit->maybe_tree = tree;
index d33e2a5cc84623451a0cc02c0345233675b0340d..10d167825ea8d8048640001f28750dd0834aa169 100644 (file)
--- a/object.c
+++ b/object.c
@@ -5,20 +5,18 @@
 #include "tree.h"
 #include "commit.h"
 #include "tag.h"
+#include "alloc.h"
 #include "object-store.h"
 #include "packfile.h"
 
-static struct object **obj_hash;
-static int nr_objs, obj_hash_size;
-
 unsigned int get_max_object_index(void)
 {
-       return obj_hash_size;
+       return the_repository->parsed_objects->obj_hash_size;
 }
 
 struct object *get_indexed_object(unsigned int idx)
 {
-       return obj_hash[idx];
+       return the_repository->parsed_objects->obj_hash[idx];
 }
 
 static const char *object_type_strings[] = {
@@ -90,15 +88,16 @@ struct object *lookup_object(const unsigned char *sha1)
        unsigned int i, first;
        struct object *obj;
 
-       if (!obj_hash)
+       if (!the_repository->parsed_objects->obj_hash)
                return NULL;
 
-       first = i = hash_obj(sha1, obj_hash_size);
-       while ((obj = obj_hash[i]) != NULL) {
+       first = i = hash_obj(sha1,
+                            the_repository->parsed_objects->obj_hash_size);
+       while ((obj = the_repository->parsed_objects->obj_hash[i]) != NULL) {
                if (!hashcmp(sha1, obj->oid.hash))
                        break;
                i++;
-               if (i == obj_hash_size)
+               if (i == the_repository->parsed_objects->obj_hash_size)
                        i = 0;
        }
        if (obj && i != first) {
@@ -107,7 +106,8 @@ struct object *lookup_object(const unsigned char *sha1)
                 * that we do not need to walk the hash table the next
                 * time we look for it.
                 */
-               SWAP(obj_hash[i], obj_hash[first]);
+               SWAP(the_repository->parsed_objects->obj_hash[i],
+                    the_repository->parsed_objects->obj_hash[first]);
        }
        return obj;
 }
@@ -117,29 +117,30 @@ struct object *lookup_object(const unsigned char *sha1)
  * power of 2 (but at least 32).  Copy the existing values to the new
  * hash map.
  */
-static void grow_object_hash(void)
+static void grow_object_hash(struct repository *r)
 {
        int i;
        /*
         * Note that this size must always be power-of-2 to match hash_obj
         * above.
         */
-       int new_hash_size = obj_hash_size < 32 ? 32 : 2 * obj_hash_size;
+       int new_hash_size = r->parsed_objects->obj_hash_size < 32 ? 32 : 2 * r->parsed_objects->obj_hash_size;
        struct object **new_hash;
 
        new_hash = xcalloc(new_hash_size, sizeof(struct object *));
-       for (i = 0; i < obj_hash_size; i++) {
-               struct object *obj = obj_hash[i];
+       for (i = 0; i < r->parsed_objects->obj_hash_size; i++) {
+               struct object *obj = r->parsed_objects->obj_hash[i];
+
                if (!obj)
                        continue;
                insert_obj_hash(obj, new_hash, new_hash_size);
        }
-       free(obj_hash);
-       obj_hash = new_hash;
-       obj_hash_size = new_hash_size;
+       free(r->parsed_objects->obj_hash);
+       r->parsed_objects->obj_hash = new_hash;
+       r->parsed_objects->obj_hash_size = new_hash_size;
 }
 
-void *create_object(const unsigned char *sha1, void *o)
+void *create_object(struct repository *r, const unsigned char *sha1, void *o)
 {
        struct object *obj = o;
 
@@ -147,11 +148,12 @@ void *create_object(const unsigned char *sha1, void *o)
        obj->flags = 0;
        hashcpy(obj->oid.hash, sha1);
 
-       if (obj_hash_size - 1 <= nr_objs * 2)
-               grow_object_hash();
+       if (r->parsed_objects->obj_hash_size - 1 <= r->parsed_objects->nr_objs * 2)
+               grow_object_hash(r);
 
-       insert_obj_hash(obj, obj_hash, obj_hash_size);
-       nr_objs++;
+       insert_obj_hash(obj, r->parsed_objects->obj_hash,
+                       r->parsed_objects->obj_hash_size);
+       r->parsed_objects->nr_objs++;
        return obj;
 }
 
@@ -161,7 +163,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)
                return obj;
        else if (obj->type == OBJ_NONE) {
                if (type == OBJ_COMMIT)
-                       ((struct commit *)obj)->index = alloc_commit_index();
+                       ((struct commit *)obj)->index = alloc_commit_index(the_repository);
                obj->type = type;
                return obj;
        }
@@ -178,7 +180,8 @@ struct object *lookup_unknown_object(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
        if (!obj)
-               obj = create_object(sha1, alloc_object_node());
+               obj = create_object(the_repository, sha1,
+                                   alloc_object_node(the_repository));
        return obj;
 }
 
@@ -431,8 +434,8 @@ void clear_object_flags(unsigned flags)
 {
        int i;
 
-       for (i=0; i < obj_hash_size; i++) {
-               struct object *obj = obj_hash[i];
+       for (i=0; i < the_repository->parsed_objects->obj_hash_size; i++) {
+               struct object *obj = the_repository->parsed_objects->obj_hash[i];
                if (obj)
                        obj->flags &= ~flags;
        }
@@ -442,13 +445,27 @@ void clear_commit_marks_all(unsigned int flags)
 {
        int i;
 
-       for (i = 0; i < obj_hash_size; i++) {
-               struct object *obj = obj_hash[i];
+       for (i = 0; i < the_repository->parsed_objects->obj_hash_size; i++) {
+               struct object *obj = the_repository->parsed_objects->obj_hash[i];
                if (obj && obj->type == OBJ_COMMIT)
                        obj->flags &= ~flags;
        }
 }
 
+struct parsed_object_pool *parsed_object_pool_new(void)
+{
+       struct parsed_object_pool *o = xmalloc(sizeof(*o));
+       memset(o, 0, sizeof(*o));
+
+       o->blob_state = allocate_alloc_state();
+       o->tree_state = allocate_alloc_state();
+       o->commit_state = allocate_alloc_state();
+       o->tag_state = allocate_alloc_state();
+       o->object_state = allocate_alloc_state();
+
+       return o;
+}
+
 struct raw_object_store *raw_object_store_new(void)
 {
        struct raw_object_store *o = xmalloc(sizeof(*o));
@@ -491,3 +508,43 @@ void raw_object_store_clear(struct raw_object_store *o)
        close_all_packs(o);
        o->packed_git = NULL;
 }
+
+void parsed_object_pool_clear(struct parsed_object_pool *o)
+{
+       /*
+        * As objects are allocated in slabs (see alloc.c), we do
+        * not need to free each object, but each slab instead.
+        *
+        * Before doing so, we need to free any additional memory
+        * the objects may hold.
+        */
+       unsigned i;
+
+       for (i = 0; i < o->obj_hash_size; i++) {
+               struct object *obj = o->obj_hash[i];
+
+               if (!obj)
+                       continue;
+
+               if (obj->type == OBJ_TREE)
+                       free_tree_buffer((struct tree*)obj);
+               else if (obj->type == OBJ_COMMIT)
+                       release_commit_memory((struct commit*)obj);
+               else if (obj->type == OBJ_TAG)
+                       release_tag_memory((struct tag*)obj);
+       }
+
+       FREE_AND_NULL(o->obj_hash);
+       o->obj_hash_size = 0;
+
+       clear_alloc_state(o->blob_state);
+       clear_alloc_state(o->tree_state);
+       clear_alloc_state(o->commit_state);
+       clear_alloc_state(o->tag_state);
+       clear_alloc_state(o->object_state);
+       FREE_AND_NULL(o->blob_state);
+       FREE_AND_NULL(o->tree_state);
+       FREE_AND_NULL(o->commit_state);
+       FREE_AND_NULL(o->tag_state);
+       FREE_AND_NULL(o->object_state);
+}
index acc560b24e4ba57d820b61896ba07d4d3f640f33..47d1b4902263c4059d8b27e17c7d7fc042dc6771 100644 (file)
--- a/object.h
+++ b/object.h
@@ -1,6 +1,22 @@
 #ifndef OBJECT_H
 #define OBJECT_H
 
+struct parsed_object_pool {
+       struct object **obj_hash;
+       int nr_objs, obj_hash_size;
+
+       /* TODO: migrate alloc_states to mem-pool? */
+       struct alloc_state *blob_state;
+       struct alloc_state *tree_state;
+       struct alloc_state *commit_state;
+       struct alloc_state *tag_state;
+       struct alloc_state *object_state;
+       unsigned commit_count;
+};
+
+struct parsed_object_pool *parsed_object_pool_new(void);
+void parsed_object_pool_clear(struct parsed_object_pool *o);
+
 struct object_list {
        struct object *item;
        struct object_list *next;
@@ -85,7 +101,7 @@ extern struct object *get_indexed_object(unsigned int);
  */
 struct object *lookup_object(const unsigned char *sha1);
 
-extern void *create_object(const unsigned char *sha1, void *obj);
+extern void *create_object(struct repository *r, const unsigned char *sha1, void *obj);
 
 void *object_as_type(struct object *obj, enum object_type type, int quiet);
 
index 02fe884603df56ea0996121152b7640afb56a48f..5dd148671811b383a64b8f3adab87804cea9db08 100644 (file)
@@ -2,6 +2,7 @@
 #include "repository.h"
 #include "object-store.h"
 #include "config.h"
+#include "object.h"
 #include "submodule-config.h"
 
 /* The main repository */
@@ -14,6 +15,8 @@ void initialize_the_repository(void)
 
        the_repo.index = &the_index;
        the_repo.objects = raw_object_store_new();
+       the_repo.parsed_objects = parsed_object_pool_new();
+
        repo_set_hash_algo(&the_repo, GIT_HASH_SHA1);
 }
 
@@ -143,6 +146,7 @@ int repo_init(struct repository *repo,
        memset(repo, 0, sizeof(*repo));
 
        repo->objects = raw_object_store_new();
+       repo->parsed_objects = parsed_object_pool_new();
 
        if (repo_init_gitdir(repo, gitdir))
                goto error;
@@ -226,6 +230,9 @@ void repo_clear(struct repository *repo)
        raw_object_store_clear(repo->objects);
        FREE_AND_NULL(repo->objects);
 
+       parsed_object_pool_clear(repo->parsed_objects);
+       FREE_AND_NULL(repo->parsed_objects);
+
        if (repo->config) {
                git_configset_clear(repo->config);
                FREE_AND_NULL(repo->config);
index f2646f0c52aa83f6da8950cfd96c4308498cf417..dba3ddbfdd2d48068d60100425d1a22025cd25b0 100644 (file)
@@ -26,6 +26,15 @@ struct repository {
         */
        struct raw_object_store *objects;
 
+       /*
+        * All objects in this repository that have been parsed. This structure
+        * owns all objects it references, so users of "struct object *"
+        * generally do not need to free them; instead, when a repository is no
+        * longer used, call parsed_object_pool_clear() on this structure, which
+        * is called by the repositories repo_clear on its desconstruction.
+        */
+       struct parsed_object_pool *parsed_objects;
+
        /* The store in which the refs are held. */
        struct ref_store *refs;
 
diff --git a/tag.c b/tag.c
index 3d37c1bd251c5f8c5eb06ede72ab57b323888709..7c12426b4eaba595b9b652fa47952c961306e44f 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -3,6 +3,7 @@
 #include "commit.h"
 #include "tree.h"
 #include "blob.h"
+#include "alloc.h"
 #include "gpg-interface.h"
 
 const char *tag_type = "tag";
@@ -93,7 +94,8 @@ struct tag *lookup_tag(const struct object_id *oid)
 {
        struct object *obj = lookup_object(oid->hash);
        if (!obj)
-               return create_object(oid->hash, alloc_tag_node());
+               return create_object(the_repository, oid->hash,
+                                    alloc_tag_node(the_repository));
        return object_as_type(obj, OBJ_TAG, 0);
 }
 
@@ -114,6 +116,14 @@ static timestamp_t parse_tag_date(const char *buf, const char *tail)
        return parse_timestamp(dateptr, NULL, 10);
 }
 
+void release_tag_memory(struct tag *t)
+{
+       free(t->tag);
+       t->tagged = NULL;
+       t->object.parsed = 0;
+       t->date = 0;
+}
+
 int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)
 {
        struct object_id oid;
diff --git a/tag.h b/tag.h
index d469534e82a87b651abe752469d0547c2b560e10..9057d76a50639d65aae1340b752d2daa7dc67aa9 100644 (file)
--- a/tag.h
+++ b/tag.h
@@ -15,6 +15,7 @@ struct tag {
 extern struct tag *lookup_tag(const struct object_id *oid);
 extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size);
 extern int parse_tag(struct tag *item);
+extern void release_tag_memory(struct tag *t);
 extern struct object *deref_tag(struct object *, const char *, int);
 extern struct object *deref_tag_noverify(struct object *);
 extern int gpg_verify_tag(const struct object_id *oid,
diff --git a/tree.c b/tree.c
index 244eb5e665e931a6b735366d74b5ed2bcbce4c9b..2c9c49725ca0eb311a4e82081a6748db7c8e1fcd 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -5,6 +5,7 @@
 #include "blob.h"
 #include "commit.h"
 #include "tag.h"
+#include "alloc.h"
 #include "tree-walk.h"
 
 const char *tree_type = "tree";
@@ -196,7 +197,8 @@ struct tree *lookup_tree(const struct object_id *oid)
 {
        struct object *obj = lookup_object(oid->hash);
        if (!obj)
-               return create_object(oid->hash, alloc_tree_node());
+               return create_object(the_repository, oid->hash,
+                                    alloc_tree_node(the_repository));
        return object_as_type(obj, OBJ_TREE, 0);
 }