Skip to content

Commit 7424fb7

Browse files
committed
Merge branch 'ps/pack-refs-auto' into jt/reftable-geometric-compaction
* ps/pack-refs-auto: builtin/gc: pack refs when using `git maintenance run --auto` builtin/gc: forward git-gc(1)'s `--auto` flag when packing refs t6500: extract objects with "17" prefix builtin/gc: move `struct maintenance_run_opts` builtin/pack-refs: introduce new "--auto" flag builtin/pack-refs: release allocated memory refs/reftable: expose auto compaction via new flag refs: remove `PACK_REFS_ALL` flag refs: move `struct pack_refs_opts` to where it's used t/helper: drop pack-refs wrapper refs/reftable: print errors on compaction failure reftable/stack: gracefully handle failed auto-compaction due to locks reftable/stack: use error codes when locking fails during compaction reftable/error: discern locked/outdated errors reftable/stack: fix error handling in `reftable_stack_init_addition()`
2 parents d6fd043 + 9f6714a commit 7424fb7

File tree

14 files changed

+308
-125
lines changed

14 files changed

+308
-125
lines changed

Documentation/git-pack-refs.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ git-pack-refs - Pack heads and tags for efficient repository access
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git pack-refs' [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]
11+
'git pack-refs' [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
1212

1313
DESCRIPTION
1414
-----------
@@ -60,6 +60,19 @@ with many branches of historical interests.
6060
The command usually removes loose refs under `$GIT_DIR/refs`
6161
hierarchy after packing them. This option tells it not to.
6262

63+
--auto::
64+
65+
Pack refs as needed depending on the current state of the ref database. The
66+
behavior depends on the ref format used by the repository and may change in the
67+
future.
68+
+
69+
- "files": No special handling for `--auto` has been implemented.
70+
+
71+
- "reftable": Tables are compacted such that they form a geometric
72+
sequence. For two tables N and N+1, where N+1 is newer, this
73+
maintains the property that N is at least twice as big as N+1. Only
74+
tables that violate this property are compacted.
75+
6376
--include <pattern>::
6477

6578
Pack refs based on a `glob(7)` pattern. Repetitions of this option

builtin/gc.c

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,51 @@ static void gc_config(void)
180180
git_config(git_default_config, NULL);
181181
}
182182

183-
struct maintenance_run_opts;
183+
enum schedule_priority {
184+
SCHEDULE_NONE = 0,
185+
SCHEDULE_WEEKLY = 1,
186+
SCHEDULE_DAILY = 2,
187+
SCHEDULE_HOURLY = 3,
188+
};
189+
190+
static enum schedule_priority parse_schedule(const char *value)
191+
{
192+
if (!value)
193+
return SCHEDULE_NONE;
194+
if (!strcasecmp(value, "hourly"))
195+
return SCHEDULE_HOURLY;
196+
if (!strcasecmp(value, "daily"))
197+
return SCHEDULE_DAILY;
198+
if (!strcasecmp(value, "weekly"))
199+
return SCHEDULE_WEEKLY;
200+
return SCHEDULE_NONE;
201+
}
202+
203+
struct maintenance_run_opts {
204+
int auto_flag;
205+
int quiet;
206+
enum schedule_priority schedule;
207+
};
208+
209+
static int pack_refs_condition(void)
210+
{
211+
/*
212+
* The auto-repacking logic for refs is handled by the ref backends and
213+
* exposed via `git pack-refs --auto`. We thus always return truish
214+
* here and let the backend decide for us.
215+
*/
216+
return 1;
217+
}
218+
184219
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
185220
{
186221
struct child_process cmd = CHILD_PROCESS_INIT;
187222

188223
cmd.git_cmd = 1;
189224
strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
225+
if (opts->auto_flag)
226+
strvec_push(&cmd.args, "--auto");
227+
190228
return run_command(&cmd);
191229
}
192230

@@ -547,7 +585,7 @@ static int report_last_gc_error(void)
547585
return ret;
548586
}
549587

