diff options
Diffstat (limited to 'src/pack-objects.c')
-rw-r--r-- | src/pack-objects.c | 143 |
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) |