From 394737eb4202844b6501851d7c8588164d370060 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 15 Oct 2006 00:34:47 -0700 Subject: [PATCH] pack-objects: use of version 3 delta is now optional. This introduces a new configuration item, pack.deltaversion, to control whether pack-objects is allowed to use version 3 delta. By default, we keep generating version 2 delta (and version 2 packfile format) to be compatible with git earlier than v1.2.0. This configuration affects the command in the following ways: - the resulting packfile will have the specified version; - when generating delta, larger copies are allowed only when deltaversion is 3; - the logic to reuse delta from existing packs refuses to reuse delta from packs that uses delta version 3 when the configuration is set to 2. Signed-off-by: Junio C Hamano --- builtin-pack-objects.c | 17 +++++++++++++---- cache.h | 1 + delta.h | 2 ++ diff-delta.c | 15 +++++++++++++-- environment.c | 3 +++ sha1_file.c | 1 + 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 96c069a81d..3532dc8557 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -456,7 +456,7 @@ static void write_pack_file(void) fprintf(stderr, "Writing %d objects.\n", nr_result); hdr.hdr_signature = htonl(PACK_SIGNATURE); - hdr.hdr_version = htonl(PACK_VERSION); + hdr.hdr_version = htonl(delta_version); hdr.hdr_entries = htonl(nr_result); sha1write(f, &hdr, sizeof(hdr)); offset = sizeof(hdr); @@ -914,12 +914,15 @@ static void check_object(struct object_entry *entry) /* Check if it is delta, and the base is also an object * we are going to pack. If so we will reuse the existing * delta. + * + * Also make sure that we do not reuse delta from an existing + * pack that uses higher delta version than allowed. */ if (!no_reuse_delta && entry->in_pack_type == OBJ_DELTA && (base_entry = locate_object_entry(base)) && - (!base_entry->preferred_base)) { - + (!base_entry->preferred_base) && + entry->in_pack->pack_version <= delta_version) { /* Depth value does not matter - find_deltas() * will never consider reused delta as the * base object to deltify other objects @@ -1101,6 +1104,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, * on an earlier try, but only when reusing delta data. */ if (!no_reuse_delta && trg_entry->in_pack && + trg_entry->in_pack->pack_version <= delta_version && trg_entry->in_pack == src_entry->in_pack) return 0; @@ -1326,10 +1330,15 @@ static void setup_progress_signal(void) static int git_pack_config(const char *k, const char *v) { - if(!strcmp(k, "pack.window")) { + if (!strcmp(k, "pack.window")) { window = git_config_int(k, v); return 0; } + if (!strcmp(k, "pack.deltaversion")) { + delta_version = git_config_int(k, v); + if (!pack_version_ok(htonl(delta_version))) + die("value %s for '%s' not allowed", v, k); + } return git_default_config(k, v); } diff --git a/cache.h b/cache.h index c35470107d..724c09ae4f 100644 --- a/cache.h +++ b/cache.h @@ -337,6 +337,7 @@ extern struct packed_git { unsigned int pack_last_used; unsigned int pack_use_cnt; int pack_local; + int pack_version; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ diff --git a/delta.h b/delta.h index 7b3f86d85f..55af3d285e 100644 --- a/delta.h +++ b/delta.h @@ -1,6 +1,8 @@ #ifndef DELTA_H #define DELTA_H +extern int delta_version; + /* opaque object for delta index */ struct delta_index; diff --git a/diff-delta.c b/diff-delta.c index fa16d06c8d..2f6dcfb0d7 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -253,10 +253,13 @@ create_delta(const struct delta_index *index, int inscnt; const unsigned char *ref_data, *ref_top, *data, *top; unsigned char *out; + unsigned int ref_size_limit; if (!trg_buf || !trg_size) return NULL; + ref_size_limit = (delta_version > 2) ? 0xffffff : 0x10000; + outpos = 0; outsize = 8192; if (max_size && outsize >= max_size) @@ -308,8 +311,8 @@ create_delta(const struct delta_index *index, continue; if (ref_size > top - src) ref_size = top - src; - if (ref_size > 0x10000) - ref_size = 0x10000; + if (ref_size > ref_size_limit) + ref_size = ref_size_limit; if (ref_size <= msize) break; while (ref_size-- && *src++ == *ref) @@ -318,6 +321,8 @@ create_delta(const struct delta_index *index, /* this is our best match so far */ msize = ref - entry->ptr; moff = entry->ptr - ref_data; + if (delta_version > 2 && msize >= 0x10000) + break; /* this is good enough */ } } @@ -381,6 +386,12 @@ create_delta(const struct delta_index *index, if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; } msize >>= 8; if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; } + if (delta_version > 2) { + msize >>= 8; + if (msize & 0xff) { + out[outpos++] = msize; i |= 0x40; + } + } *op = i; } diff --git a/environment.c b/environment.c index 63b1d155be..e266f83a8e 100644 --- a/environment.c +++ b/environment.c @@ -8,6 +8,7 @@ * are. */ #include "cache.h" +#include "pack.h" char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; @@ -25,6 +26,8 @@ const char *apply_default_whitespace; int zlib_compression_level = Z_DEFAULT_COMPRESSION; int pager_in_use; int pager_use_color = 1; +/* by default we allow 2 but up to PACK_VERSION is allowed */ +int delta_version = 2; static const char *git_dir; static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; diff --git a/sha1_file.c b/sha1_file.c index d111be74a3..665318243c 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -527,6 +527,7 @@ int use_packed_git(struct packed_git *p) p->pack_size - 20)) { die("packfile %s does not match index.", p->pack_name); } + p->pack_version = ntohl(hdr->hdr_version); } p->pack_last_used = pack_used_ctr++; p->pack_use_cnt++;