Skip to content

Commit 3c12d0b

Browse files
committed
Merge branch 'tb/pack-revindex-on-disk'
Introduce an on-disk file to record revindex for packdata, which traditionally was always created on the fly and only in-core. * tb/pack-revindex-on-disk: t5325: check both on-disk and in-memory reverse index pack-revindex: ensure that on-disk reverse indexes are given precedence t: support GIT_TEST_WRITE_REV_INDEX t: prepare for GIT_TEST_WRITE_REV_INDEX Documentation/config/pack.txt: advertise 'pack.writeReverseIndex' builtin/pack-objects.c: respect 'pack.writeReverseIndex' builtin/index-pack.c: write reverse indexes builtin/index-pack.c: allow stripping arbitrary extensions pack-write.c: prepare to write 'pack-*.rev' files packfile: prepare for the existence of '*.rev' files
2 parents 2c873f9 + 6885cd7 commit 3c12d0b

22 files changed

+545
-42
lines changed

Documentation/config/pack.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,10 @@ pack.writeBitmapHashCache::
133133
between an older, bitmapped pack and objects that have been
134134
pushed since the last gc). The downside is that it consumes 4
135135
bytes per object of disk space. Defaults to true.
136+
137+
pack.writeReverseIndex::
138+
When true, git will write a corresponding .rev file (see:
139+
link:../technical/pack-format.html[Documentation/technical/pack-format.txt])
140+
for each new packfile that it writes in all places except for
141+
linkgit:git-fast-import[1] and in the bulk checkin mechanism.
142+
Defaults to false.

Documentation/git-index-pack.txt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ git-index-pack - Build pack index file for an existing packed archive
99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git index-pack' [-v] [-o <index-file>] <pack-file>
12+
'git index-pack' [-v] [-o <index-file>] [--[no-]rev-index] <pack-file>
1313
'git index-pack' --stdin [--fix-thin] [--keep] [-v] [-o <index-file>]
14-
[<pack-file>]
14+
[--[no-]rev-index] [<pack-file>]
1515

1616

1717
DESCRIPTION
1818
-----------
1919
Reads a packed archive (.pack) from the specified file, and
20-
builds a pack index file (.idx) for it. The packed archive
21-
together with the pack index can then be placed in the
22-
objects/pack/ directory of a Git repository.
20+
builds a pack index file (.idx) for it. Optionally writes a
21+
reverse-index (.rev) for the specified pack. The packed
22+
archive together with the pack index can then be placed in
23+
the objects/pack/ directory of a Git repository.
2324

2425

2526
OPTIONS
@@ -35,6 +36,13 @@ OPTIONS
3536
fails if the name of packed archive does not end
3637
with .pack).
3738

39+
--[no-]rev-index::
40+
When this flag is provided, generate a reverse index
41+
(a `.rev` file) corresponding to the given pack. If
42+
`--verify` is given, ensure that the existing
43+
reverse index is correct. Takes precedence over
44+
`pack.writeReverseIndex`.
45+
3846
--stdin::
3947
When this flag is provided, the pack is read from stdin
4048
instead and a copy is then written to <pack-file>. If

Documentation/technical/pack-format.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,26 @@ Pack file entry: <+
274274

275275
Index checksum of all of the above.
276276

277+
== pack-*.rev files have the format:
278+
279+
- A 4-byte magic number '0x52494458' ('RIDX').
280+
281+
- A 4-byte version identifier (= 1).
282+
283+
- A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).
284+
285+
- A table of index positions (one per packed object, num_objects in
286+
total, each a 4-byte unsigned integer in network order), sorted by
287+
their corresponding offsets in the packfile.
288+
289+
- A trailer, containing a:
290+
291+
checksum of the corresponding packfile, and
292+
293+
a checksum of all of the above.
294+
295+
All 4-byte numbers are in network order.
296+
277297
== multi-pack-index (MIDX) files have the following format:
278298

279299
The multi-pack-index files refer to multiple pack-files and loose objects.

builtin/index-pack.c

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include "promisor-remote.h"
1818

1919
static const char index_pack_usage[] =
20-
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
20+
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
2121

2222
struct object_entry {
2323
struct pack_idx_entry idx;
@@ -1436,15 +1436,15 @@ static void fix_unresolved_deltas(struct hashfile *f)
14361436
free(sorted_by_pos);
14371437
}
14381438

