summaryrefslogtreecommitdiff
path: root/src/pack-objects.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pack-objects.c')
-rw-r--r--src/pack-objects.c143
1 files changed, 77 insertions, 66 deletions
diff --git a/src/pack-objects.c b/src/pack-objects.c
index 500104c55..2d62507f2 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -14,6 +14,7 @@
#include "pack.h"
#include "thread-utils.h"
#include "tree.h"
+#include "util.h"
#include "git2/pack.h"
#include "git2/commit.h"
@@ -25,7 +26,7 @@ struct unpacked {
git_pobject *object;
void *data;
struct git_delta_index *index;
- unsigned int depth;
+ int depth;
};
struct tree_walk_context {
@@ -34,7 +35,7 @@ struct tree_walk_context {
};
struct pack_write_context {
- git_indexer_stream *indexer;
+ git_indexer *indexer;
git_transfer_progress *stats;
};
@@ -57,6 +58,9 @@ struct pack_write_context {
#define git_packbuilder__progress_lock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, progress_mutex, lock)
#define git_packbuilder__progress_unlock(pb) GIT_PACKBUILDER__MUTEX_OP(pb, progress_mutex, unlock)
+/* The minimal interval between progress updates (in seconds). */
+#define MIN_PROGRESS_UPDATE_INTERVAL 0.5
+
static unsigned name_hash(const char *name)
{
unsigned c, hash = 0;
@@ -213,41 +217,19 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
kh_value(pb->object_ix, pos) = po;
pb->done = false;
- return 0;
-}
-
-/*
- * The per-object header is a pretty dense thing, which is
- * - first byte: low four bits are "size",
- * then three bits of "type",
- * with the high bit being "size continues".
- * - each byte afterwards: low seven bits are size continuation,
- * with the high bit being "size continues"
- */
-static int gen_pack_object_header(
- unsigned char *hdr,
- unsigned long size,
- git_otype type)
-{
- unsigned char *hdr_base;
- unsigned char c;
-
- assert(type >= GIT_OBJ_COMMIT && type <= GIT_OBJ_REF_DELTA);
-
- /* TODO: add support for chunked objects; see git.git 6c0d19b1 */
-
- c = (unsigned char)((type << 4) | (size & 15));
- size >>= 4;
- hdr_base = hdr;
- while (size) {
- *hdr++ = c | 0x80;
- c = size & 0x7f;
- size >>= 7;
+ if (pb->progress_cb) {
+ double current_time = git__timer();
+ if ((current_time - pb->last_progress_report_time) >= MIN_PROGRESS_UPDATE_INTERVAL) {
+ pb->last_progress_report_time = current_time;
+ if (pb->progress_cb(GIT_PACKBUILDER_ADDING_OBJECTS, pb->nr_objects, 0, pb->progress_cb_payload)) {
+ giterr_clear();
+ return GIT_EUSER;
+ }
+ }
}
- *hdr++ = c;
- return (int)(hdr - hdr_base);
+ return 0;
}
static int get_delta(void **out, git_odb *odb, git_pobject *po)
@@ -290,7 +272,7 @@ static int write_object(git_buf *buf, git_packbuilder *pb, git_pobject *po)
git_buf zbuf = GIT_BUF_INIT;
git_otype type;
unsigned char hdr[10];
- unsigned int hdr_len;
+ size_t hdr_len;
unsigned long size;
void *data;
@@ -311,7 +293,7 @@ static int write_object(git_buf *buf, git_packbuilder *pb, git_pobject *po)
}
/* Write header */
- hdr_len = gen_pack_object_header(hdr, size, type);
+ hdr_len = git_packfile__object_header(hdr, size, type);
if (git_buf_put(buf, (char *)hdr, hdr_len) < 0)
goto on_error;
@@ -505,8 +487,10 @@ static git_pobject **compute_write_order(git_packbuilder *pb)
/*
* Mark objects that are at the tip of tags.
*/
- if (git_tag_foreach(pb->repo, &cb_tag_foreach, pb) < 0)
+ if (git_tag_foreach(pb->repo, &cb_tag_foreach, pb) < 0) {
+ git__free(wo);
return NULL;
+ }
/*
* Give the objects in the original recency order until
@@ -576,50 +560,52 @@ static int write_pack(git_packbuilder *pb,
git_buf buf = GIT_BUF_INIT;
enum write_one_status status;
struct git_pack_header ph;
+ git_oid entry_oid;
unsigned int i = 0;
+ int error = 0;
write_order = compute_write_order(pb);
- if (write_order == NULL)
- goto on_error;
+ if (write_order == NULL) {
+ error = -1;
+ goto done;
+ }
/* Write pack header */
ph.hdr_signature = htonl(PACK_SIGNATURE);
ph.hdr_version = htonl(PACK_VERSION);
ph.hdr_entries = htonl(pb->nr_objects);
- if (cb(&ph, sizeof(ph), data) < 0)
- goto on_error;
+ if ((error = cb(&ph, sizeof(ph), data)) < 0)
+ goto done;
- if (git_hash_update(&pb->ctx, &ph, sizeof(ph)) < 0)
- goto on_error;
+ if ((error = git_hash_update(&pb->ctx, &ph, sizeof(ph))) < 0)
+ goto done;
pb->nr_remaining = pb->nr_objects;
do {
pb->nr_written = 0;
for ( ; i < pb->nr_objects; ++i) {
po = write_order[i];
- if (write_one(&buf, pb, po, &status) < 0)
- goto on_error;
- if (cb(buf.ptr, buf.size, data) < 0)
- goto on_error;
+ if ((error = write_one(&buf, pb, po, &status)) < 0)
+ goto done;
+ if ((error = cb(buf.ptr, buf.size, data)) < 0)
+ goto done;
git_buf_clear(&buf);
}
pb->nr_remaining -= pb->nr_written;
} while (pb->nr_remaining && i < pb->nr_objects);
- git__free(write_order);
- git_buf_free(&buf);
- if (git_hash_final(&pb->pack_oid, &pb->ctx) < 0)
- goto on_error;
+ if ((error = git_hash_final(&entry_oid, &pb->ctx)) < 0)
+ goto done;
- return cb(pb->pack_oid.id, GIT_OID_RAWSZ, data);
+ error = cb(entry_oid.id, GIT_OID_RAWSZ, data);
-on_error:
+done:
git__free(write_order);
git_buf_free(&buf);
- return -1;
+ return error;
}
static int write_pack_buf(void *buf, size_t size, void *data)
@@ -674,7 +660,7 @@ static int delta_cacheable(git_packbuilder *pb, unsigned long src_size,
}
static int try_delta(git_packbuilder *pb, struct unpacked *trg,
- struct unpacked *src, unsigned int max_depth,
+ struct unpacked *src, int max_depth,
unsigned long *mem_usage, int *ret)
{
git_pobject *trg_object = trg->object;
@@ -839,7 +825,7 @@ static unsigned long free_unpacked(struct unpacked *n)
static int find_deltas(git_packbuilder *pb, git_pobject **list,
unsigned int *list_size, unsigned int window,
- unsigned int depth)
+ int depth)
{
git_pobject *po;
git_buf zbuf = GIT_BUF_INIT;
@@ -854,8 +840,7 @@ static int find_deltas(git_packbuilder *pb, git_pobject **list,
for (;;) {
struct unpacked *n = array + idx;
- unsigned int max_depth;
- int j, best_base = -1;
+ int max_depth, j, best_base = -1;
git_packbuilder__progress_lock(pb);
if (!*list_size) {
@@ -1048,7 +1033,7 @@ static void *threaded_find_deltas(void *arg)
static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
unsigned int list_size, unsigned int window,
- unsigned int depth)
+ int depth)
{
struct thread_params *p;
int i, ret, active_threads = 0;
@@ -1205,6 +1190,13 @@ static int prepare_pack(git_packbuilder *pb)
if (pb->nr_objects == 0 || pb->done)
return 0; /* nothing to do */
+ /*
+ * Although we do not report progress during deltafication, we
+ * at least report that we are in the deltafication stage
+ */
+ if (pb->progress_cb)
+ pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload);
+
delta_list = git__malloc(pb->nr_objects * sizeof(*delta_list));
GITERR_CHECK_ALLOC(delta_list);
@@ -1250,40 +1242,48 @@ int git_packbuilder_write_buf(git_buf *buf, git_packbuilder *pb)
static int write_cb(void *buf, size_t len, void *payload)
{
struct pack_write_context *ctx = payload;
- return git_indexer_stream_add(ctx->indexer, buf, len, ctx->stats);
+ return git_indexer_append(ctx->indexer, buf, len, ctx->stats);
}
int git_packbuilder_write(
git_packbuilder *pb,
const char *path,
+ unsigned int mode,
git_transfer_progress_callback progress_cb,
void *progress_cb_payload)
{
- git_indexer_stream *indexer;
+ git_indexer *indexer;
git_transfer_progress stats;
struct pack_write_context ctx;
PREPARE_PACK;
- if (git_indexer_stream_new(
- &indexer, path, progress_cb, progress_cb_payload) < 0)
+ if (git_indexer_new(
+ &indexer, path, mode, pb->odb, progress_cb, progress_cb_payload) < 0)
return -1;
ctx.indexer = indexer;
ctx.stats = &stats;
if (git_packbuilder_foreach(pb, write_cb, &ctx) < 0 ||
- git_indexer_stream_finalize(indexer, &stats) < 0) {
- git_indexer_stream_free(indexer);
+ git_indexer_commit(indexer, &stats) < 0) {
+ git_indexer_free(indexer);
return -1;
}
- git_indexer_stream_free(indexer);
+ git_oid_cpy(&pb->pack_oid, git_indexer_hash(indexer));
+
+ git_indexer_free(indexer);
return 0;
}
#undef PREPARE_PACK
+const git_oid *git_packbuilder_hash(git_packbuilder *pb)
+{
+ return &pb->pack_oid;
+}
+
static int cb_tree_walk(const char *root, const git_tree_entry *entry, void *payload)
{
struct tree_walk_context *ctx = payload;
@@ -1346,6 +1346,17 @@ uint32_t git_packbuilder_written(git_packbuilder *pb)
return pb->nr_written;
}
+int git_packbuilder_set_callbacks(git_packbuilder *pb, git_packbuilder_progress progress_cb, void *progress_cb_payload)
+{
+ if (!pb)
+ return -1;
+
+ pb->progress_cb = progress_cb;
+ pb->progress_cb_payload = progress_cb_payload;
+
+ return 0;
+}
+
void git_packbuilder_free(git_packbuilder *pb)
{
if (pb == NULL)