summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-05-11 03:50:34 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-05-13 02:48:48 +0200
commita3ffbf230e454309c96961a182520a53f555d356 (patch)
treedd4a0d4b86b6db7e71f9dcb6de5f39ad39a774cd
parent9dbd150f5f499bbf768d65c4ebb596651e77a1b8 (diff)
downloadlibgit2-a3ffbf230e454309c96961a182520a53f555d356.tar.gz
pack: expose a cached delta base directly
Instead of going through a special entry in the chain, let's pass it as an output parameter.
-rw-r--r--src/pack.c185
-rw-r--r--src/pack.h4
2 files changed, 92 insertions, 97 deletions
diff --git a/src/pack.c b/src/pack.c
index e1fd276b7..b5e8febd4 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -40,14 +40,6 @@ static int pack_entry_find_offset(
const git_oid *short_oid,
size_t len);
-/**
- * Generate the chain of dependencies which we need to get to the
- * object at `off`. `chain` is used a stack, popping gives the right
- * order to apply deltas on. If an object is found in the pack's base
- * cache, we stop calculating there.
- */
-static int pack_dependency_chain(git_dependency_chain *chain, struct git_pack_file *p, git_off_t off);
-
static int packfile_error(const char *message)
{
giterr_set(GITERR_ODB, "Invalid pack file - %s", message);
@@ -522,6 +514,87 @@ int git_packfile_resolve_header(
return error;
}
+/**
+ * Generate the chain of dependencies which we need to get to the
+ * object at `off`. `chain` is used a stack, popping gives the right
+ * order to apply deltas on. If an object is found in the pack's base
+ * cache, we stop calculating there.
+ */
+static int pack_dependency_chain(git_dependency_chain *chain_out, git_pack_cache_entry **cached_out,
+ git_off_t *cached_off, struct git_pack_file *p, git_off_t obj_offset)
+{
+ git_dependency_chain chain = GIT_ARRAY_INIT;
+ git_mwindow *w_curs = NULL;
+ git_off_t curpos = obj_offset, base_offset;
+ int error = 0;
+ size_t size;
+ git_otype type;
+
+ if (!p->bases.entries && (cache_init(&p->bases) < 0))
+ return -1;
+
+ git_array_init_to_size(chain, 64);
+ while (true) {
+ struct pack_chain_elem *elem;
+ git_pack_cache_entry *cached = NULL;
+
+ /* if we have a base cached, we can stop here instead */
+ if ((cached = cache_get(&p->bases, obj_offset)) != NULL) {
+ *cached_out = cached;
+ *cached_off = obj_offset;
+ break;
+ }
+
+ curpos = obj_offset;
+ elem = git_array_alloc(chain);
+ if (!elem) {
+ error = -1;
+ goto on_error;
+ }
+
+ elem->base_key = obj_offset;
+
+ error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
+ git_mwindow_close(&w_curs);
+
+ if (error < 0)
+ goto on_error;
+
+ elem->offset = curpos;
+ elem->size = size;
+ elem->type = type;
+ elem->base_key = obj_offset;
+
+ if (type != GIT_OBJ_OFS_DELTA && type != GIT_OBJ_REF_DELTA)
+ break;
+
+ base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
+ git_mwindow_close(&w_curs);
+
+ if (base_offset == 0) {
+ error = packfile_error("delta offset is zero");
+ goto on_error;
+ }
+ if (base_offset < 0) { /* must actually be an error code */
+ error = (int)base_offset;
+ goto on_error;
+ }
+
+ /* we need to pass the pos *after* the delta-base bit */
+ elem->offset = curpos;
+
+ /* go through the loop again, but with the new object */
+ obj_offset = base_offset;
+ }
+
+ *chain_out = chain;
+ return error;
+
+on_error:
+ git_array_clear(chain);
+ return error;
+}
+
int git_packfile_unpack(
git_rawobj *obj,
struct git_pack_file *p,
@@ -531,7 +604,7 @@ int git_packfile_unpack(
git_off_t curpos = *obj_offset;
int error, free_base = 0;
git_dependency_chain chain = GIT_ARRAY_INIT;
- struct pack_chain_elem *elem;
+ struct pack_chain_elem *elem = NULL;
git_pack_cache_entry *cached = NULL;
git_otype base_type;
@@ -539,7 +612,7 @@ int git_packfile_unpack(
* TODO: optionally check the CRC on the packfile
*/
- error = pack_dependency_chain(&chain, p, *obj_offset);
+ error = pack_dependency_chain(&chain, &cached, obj_offset, p, *obj_offset);
if (error < 0)
return error;
@@ -547,12 +620,12 @@ int git_packfile_unpack(
obj->len = 0;
obj->type = GIT_OBJ_BAD;
- /* the first one is the base, so we expand that one */
- elem = git_array_pop(chain);
- base_type = elem->type;
- if (elem->cached) {
- cached = elem->cached_entry;
+ if (cached) {
memcpy(obj, &cached->raw, sizeof(git_rawobj));
+ base_type = obj->type;
+ } else {
+ elem = git_array_pop(chain);
+ base_type = elem->type;
}
if (error < 0)
@@ -563,10 +636,11 @@ int git_packfile_unpack(
case GIT_OBJ_TREE:
case GIT_OBJ_BLOB:
case GIT_OBJ_TAG:
- if (!elem->cached) {
+ if (!cached) {
curpos = elem->offset;
error = packfile_unpack_compressed(obj, p, &w_curs, &curpos, elem->size, elem->type);
git_mwindow_close(&w_curs);
+ base_type = elem->type;
free_base = 1;
}
if (error < 0)
@@ -646,7 +720,8 @@ cleanup:
if (error < 0)
git__free(obj->data);
- *obj_offset = elem->offset;
+ if (elem)
+ *obj_offset = elem->offset;
git_array_clear(chain);
return error;
@@ -1240,79 +1315,3 @@ int git_pack_entry_find(
git_oid_cpy(&e->sha1, &found_oid);
return 0;
}
-
-static int pack_dependency_chain(git_dependency_chain *chain_out, struct git_pack_file *p, git_off_t obj_offset)
-{
- git_dependency_chain chain = GIT_ARRAY_INIT;
- git_mwindow *w_curs = NULL;
- git_off_t curpos = obj_offset, base_offset;
- int error = 0;
- size_t size;
- git_otype type;
-
- if (!p->bases.entries && (cache_init(&p->bases) < 0))
- return -1;
-
- git_array_init_to_size(chain, 64);
- while (true) {
- struct pack_chain_elem *elem;
- git_pack_cache_entry *cached = NULL;
-
- curpos = obj_offset;
- elem = git_array_alloc(chain);
- if (!elem) {
- error = -1;
- goto on_error;
- }
-
- elem->base_key = obj_offset;
-
- /* if we have a base cached, we can stop here instead */
- if ((cached = cache_get(&p->bases, obj_offset)) != NULL) {
- elem->cached_entry = cached;
- elem->cached = 1;
- elem->type = cached->raw.type;
- break;
- }
-
- error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
- git_mwindow_close(&w_curs);
-
- if (error < 0)
- goto on_error;
-
- elem->cached = 0;
- elem->offset = curpos;
- elem->size = size;
- elem->type = type;
- elem->base_key = obj_offset;
-
- if (type != GIT_OBJ_OFS_DELTA && type != GIT_OBJ_REF_DELTA)
- break;
-
- base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
- git_mwindow_close(&w_curs);
-
- if (base_offset == 0) {
- error = packfile_error("delta offset is zero");
- goto on_error;
- }
- if (base_offset < 0) { /* must actually be an error code */
- error = (int)base_offset;
- goto on_error;
- }
-
- /* we need to pass the pos *after* the delta-base bit */
- elem->offset = curpos;
-
- /* go through the loop again, but with the new object */
- obj_offset = base_offset;
- }
-
- *chain_out = chain;
- return error;
-
-on_error:
- git_array_clear(chain);
- return error;
-}
diff --git a/src/pack.h b/src/pack.h
index e86889d1b..610e70c18 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -62,14 +62,10 @@ typedef struct git_pack_cache_entry {
} git_pack_cache_entry;
struct pack_chain_elem {
- int cached;
git_off_t base_key;
- /* if we don't have it cached we have this */
git_off_t offset;
size_t size;
git_otype type;
- /* if cached, we have this instead */
- git_pack_cache_entry *cached_entry;
};
typedef git_array_t(struct pack_chain_elem) git_dependency_chain;