550-
static void gc_before_repack(void)
588+
static void gc_before_repack(struct maintenance_run_opts *opts)
551589
{
552590
/*
553591
* We may be called twice, as both the pre- and
@@ -558,7 +596,7 @@ static void gc_before_repack(void)
558596
if (done++)
559597
return;
560598

561-
if (pack_refs && maintenance_task_pack_refs(NULL))
599+
if (pack_refs && maintenance_task_pack_refs(opts))
562600
die(FAILED_RUN, "pack-refs");
563601

564602
if (prune_reflogs) {
@@ -574,7 +612,6 @@ static void gc_before_repack(void)
574612
int cmd_gc(int argc, const char **argv, const char *prefix)
575613
{
576614
int aggressive = 0;
577-
int auto_gc = 0;
578615
int quiet = 0;
579616
int force = 0;
580617
const char *name;
@@ -583,6 +620,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
583620
int keep_largest_pack = -1;
584621
timestamp_t dummy;
585622
struct child_process rerere_cmd = CHILD_PROCESS_INIT;
623+
struct maintenance_run_opts opts = {0};
586624

587625
struct option builtin_gc_options[] = {
588626
OPT__QUIET(&quiet, N_("suppress progress reporting")),
@@ -593,7 +631,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
593631
OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
594632
N_("with --cruft, limit the size of new cruft packs")),
595633
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
596-
OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
634+
OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
597635
PARSE_OPT_NOCOMPLETE),
598636
OPT_BOOL_F(0, "force", &force,
599637
N_("force running gc even if there may be another gc running"),
@@ -638,7 +676,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
638676
if (quiet)
639677
strvec_push(&repack, "-q");
640678

641-
if (auto_gc) {
679+
if (opts.auto_flag) {
642680
/*
643681
* Auto-gc should be least intrusive as possible.
644682
*/
@@ -663,7 +701,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
663701

664702
if (lock_repo_for_gc(force, &pid))
665703
return 0;
666-
gc_before_repack(); /* dies on failure */
704+
gc_before_repack(&opts); /* dies on failure */
667705
delete_tempfile(&pidfile);
668706

669707
/*
@@ -688,7 +726,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
688726

689727
name = lock_repo_for_gc(force, &pid);
690728
if (name) {
691-
if (auto_gc)
729+
if (opts.auto_flag)
692730
return 0; /* be quiet on --auto */
693731
die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
694732
name, (uintmax_t)pid);
@@ -703,7 +741,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
703741
atexit(process_log_file_at_exit);
704742
}
705743

706-
gc_before_repack();
744+
gc_before_repack(&opts);
707745

708746
if (!repository_format_precious_objects) {
709747
struct child_process repack_cmd = CHILD_PROCESS_INIT;
@@ -758,7 +796,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
758796
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
759797
NULL);
760798

761-
if (auto_gc && too_many_loose_objects())
799+
if (opts.auto_flag && too_many_loose_objects())
762800
warning(_("There are too many unreachable loose objects; "
763801
"run 'git prune' to remove them."));
764802

@@ -773,26 +811,6 @@ static const char *const builtin_maintenance_run_usage[] = {
773811
NULL
774812
};
775813

776-
enum schedule_priority {
777-
SCHEDULE_NONE = 0,
778-
SCHEDULE_WEEKLY = 1,
779-
SCHEDULE_DAILY = 2,
780-
SCHEDULE_HOURLY = 3,
781-
};
782-
783-
static enum schedule_priority parse_schedule(const char *value)
784-
{
785-
if (!value)
786-
return SCHEDULE_NONE;
787-
if (!strcasecmp(value, "hourly"))
788-
return SCHEDULE_HOURLY;
789-
if (!strcasecmp(value, "daily"))
790-
return SCHEDULE_DAILY;
791-
if (!strcasecmp(value, "weekly"))
792-
return SCHEDULE_WEEKLY;
793-
return SCHEDULE_NONE;
794-
}
795-
796814
static int maintenance_opt_schedule(const struct option *opt, const char *arg,
797815
int unset)
798816
{
@@ -809,12 +827,6 @@ static int maintenance_opt_schedule(const struct option *opt, const char *arg,
809827
return 0;
810828
}
811829

812-
struct maintenance_run_opts {
813-
int auto_flag;
814-
int quiet;
815-
enum schedule_priority schedule;
816-
};
817-
818830
/* Remember to update object flag allocation in object.h */
819831
#define SEEN (1u<<0)
820832

@@ -1296,7 +1308,7 @@ static struct maintenance_task tasks[] = {
12961308
[TASK_PACK_REFS] = {
12971309
"pack-refs",
12981310
maintenance_task_pack_refs,
1299-
NULL,
1311+
pack_refs_condition,
13001312
},
13011313
};
13021314

builtin/pack-refs.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,28 @@
77
#include "revision.h"
88

99
static char const * const pack_refs_usage[] = {
10-
N_("git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]"),
10+
N_("git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]"),
1111
NULL
1212
};
1313

1414
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
1515
{
16-
unsigned int flags = PACK_REFS_PRUNE;
17-
static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
18-
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
19-
struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
20-
.includes = &included_refs,
21-
.flags = flags };
22-
static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
16+
struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
17+
struct string_list included_refs = STRING_LIST_INIT_NODUP;
18+
struct pack_refs_opts pack_refs_opts = {
19+
.exclusions = &excludes,
20+
.includes = &included_refs,
21+
.flags = PACK_REFS_PRUNE,
22+
};
23+
struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
2324
struct string_list_item *item;
25+
int pack_all = 0;
26+
int ret;
2427

2528
struct option opts[] = {
26-
OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
29+
OPT_BOOL(0, "all", &pack_all, N_("pack everything")),
2730
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
31+
OPT_BIT(0, "auto", &pack_refs_opts.flags, N_("auto-pack refs as needed"), PACK_REFS_AUTO),
2832
OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
2933
N_("references to include")),
3034
OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
@@ -38,11 +42,16 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
3842
for_each_string_list_item(item, &option_excluded_refs)
3943
add_ref_exclusion(pack_refs_opts.exclusions, item->string);
4044

41-
if (pack_refs_opts.flags & PACK_REFS_ALL)
45+
if (pack_all)
4246
string_list_append(pack_refs_opts.includes, "*");
4347

4448
if (!pack_refs_opts.includes->nr)
4549
string_list_append(pack_refs_opts.includes, "refs/tags/*");
4650

47-
return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
51+
ret = refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
52+
53+
clear_ref_exclusions(&excludes);
54+
string_list_clear(&included_refs, 0);
55+
string_list_clear(&option_excluded_refs, 0);
56+
return ret;
4857
}

