Skip to content

Commit b47cffd

Browse files
hanwenpeff
authored andcommitted
Reftable support for git-core
For background, see the previous commit introducing the library. TODO: * Resolve spots marked with XXX * Test strategy? Example use: see t/t0031-reftable.sh Signed-off-by: Han-Wen Nienhuys <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]> Co-authored-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b624db0 commit b47cffd

File tree

13 files changed

+1158
-29
lines changed

13 files changed

+1158
-29
lines changed

Documentation/technical/repository-version.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,10 @@ If set, by default "git config" reads from both "config" and
100100
multiple working directory mode, "config" file is shared while
101101
"config.worktree" is per-working directory (i.e., it's in
102102
GIT_COMMON_DIR/worktrees/<id>/config.worktree)
103+
104+
==== `refStorage`
105+
106+
Specifies the file format for the ref database. Values are `files`
107+
(for the traditional packed + loose ref format) and `reftable` for the
108+
binary reftable format. See https://github.com/google/reftable for
109+
more information.

Makefile

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,7 @@ TEST_SHELL_PATH = $(SHELL_PATH)
814814
LIB_FILE = libgit.a
815815
XDIFF_LIB = xdiff/lib.a
816816
VCSSVN_LIB = vcs-svn/lib.a
817+
REFTABLE_LIB = reftable/libreftable.a
817818

818819
GENERATED_H += command-list.h
819820

@@ -960,6 +961,7 @@ LIB_OBJS += rebase-interactive.o
960961
LIB_OBJS += reflog-walk.o
961962
LIB_OBJS += refs.o
962963
LIB_OBJS += refs/files-backend.o
964+
LIB_OBJS += refs/reftable-backend.o
963965
LIB_OBJS += refs/iterator.o
964966
LIB_OBJS += refs/packed-backend.o
965967
LIB_OBJS += refs/ref-cache.o
@@ -1164,7 +1166,7 @@ THIRD_PARTY_SOURCES += compat/regex/%
11641166
THIRD_PARTY_SOURCES += sha1collisiondetection/%
11651167
THIRD_PARTY_SOURCES += sha1dc/%
11661168

1167-
GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB)
1169+
GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB)
11681170
EXTLIBS =
11691171

11701172
GIT_USER_AGENT = git/$(GIT_VERSION)
@@ -2348,11 +2350,28 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
23482350
VCSSVN_OBJS += vcs-svn/svndiff.o
23492351
VCSSVN_OBJS += vcs-svn/svndump.o
23502352

2353+
REFTABLE_OBJS += reftable/basics.o
2354+
REFTABLE_OBJS += reftable/block.o
2355+
REFTABLE_OBJS += reftable/bytes.o
2356+
REFTABLE_OBJS += reftable/file.o
2357+
REFTABLE_OBJS += reftable/iter.o
2358+
REFTABLE_OBJS += reftable/merged.o
2359+
REFTABLE_OBJS += reftable/pq.o
2360+
REFTABLE_OBJS += reftable/reader.o
2361+
REFTABLE_OBJS += reftable/record.o
2362+
REFTABLE_OBJS += reftable/slice.o
2363+
REFTABLE_OBJS += reftable/stack.o
2364+
REFTABLE_OBJS += reftable/tree.o
2365+
REFTABLE_OBJS += reftable/writer.o
2366+
REFTABLE_OBJS += reftable/zlib-compat.o
2367+
2368+
23512369
TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
23522370
OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
23532371
$(XDIFF_OBJS) \
23542372
$(VCSSVN_OBJS) \
23552373
$(FUZZ_OBJS) \
2374+
$(REFTABLE_OBJS) \
23562375
common-main.o \
23572376
git.o
23582377
ifndef NO_CURL
@@ -2489,6 +2508,9 @@ $(XDIFF_LIB): $(XDIFF_OBJS)
24892508
$(VCSSVN_LIB): $(VCSSVN_OBJS)
24902509
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
24912510

2511+
$(REFTABLE_LIB): $(REFTABLE_OBJS)
2512+
$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
2513+
24922514
export DEFAULT_EDITOR DEFAULT_PAGER
24932515

24942516
Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -3104,7 +3126,7 @@ cocciclean:
31043126
clean: profile-clean coverage-clean cocciclean
31053127
$(RM) *.res
31063128
$(RM) $(OBJECTS)
3107-
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
3129+
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) $(REFTABLE_LIB)
31083130
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
31093131
$(RM) $(TEST_PROGRAMS)
31103132
$(RM) $(FUZZ_PROGRAMS)

builtin/clone.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
11091109
}
11101110
}
11111111

1112-
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
1112+
init_db(git_dir, real_git_dir, option_template,
1113+
GIT_HASH_UNKNOWN,
1114+
DEFAULT_REF_STORAGE, /* XXX */
1115+
INIT_DB_QUIET);
11131116

11141117
if (real_git_dir)
11151118
git_dir = real_git_dir;

