From 9c9f4fc11c85d621dc5fdcf46bbcb5b5da9ed73f Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 12 Aug 2010 23:40:54 +0200 Subject: [PATCH] Add support for manually freeing repo objects A new method 'git_repository_object_free' allows to manually force the freeing of a repository object, even though they are still automatically managed by the repository and don't need to be freed by the user. Signed-off-by: Vicent Marti --- src/git/repository.h | 15 ++++++++++++++ src/hashtable.c | 31 ++++++++++++++++++++++++++++ src/hashtable.h | 1 + src/repository.c | 48 ++++++++++++++++++++++++-------------------- 4 files changed, 73 insertions(+), 22 deletions(-) diff --git a/src/git/repository.h b/src/git/repository.h index 3b6981d50..001e4e9fb 100644 --- a/src/git/repository.h +++ b/src/git/repository.h @@ -49,6 +49,21 @@ GIT_EXTERN(git_repository *) git_repository_alloc(git_odb *odb); */ GIT_EXTERN(git_repository_object *) git_repository_lookup(git_repository *repo, const git_oid *id, git_otype type); + +/** + * Free a reference to one of the objects in the repostory. + * + * Repository objects are managed automatically by the library, + * but this method can be used to force freeing one of the + * objects. + * + * Careful: freeing objects in the middle of a repository + * traversal will most likely cause errors. + * + * @param object the object to free + */ +GIT_EXTERN(void) git_repository_object_free(git_repository_object *object); + /** * Free a previously allocated repository * @param repo repository handle to close. If NULL nothing occurs. diff --git a/src/hashtable.c b/src/hashtable.c index 4006a8714..242a6fa1d 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -183,6 +183,37 @@ void *git_hashtable_lookup(git_hashtable *table, const void *key) return NULL; } +int git_hashtable_remove(git_hashtable *table, const void *key) +{ + git_hashtable_node *node, *prev_node; + uint32_t index, hash; + + assert(table); + + hash = table->hash(key); + index = (hash & table->size_mask); + node = table->nodes[index]; + + prev_node = NULL; + + while (node != NULL) { + if (node->hash == hash && table->key_equal(node->object, key)) { + if (prev_node == NULL) + table->nodes[index] = node->next; + else + prev_node->next = node->next; + + free(node); + return GIT_SUCCESS; + } + + prev_node = node; + node = node->next; + } + + return GIT_ENOTFOUND; +} + void git_hashtable_iterator_init(git_hashtable *table, git_hashtable_iterator *it) diff --git a/src/hashtable.h b/src/hashtable.h index 622a260e1..cd390b9e9 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -42,6 +42,7 @@ git_hashtable *git_hashtable_alloc(unsigned int min_size, git_hash_keyeq_ptr key_eq); int git_hashtable_insert(git_hashtable *h, const void *key, void *value); void *git_hashtable_lookup(git_hashtable *h, const void *key); +int git_hashtable_remove(git_hashtable *table, const void *key); void git_hashtable_free(git_hashtable *h); void git_hashtable_clear(git_hashtable *h); diff --git a/src/repository.c b/src/repository.c index 58f29ce44..86f2216cb 100644 --- a/src/repository.c +++ b/src/repository.c @@ -83,28 +83,8 @@ void git_repository_free(git_repository *repo) git_hashtable_iterator_init(repo->objects, &it); while ((object = (git_repository_object *) - git_hashtable_iterator_next(&it)) != NULL) { - - git_obj_close(&object->dbo); - - switch (object->dbo.type) { - case GIT_OBJ_COMMIT: - git_commit__free((git_commit *)object); - break; - - case GIT_OBJ_TREE: - git_tree__free((git_tree *)object); - break; - - case GIT_OBJ_TAG: - git_tag__free((git_tag *)object); - break; - - default: - free(object); - break; - } - } + git_hashtable_iterator_next(&it)) != NULL) + git_repository_object_free(object); git_hashtable_free(repo->objects); /* TODO: free odb */ @@ -134,6 +114,30 @@ void git_repository__close_dbo(git_repository_object *object) } } +void git_repository_object_free(git_repository_object *object) +{ + git_hashtable_remove(object->repo->objects, &object->id); + git_obj_close(&object->dbo); + + switch (object->dbo.type) { + case GIT_OBJ_COMMIT: + git_commit__free((git_commit *)object); + break; + + case GIT_OBJ_TREE: + git_tree__free((git_tree *)object); + break; + + case GIT_OBJ_TAG: + git_tag__free((git_tag *)object); + break; + + default: + free(object); + break; + } +} + git_repository_object *git_repository_lookup(git_repository *repo, const git_oid *id, git_otype type) { static const size_t object_sizes[] = {