1439-
static const char *derive_filename(const char *pack_name, const char *suffix,
1440-
struct strbuf *buf)
1439+
static const char *derive_filename(const char *pack_name, const char *strip,
1440+
const char *suffix, struct strbuf *buf)
14411441
{
14421442
size_t len;
1443-
if (!strip_suffix(pack_name, ".pack", &len))
1444-
die(_("packfile name '%s' does not end with '.pack'"),
1445-
pack_name);
1443+
if (!strip_suffix(pack_name, strip, &len) || !len ||
1444+
pack_name[len - 1] != '.')
1445+
die(_("packfile name '%s' does not end with '.%s'"),
1446+
pack_name, strip);
14461447
strbuf_add(buf, pack_name, len);
1447-
strbuf_addch(buf, '.');
14481448
strbuf_addstr(buf, suffix);
14491449
return buf->buf;
14501450
}
@@ -1459,7 +1459,7 @@ static void write_special_file(const char *suffix, const char *msg,
14591459
int msg_len = strlen(msg);
14601460

14611461
if (pack_name)
1462-
filename = derive_filename(pack_name, suffix, &name_buf);
1462+
filename = derive_filename(pack_name, "pack", suffix, &name_buf);
14631463
else
14641464
filename = odb_pack_name(&name_buf, hash, suffix);
14651465

@@ -1484,12 +1484,14 @@ static void write_special_file(const char *suffix, const char *msg,
14841484

14851485
static void final(const char *final_pack_name, const char *curr_pack_name,
14861486
const char *final_index_name, const char *curr_index_name,
1487+
const char *final_rev_index_name, const char *curr_rev_index_name,
14871488
const char *keep_msg, const char *promisor_msg,
14881489
unsigned char *hash)
14891490
{
14901491
const char *report = "pack";
14911492
struct strbuf pack_name = STRBUF_INIT;
14921493
struct strbuf index_name = STRBUF_INIT;
1494+
struct strbuf rev_index_name = STRBUF_INIT;
14931495
int err;
14941496

14951497
if (!from_stdin) {
@@ -1524,6 +1526,16 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
15241526
} else
15251527
chmod(final_index_name, 0444);
15261528

1529+
if (curr_rev_index_name) {
1530+
if (final_rev_index_name != curr_rev_index_name) {
1531+
if (!final_rev_index_name)
1532+
final_rev_index_name = odb_pack_name(&rev_index_name, hash, "rev");
1533+
if (finalize_object_file(curr_rev_index_name, final_rev_index_name))
1534+
die(_("cannot store reverse index file"));
1535+
} else
1536+
chmod(final_rev_index_name, 0444);
1537+
}
1538+
15271539
if (do_fsck_object) {
15281540
struct packed_git *p;
15291541
p = add_packed_git(final_index_name, strlen(final_index_name), 0);
@@ -1553,6 +1565,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
15531565
}
15541566
}
15551567

1568+
strbuf_release(&rev_index_name);
15561569
strbuf_release(&index_name);
15571570
strbuf_release(&pack_name);
15581571
}
@@ -1578,6 +1591,12 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
15781591
}
15791592
return 0;
15801593
}
1594+
if (!strcmp(k, "pack.writereverseindex")) {
1595+
if (git_config_bool(k, v))
1596+
opts->flags |= WRITE_REV;
1597+
else
1598+
opts->flags &= ~WRITE_REV;
1599+
}
15811600
return git_default_config(k, v, cb);
15821601
}
15831602

@@ -1695,12 +1714,14 @@ static void show_pack_info(int stat_only)
16951714

16961715
int cmd_index_pack(int argc, const char **argv, const char *prefix)
16971716
{
1698-
int i, fix_thin_pack = 0, verify = 0, stat_only = 0;
1717+
int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
16991718
const char *curr_index;
1700-
const char *index_name = NULL, *pack_name = NULL;
1719+
const char *curr_rev_index = NULL;
1720+
const char *index_name = NULL, *pack_name = NULL, *rev_index_name = NULL;
17011721
const char *keep_msg = NULL;
17021722
const char *promisor_msg = NULL;
17031723
struct strbuf index_name_buf = STRBUF_INIT;
1724+
struct strbuf rev_index_name_buf = STRBUF_INIT;
17041725
struct pack_idx_entry **idx_objects;
17051726
struct pack_idx_option opts;
17061727
unsigned char pack_hash[GIT_MAX_RAWSZ];
@@ -1727,6 +1748,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
17271748
if (prefix && chdir(prefix))
17281749
die(_("Cannot come back to cwd"));
17291750

1751+
if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
1752+
rev_index = 1;
1753+
else
1754+
rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV));
1755+
17301756
for (i = 1; i < argc; i++) {
17311757
const char *arg = argv[i];
17321758

@@ -1805,6 +1831,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
18051831
if (hash_algo == GIT_HASH_UNKNOWN)
18061832
die(_("unknown hash algorithm '%s'"), arg);
18071833
repo_set_hash_algo(the_repository, hash_algo);
1834+
} else if (!strcmp(arg, "--rev-index")) {
1835+
rev_index = 1;
1836+
} else if (!strcmp(arg, "--no-rev-index")) {
1837+
rev_index = 0;
18081838
} else
18091839
usage(index_pack_usage);
18101840
continue;
@@ -1824,7 +1854,16 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
18241854
if (from_stdin && hash_algo)
18251855
die(_("--object-format cannot be used with --stdin"));
18261856
if (!index_name && pack_name)
1827-
index_name = derive_filename(pack_name, "idx", &index_name_buf);
1857+
index_name = derive_filename(pack_name, "pack", "idx", &index_name_buf);
1858+
1859+
opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
1860+
if (rev_index) {
1861+
opts.flags |= verify ? WRITE_REV_VERIFY : WRITE_REV;
1862+
if (index_name)
1863+
rev_index_name = derive_filename(index_name,
1864+
"idx", "rev",
1865+
&rev_index_name_buf);
1866+
}
18281867

