Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace "git pack-refs" with C function refs_pack_refs #1695

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 14 additions & 1 deletion Documentation/git-pack-refs.txt
Expand Up @@ -8,7 +8,7 @@ git-pack-refs - Pack heads and tags for efficient repository access
SYNOPSIS
--------
[verse]
'git pack-refs' [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]
'git pack-refs' [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]

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

--auto::

Pack refs as needed depending on the current state of the ref database. The
behavior depends on the ref format used by the repository and may change in the
future.
+
- "files": No special handling for `--auto` has been implemented.
+
- "reftable": Tables are compacted such that they form a geometric
sequence. For two tables N and N+1, where N+1 is newer, this
maintains the property that N is at least twice as big as N+1. Only
tables that violate this property are compacted.

--include <pattern>::

Pack refs based on a `glob(7)` pattern. Repetitions of this option
Expand Down
111 changes: 70 additions & 41 deletions builtin/gc.c
Expand Up @@ -42,6 +42,8 @@
#include "setup.h"
#include "trace2.h"

#include <revision.h>

#define FAILED_RUN "failed to run %s"

static const char * const builtin_gc_usage[] = {
Expand Down Expand Up @@ -180,14 +182,67 @@ static void gc_config(void)
git_config(git_default_config, NULL);
}

struct maintenance_run_opts;
enum schedule_priority {
SCHEDULE_NONE = 0,
SCHEDULE_WEEKLY = 1,
SCHEDULE_DAILY = 2,
SCHEDULE_HOURLY = 3,
};

static enum schedule_priority parse_schedule(const char *value)
{
if (!value)
return SCHEDULE_NONE;
if (!strcasecmp(value, "hourly"))
return SCHEDULE_HOURLY;
if (!strcasecmp(value, "daily"))
return SCHEDULE_DAILY;
if (!strcasecmp(value, "weekly"))
return SCHEDULE_WEEKLY;
return SCHEDULE_NONE;
}

struct maintenance_run_opts {
int auto_flag;
int quiet;
enum schedule_priority schedule;
};

static int pack_refs_condition(void)
{
/*
* The auto-repacking logic for refs is handled by the ref backends and
* exposed via `git pack-refs --auto`. We thus always return truish
* here and let the backend decide for us.
*/
return 1;
}

static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
{
struct child_process cmd = CHILD_PROCESS_INIT;

cmd.git_cmd = 1;
strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
return run_command(&cmd);
//following coding convention in pack-refs.c
int ret;

struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
struct string_list included_refs = STRING_LIST_INIT_NODUP;

//default flag is to prune
struct pack_refs_opts pack_refs_opts = {
.exclusions = &excludes,
.includes = &included_refs,
.flags = PACK_REFS_PRUNE,
};


//--all flag
string_list_append(pack_refs_opts.includes, "*");

ret = refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);

//same as run_command return since ret is directly returned in cmd_pack_refs
return ret;

}

static int too_many_loose_objects(void)
Expand Down Expand Up @@ -547,7 +602,7 @@ static int report_last_gc_error(void)
return ret;
}

static void gc_before_repack(void)
static void gc_before_repack(struct maintenance_run_opts *opts)
{
/*
* We may be called twice, as both the pre- and
Expand All @@ -558,7 +613,7 @@ static void gc_before_repack(void)
if (done++)
return;

if (pack_refs && maintenance_task_pack_refs(NULL))
if (pack_refs && maintenance_task_pack_refs(opts))
die(FAILED_RUN, "pack-refs");

if (prune_reflogs) {
Expand All @@ -574,7 +629,6 @@ static void gc_before_repack(void)
int cmd_gc(int argc, const char **argv, const char *prefix)
{
int aggressive = 0;
int auto_gc = 0;
int quiet = 0;
int force = 0;
const char *name;
Expand All @@ -583,6 +637,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int keep_largest_pack = -1;
timestamp_t dummy;
struct child_process rerere_cmd = CHILD_PROCESS_INIT;
struct maintenance_run_opts opts = {0};

struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
Expand All @@ -593,7 +648,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
PARSE_OPT_NOCOMPLETE),
OPT_BOOL_F(0, "force", &force,
N_("force running gc even if there may be another gc running"),
Expand Down Expand Up @@ -638,7 +693,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (quiet)
strvec_push(&repack, "-q");

if (auto_gc) {
if (opts.auto_flag) {
/*
* Auto-gc should be least intrusive as possible.
*/
Expand All @@ -663,7 +718,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)

if (lock_repo_for_gc(force, &pid))
return 0;
gc_before_repack(); /* dies on failure */
gc_before_repack(&opts); /* dies on failure */
delete_tempfile(&pidfile);

/*
Expand All @@ -688,7 +743,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)

name = lock_repo_for_gc(force, &pid);
if (name) {
if (auto_gc)
if (opts.auto_flag)
return 0; /* be quiet on --auto */
die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
name, (uintmax_t)pid);
Expand All @@ -703,7 +758,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
atexit(process_log_file_at_exit);
}

gc_before_repack();
gc_before_repack(&opts);

if (!repository_format_precious_objects) {
struct child_process repack_cmd = CHILD_PROCESS_INIT;
Expand Down Expand Up @@ -758,7 +813,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
NULL);

if (auto_gc && too_many_loose_objects())
if (opts.auto_flag && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
"run 'git prune' to remove them."));

Expand All @@ -773,26 +828,6 @@ static const char *const builtin_maintenance_run_usage[] = {
NULL
};

enum schedule_priority {
SCHEDULE_NONE = 0,
SCHEDULE_WEEKLY = 1,
SCHEDULE_DAILY = 2,
SCHEDULE_HOURLY = 3,
};

