Commit c3703302b15feb5ec68b86fa86ffbc78a7aa670b

Stefan Sperling 2018-01-23T15:19:45

model delta chains in a better way

diff --git a/lib/delta.c b/lib/delta.c
index 9c70b67..e3a0f89 100644
--- a/lib/delta.c
+++ b/lib/delta.c
@@ -28,51 +28,51 @@
 
 #include "delta.h"
 
-struct got_delta_base *
-got_delta_base_open(const char *path_packfile, int type, off_t offset,
+struct got_delta *
+got_delta_open(const char *path_packfile, int type, off_t offset,
     size_t size)
 {
-	struct got_delta_base *base;
+	struct got_delta *delta;
 
-	base = calloc(1, sizeof(*base));
-	if (base == NULL)
+	delta = calloc(1, sizeof(*delta));
+	if (delta == NULL)
 		return NULL;
 
-	base->path_packfile = strdup(path_packfile);
-	if (base->path_packfile == NULL) {
-		free(base);
+	delta->path_packfile = strdup(path_packfile);
+	if (delta->path_packfile == NULL) {
+		free(delta);
 		return NULL;
 	}
-	base->type = type;
-	base->offset = offset;
-	base->size = size;
-	return base;
+	delta->type = type;
+	delta->offset = offset;
+	delta->size = size;
+	return delta;
 }
 
 void
-got_delta_base_close(struct got_delta_base *base)
+got_delta_close(struct got_delta *delta)
 {
-	free(base->path_packfile);
-	free(base);
+	free(delta->path_packfile);
+	free(delta);
 
 }
 
 const struct got_error *
 got_delta_chain_get_base_type(int *type, struct got_delta_chain *deltas)
 {
-	struct got_delta_base *base;
+	struct got_delta *delta;
 	int n = 0;
 
-	/* Find the last base in the chain. It should be a plain object. */
-	SIMPLEQ_FOREACH(base, &deltas->entries, entry) {
+	/* Find the last delta in the chain. It should be a plain object. */
+	SIMPLEQ_FOREACH(delta, &deltas->entries, entry) {
 		n++;
-		if (base->type == GOT_OBJ_TYPE_COMMIT ||
-		    base->type == GOT_OBJ_TYPE_TREE ||
-		    base->type == GOT_OBJ_TYPE_BLOB ||
-		    base->type == GOT_OBJ_TYPE_TAG) {
+		if (delta->type == GOT_OBJ_TYPE_COMMIT ||
+		    delta->type == GOT_OBJ_TYPE_TREE ||
+		    delta->type == GOT_OBJ_TYPE_BLOB ||
+		    delta->type == GOT_OBJ_TYPE_TAG) {
 			if (n != deltas->nentries)
 				return got_error(GOT_ERR_BAD_DELTA_CHAIN);
-			*type = base->type;
+			*type = delta->type;
 			return NULL;
 		}
 	}
diff --git a/lib/delta.h b/lib/delta.h
index 62886c7..1410200 100644
--- a/lib/delta.h
+++ b/lib/delta.h
@@ -14,8 +14,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-struct got_delta_base {
-	SIMPLEQ_ENTRY(got_delta_base) entry;
+struct got_delta {
+	SIMPLEQ_ENTRY(got_delta) entry;
 	char *path_packfile;
 	off_t offset;
 	int type;
@@ -24,11 +24,11 @@ struct got_delta_base {
 
 struct got_delta_chain {
 	int nentries;
-	SIMPLEQ_HEAD(, got_delta_base) entries;
+	SIMPLEQ_HEAD(, got_delta) entries;
 };
 
-struct got_delta_base *got_delta_base_open(const char *, int, off_t, size_t);
-void got_delta_base_close(struct got_delta_base *);
+struct got_delta *got_delta_open(const char *, int, off_t, size_t);
+void got_delta_close(struct got_delta *);
 const struct got_error *got_delta_chain_get_base_type(int *,
     struct got_delta_chain *) ;
 const struct got_error *
diff --git a/lib/object.c b/lib/object.c
index e3f1c9f..a721709 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -336,11 +336,11 @@ void
 got_object_close(struct got_object *obj)
 {
 	if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
-		struct got_delta_base *base;
+		struct got_delta *delta;
 		while (!SIMPLEQ_EMPTY(&obj->deltas.entries)) {
-			base = SIMPLEQ_FIRST(&obj->deltas.entries);
+			delta = SIMPLEQ_FIRST(&obj->deltas.entries);
 			SIMPLEQ_REMOVE_HEAD(&obj->deltas.entries, entry);
-			got_delta_base_close(base);
+			got_delta_close(delta);
 		}
 	}
 	if (obj->flags & GOT_OBJ_FLAG_PACKED)
diff --git a/lib/pack.c b/lib/pack.c
index 6c4139f..3640379 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -329,7 +329,8 @@ read_packfile_hdr(FILE *f, struct got_packidx_v2_hdr *packidx)
 }
 
 static const struct got_error *
-decode_type_and_size(uint8_t *type, uint64_t *size, size_t *len, FILE *packfile)
+decode_object_type_and_size(uint8_t *type, uint64_t *size, size_t *len,
+    FILE *packfile)
 {
 	uint8_t t = 0;
 	uint64_t s = 0;
@@ -440,59 +441,61 @@ parse_offset_delta(off_t *base_offset, FILE *packfile, off_t offset)
 }
 
 static const struct got_error *resolve_delta_chain(struct got_delta_chain *,
-    FILE *, const char *, off_t, size_t);
+    FILE *, const char *, int, off_t, size_t);
 
 static const struct got_error *
 resolve_offset_delta(struct got_delta_chain *deltas, FILE *packfile,
-    const char *path_packfile, off_t offset, size_t delta_size)
+    const char *path_packfile, off_t delta_offset)
 {
 	const struct got_error *err;
-	off_t next_offset;
+	off_t base_offset;
+	uint8_t base_type;
+	uint64_t base_size;
+	size_t base_tslen;
+
+	err = parse_offset_delta(&base_offset, packfile, delta_offset);
+	if (err)
+		return err;
+
+	/* An offset delta must be in the same packfile. */
+	if (fseeko(packfile, base_offset, SEEK_SET) != 0)
+		return got_error_from_errno();
 
-	err = parse_offset_delta(&next_offset, packfile, offset);
+	err = decode_object_type_and_size(&base_type, &base_size, &base_tslen,
+	    packfile);
 	if (err)
 		return err;
 
-	/* Next offset must be in the same packfile. */
 	return resolve_delta_chain(deltas, packfile, path_packfile,
-	    next_offset, delta_size);
+	    base_type, base_offset + base_tslen, base_size);
 }
 
 static const struct got_error *
 resolve_delta_chain(struct got_delta_chain *deltas, FILE *packfile,
-    const char *path_packfile, off_t offset, size_t delta_size)
+    const char *path_packfile, int delta_type, off_t delta_offset,
+    size_t delta_size)
 {
 	const struct got_error *err = NULL;
-	uint8_t base_type;
-	uint64_t base_size;
-	size_t base_tslen;
-	struct got_delta_base *base;
-
-	if (fseeko(packfile, offset, SEEK_SET) != 0)
-		return got_error_from_errno();
-
-	err = decode_type_and_size(&base_type, &base_size, &base_tslen,
-	    packfile);
-	if (err)
-		return err;
+	struct got_delta *delta;
 
-	base = got_delta_base_open(path_packfile, base_type, offset,
+	delta = got_delta_open(path_packfile, delta_type, delta_offset,
 	    delta_size);
-	if (base == NULL)
+	if (delta == NULL)
 		return got_error(GOT_ERR_NO_MEM);
 	deltas->nentries++;
-	SIMPLEQ_INSERT_TAIL(&deltas->entries, base, entry);
-	/* In case of error below, base will be freed in got_object_close(). */
+	SIMPLEQ_INSERT_TAIL(&deltas->entries, delta, entry);
+	/* In case of error below, delta is freed in got_object_close(). */
 
-	switch (base_type) {
+	switch (delta_type) {
 	case GOT_OBJ_TYPE_COMMIT:
 	case GOT_OBJ_TYPE_TREE:
 	case GOT_OBJ_TYPE_BLOB:
 	case GOT_OBJ_TYPE_TAG:
+		/* Plain types are the final delta base. Recursion ends. */
 		break;
 	case GOT_OBJ_TYPE_OFFSET_DELTA:
 		err = resolve_offset_delta(deltas, packfile, path_packfile,
-		    offset, base_size);
+		    delta_offset);
 		break;
 	case GOT_OBJ_TYPE_REF_DELTA:
 	default:
@@ -506,20 +509,15 @@ static const struct got_error *
 open_offset_delta_object(struct got_object **obj,
     struct got_repository *repo, struct got_packidx_v2_hdr *packidx,
     const char *path_packfile, FILE *packfile, struct got_object_id *id,
-    off_t offset, size_t tslen, size_t size)
+    off_t offset, size_t tslen, size_t delta_size)
 {
 	const struct got_error *err = NULL;
-	off_t base_offset;
 	struct got_object_id base_id;
 	uint8_t base_type;
 	int resolved_type;
 	uint64_t base_size;
 	size_t base_tslen;
 
-	err = parse_offset_delta(&base_offset, packfile, offset);
-	if (err)
-		return err;
-
 	*obj = calloc(1, sizeof(**obj));
 	if (*obj == NULL)
 		return got_error(GOT_ERR_NO_MEM);
@@ -539,8 +537,9 @@ open_offset_delta_object(struct got_object **obj,
 
 	SIMPLEQ_INIT(&(*obj)->deltas.entries);
 	(*obj)->flags |= GOT_OBJ_FLAG_DELTIFIED;
+
 	err = resolve_delta_chain(&(*obj)->deltas, packfile, path_packfile,
-	    base_offset, size);
+	    GOT_OBJ_TYPE_OFFSET_DELTA, offset, delta_size);
 	if (err)
 		goto done;
 
@@ -605,7 +604,7 @@ open_packed_object(struct got_object **obj, struct got_repository *repo,
 		goto done;
 	}
 
-	err = decode_type_and_size(&type, &size, &tslen, packfile);
+	err = decode_object_type_and_size(&type, &size, &tslen, packfile);
 	if (err)
 		goto done;