refs.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@ const char *ref_storage_format_to_name(unsigned int ref_storage_format);
6666
#define RESOLVE_REF_NO_RECURSE 0x02
6767
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
6868

69-
struct pack_refs_opts {
70-
unsigned int flags;
71-
struct ref_exclusions *exclusions;
72-
struct string_list *includes;
73-
};
74-
7569
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
7670
const char *refname,
7771
int resolve_flags,
@@ -428,10 +422,18 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
428422
/*
429423
* Flags for controlling behaviour of pack_refs()
430424
* PACK_REFS_PRUNE: Prune loose refs after packing
431-
* PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs
425+
* PACK_REFS_AUTO: Pack refs on a best effort basis. The heuristics and end
426+
* result are decided by the ref backend. Backends may ignore
427+
* this flag and fall back to a normal repack.
432428
*/
433-
#define PACK_REFS_PRUNE 0x0001
434-
#define PACK_REFS_ALL 0x0002
429+
#define PACK_REFS_PRUNE (1 << 0)
430+
#define PACK_REFS_AUTO (1 << 1)
431+
432+
struct pack_refs_opts {
433+
unsigned int flags;
434+
struct ref_exclusions *exclusions;
435+
struct string_list *includes;
436+
};
435437

436438
/*
437439
* Write a packed-refs file for the current repository.

refs/reftable-backend.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,9 +1203,16 @@ static int reftable_be_pack_refs(struct ref_store *ref_store,
12031203
if (!stack)
12041204
stack = refs->main_stack;
12051205

1206-
ret = reftable_stack_compact_all(stack, NULL);
1207-
if (ret)
1206+
if (opts->flags & PACK_REFS_AUTO)
1207+
ret = reftable_stack_auto_compact(stack);
1208+
else
1209+
ret = reftable_stack_compact_all(stack, NULL);
1210+
if (ret < 0) {
1211+
ret = error(_("unable to compact stack: %s"),
1212+
reftable_error_str(ret));
12081213
goto out;
1214+
}
1215+
12091216
ret = reftable_stack_clean(stack);
12101217
if (ret)
12111218
goto out;

reftable/error.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const char *reftable_error_str(int err)
2222
case REFTABLE_NOT_EXIST_ERROR:
2323
return "file does not exist";
2424
case REFTABLE_LOCK_ERROR:
25-
return "data is outdated";
25+
return "data is locked";
2626
case REFTABLE_API_ERROR:
2727
return "misuse of the reftable API";
2828
case REFTABLE_ZLIB_ERROR:
@@ -35,6 +35,8 @@ const char *reftable_error_str(int err)
3535
return "invalid refname";
3636
case REFTABLE_ENTRY_TOO_BIG_ERROR:
3737
return "entry too large";
38+
case REFTABLE_OUTDATED_ERROR:
39+
return "data concurrently modified";
3840
case -1:
3941
return "general error";
4042
default:

reftable/reftable-error.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ enum reftable_error {
2525
*/
2626
REFTABLE_NOT_EXIST_ERROR = -4,
2727

28-
/* Trying to write out-of-date data. */
28+
/* Trying to access locked data. */
2929
REFTABLE_LOCK_ERROR = -5,
3030

3131
/* Misuse of the API:
@@ -57,6 +57,9 @@ enum reftable_error {
5757
/* Entry does not fit. This can happen when writing outsize reflog
5858
messages. */
5959
REFTABLE_ENTRY_TOO_BIG_ERROR = -11,
60+
61+
/* Trying to write out-of-date data. */
62+
REFTABLE_OUTDATED_ERROR = -12,
6063
};
6164

6265
/* convert the numeric error code to a string. The string should not be

0 commit comments

Comments
 (0)