mirror of
https://git.proxmox.com/git/libgit2
synced 2025-12-25 22:12:55 +00:00
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>
This commit is contained in:
parent
971c90befe
commit
584f49a5ce
27
src/commit.c
27
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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
*
|
||||
|
||||
15
src/object.c
15
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) {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user