builtin/init-db.c

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
178178
return 1;
179179
}
180180

181-
void initialize_repository_version(int hash_algo)
181+
void initialize_repository_version(int hash_algo, const char *ref_storage_format)
182182
{
183183
char repo_version_string[10];
184184
int repo_version = GIT_REPO_VERSION;
@@ -188,7 +188,7 @@ void initialize_repository_version(int hash_algo)
188188
die(_("The hash algorithm %s is not supported in this build."), hash_algos[hash_algo].name);
189189
#endif
190190

191-
if (hash_algo != GIT_HASH_SHA1)
191+
if (hash_algo != GIT_HASH_SHA1 || !strcmp(ref_storage_format, "reftable"))
192192
repo_version = GIT_REPO_VERSION_READ;
193193

194194
/* This forces creation of new config file */
@@ -238,6 +238,7 @@ static int create_default_files(const char *template_path,
238238
is_bare_repository_cfg = init_is_bare_repository;
239239
if (init_shared_repository != -1)
240240
set_shared_repository(init_shared_repository);
241+
the_repository->ref_storage_format = xstrdup(fmt->ref_storage);
241242

242243
/*
243244
* We would have created the above under user's umask -- under
@@ -247,6 +248,15 @@ static int create_default_files(const char *template_path,
247248
adjust_shared_perm(get_git_dir());
248249
}
249250

251+
/*
252+
* Check to see if .git/HEAD exists; this must happen before
253+
* initializing the ref db, because we want to see if there is an
254+
* existing HEAD.
255+
*/
256+
path = git_path_buf(&buf, "HEAD");
257+
reinit = (!access(path, R_OK) ||
258+
readlink(path, junk, sizeof(junk) - 1) != -1);
259+
250260
/*
251261
* We need to create a "refs" dir in any case so that older
252262
* versions of git can tell that this is a repository.
@@ -259,15 +269,17 @@ static int create_default_files(const char *template_path,
259269
* Create the default symlink from ".git/HEAD" to the "master"
260270
* branch, if it does not exist yet.
261271
*/
262-
path = git_path_buf(&buf, "HEAD");
263-
reinit = (!access(path, R_OK)
264-
|| readlink(path, junk, sizeof(junk)-1) != -1);
265272
if (!reinit) {
266273
if (create_symref("HEAD", "refs/heads/master", NULL) < 0)
267274
exit(1);
275+
} else {
276+
/*
277+
* XXX should check whether our ref backend matches the
278+
* original one; if not, either die() or convert
279+
*/
268280
}
269281

270-
initialize_repository_version(fmt->hash_algo);
282+
initialize_repository_version(fmt->hash_algo, fmt->ref_storage);
271283

272284
/* Check filemode trustability */
273285
path = git_path_buf(&buf, "config");
@@ -381,7 +393,8 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
381393
}
382394

383395
int init_db(const char *git_dir, const char *real_git_dir,
384-
const char *template_dir, int hash, unsigned int flags)
396+
const char *template_dir, int hash, const char *ref_storage_format,
397+
unsigned int flags)
385398
{
386399
int reinit;
387400
int exist_ok = flags & INIT_DB_EXIST_OK;
@@ -420,6 +433,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
420433
* is an attempt to reinitialize new repository with an old tool.
421434
*/
422435
check_repository_format(&repo_fmt);
436+
repo_fmt.ref_storage = xstrdup(ref_storage_format);
423437

424438
validate_hash_algorithm(&repo_fmt, hash);
425439

@@ -448,6 +462,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
448462
git_config_set("receive.denyNonFastforwards", "true");
449463
}
450464

465+
git_config_set("extensions.refStorage", ref_storage_format);
466+
451467
if (!(flags & INIT_DB_QUIET)) {
452468
int len = strlen(git_dir);
453469

@@ -521,22 +537,26 @@ static const char *const init_db_usage[] = {
521537
int cmd_init_db(int argc, const char **argv, const char *prefix)
522538
{
523539
const char *git_dir;
540+
const char *ref_storage_format = DEFAULT_REF_STORAGE;
524541
const char *real_git_dir = NULL;
525542
const char *work_tree;
526543
const char *template_dir = NULL;
527544
unsigned int flags = 0;
528545
const char *object_format = NULL;
529546
int hash_algo = GIT_HASH_UNKNOWN;
530547
const struct option init_db_options[] = {
531-
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
532-
N_("directory from which templates will be used")),
548+
OPT_STRING(0, "template", &template_dir,
549+
N_("template-directory"),
550+
N_("directory from which templates will be used")),
533551
OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
534-
N_("create a bare repository"), 1),
552+
N_("create a bare repository"), 1),
535553
{ OPTION_CALLBACK, 0, "shared", &init_shared_repository,
536-
N_("permissions"),
537-
N_("specify that the git repository is to be shared amongst several users"),
538-
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
554+
N_("permissions"),
555+
N_("specify that the git repository is to be shared amongst several users"),
556+
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0 },
539557
OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
558+
OPT_STRING(0, "ref-storage", &ref_storage_format, N_("backend"),
559+
N_("the ref storage format to use")),
540560
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
541561
N_("separate git dir from working tree")),
542562
OPT_STRING(0, "object-format", &object_format, N_("hash"),
@@ -646,9 +666,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
646666
}
647667

