{"thread":{"id":"10751","subject":"[PATCH 03/11] Define free_all_objects to deallocate object pools","startedAt":"2007-11-09T11:06:16Z","lastAt":"2007-11-09T11:06:16Z","messageCount":1,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":11},"messages":[{"id":"59020","messageId":"20071109110616.GC19368@spearce.org","threadId":"10751","inReplyTo":null,"subject":"[PATCH 03/11] Define free_all_objects to deallocate object pools","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-11-09T11:06:16Z","receivedAt":"2007-11-09T11:06:16Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The new API call free_all_objects releases all struct objects that\nhave been allocated thus far in the process, invalidating all of\nthose pointers and clearing out the object hash.  This resets the\nprocess to before any objects were parsed and allocated, allowing\na future revision walk to start from a clean slate without needing\nto clear_commit_marks() first, or worry about parent rewriting.\n\nThe release routines support recursively releasing any buffers held\nby an active object through object specific scrub functions.  These\nonly need to free any buffers that had been held by the object and\nare not yet released as any other clearing activity would be handled\nby the next user of the memory.\n\nPerformance testing with `git rev-list --objects --all` shows that\ncalling free_all_objects() after completing the traversal doesn't\ncost us any additional significant running time.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n alloc.c  |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----\n cache.h  |    1 +\n commit.c |    6 ++++++\n commit.h |    1 +\n object.c |   11 +++++++++++\n object.h |    1 +\n tag.c    |    5 +++++\n tag.h    |    1 +\n tree.c   |    5 +++++\n tree.h   |    1 +\n 10 files changed, 87 insertions(+), 5 deletions(-)\n\ndiff --git a/alloc.c b/alloc.c\nindex a61ae41..aa429ec 100644\n--- a/alloc.c\n+++ b/alloc.c\n@@ -51,7 +51,7 @@ static void report(const char* name, struct node_pool *p, size_t sz)\n \n #undef SZ_FMT\n \n-#define DEFINE_ALLOCATOR(name, t)\t\t\t\t\\\n+#define DEFINE_BASE_ALLOCATOR(name, t)\t\t\t\t\\\n static struct node_pool name##_pool;\t\t\t\t\\\n void *alloc_##name##_node(void)\t\t\t\t\t\\\n {\t\t\t\t\t\t\t\t\\\n@@ -76,6 +76,36 @@ static void report_##name(void)\t\t\t\t\t\\\n \treport(#name, &name##_pool, sizeof(t));\t\t\t\\\n }\n \n+#define DEFINE_ALLOCATOR(name, t)\t\t\t\t\\\n+DEFINE_BASE_ALLOCATOR(name, t)\t\t\t\t\t\\\n+static void free_all_##name(void)\t\t\t\t\\\n+{\t\t\t\t\t\t\t\t\\\n+\tstruct node_block *b, *n;\t\t\t\t\\\n+\tfor (b = name##_pool.block_list; b; b = n) {\t\t\\\n+\t\tn = b->next;\t\t\t\t\t\\\n+\t\tfree(b);\t\t\t\t\t\\\n+\t}\t\t\t\t\t\t\t\\\n+\tmemset(&name##_pool, 0, sizeof(name##_pool));\t\t\\\n+}\n+\n+#define DEFINE_SCRUBBING_ALLOCATOR(name, t, scrub)\t\t\\\n+DEFINE_BASE_ALLOCATOR(name, t)\t\t\t\t\t\\\n+static void free_all_##name(void)\t\t\t\t\\\n+{\t\t\t\t\t\t\t\t\\\n+\tstruct node_block *b, *n;\t\t\t\t\\\n+\tfor (b = name##_pool.block_list; b; b = n) {\t\t\\\n+\t\tsize_t nr = BLOCKING;\t\t\t\t\\\n+\t\tchar *e = (char*)(b + 1);\t\t\t\\\n+\t\tif (b == name##_pool.block_list)\t\t\\\n+\t\t\tnr -= name##_pool.nr;\t\t\t\\\n+\t\tfor (; nr--; e += sizeof(t))\t\t\t\\\n+\t\t\tscrub((t*)e);\t\t\t\t\\\n+\t\tn = b->next;\t\t\t\t\t\\\n+\t\tfree(b);\t\t\t\t\t\\\n+\t}\t\t\t\t\t\t\t\\\n+\tmemset(&name##_pool, 0, sizeof(name##_pool));\t\t\\\n+}\n+\n union any_object {\n \tstruct object object;\n \tstruct blob blob;\n@@ -84,11 +114,22 @@ union any_object {\n \tstruct tag tag;\n };\n \n+static void scrub_any_object(union any_object *o)\n+{\n+\tswitch (o->object.type) {\n+\tcase OBJ_COMMIT: scrub_commit(&o->commit); break;\n+\tcase OBJ_TREE: scrub_tree(&o->tree); break;\n+\tcase OBJ_BLOB: break;\n+\tcase OBJ_TAG: scrub_tag(&o->tag); break;\n+\tdefault: die(\"unknown type %s\", typename(o->object.type));\n+\t}\n+}\n+\n DEFINE_ALLOCATOR(blob, struct blob)\n-DEFINE_ALLOCATOR(tree, struct tree)\n-DEFINE_ALLOCATOR(commit, struct commit)\n-DEFINE_ALLOCATOR(tag, struct tag)\n-DEFINE_ALLOCATOR(object, union any_object)\n+DEFINE_SCRUBBING_ALLOCATOR(tree, struct tree, scrub_tree)\n+DEFINE_SCRUBBING_ALLOCATOR(commit, struct commit, scrub_commit)\n+DEFINE_SCRUBBING_ALLOCATOR(tag, struct tag, scrub_tag)\n+DEFINE_SCRUBBING_ALLOCATOR(object, union any_object, scrub_any_object)\n \n void alloc_report(void)\n {\n@@ -98,3 +139,12 @@ void alloc_report(void)\n \treport_tag();\n \treport_object();\n }\n+\n+void alloc_free_everything(void)\n+{\n+\tfree_all_blob();\n+\tfree_all_tree();\n+\tfree_all_commit();\n+\tfree_all_tag();\n+\tfree_all_object();\n+}\ndiff --git a/cache.h b/cache.h\nindex 7174eb1..8289de1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -587,6 +587,7 @@ extern void *alloc_commit_node(void);\n extern void *alloc_tag_node(void);\n extern void *alloc_object_node(void);\n extern void alloc_report(void);\n+extern void alloc_free_everything(void);\n \n /* trace.c */\n extern void trace_printf(const char *format, ...);\ndiff --git a/commit.c b/commit.c\nindex f074811..05f3cd6 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -318,6 +318,12 @@ int parse_commit(struct commit *item)\n \treturn ret;\n }\n \n+void scrub_commit(struct commit *item)\n+{\n+\tfree_commit_list(item->parents);\n+\tfree(item->buffer);\n+}\n+\n struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p)\n {\n \tstruct commit_list *new_list = xmalloc(sizeof(struct commit_list));\ndiff --git a/commit.h b/commit.h\nindex aa67986..cd0d286 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -39,6 +39,7 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1,\n int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);\n \n int parse_commit(struct commit *item);\n+void scrub_commit(struct commit *item);\n \n struct commit_list * commit_list_insert(struct commit *item, struct commit_list **list_p);\n struct commit_list * insert_by_date(struct commit *item, struct commit_list **list);\ndiff --git a/object.c b/object.c\nindex 16793d9..9b49472 100644\n--- a/object.c\n+++ b/object.c\n@@ -43,6 +43,17 @@ int type_from_string(const char *str)\n \tdie(\"invalid object type \\\"%s\\\"\", str);\n }\n \n+void free_all_objects(void)\n+{\n+\tif (obj_hash) {\n+\t\tfree(obj_hash);\n+\t\tobj_hash = NULL;\n+\t\tnr_objs = 0;\n+\t\tobj_hash_size = 0;\n+\t\talloc_free_everything();\n+\t}\n+}\n+\n static unsigned int hash_obj(struct object *obj, unsigned int n)\n {\n \tunsigned int hash = *(unsigned int *)obj->sha1;\ndiff --git a/object.h b/object.h\nindex 397bbfa..642beeb 100644\n--- a/object.h\n+++ b/object.h\n@@ -40,6 +40,7 @@ extern int track_object_refs;\n extern const char *typename(unsigned int type);\n extern int type_from_string(const char *str);\n \n+extern void free_all_objects(void);\n extern unsigned int get_max_object_index(void);\n extern struct object *get_indexed_object(unsigned int);\n extern struct object_refs *lookup_object_refs(struct object *);\ndiff --git a/tag.c b/tag.c\nindex f62bcdd..c39d3f0 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -114,3 +114,8 @@ int parse_tag(struct tag *item)\n \tfree(data);\n \treturn ret;\n }\n+\n+void scrub_tag(struct tag *item)\n+{\n+\tfree(item->tag);\n+}\ndiff --git a/tag.h b/tag.h\nindex 7a0cb00..933b876 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -15,6 +15,7 @@ struct tag {\n extern struct tag *lookup_tag(const unsigned char *sha1);\n extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size);\n extern int parse_tag(struct tag *item);\n+extern void scrub_tag(struct tag *item);\n extern struct object *deref_tag(struct object *, const char *, int);\n \n #endif /* TAG_H */\ndiff --git a/tree.c b/tree.c\nindex 8c0819f..278dad7 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -281,6 +281,11 @@ int parse_tree(struct tree *item)\n \treturn parse_tree_buffer(item, buffer, size);\n }\n \n+void scrub_tree(struct tree *tree)\n+{\n+\tfree(tree->buffer);\n+}\n+\n struct tree *parse_tree_indirect(const unsigned char *sha1)\n {\n \tstruct object *obj = parse_object(sha1);\ndiff --git a/tree.h b/tree.h\nindex dd25c53..d03cfd7 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -16,6 +16,7 @@ struct tree *lookup_tree(const unsigned char *sha1);\n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);\n \n int parse_tree(struct tree *tree);\n+void scrub_tree(struct tree *tree);\n \n /* Parses and returns the tree in the given ent, chasing tags and commits. */\n struct tree *parse_tree_indirect(const unsigned char *sha1);\n-- \n1.5.3.5.1622.g41d10\n"}]}