diff --git a/src/commit.c b/src/commit.c index 8a3eb5ff9..ce3a4184c 100644 --- a/src/commit.c +++ b/src/commit.c @@ -69,14 +69,14 @@ int git_commit__parse(git_commit *commit, unsigned int parse_flags, int close_db { int error = 0; - if ((error = git_repository__open_dbo((git_repository_object *)commit)) < 0) + if ((error = git_repository__dbo_open((git_repository_object *)commit)) < 0) return error; error = git_commit__parse_buffer(commit, commit->object.dbo.data, commit->object.dbo.len, parse_flags); if (close_db_object) - git_repository__close_dbo((git_repository_object *)commit); + git_repository__dbo_close((git_repository_object *)commit); return error; } diff --git a/src/repository.c b/src/repository.c index 3f07bd608..443697155 100644 --- a/src/repository.c +++ b/src/repository.c @@ -91,9 +91,83 @@ void git_repository_free(git_repository *repo) free(repo); } -int git_repository__open_dbo(git_repository_object *object) +void git_repository__dbo_prepare_write(git_repository_object *object) +{ + size_t base_size = 512; + + if (object->writeback.write_ptr != NULL || object->dbo_open) + git_repository__dbo_close(object); + + /* TODO: proper size calculation */ + object->dbo.data = git__malloc(base_size); + object->dbo.len = 0; + + object->writeback.write_ptr = object->dbo.data; + object->writeback.ptr_size = base_size; + object->writeback.written_bytes = 0; + + object->dbo_open = 1; + object->out_of_sync = 1; +} + +int git_repository__dbo_write(git_repository_object *object, const void *bytes, size_t len) +{ + assert(object); + + if (!object->dbo_open || object->writeback.write_ptr == NULL) + return GIT_ERROR; + + /* TODO: resize buffer on overflow */ + if (object->writeback.written_bytes + len >= object->writeback.ptr_size) + return GIT_ENOMEM; + + memcpy(object->writeback.write_ptr, bytes, len); + object->writeback.write_ptr += len; + object->writeback.written_bytes += len; + + return GIT_SUCCESS; +} + +int git_repository__dbo_writeback(git_repository_object *object) { int error; + git_oid new_id; + + assert(object); + + if (!object->dbo_open) + return GIT_ERROR; + + if (!object->out_of_sync) + return GIT_SUCCESS; + + object->dbo.len = object->writeback.written_bytes; + + git_obj_hash(&new_id, &object->dbo); + + if ((error = git_odb_write(&new_id, object->repo->db, &object->dbo)) < 0) + return error; + + git_hashtable_remove(object->repo->objects, &object->id); + git_oid_cpy(&object->id, &new_id); + git_hashtable_insert(object->repo->objects, &object->id, object); + + object->writeback.write_ptr = NULL; + object->writeback.ptr_size = 0; + object->writeback.written_bytes = 0; + + git_repository__dbo_close(object); + return GIT_SUCCESS; +} + +int git_repository__dbo_open(git_repository_object *object) +{ + int error; + + assert(object); + + if (object->dbo_open && object->out_of_sync) + git_repository__dbo_close(object); if (object->dbo_open) return GIT_SUCCESS; @@ -103,19 +177,25 @@ int git_repository__open_dbo(git_repository_object *object) return error; object->dbo_open = 1; + object->out_of_sync = 0; return GIT_SUCCESS; } -void git_repository__close_dbo(git_repository_object *object) +void git_repository__dbo_close(git_repository_object *object) { + assert(object); + if (!object->dbo_open) { git_obj_close(&object->dbo); object->dbo_open = 0; + object->out_of_sync = 0; } } void git_repository_object_free(git_repository_object *object) { + assert(object); + git_hashtable_remove(object->repo->objects, &object->id); git_obj_close(&object->dbo); diff --git a/src/repository.h b/src/repository.h index 712874cd3..1b5e6a041 100644 --- a/src/repository.h +++ b/src/repository.h @@ -12,7 +12,14 @@ struct git_repository_object { git_oid id; git_repository *repo; git_obj dbo; - int dbo_open; + + struct { + void *write_ptr; + size_t ptr_size; + size_t written_bytes; + } writeback; + + int dbo_open:1, out_of_sync:1; }; struct git_repository { @@ -21,7 +28,10 @@ struct git_repository { }; -int git_repository__open_dbo(git_repository_object *object); -void git_repository__close_dbo(git_repository_object *object); +int git_repository__dbo_open(git_repository_object *object); +void git_repository__dbo_close(git_repository_object *object); +void git_repository__dbo_prepare_write(git_repository_object *object); +int git_repository__dbo_write(git_repository_object *object, const void *bytes, size_t len); +int git_repository__dbo_writeback(git_repository_object *object); #endif diff --git a/src/tag.c b/src/tag.c index 5d094ea94..ec0531b6e 100644 --- a/src/tag.c +++ b/src/tag.c @@ -161,13 +161,13 @@ int git_tag__parse(git_tag *tag) { int error = 0; - error = git_repository__open_dbo((git_repository_object *)tag); + error = git_repository__dbo_open((git_repository_object *)tag); if (error < 0) return error; error = parse_tag_buffer(tag, tag->object.dbo.data, tag->object.dbo.data + tag->object.dbo.len); - git_repository__close_dbo((git_repository_object *)tag); + git_repository__dbo_close((git_repository_object *)tag); return error; } diff --git a/src/tree.c b/src/tree.c index 6760654f6..7599c3fc2 100644 --- a/src/tree.c +++ b/src/tree.c @@ -107,7 +107,7 @@ int git_tree__parse(git_tree *tree) if (tree->entries != NULL) return GIT_SUCCESS; - error = git_repository__open_dbo((git_repository_object *)tree); + error = git_repository__dbo_open((git_repository_object *)tree); if (error < 0) return error; @@ -155,6 +155,6 @@ int git_tree__parse(git_tree *tree) buffer += GIT_OID_RAWSZ; } - git_repository__close_dbo((git_repository_object *)tree); + git_repository__dbo_close((git_repository_object *)tree); return error; }