Commit da3b391c32b973d5c073951b6848eedd40434e5e

Russell Belfer 2012-04-18T10:57:08

Convert revwalk to use git_pool This removes the custom paged allocator from revwalk and replaces it with a `git_pool`.

diff --git a/src/pool.c b/src/pool.c
index 2e64bde..8f5c7e7 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -29,11 +29,8 @@ int git_pool_init(
 	else if (item_size == 3)
 		item_size = 4;
 
-	if (!items_per_page) {
-		uint32_t page_bytes =
-			git_pool__system_page_size() - sizeof(git_pool_page);
-		items_per_page = page_bytes / item_size;
-	}
+	if (!items_per_page)
+		items_per_page = git_pool__suggest_items_per_page(item_size);
 	if (item_size * items_per_page < GIT_POOL_MIN_PAGESZ)
 		items_per_page = (GIT_POOL_MIN_PAGESZ + item_size - 1) / item_size;
 
@@ -288,3 +285,10 @@ uint32_t git_pool__system_page_size(void)
 	return size;
 }
 
+uint32_t git_pool__suggest_items_per_page(uint32_t item_size)
+{
+	uint32_t page_bytes =
+		git_pool__system_page_size() - sizeof(git_pool_page);
+	return page_bytes / item_size;
+}
+
diff --git a/src/pool.h b/src/pool.h
index a925890..54a2861 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -120,4 +120,6 @@ extern bool git_pool__ptr_in_pool(git_pool *pool, void *ptr);
 
 extern uint32_t git_pool__system_page_size(void);
 
+extern uint32_t git_pool__suggest_items_per_page(uint32_t item_size);
+
 #endif
diff --git a/src/revwalk.c b/src/revwalk.c
index a625760..557966b 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -10,6 +10,7 @@
 #include "odb.h"
 #include "hashtable.h"
 #include "pqueue.h"
+#include "pool.h"
 
 #include "git2/revwalk.h"
 #include "git2/merge.h"
@@ -46,6 +47,7 @@ struct git_revwalk {
 	git_odb *odb;
 
 	git_hashtable *commits;
+	git_pool commit_pool;
 
 	commit_list *iterator_topo;
 	commit_list *iterator_rand;
@@ -55,9 +57,6 @@ struct git_revwalk {
 	int (*get_next)(commit_object **, git_revwalk *);
 	int (*enqueue)(git_revwalk *, commit_object *);
 
-	git_vector memory_alloc;
-	size_t chunk_size;
-
 	unsigned walking:1;
 	unsigned int sorting;
 
@@ -133,42 +132,23 @@ static uint32_t object_table_hash(const void *key, int hash_id)
 	return r;
 }
 
-#define COMMITS_PER_CHUNK 128
-#define CHUNK_STEP 64
-#define PARENTS_PER_COMMIT ((CHUNK_STEP - sizeof(commit_object)) / sizeof(commit_object *))
-
-static int alloc_chunk(git_revwalk *walk)
-{
-	void *chunk;
-
-	chunk = git__calloc(COMMITS_PER_CHUNK, CHUNK_STEP);
-	GITERR_CHECK_ALLOC(chunk);
-
-	walk->chunk_size = 0;
-	return git_vector_insert(&walk->memory_alloc, chunk);
-}
+#define PARENTS_PER_COMMIT	2
+#define COMMIT_ALLOC \
+	(sizeof(commit_object) + PARENTS_PER_COMMIT * sizeof(commit_object *))
 
 static commit_object *alloc_commit(git_revwalk *walk)
 {
-	unsigned char *chunk;
-
-	if (walk->chunk_size == COMMITS_PER_CHUNK)
-		if (alloc_chunk(walk) < 0)
-			return NULL;
-
-	chunk = git_vector_get(&walk->memory_alloc, walk->memory_alloc.length - 1);
-	chunk += (walk->chunk_size * CHUNK_STEP);
-	walk->chunk_size++;
-
-	return (commit_object *)chunk;
+	return (commit_object *)git_pool_malloc(&walk->commit_pool, COMMIT_ALLOC);
 }
 
-static commit_object **alloc_parents(commit_object *commit, size_t n_parents)
+static commit_object **alloc_parents(
+	git_revwalk *walk, commit_object *commit, size_t n_parents)
 {
 	if (n_parents <= PARENTS_PER_COMMIT)
-		return (commit_object **)((unsigned char *)commit + sizeof(commit_object));
+		return (commit_object **)((char *)commit + sizeof(commit_object));
 
-	return git__malloc(n_parents * sizeof(commit_object *));
+	return (commit_object **)git_pool_malloc(
+		&walk->commit_pool, n_parents * sizeof(commit_object *));
 }
 
 
@@ -185,10 +165,8 @@ static commit_object *commit_lookup(git_revwalk *walk, const git_oid *oid)
 
 	git_oid_cpy(&commit->oid, oid);
 
-	if (git_hashtable_insert(walk->commits, &commit->oid, commit) < 0) {
-		git__free(commit);
+	if (git_hashtable_insert(walk->commits, &commit->oid, commit) < 0)
 		return NULL;
-	}
 
 	return commit;
 }
@@ -212,7 +190,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
 		buffer += parent_len;
 	}
 
-	commit->parents = alloc_parents(commit, parents);
+	commit->parents = alloc_parents(walk, commit, parents);
 	GITERR_CHECK_ALLOC(commit->parents);
 
 	buffer = parents_start;
@@ -756,9 +734,9 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
 	GITERR_CHECK_ALLOC(walk->commits);
 
 	if (git_pqueue_init(&walk->iterator_time, 8, commit_time_cmp) < 0 ||
-		git_vector_init(&walk->memory_alloc, 8, NULL) < 0 ||
 		git_vector_init(&walk->twos, 4, NULL) < 0 ||
-		alloc_chunk(walk) < 0)
+		git_pool_init(&walk->commit_pool, 1,
+			git_pool__suggest_items_per_page(COMMIT_ALLOC) * COMMIT_ALLOC) < 0)
 		return -1;
 
 	walk->get_next = &revwalk_next_unsorted;
@@ -777,30 +755,15 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
 
 void git_revwalk_free(git_revwalk *walk)
 {
-	unsigned int i;
-	commit_object *commit;
-
 	if (walk == NULL)
 		return;
 
 	git_revwalk_reset(walk);
 	git_odb_free(walk->odb);
 
-	/* if the parent has more than PARENTS_PER_COMMIT parents,
-	 * we had to allocate a separate array for those parents.
-	 * make sure it's being free'd */
-	GIT_HASHTABLE_FOREACH_VALUE(walk->commits, commit, {
-		if (commit->out_degree > PARENTS_PER_COMMIT)
-			git__free(commit->parents);
-	});
-
 	git_hashtable_free(walk->commits);
+	git_pool_clear(&walk->commit_pool);
 	git_pqueue_free(&walk->iterator_time);
-
-	for (i = 0; i < walk->memory_alloc.length; ++i)
-		git__free(git_vector_get(&walk->memory_alloc, i));
-
-	git_vector_free(&walk->memory_alloc);
 	git_vector_free(&walk->twos);
 	git__free(walk);
 }