summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blob.c4
-rw-r--r--src/commit.c202
-rw-r--r--src/commit.h7
-rw-r--r--src/object.c22
-rw-r--r--src/refs.c7
-rw-r--r--src/repository.c65
-rw-r--r--src/repository.h22
-rw-r--r--src/tag.c36
-rw-r--r--src/tag.h3
9 files changed, 133 insertions, 235 deletions
diff --git a/src/blob.c b/src/blob.c
index f157f4787..1e03b6b67 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -130,9 +130,7 @@ int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *pa
git_oid_cpy(written_id, git_object_id((git_object *)blob));
- /* FIXME: maybe we don't want to free this already?
- * the user may want to access it again */
- GIT_OBJECT_DECREF(repo, blob);
+ git_object_close((git_object*)blob);
return GIT_SUCCESS;
}
diff --git a/src/commit.c b/src/commit.c
index 974999a4a..1c5cddf7a 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -46,24 +46,22 @@ 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_DECREF(commit->object.repo, parent);
+ for (i = 0; i < commit->parent_oids.length; ++i) {
+ git_oid *parent = git_vector_get(&commit->parent_oids, i);
+ free(parent);
}
- git_vector_clear(&commit->parents);
+ git_vector_clear(&commit->parent_oids);
}
void git_commit__free(git_commit *commit)
{
clear_parents(commit);
- git_vector_free(&commit->parents);
+ git_vector_free(&commit->parent_oids);
git_signature_free(commit->author);
git_signature_free(commit->committer);
- GIT_OBJECT_DECREF(commit->object.repo, commit->tree);
-
free(commit->message);
free(commit->message_short);
free(commit);
@@ -78,16 +76,13 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src)
{
unsigned int i;
- if (commit->tree == NULL)
- return GIT_EMISSINGOBJDATA;
-
- git__write_oid(src, "tree", git_tree_id(commit->tree));
+ git__write_oid(src, "tree", &commit->tree_oid);
- for (i = 0; i < commit->parents.length; ++i) {
- git_commit *parent;
+ for (i = 0; i < commit->parent_oids.length; ++i) {
+ git_oid *parent_oid;
- parent = git_vector_get(&commit->parents, i);
- git__write_oid(src, "parent", git_commit_id(parent));
+ parent_oid = git_vector_get(&commit->parent_oids, i);
+ git__write_oid(src, "parent", parent_oid);
}
if (commit->author == NULL)
@@ -103,66 +98,49 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src)
if (commit->message != NULL) {
git__source_write(src, "\n", 1);
git__source_write(src, commit->message, strlen(commit->message));
- }
-
- /* Mark the commit as having all attributes */
- commit->full_parse = 1;
+ }
return GIT_SUCCESS;
}
-int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags)
+int commit_parse_buffer(git_commit *commit, void *data, size_t len)
{
char *buffer = (char *)data;
const char *buffer_end = (char *)data + len;
- git_oid oid;
+ git_oid parent_oid;
int error;
/* first parse; the vector hasn't been initialized yet */
- if (commit->parents.contents == NULL) {
- git_vector_init(&commit->parents, 4, NULL);
+ if (commit->parent_oids.contents == NULL) {
+ git_vector_init(&commit->parent_oids, 4, NULL);
}
clear_parents(commit);
-
- if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
- return error;
-
- GIT_OBJECT_DECREF(commit->object.repo, commit->tree);
- if ((error = git_object_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS)
+ if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
return error;
/*
* TODO: commit grafts!
*/
- while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) {
- git_commit *parent;
+ while (git__parse_oid(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) {
+ git_oid *new_oid;
- if ((error = git_object_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
- return error;
+ new_oid = git__malloc(sizeof(git_oid));
+ git_oid_cpy(new_oid, &parent_oid);
- if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS)
+ if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS)
return GIT_ENOMEM;
}
+ if (commit->author)
+ git_signature_free(commit->author);
- if (parse_flags & COMMIT_FULL_PARSE) {
- if (commit->author)
- git_signature_free(commit->author);
-
- commit->author = git__malloc(sizeof(git_signature));
- if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)
- return error;
-
- } else {
- if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
- return GIT_EOBJCORRUPTED;
-
- buffer++;
- }
+ commit->author = git__malloc(sizeof(git_signature));
+ if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)
+ return error;
/* Always parse the committer; we need the commit time */
if (commit->committer)
@@ -176,7 +154,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
while (buffer <= buffer_end && *buffer == '\n')
buffer++;
- if (parse_flags & COMMIT_FULL_PARSE && buffer < buffer_end) {
+ if (buffer < buffer_end) {
const char *line_end;
size_t message_len = buffer_end - buffer;
@@ -203,106 +181,81 @@ int git_commit__parse(git_commit *commit)
{
assert(commit && commit->object.source.open);
return commit_parse_buffer(commit,
- commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE);
+ commit->object.source.raw.data, commit->object.source.raw.len);
}
-int git_commit__parse_full(git_commit *commit)
-{
- int error;
-
- if (commit->full_parse)
- return GIT_SUCCESS;
-
- if ((error = git_object__source_open((git_object *)commit)) < GIT_SUCCESS)
- return error;
-
- error = commit_parse_buffer(commit,
- commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE);
-
- git_object__source_close((git_object *)commit);
-
- commit->full_parse = 1;
- return error;
-}
-
-
-
-#define GIT_COMMIT_GETTER(_rvalue, _name) \
- const _rvalue git_commit_##_name(git_commit *commit) \
+#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
+ _rvalue git_commit_##_name(git_commit *commit) \
{\
assert(commit); \
- if (commit->_name) \
- return commit->_name; \
- if (!commit->object.in_memory) \
- git_commit__parse_full(commit); \
- return commit->_name; \
+ return _return; \
}
-#define CHECK_FULL_PARSE() \
- if (!commit->object.in_memory && !commit->full_parse)\
- git_commit__parse_full(commit);
+GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
+GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
+GIT_COMMIT_GETTER(const char *, message, commit->message)
+GIT_COMMIT_GETTER(const char *, message_short, commit->message_short)
+GIT_COMMIT_GETTER(time_t, time, commit->committer->when.time)
+GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
+GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length)
+
+
+int git_commit_tree(git_tree **tree_out, git_commit *commit)
+{
+ assert(commit);
+ return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid);
+}
-const git_tree *git_commit_tree(git_commit *commit)
+int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n)
{
+ git_oid *parent_oid;
assert(commit);
- if (!commit->object.in_memory && commit->tree == NULL)
- git_commit__parse_full(commit);
+ parent_oid = git_vector_get(&commit->parent_oids, n);
+ if (parent_oid == NULL)
+ return GIT_ENOTFOUND;
- GIT_OBJECT_INCREF(commit->object.repo, commit->tree);
- return commit->tree;
+ return git_commit_lookup(parent, commit->object.repo, parent_oid);
}
-GIT_COMMIT_GETTER(git_signature *, author)
-GIT_COMMIT_GETTER(git_signature *, committer)
-GIT_COMMIT_GETTER(char *, message)
-GIT_COMMIT_GETTER(char *, message_short)
-time_t git_commit_time(git_commit *commit)
-{
- assert(commit && commit->committer);
- return commit->committer->when.time;
-}
-int git_commit_time_offset(git_commit *commit)
+int git_commit_set_tree(git_commit *commit, git_tree *tree)
{
- assert(commit && commit->committer);
- return commit->committer->when.offset;
-}
+ const git_oid *oid;
-unsigned int git_commit_parentcount(git_commit *commit)
-{
- assert(commit);
- return commit->parents.length;
+ assert(commit && tree);
+
+ if ((oid = git_object_id((git_object *)tree)) == NULL)
+ return GIT_EMISSINGOBJDATA;
+
+ commit->object.modified = 1;
+ git_oid_cpy(&commit->tree_oid, oid);
+ return GIT_SUCCESS;
}
-git_commit *git_commit_parent(git_commit *commit, unsigned int n)
+int git_commit_add_parent(git_commit *commit, git_commit *new_parent)
{
- git_commit *parent;
+ const git_oid *parent_oid;
+ git_oid *new_oid;
+ assert(commit && new_parent);
- assert(commit);
+ if ((parent_oid = git_object_id((git_object *)new_parent)) == NULL)
+ return GIT_EMISSINGOBJDATA;
- parent = git_vector_get(&commit->parents, n);
- GIT_OBJECT_INCREF(commit->object.repo, parent);
- return parent;
-}
+ new_oid = git__malloc(sizeof(git_oid));
+ if (new_oid == NULL)
+ return GIT_ENOMEM;
-void git_commit_set_tree(git_commit *commit, git_tree *tree)
-{
- assert(commit && tree);
commit->object.modified = 1;
- CHECK_FULL_PARSE();
-
- GIT_OBJECT_DECREF(commit->object.repo, commit->tree);
- GIT_OBJECT_INCREF(commit->object.repo, tree);
- commit->tree = tree;
+ git_oid_cpy(new_oid, parent_oid);
+ return git_vector_insert(&commit->parent_oids, new_oid);
}
void git_commit_set_author(git_commit *commit, const git_signature *author_sig)
{
assert(commit && author_sig);
commit->object.modified = 1;
- CHECK_FULL_PARSE();
git_signature_free(commit->author);
commit->author = git_signature_dup(author_sig);
@@ -312,7 +265,6 @@ void git_commit_set_committer(git_commit *commit, const git_signature *committer
{
assert(commit && committer_sig);
commit->object.modified = 1;
- CHECK_FULL_PARSE();
git_signature_free(commit->committer);
commit->committer = git_signature_dup(committer_sig);
@@ -324,7 +276,6 @@ void git_commit_set_message(git_commit *commit, const char *message)
size_t message_len;
commit->object.modified = 1;
- CHECK_FULL_PARSE();
if (commit->message)
free(commit->message);
@@ -347,12 +298,3 @@ void git_commit_set_message(git_commit *commit, const char *message)
commit->message_short[message_len] = 0;
}
-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(commit->object.repo, new_parent);
- return git_vector_insert(&commit->parents, new_parent);
-}
diff --git a/src/commit.h b/src/commit.h
index b53ee9b23..aaf349ca6 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -11,21 +11,18 @@
struct git_commit {
git_object object;
- git_vector parents;
+ git_vector parent_oids;
+ git_oid tree_oid;
- git_tree *tree;
git_signature *author;
git_signature *committer;
char *message;
char *message_short;
-
- unsigned full_parse:1;
};
void git_commit__free(git_commit *c);
int git_commit__parse(git_commit *commit);
-int git_commit__parse_full(git_commit *commit);
int git_commit__writeback(git_commit *commit, git_odb_source *src);
diff --git a/src/object.c b/src/object.c
index 7891893a0..fce99153b 100644
--- a/src/object.c
+++ b/src/object.c
@@ -261,7 +261,7 @@ int git_object_new(git_object **object_out, git_repository *repo, git_otype type
object->source.raw.type = type;
- object->refcount++;
+ object->lru = ++repo->lru_counter;
*object_out = object;
return GIT_SUCCESS;
}
@@ -277,7 +277,8 @@ 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(repo, object);
+ object->lru = ++repo->lru_counter;
+ object->can_free = 0;
return GIT_SUCCESS;
}
@@ -330,7 +331,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);
- GIT_OBJECT_INCREF(repo, object);
+ object->lru = ++repo->lru_counter;
*object_out = object;
return GIT_SUCCESS;
}
@@ -412,17 +413,12 @@ void git_object_close(git_object *object)
if (object == NULL)
return;
- if (--object->refcount <= 0) {
- 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);
- }
- }
-
+ if (object->in_memory) {
+ int idx = git_vector_search(&object->repo->memory_objects, object);
+ git_vector_remove(&object->repo->memory_objects, idx);
git_object__free(object);
+ } else {
+ object->can_free = 1;
}
}
diff --git a/src/refs.c b/src/refs.c
index 93897a7f9..1ed6b567c 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -681,7 +681,6 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file)
static int packed_find_peel(reference_oid *ref)
{
git_tag *tag;
- const git_object *peeled_target;
int error;
if (ref->ref.type & GIT_REF_HAS_PEEL)
@@ -706,11 +705,7 @@ static int packed_find_peel(reference_oid *ref)
/*
* Find the object pointed at by this tag
*/
- peeled_target = git_tag_target(tag);
- if (peeled_target == NULL)
- return GIT_EOBJCORRUPTED;
-
- git_oid_cpy(&ref->peel_target, git_object_id(peeled_target));
+ git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag));
ref->ref.type |= GIT_REF_HAS_PEEL;
/*
diff --git a/src/repository.c b/src/repository.c
index c24560665..37aa44781 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -209,7 +209,6 @@ static git_repository *repository_alloc()
return NULL;
}
- repo->gc_enabled = 1;
return repo;
}
@@ -331,50 +330,20 @@ cleanup:
return error;
}
-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)
+int git_repository_gc(git_repository *repo)
{
+ int collected = 0;
git_object *object;
const void *_unused;
- unsigned int i;
-
- if (repo == NULL)
- return;
GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
- object->repo = NULL;
- object->refcount = 0;
+ if (object->can_free) {
+ git_object__free(object);
+ collected++;
+ }
);
- 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);
+ return collected;
}
void git_repository_free(git_repository *repo)
@@ -386,8 +355,6 @@ void git_repository_free(git_repository *repo)
if (repo == NULL)
return;
- repo->gc_enabled = 0;
-
/* force free all the objects */
GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
git_object__free(object);
@@ -398,7 +365,23 @@ void git_repository_free(git_repository *repo)
git_object__free(object);
}
- repository_free(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);
}
int git_repository_index(git_index **index_out, git_repository *repo)
diff --git a/src/repository.h b/src/repository.h
index 5318ed45c..48b8dae6b 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -27,8 +27,8 @@ struct git_object {
git_oid id;
git_repository *repo;
git_odb_source source;
- unsigned short refcount;
- unsigned char in_memory, modified;
+ unsigned int lru;
+ unsigned char in_memory, modified, can_free, _pad;
};
struct git_repository {
@@ -45,7 +45,8 @@ struct git_repository {
char *path_odb;
char *path_workdir;
- unsigned is_bare:1, gc_enabled:1;
+ unsigned is_bare:1;
+ unsigned int lru_counter;
};
int git_object__source_open(git_object *object);
@@ -61,19 +62,4 @@ 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(repo, ob) git_object__incref((repo), (git_object *)(ob))
-#define GIT_OBJECT_DECREF(repo, ob) git_object__decref((repo), (git_object *)(ob))
-
-GIT_INLINE(void) git_object__incref(git_repository *repo, struct git_object *object)
-{
- if (repo && repo->gc_enabled && object)
- object->refcount++;
-}
-
-GIT_INLINE(void) git_object__decref(git_repository *repo, struct git_object *object)
-{
- if (repo && repo->gc_enabled && object)
- git_object_close(object);
-}
-
#endif
diff --git a/src/tag.c b/src/tag.c
index 1ac2067c2..1379425a1 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -35,7 +35,6 @@
void git_tag__free(git_tag *tag)
{
git_signature_free(tag->tagger);
- GIT_OBJECT_DECREF(tag->object.repo, tag->target);
free(tag->message);
free(tag->tag_name);
free(tag);
@@ -46,23 +45,31 @@ const git_oid *git_tag_id(git_tag *c)
return git_object_id((git_object *)c);
}
-const git_object *git_tag_target(git_tag *t)
+int git_tag_target(git_object **target, git_tag *t)
{
assert(t);
- GIT_OBJECT_INCREF(t->object.repo, t->target);
- return t->target;
+ return git_object_lookup(target, t->object.repo, &t->target, t->type);
}
-void git_tag_set_target(git_tag *tag, git_object *target)
+const git_oid *git_tag_target_oid(git_tag *t)
{
+ assert(t);
+ return &t->target;
+}
+
+int git_tag_set_target(git_tag *tag, git_object *target)
+{
+ const git_oid *oid;
+
assert(tag && target);
- GIT_OBJECT_DECREF(tag->object.repo, tag->target);
- GIT_OBJECT_INCREF(tag->object.repo, target);
+ if ((oid = git_object_id(target)) == NULL)
+ return GIT_EMISSINGOBJDATA;
tag->object.modified = 1;
- tag->target = target;
+ git_oid_cpy(&tag->target, oid);
tag->type = git_object_type(target);
+ return GIT_SUCCESS;
}
git_otype git_tag_type(git_tag *t)
@@ -81,7 +88,6 @@ void git_tag_set_name(git_tag *tag, const char *name)
{
assert(tag && name);
- /* TODO: sanity check? no newlines in message */
tag->object.modified = 1;
if (tag->tag_name)
@@ -128,12 +134,11 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
NULL, "commit\n", "tree\n", "blob\n", "tag\n"
};
- git_oid target_oid;
unsigned int i, text_len;
char *search;
int error;
- if ((error = git__parse_oid(&target_oid, &buffer, buffer_end, "object ")) < 0)
+ if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0)
return error;
if (buffer + 5 >= buffer_end)
@@ -161,11 +166,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
if (tag->type == GIT_OBJ_BAD)
return GIT_EOBJCORRUPTED;
- git_object_close(tag->target);
- error = git_object_lookup(&tag->target, tag->object.repo, &target_oid, tag->type);
- if (error < 0)
- return error;
-
if (buffer + 4 >= buffer_end)
return GIT_EOBJCORRUPTED;
@@ -210,10 +210,10 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
int git_tag__writeback(git_tag *tag, git_odb_source *src)
{
- if (tag->target == NULL || tag->tag_name == NULL || tag->tagger == NULL)
+ if (tag->tag_name == NULL || tag->tagger == NULL)
return GIT_EMISSINGOBJDATA;
- git__write_oid(src, "object", git_object_id(tag->target));
+ git__write_oid(src, "object", &tag->target);
git__source_printf(src, "type %s\n", git_object_type2string(tag->type));
git__source_printf(src, "tag %s\n", tag->tag_name);
git_signature__write(src, "tagger", tag->tagger);
diff --git a/src/tag.h b/src/tag.h
index 624fcc654..a1782d064 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -7,8 +7,9 @@
struct git_tag {
git_object object;
- git_object *target;
+ git_oid target;
git_otype type;
+
char *tag_name;
git_signature *tagger;
char *message;