static enum schedule_priority parse_schedule(const char *value)
{
if (!value)
return SCHEDULE_NONE;
if (!strcasecmp(value, "hourly"))
return SCHEDULE_HOURLY;
if (!strcasecmp(value, "daily"))
return SCHEDULE_DAILY;
if (!strcasecmp(value, "weekly"))
return SCHEDULE_WEEKLY;
return SCHEDULE_NONE;
}

static int maintenance_opt_schedule(const struct option *opt, const char *arg,
int unset)
{
Expand All @@ -809,12 +844,6 @@ static int maintenance_opt_schedule(const struct option *opt, const char *arg,
return 0;
}

struct maintenance_run_opts {
int auto_flag;
int quiet;
enum schedule_priority schedule;
};

/* Remember to update object flag allocation in object.h */
#define SEEN (1u<<0)

Expand Down Expand Up @@ -1296,7 +1325,7 @@ static struct maintenance_task tasks[] = {
[TASK_PACK_REFS] = {
"pack-refs",
maintenance_task_pack_refs,
NULL,
pack_refs_condition,
},
};

Expand Down
31 changes: 20 additions & 11 deletions builtin/pack-refs.c
Expand Up @@ -7,24 +7,28 @@
#include "revision.h"

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

int cmd_pack_refs(int argc, const char **argv, const char *prefix)
{
unsigned int flags = PACK_REFS_PRUNE;
static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
.includes = &included_refs,
.flags = flags };
static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
struct string_list included_refs = STRING_LIST_INIT_NODUP;
struct pack_refs_opts pack_refs_opts = {
.exclusions = &excludes,
.includes = &included_refs,
.flags = PACK_REFS_PRUNE,
};
struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
struct string_list_item *item;
int pack_all = 0;
int ret;

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

if (pack_refs_opts.flags & PACK_REFS_ALL)
if (pack_all)
string_list_append(pack_refs_opts.includes, "*");

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

return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
ret = refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);

clear_ref_exclusions(&excludes);
string_list_clear(&included_refs, 0);
string_list_clear(&option_excluded_refs, 0);
return ret;
}
6 changes: 3 additions & 3 deletions lockfile.h
Expand Up @@ -321,11 +321,11 @@ static inline int commit_lock_file_to(struct lock_file *lk, const char *path)
* Roll back `lk`: close the file descriptor and/or file pointer and
* remove the lockfile. It is a NOOP to call `rollback_lock_file()`
* for a `lock_file` object that has already been committed or rolled
* back.
* back. No error will be returned in this case.
*/
static inline void rollback_lock_file(struct lock_file *lk)
static inline int rollback_lock_file(struct lock_file *lk)
{
delete_tempfile(&lk->tempfile);
return delete_tempfile(&lk->tempfile);
}

#endif /* LOCKFILE_H */
20 changes: 11 additions & 9 deletions refs.h
Expand Up @@ -66,12 +66,6 @@ const char *ref_storage_format_to_name(unsigned int ref_storage_format);
#define RESOLVE_REF_NO_RECURSE 0x02
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04

struct pack_refs_opts {
unsigned int flags;
struct ref_exclusions *exclusions;
struct string_list *includes;
};

const char *refs_resolve_ref_unsafe(struct ref_store *refs,
const char *refname,
int resolve_flags,
Expand Down Expand Up @@ -428,10 +422,18 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
/*
* Flags for controlling behaviour of pack_refs()
* PACK_REFS_PRUNE: Prune loose refs after packing
* PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs
* PACK_REFS_AUTO: Pack refs on a best effort basis. The heuristics and end
* result are decided by the ref backend. Backends may ignore
* this flag and fall back to a normal repack.
*/
#define PACK_REFS_PRUNE 0x0001
#define PACK_REFS_ALL 0x0002
#define PACK_REFS_PRUNE (1 << 0)
#define PACK_REFS_AUTO (1 << 1)

struct pack_refs_opts {
unsigned int flags;
struct ref_exclusions *exclusions;
struct string_list *includes;
};

/*
* Write a packed-refs file for the current repository.
Expand Down
11 changes: 9 additions & 2 deletions refs/reftable-backend.c
Expand Up @@ -1220,9 +1220,16 @@ static int reftable_be_pack_refs(struct ref_store *ref_store,
if (!stack)
stack = refs->main_stack;

ret = reftable_stack_compact_all(stack, NULL);
if (ret)
if (opts->flags & PACK_REFS_AUTO)
ret = reftable_stack_auto_compact(stack);
else
ret = reftable_stack_compact_all(stack, NULL);
if (ret < 0) {
ret = error(_("unable to compact stack: %s"),
reftable_error_str(ret));
goto out;
}

ret = reftable_stack_clean(stack);
if (ret)
goto out;
Expand Down
4 changes: 3 additions & 1 deletion reftable/error.c
Expand Up @@ -22,7 +22,7 @@ const char *reftable_error_str(int err)
case REFTABLE_NOT_EXIST_ERROR:
return "file does not exist";
case REFTABLE_LOCK_ERROR:
return "data is outdated";
return "data is locked";
case REFTABLE_API_ERROR:
return "misuse of the reftable API";
case REFTABLE_ZLIB_ERROR:
Expand All @@ -35,6 +35,8 @@ const char *reftable_error_str(int err)
return "invalid refname";
case REFTABLE_ENTRY_TOO_BIG_ERROR:
return "entry too large";
case REFTABLE_OUTDATED_ERROR:
return "data concurrently modified";
case -1:
return "general error";
default:
Expand Down