648668
UNLEAK(real_git_dir);
669+
UNLEAK(ref_storage_format);
649670
UNLEAK(git_dir);
650671
UNLEAK(work_tree);
651672

652673
flags |= INIT_DB_EXIST_OK;
653-
return init_db(git_dir, real_git_dir, template_dir, hash_algo, flags);
674+
return init_db(git_dir, real_git_dir, template_dir, hash_algo, ref_storage_format, flags);
654675
}

cache.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,8 +628,9 @@ int path_inside_repo(const char *prefix, const char *path);
628628

629629
int init_db(const char *git_dir, const char *real_git_dir,
630630
const char *template_dir, int hash_algo,
631+
const char *ref_storage_format,
631632
unsigned int flags);
632-
void initialize_repository_version(int hash_algo);
633+
void initialize_repository_version(int hash_algo, const char *ref_storage_format);
633634

634635
void sanitize_stdfds(void);
635636
int daemonize(void);
@@ -1043,6 +1044,7 @@ struct repository_format {
10431044
int is_bare;
10441045
int hash_algo;
10451046
char *work_tree;
1047+
char *ref_storage;
10461048
struct string_list unknown_extensions;
10471049
};
10481050

refs.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/*
2121
* List of all available backends
2222
*/
23-
static struct ref_storage_be *refs_backends = &refs_be_files;
23+
static struct ref_storage_be *refs_backends = &refs_be_reftable;
2424

2525
static struct ref_storage_be *find_ref_storage_backend(const char *name)
2626
{
@@ -1836,13 +1836,13 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map,
18361836
* Create, record, and return a ref_store instance for the specified
18371837
* gitdir.
18381838
*/
1839-
static struct ref_store *ref_store_init(const char *gitdir,
1839+
static struct ref_store *ref_store_init(const char *gitdir, const char *be_name,
18401840
unsigned int flags)
18411841
{
1842-
const char *be_name = "files";
1843-
struct ref_storage_be *be = find_ref_storage_backend(be_name);
1842+
struct ref_storage_be *be;
18441843
struct ref_store *refs;
18451844

1845+
be = find_ref_storage_backend(be_name);
18461846
if (!be)
18471847
BUG("reference backend %s is unknown", be_name);
18481848

@@ -1858,7 +1858,10 @@ struct ref_store *get_main_ref_store(struct repository *r)
18581858
if (!r->gitdir)
18591859
BUG("attempting to get main_ref_store outside of repository");
18601860

1861-
r->refs = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS);
1861+
r->refs = ref_store_init(r->gitdir,
1862+
r->ref_storage_format ? r->ref_storage_format :
1863+
DEFAULT_REF_STORAGE,
1864+
REF_STORE_ALL_CAPS);
18621865
return r->refs;
18631866
}
18641867

@@ -1913,7 +1916,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
19131916
goto done;
19141917

19151918
/* assume that add_submodule_odb() has been called */
1916-
refs = ref_store_init(submodule_sb.buf,
1919+
refs = ref_store_init(submodule_sb.buf, DEFAULT_REF_STORAGE, /* XXX */
19171920
REF_STORE_READ | REF_STORE_ODB);
19181921
register_ref_store_map(&submodule_ref_stores, "submodule",
19191922
refs, submodule);
@@ -1927,6 +1930,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
19271930

19281931
struct ref_store *get_worktree_ref_store(const struct worktree *wt)
19291932
{
1933+
const char *format = DEFAULT_REF_STORAGE; /* XXX */
19301934
struct ref_store *refs;
19311935
const char *id;
19321936

@@ -1940,9 +1944,9 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
19401944

19411945
if (wt->id)
19421946
refs = ref_store_init(git_common_path("worktrees/%s", wt->id),
1943-
REF_STORE_ALL_CAPS);
1947+
format, REF_STORE_ALL_CAPS);
19441948
else
1945-
refs = ref_store_init(get_git_common_dir(),
1949+
refs = ref_store_init(get_git_common_dir(), format,
19461950
REF_STORE_ALL_CAPS);
19471951

19481952
if (refs)

refs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ struct string_list;
99
struct string_list_item;
1010
struct worktree;
1111

12+
#define DEFAULT_REF_STORAGE "files"
13+
1214
/*
1315
* Resolve a reference, recursively following symbolic refererences.
1416
*

refs/refs-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ struct ref_storage_be {
661661
};
662662

663663
extern struct ref_storage_be refs_be_files;
664+
extern struct ref_storage_be refs_be_reftable;
664665
extern struct ref_storage_be refs_be_packed;
665666

666667
/*

0 commit comments

Comments
 (0)