* [PATCH] index-pack: support --pack-stream to concatenate packs
@ 2011-01-09 7:45 Nguyễn Thái Ngọc Duy
0 siblings, 0 replies; only message in thread
From: Nguyễn Thái Ngọc Duy @ 2011-01-09 7:45 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
--pack-stream --stdin assumes stdin is a stream of packs and creates
a single pack containing all objects of the stream.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Don't know if it's useful for anybody else. Might be a cheaper way
than git-repack to reduce the number of packs.
builtin/index-pack.c | 119 ++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 101 insertions(+), 18 deletions(-)
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 8dc5c0b..4864913 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -59,6 +59,7 @@ static int nr_deltas;
static int nr_resolved_deltas;
static int from_stdin;
+static int pack_stream;
static int strict;
static int verbose;
@@ -68,7 +69,7 @@ static struct progress *progress;
static unsigned char input_buffer[4096];
static unsigned int input_offset, input_len;
static off_t consumed_bytes;
-static git_SHA_CTX input_ctx;
+static git_SHA_CTX input_ctx, pack_stream_ctx;
static uint32_t input_crc32;
static int input_fd, output_fd, pack_fd;
@@ -115,23 +116,35 @@ static void check_objects(void)
/* Discard current buffer used content. */
-static void flush(void)
+static void flush_1(int in_pack_stream)
{
if (input_offset) {
- if (output_fd >= 0)
- write_or_die(output_fd, input_buffer, input_offset);
+ if (output_fd >= 0 &&
+ (!pack_stream || (pack_stream && in_pack_stream)))
+ write_or_die(output_fd, input_buffer, input_offset);
+
git_SHA1_Update(&input_ctx, input_buffer, input_offset);
+ if (pack_stream && in_pack_stream)
+ git_SHA1_Update(&pack_stream_ctx, input_buffer, input_offset);
memmove(input_buffer, input_buffer + input_offset, input_len);
input_offset = 0;
}
}
+static void flush(void)
+{
+ flush_1(1);
+}
+
/*
* Make sure at least "min" bytes are available in the buffer, and
* return the pointer to the buffer.
*/
-static void *fill(int min)
+static void *fill_gently(int min, int *got_eof)
{
+ if (got_eof)
+ *got_eof = 0;
+
if (min <= input_len)
return input_buffer + input_offset;
if (min > sizeof(input_buffer))
@@ -141,9 +154,16 @@ static void *fill(int min)
ssize_t ret = xread(input_fd, input_buffer + input_len,
sizeof(input_buffer) - input_len);
if (ret <= 0) {
- if (!ret)
- die("early EOF");
- die_errno("read error on input");
+ if (!ret) {
+ if (!got_eof)
+ die("early EOF");
+ else {
+ *got_eof = 1;
+ return NULL;
+ }
+ }
+ else
+ die_errno("read error on input");
}
input_len += ret;
if (from_stdin)
@@ -152,6 +172,11 @@ static void *fill(int min)
return input_buffer;
}
+static void *fill(int min)
+{
+ return fill_gently(min, NULL);
+}
+
static void use(int bytes)
{
if (bytes > input_len)
@@ -188,6 +213,8 @@ static const char *open_pack_file(const char *pack_name)
pack_fd = input_fd;
}
git_SHA1_Init(&input_ctx);
+ if (pack_stream)
+ git_SHA1_Init(&pack_stream_ctx);
return pack_name;
}
@@ -202,7 +229,7 @@ static void parse_pack_header(void)
die("pack version %"PRIu32" unsupported",
ntohl(hdr->hdr_version));
- nr_objects = ntohl(hdr->hdr_entries);
+ nr_objects += ntohl(hdr->hdr_entries);
use(sizeof(struct pack_header));
}
@@ -590,10 +617,10 @@ static int compare_delta_entry(const void *a, const void *b)
}
/* Parse all objects and return the pack content SHA1 hash */
-static void parse_pack_objects(unsigned char *sha1)
+static void parse_pack_objects(unsigned char *sha1, int start_object)
{
int i;
- struct delta_entry *delta = deltas;
+ struct delta_entry *delta = deltas + nr_deltas;
struct stat st;
/*
@@ -606,7 +633,7 @@ static void parse_pack_objects(unsigned char *sha1)
progress = start_progress(
from_stdin ? "Receiving objects" : "Indexing objects",
nr_objects);
- for (i = 0; i < nr_objects; i++) {
+ for (i = start_object; i < nr_objects; i++) {
struct object_entry *obj = &objects[i];
void *data = unpack_raw_entry(obj, &delta->base);
obj->real_type = obj->type;
@@ -630,11 +657,13 @@ static void parse_pack_objects(unsigned char *sha1)
use(20);
/* If input_fd is a file, we should have reached its end now. */
- if (fstat(input_fd, &st))
- die_errno("cannot fstat packfile");
- if (S_ISREG(st.st_mode) &&
- lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
- die("pack has junk at the end");
+ if (!pack_stream) {
+ if (fstat(input_fd, &st))
+ die_errno("cannot fstat packfile");
+ if (S_ISREG(st.st_mode) &&
+ lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
+ die("pack has junk at the end");
+ }
if (!nr_deltas)
return;
@@ -871,6 +900,54 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
return git_default_config(k, v, cb);
}
+static void parse_following_packs(unsigned char *pack_sha1,
+ const char *curr_pack,
+ int fix_thin_pack)
+{
+ unsigned char sha1[20];
+
+ for (;;) {
+ int got_eof;
+ int last_nr_objects = nr_objects;
+
+ /* SHA1 trailer of the previous pack */
+ consumed_bytes -= 20;
+ flush_1(0);
+
+ fill_gently(sizeof(struct pack_header), &got_eof);
+ if (got_eof) {
+ /*
+ * pretend we also consume the trailer like in
+ * single pack case, a new trailer will be
+ * rewritten by fixup_pack_header_footer().
+ */
+ consumed_bytes += 20;
+ break;
+ }
+
+ git_SHA1_Init(&input_ctx);
+ parse_pack_header();
+ /* un-use() pack headers */
+ consumed_bytes -= sizeof(struct pack_header);
+ flush_1(0);
+
+ objects = xrealloc(objects, (nr_objects + 1) * sizeof(struct object_entry));
+ deltas = xrealloc(deltas, nr_objects * sizeof(struct delta_entry));
+ parse_pack_objects(sha1, last_nr_objects);
+ }
+ git_SHA1_Final(pack_sha1, &pack_stream_ctx);
+
+ if (!fix_thin_pack ||
+ (nr_deltas - nr_resolved_deltas) == 0) {
+ unsigned char read_sha1[20];
+
+ hashcpy(read_sha1, pack_sha1);
+ fixup_pack_header_footer(output_fd, pack_sha1,
+ curr_pack, nr_objects,
+ read_sha1, consumed_bytes-20);
+ }
+}
+
int cmd_index_pack(int argc, const char **argv, const char *prefix)
{
int i, fix_thin_pack = 0;
@@ -898,6 +975,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
from_stdin = 1;
} else if (!strcmp(arg, "--fix-thin")) {
fix_thin_pack = 1;
+ } else if (!strcmp(arg, "--pack-stream")) {
+ pack_stream = 1;
} else if (!strcmp(arg, "--strict")) {
strict = 1;
} else if (!strcmp(arg, "--keep")) {
@@ -946,6 +1025,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
usage(index_pack_usage);
if (fix_thin_pack && !from_stdin)
die("--fix-thin cannot be used without --stdin");
+ if (pack_stream && !from_stdin)
+ die("--pack-stream cannot be used without --stdin");
if (!index_name && pack_name) {
int len = strlen(pack_name);
if (!has_extension(pack_name, ".pack"))
@@ -971,7 +1052,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
parse_pack_header();
objects = xmalloc((nr_objects + 1) * sizeof(struct object_entry));
deltas = xmalloc(nr_objects * sizeof(struct delta_entry));
- parse_pack_objects(pack_sha1);
+ parse_pack_objects(pack_sha1, 0);
+ if (pack_stream)
+ parse_following_packs(pack_sha1, curr_pack, fix_thin_pack);
if (nr_deltas == nr_resolved_deltas) {
stop_progress(&progress);
/* Flush remaining pack final 20-byte SHA1. */
--
1.7.2.2
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2011-01-09 7:46 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-09 7:45 [PATCH] index-pack: support --pack-stream to concatenate packs Nguyễn Thái Ngọc Duy
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.