summaryrefslogtreecommitdiff
path: root/src/commit.c
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-03-12 23:09:16 +0200
committerVicent Marti <tanoku@gmail.com>2011-03-14 23:52:32 +0200
commit6b2a19418cb08e7bccefc2362f290a67555594a0 (patch)
tree44e666e45a50a59a444886b70c25c7c954d0ba4f /src/commit.c
parent005718280712634486a097427212e652b0e29f36 (diff)
downloadlibgit2-6b2a19418cb08e7bccefc2362f290a67555594a0.tar.gz
Fix the retarded object interdependency system
It's no longer retarded. All object interdependencies are stored as OIDs instead of actual objects. This should be hundreds of times faster, specially on big repositories. Heck, who knows, maye it doesn't even segfault -- wouldn't that be awesome? What has changed on the API? `git_commit_parent`, `git_commit_tree`, `git_tag_target` now return their values through a pointer-to-pointer, and have an error code. `git_commit_set_tree` and `git_tag_set_target` now return an error code and may fail. `git_repository_free__no_gc` has been deprecated because it's stupid. Since there are no longer any interdependencies between objects, we don't need internal reference counting, and GC never fails or double-free's pointers. `git_object_close` now does a very sane thing: marks an object as unused. Closed objects will be eventually free'd from the object cache based on LRU. Please use `git_object_close` from the garbage collector `destroy` method on your bindings. It's 100% safe. `git_repository_gc` is a new method that forces a garbage collector pass through the repo, to free as many LRU objects as possible. This is useful if we are running out of memory.
Diffstat (limited to 'src/commit.c')
-rw-r--r--src/commit.c202
1 files changed, 72 insertions, 130 deletions
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);
-}