18291868
if (verify) {
18301869
if (!index_name)
@@ -1878,11 +1917,16 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
18781917
for (i = 0; i < nr_objects; i++)
18791918
idx_objects[i] = &objects[i].idx;
18801919
curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
1920+
if (rev_index)
1921+
curr_rev_index = write_rev_file(rev_index_name, idx_objects,
1922+
nr_objects, pack_hash,
1923+
opts.flags);
18811924
free(idx_objects);
18821925

18831926
if (!verify)
18841927
final(pack_name, curr_pack,
18851928
index_name, curr_index,
1929+
rev_index_name, curr_rev_index,
18861930
keep_msg, promisor_msg,
18871931
pack_hash);
18881932
else
@@ -1893,10 +1937,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
18931937

18941938
free(objects);
18951939
strbuf_release(&index_name_buf);
1940+
strbuf_release(&rev_index_name_buf);
18961941
if (pack_name == NULL)
18971942
free((void *) curr_pack);
18981943
if (index_name == NULL)
18991944
free((void *) curr_index);
1945+
if (rev_index_name == NULL)
1946+
free((void *) curr_rev_index);
19001947

19011948
/*
19021949
* Let the caller know this pack is not self contained

builtin/pack-objects.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2953,6 +2953,13 @@ static int git_pack_config(const char *k, const char *v, void *cb)
29532953
pack_idx_opts.version);
29542954
return 0;
29552955
}
2956+
if (!strcmp(k, "pack.writereverseindex")) {
2957+
if (git_config_bool(k, v))
2958+
pack_idx_opts.flags |= WRITE_REV;
2959+
else
2960+
pack_idx_opts.flags &= ~WRITE_REV;
2961+
return 0;
2962+
}
29562963
if (!strcmp(k, "uploadpack.blobpackfileuri")) {
29572964
struct configured_exclusion *ex = xmalloc(sizeof(*ex));
29582965
const char *oid_end, *pack_end;
@@ -3592,6 +3599,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
35923599

35933600
reset_pack_idx_option(&pack_idx_opts);
35943601
git_config(git_pack_config, NULL);
3602+
if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
3603+
pack_idx_opts.flags |= WRITE_REV;
35953604

35963605
progress = isatty(2);
35973606
argc = parse_options(argc, argv, prefix, pack_objects_options,

builtin/repack.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ static struct {
209209
} exts[] = {
210210
{".pack"},
211211
{".idx"},
212+
{".rev", 1},
212213
{".bitmap", 1},
213214
{".promisor", 1},
214215
};

ci/run-build-and-tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ linux-gcc)
2424
export GIT_TEST_MULTI_PACK_INDEX=1
2525
export GIT_TEST_ADD_I_USE_BUILTIN=1
2626
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
27+
export GIT_TEST_WRITE_REV_INDEX=1
2728
make test
2829
;;
2930
linux-clang)

object-store.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ struct packed_git {
8585
multi_pack_index:1;
8686
unsigned char hash[GIT_MAX_RAWSZ];
8787
struct revindex_entry *revindex;
88+
const uint32_t *revindex_data;
89+
const uint32_t *revindex_map;
90+
size_t revindex_size;
8891
/* something like ".git/objects/pack/xxxxx.pack" */
8992
char pack_name[FLEX_ARRAY]; /* more */
9093
};

0 commit comments

Comments
 (0)