diff options
author | Vicent Marti <tanoku@gmail.com> | 2011-03-01 01:37:28 +0200 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2011-03-03 20:23:53 +0200 |
commit | 584f49a5ceff463581f7f1b8bc23880dabca27ac (patch) | |
tree | a57c65fd2e530c2b096285c8625d62ea13685451 | |
parent | 971c90befe4dfac4c235fa59d65f7e652fc27e1d (diff) | |
download | libgit2-584f49a5ceff463581f7f1b8bc23880dabca27ac.tar.gz |
Fix several issues with refcounting
- Added several missing reference increases
- Add new destructor to the repository that does not GC the objects
Signed-off-by: Vicent Marti <tanoku@gmail.com>
-rw-r--r-- | src/commit.c | 27 | ||||
-rw-r--r-- | src/git2/repository.h | 3 | ||||
-rw-r--r-- | src/object.c | 15 | ||||
-rw-r--r-- | src/repository.c | 64 | ||||
-rw-r--r-- | src/repository.h | 10 |
5 files changed, 86 insertions, 33 deletions
diff --git a/src/commit.c b/src/commit.c index 3edc5733..dff3f1e3 100644 --- a/src/commit.c +++ b/src/commit.c @@ -44,6 +44,13 @@ static void clear_parents(git_commit *commit) { + unsigned int i; + + for (i = 0; i < commit->parents.length; ++i) { + git_commit *parent = git_vector_get(&commit->parents, i); + git_object_close((git_object *)parent); + } + git_vector_clear(&commit->parents); } @@ -242,12 +249,8 @@ const git_tree *git_commit_tree(git_commit *commit) if (!commit->object.in_memory && commit->tree == NULL) git_commit__parse_full(commit); - if (commit->tree) { - GIT_OBJECT_INCREF(commit->tree); - return commit->tree; - } - - return NULL; + GIT_OBJECT_INCREF(commit->tree); + return commit->tree; } GIT_COMMIT_GETTER(git_signature *, author) @@ -273,10 +276,15 @@ unsigned int git_commit_parentcount(git_commit *commit) return commit->parents.length; } -git_commit * git_commit_parent(git_commit *commit, unsigned int n) +git_commit *git_commit_parent(git_commit *commit, unsigned int n) { + git_commit *parent; + assert(commit); - return git_vector_get(&commit->parents, n); + + parent = git_vector_get(&commit->parents, n); + GIT_OBJECT_INCREF(parent); + return parent; } void git_commit_set_tree(git_commit *commit, git_tree *tree) @@ -341,7 +349,10 @@ void git_commit_set_message(git_commit *commit, const char *message) int git_commit_add_parent(git_commit *commit, git_commit *new_parent) { + assert(commit && new_parent); + CHECK_FULL_PARSE(); commit->object.modified = 1; + GIT_OBJECT_INCREF(new_parent); return git_vector_insert(&commit->parents, new_parent); } diff --git a/src/git2/repository.h b/src/git2/repository.h index dbb9ddde..5327f8c5 100644 --- a/src/git2/repository.h +++ b/src/git2/repository.h @@ -158,6 +158,9 @@ GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo); */ GIT_EXTERN(void) git_repository_free(git_repository *repo); + +GIT_EXTERN(void) git_repository_free__no_gc(git_repository *repo); + /** * Creates a new Git repository in the given folder. * diff --git a/src/object.c b/src/object.c index e2327144..de02ef5f 100644 --- a/src/object.c +++ b/src/object.c @@ -277,6 +277,7 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o object = git_hashtable_lookup(repo->objects, id); if (object != NULL) { *object_out = object; + GIT_OBJECT_INCREF(object); return GIT_SUCCESS; } @@ -329,7 +330,7 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o git_object__source_close(object); git_hashtable_insert(repo->objects, &object->id, object); - object->refcount++; + GIT_OBJECT_INCREF(object); *object_out = object; return GIT_SUCCESS; } @@ -383,11 +384,13 @@ void git_object__free(git_object *object) git_object__source_close(object); - if (object->in_memory) { - int idx = git_vector_search(&object->repo->memory_objects, object); - git_vector_remove(&object->repo->memory_objects, idx); - } else { - git_hashtable_remove(object->repo->objects, &object->id); + if (object->repo != NULL) { + if (object->in_memory) { + int idx = git_vector_search(&object->repo->memory_objects, object); + git_vector_remove(&object->repo->memory_objects, idx); + } else { + git_hashtable_remove(object->repo->objects, &object->id); + } } switch (object->source.raw.type) { diff --git a/src/repository.c b/src/repository.c index 9f27a38e..d3852d3a 100644 --- a/src/repository.c +++ b/src/repository.c @@ -332,7 +332,30 @@ int git_repository_open(git_repository **repo_out, const char *path) return repository_open_internal(repo_out, path, 0); } -void git_repository_free(git_repository *repo) +static void repository_free(git_repository *repo) +{ + assert(repo); + + free(repo->path_workdir); + free(repo->path_index); + free(repo->path_repository); + free(repo->path_odb); + + git_hashtable_free(repo->objects); + git_vector_free(&repo->memory_objects); + + git_repository__refcache_free(&repo->references); + + if (repo->db != NULL) + git_odb_close(repo->db); + + if (repo->index != NULL) + git_index_free(repo->index); + + free(repo); +} + +void git_repository_free__no_gc(git_repository *repo) { git_object *object; const void *_unused; @@ -341,10 +364,28 @@ void git_repository_free(git_repository *repo) if (repo == NULL) return; - free(repo->path_workdir); - free(repo->path_index); - free(repo->path_repository); - free(repo->path_odb); + GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, + object->repo = NULL; + object->refcount = 0; + ); + + for (i = 0; i < repo->memory_objects.length; ++i) { + object = git_vector_get(&repo->memory_objects, i); + object->repo = NULL; + object->refcount = 0; + } + + repository_free(repo); +} + +void git_repository_free(git_repository *repo) +{ + git_object *object; + const void *_unused; + unsigned int i; + + if (repo == NULL) + return; /* Increment the refcount of all the objects in the repository * to prevent freeing dependencies */ @@ -362,18 +403,7 @@ void git_repository_free(git_repository *repo) git_object__free(object); } - git_hashtable_free(repo->objects); - git_vector_free(&repo->memory_objects); - - git_repository__refcache_free(&repo->references); - - if (repo->db != NULL) - git_odb_close(repo->db); - - if (repo->index != NULL) - git_index_free(repo->index); - - free(repo); + repository_free(repo); } int git_repository_index(git_index **index_out, git_repository *repo) diff --git a/src/repository.h b/src/repository.h index 2e8d187b..4af062e9 100644 --- a/src/repository.h +++ b/src/repository.h @@ -15,8 +15,6 @@ #define GIT_OBJECTS_DIR "objects/" #define GIT_INDEX_FILE "index" -#define GIT_OBJECT_INCREF(ob) ++(((git_object *)(ob))->refcount) - typedef struct { git_rawobj raw; void *write_ptr; @@ -62,4 +60,12 @@ int git__source_write(git_odb_source *source, const void *bytes, size_t len); int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid); +#define GIT_OBJECT_INCREF(ob) git_object__incref((git_object *)(ob)) + +GIT_INLINE(void) git_object__incref(struct git_object *object) +{ + if (object) + object->refcount++; +} + #endif |