Commit d45b4a9a by Vicent Marti

Add support for in-memory objects

All repository objects can now be created from scratch in memory using
either the git_object_new() method, or the corresponding git_XXX_new()
for each object.

So far, only git_commits can be written back to disk once created in
memory.

Signed-off-by: Vicent Marti <tanoku@gmail.com>
parent 0c3596f1
...@@ -63,9 +63,14 @@ void git_commit__free(git_commit *commit) ...@@ -63,9 +63,14 @@ void git_commit__free(git_commit *commit)
free(commit); free(commit);
} }
git_commit *git_commit_new(git_repository *repo)
{
return (git_commit *)git_object_new(repo, GIT_OBJ_COMMIT);
}
const git_oid *git_commit_id(git_commit *c) const git_oid *git_commit_id(git_commit *c)
{ {
return &c->object.id; return git_object_id((git_object *)c);
} }
int git_commit__parse(git_commit *commit) int git_commit__parse(git_commit *commit)
......
...@@ -30,6 +30,18 @@ typedef struct git_commit git_commit; ...@@ -30,6 +30,18 @@ typedef struct git_commit git_commit;
*/ */
GIT_EXTERN(git_commit *) git_commit_lookup(git_repository *repo, const git_oid *id); GIT_EXTERN(git_commit *) git_commit_lookup(git_repository *repo, const git_oid *id);
/*
* Create a new in-memory git_commit.
*
* The commit object must be manually filled using
* setter methods before it can be written to its
* repository.
*
* @param repo The repository where the object will reside
* @return the object if creation was posible; NULL otherwise
*/
GIT_EXTERN(git_commit *) git_commit_new(git_repository *repo);
/** /**
* Get the id of a commit. * Get the id of a commit.
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
......
...@@ -57,9 +57,53 @@ GIT_EXTERN(git_object *) git_repository_lookup(git_repository *repo, const git_o ...@@ -57,9 +57,53 @@ GIT_EXTERN(git_object *) git_repository_lookup(git_repository *repo, const git_o
*/ */
GIT_EXTERN(git_odb *) git_repository_database(git_repository *repo); GIT_EXTERN(git_odb *) git_repository_database(git_repository *repo);
/*
* Create a new in-memory repository object with
* the given type.
*
* The object's attributes can be filled in using the
* correspondign setter methods.
*
* The object will be written back to given git_repository
* when the git_object_write() function is called; objects
* cannot be written to disk until all their main
* attributes have been properly filled.
*
* Objects are instantiated with no SHA1 id; their id
* will be automatically generated when writing to the
* repository.
*
* @parem repo Repository where the object belongs
* @param type Type of the object to be created
* @return the new object
*/
GIT_EXTERN(git_object *) git_object_new(git_repository *repo, git_otype type);
/*
* Write back an object to disk.
*
* The object will be written to its corresponding
* repository.
*
* If the object has no changes since it was first
* read from the repository, no actions will take place.
*
* If the object has been modified since it was read from
* the repository, or it has been created from scratch
* in memory, it will be written to the repository and
* its SHA1 ID will be updated accordingly.
*
* @param object Git object to write back
* @return 0 on success; otherwise an error code
*/
int git_object_write(git_object *object);
/** /**
* Get the id (SHA1) of a repository object * Get the id (SHA1) of a repository object
* *
* In-memory objects created by git_object_new() do not
* have a SHA1 ID until they are written on a repository.
*
* @param obj the repository object * @param obj the repository object
* @return the SHA1 id * @return the SHA1 id
*/ */
......
...@@ -29,6 +29,18 @@ typedef struct git_tag git_tag; ...@@ -29,6 +29,18 @@ typedef struct git_tag git_tag;
*/ */
GIT_EXTERN(git_tag *) git_tag_lookup(git_repository *repo, const git_oid *id); GIT_EXTERN(git_tag *) git_tag_lookup(git_repository *repo, const git_oid *id);
/*
* Create a new in-memory git_tag.
*
* The tag object must be manually filled using
* setter methods before it can be written to its
* repository.
*
* @param repo The repository where the object will reside
* @return the object if creation was posible; NULL otherwise
*/
GIT_EXTERN(git_tag *) git_tag_new(git_repository *repo);
/** /**
* Get the id of a tag. * Get the id of a tag.
* @param tag a previously loaded tag. * @param tag a previously loaded tag.
......
...@@ -32,6 +32,18 @@ typedef struct git_tree git_tree; ...@@ -32,6 +32,18 @@ typedef struct git_tree git_tree;
*/ */
GIT_EXTERN(git_tree *) git_tree_lookup(git_repository *repo, const git_oid *id); GIT_EXTERN(git_tree *) git_tree_lookup(git_repository *repo, const git_oid *id);
/*
* Create a new in-memory git_tree.
*
* The tree object must be manually filled using
* setter methods before it can be written to its
* repository.
*
* @param repo The repository where the object will reside
* @return the object if creation was posible; NULL otherwise
*/
GIT_EXTERN(git_tree *) git_tree_new(git_repository *repo);
/** /**
* Get the id of a tree. * Get the id of a tree.
* @param tree a previously loaded tree. * @param tree a previously loaded tree.
......
...@@ -32,6 +32,15 @@ ...@@ -32,6 +32,15 @@
static const int default_table_size = 32; static const int default_table_size = 32;
static const double max_load_factor = 0.65; static const double max_load_factor = 0.65;
static const size_t object_sizes[] = {
0,
sizeof(git_commit),
sizeof(git_tree),
sizeof(git_object), /* TODO: sizeof(git_blob) */
sizeof(git_tag)
};
uint32_t git_object_hash(const void *key) uint32_t git_object_hash(const void *key)
{ {
uint32_t r; uint32_t r;
...@@ -160,7 +169,7 @@ int git__source_write(git_odb_source *source, const void *bytes, size_t len) ...@@ -160,7 +169,7 @@ int git__source_write(git_odb_source *source, const void *bytes, size_t len)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
void git_object__source_prepare_write(git_object *object) static void prepare_write(git_object *object)
{ {
const size_t base_size = 4096; /* 4Kb base size */ const size_t base_size = 4096; /* 4Kb base size */
...@@ -175,10 +184,9 @@ void git_object__source_prepare_write(git_object *object) ...@@ -175,10 +184,9 @@ void git_object__source_prepare_write(git_object *object)
object->source.written_bytes = 0; object->source.written_bytes = 0;
object->source.open = 1; object->source.open = 1;
object->source.out_of_sync = 1;
} }
int git_object__source_writeback(git_object *object) static int write_back(git_object *object)
{ {
int error; int error;
git_oid new_id; git_oid new_id;
...@@ -188,8 +196,7 @@ int git_object__source_writeback(git_object *object) ...@@ -188,8 +196,7 @@ int git_object__source_writeback(git_object *object)
if (!object->source.open) if (!object->source.open)
return GIT_ERROR; return GIT_ERROR;
if (!object->source.out_of_sync) assert(object->modified);
return GIT_SUCCESS;
object->source.raw.len = object->source.written_bytes; object->source.raw.len = object->source.written_bytes;
...@@ -198,7 +205,9 @@ int git_object__source_writeback(git_object *object) ...@@ -198,7 +205,9 @@ int git_object__source_writeback(git_object *object)
if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < 0) if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < 0)
return error; return error;
git_hashtable_remove(object->repo->objects, &object->id); if (!object->in_memory)
git_hashtable_remove(object->repo->objects, &object->id);
git_oid_cpy(&object->id, &new_id); git_oid_cpy(&object->id, &new_id);
git_hashtable_insert(object->repo->objects, &object->id, object); git_hashtable_insert(object->repo->objects, &object->id, object);
...@@ -206,6 +215,7 @@ int git_object__source_writeback(git_object *object) ...@@ -206,6 +215,7 @@ int git_object__source_writeback(git_object *object)
object->source.written_bytes = 0; object->source.written_bytes = 0;
object->modified = 0; object->modified = 0;
object->in_memory = 0;
git_object__source_close(object); git_object__source_close(object);
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -215,9 +225,9 @@ int git_object__source_open(git_object *object) ...@@ -215,9 +225,9 @@ int git_object__source_open(git_object *object)
{ {
int error; int error;
assert(object); assert(object && !object->in_memory);
if (object->source.open && object->source.out_of_sync) if (object->source.open)
git_object__source_close(object); git_object__source_close(object);
if (object->source.open) if (object->source.open)
...@@ -228,7 +238,6 @@ int git_object__source_open(git_object *object) ...@@ -228,7 +238,6 @@ int git_object__source_open(git_object *object)
return error; return error;
object->source.open = 1; object->source.open = 1;
object->source.out_of_sync = 0;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -239,7 +248,6 @@ void git_object__source_close(git_object *object) ...@@ -239,7 +248,6 @@ void git_object__source_close(git_object *object)
if (!object->source.open) { if (!object->source.open) {
git_obj_close(&object->source.raw); git_obj_close(&object->source.raw);
object->source.open = 0; object->source.open = 0;
object->source.out_of_sync = 0;
} }
} }
...@@ -253,7 +261,7 @@ int git_object_write(git_object *object) ...@@ -253,7 +261,7 @@ int git_object_write(git_object *object)
if (object->modified == 0) if (object->modified == 0)
return GIT_SUCCESS; return GIT_SUCCESS;
git_object__source_prepare_write(object); prepare_write(object);
source = &object->source; source = &object->source;
switch (source->raw.type) { switch (source->raw.type) {
...@@ -265,14 +273,15 @@ int git_object_write(git_object *object) ...@@ -265,14 +273,15 @@ int git_object_write(git_object *object)
case GIT_OBJ_TAG: case GIT_OBJ_TAG:
default: default:
error = GIT_ERROR; error = GIT_ERROR;
break;
} }
if (error < 0) { if (error < 0) {
git_object__source_close(object); git_object__source_close(object);
return error; return error;
} }
return git_object__source_writeback(object); return write_back(object);
} }
void git_object_free(git_object *object) void git_object_free(git_object *object)
...@@ -310,6 +319,10 @@ git_odb *git_repository_database(git_repository *repo) ...@@ -310,6 +319,10 @@ git_odb *git_repository_database(git_repository *repo)
const git_oid *git_object_id(git_object *obj) const git_oid *git_object_id(git_object *obj)
{ {
assert(obj); assert(obj);
if (obj->in_memory)
return NULL;
return &obj->id; return &obj->id;
} }
...@@ -319,16 +332,38 @@ git_otype git_object_type(git_object *obj) ...@@ -319,16 +332,38 @@ git_otype git_object_type(git_object *obj)
return obj->source.raw.type; return obj->source.raw.type;
} }
git_object *git_repository_lookup(git_repository *repo, const git_oid *id, git_otype type) git_object *git_object_new(git_repository *repo, git_otype type)
{ {
static const size_t object_sizes[] = { git_object *object = NULL;
0,
sizeof(git_commit),
sizeof(git_tree),
sizeof(git_object), /* TODO: sizeof(git_blob) */
sizeof(git_tag)
};
switch (type) {
case GIT_OBJ_COMMIT:
case GIT_OBJ_TAG:
case GIT_OBJ_TREE:
case GIT_OBJ_BLOB:
break;
default:
return NULL;
}
object = git__malloc(object_sizes[type]);
if (object == NULL)
return NULL;
memset(object, 0x0, object_sizes[type]);
object->repo = repo;
object->in_memory = 1;
object->modified = 1;
object->source.raw.type = type;
return object;
}
git_object *git_repository_lookup(git_repository *repo, const git_oid *id, git_otype type)
{
git_object *object = NULL; git_object *object = NULL;
git_rawobj obj_file; git_rawobj obj_file;
......
...@@ -12,7 +12,7 @@ typedef struct { ...@@ -12,7 +12,7 @@ typedef struct {
git_rawobj raw; git_rawobj raw;
void *write_ptr; void *write_ptr;
size_t written_bytes; size_t written_bytes;
int open:1, out_of_sync:1; int open:1;
} git_odb_source; } git_odb_source;
struct git_object { struct git_object {
...@@ -30,8 +30,6 @@ struct git_repository { ...@@ -30,8 +30,6 @@ struct git_repository {
int git_object__source_open(git_object *object); int git_object__source_open(git_object *object);
void git_object__source_close(git_object *object); void git_object__source_close(git_object *object);
void git_object__source_prepare_write(git_object *object);
int git_object__source_writeback(git_object *object);
int git__source_printf(git_odb_source *source, const char *format, ...); int git__source_printf(git_odb_source *source, const char *format, ...);
int git__source_write(git_odb_source *source, const void *bytes, size_t len); int git__source_write(git_odb_source *source, const void *bytes, size_t len);
......
...@@ -38,9 +38,14 @@ void git_tag__free(git_tag *tag) ...@@ -38,9 +38,14 @@ void git_tag__free(git_tag *tag)
free(tag); free(tag);
} }
const git_oid *git_tag_id(git_tag *t) git_tag *git_tag_new(git_repository *repo)
{ {
return &t->object.id; return (git_tag *)git_object_new(repo, GIT_OBJ_TAG);
}
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) const git_object *git_tag_target(git_tag *t)
......
...@@ -40,9 +40,14 @@ void git_tree__free(git_tree *tree) ...@@ -40,9 +40,14 @@ void git_tree__free(git_tree *tree)
free(tree); free(tree);
} }
const git_oid *git_tree_id(git_tree *tree) git_tree *git_tree_new(git_repository *repo)
{ {
return &tree->object.id; return (git_tree *)git_object_new(repo, GIT_OBJ_TREE);
}
const git_oid *git_tree_id(git_tree *c)
{
return git_object_id((git_object *)c);
} }
git_tree *git_tree_lookup(git_repository *repo, const git_oid *id) git_tree *git_tree_lookup(git_repository *repo, const git_oid *id)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment