diff options
Diffstat (limited to 'reachable.c')
| -rw-r--r-- | reachable.c | 106 |
1 files changed, 95 insertions, 11 deletions
diff --git a/reachable.c b/reachable.c index aba63ebeb3..0ce8f83e56 100644 --- a/reachable.c +++ b/reachable.c @@ -1,4 +1,6 @@ -#include "cache.h" +#include "git-compat-util.h" +#include "gettext.h" +#include "hex.h" #include "refs.h" #include "tag.h" #include "commit.h" @@ -11,9 +13,11 @@ #include "list-objects.h" #include "packfile.h" #include "worktree.h" -#include "object-store.h" +#include "object-store-ll.h" #include "pack-bitmap.h" #include "pack-mtimes.h" +#include "config.h" +#include "run-command.h" struct connectivity_progress { struct progress *progress; @@ -48,7 +52,9 @@ static int add_one_ref(const char *path, const struct object_id *oid, * The traversal will have already marked us as SEEN, so we * only need to handle any progress reporting here. */ -static void mark_object(struct object *obj, const char *name, void *data) +static void mark_object(struct object *obj UNUSED, + const char *name UNUSED, + void *data) { update_progress(data); } @@ -63,8 +69,77 @@ struct recent_data { timestamp_t timestamp; report_recent_object_fn *cb; int ignore_in_core_kept_packs; + + struct oidset extra_recent_oids; + int extra_recent_oids_loaded; }; +static int run_one_gc_recent_objects_hook(struct oidset *set, + const char *args) +{ + struct child_process cmd = CHILD_PROCESS_INIT; + struct strbuf buf = STRBUF_INIT; + FILE *out; + int ret = 0; + + cmd.use_shell = 1; + cmd.out = -1; + + strvec_push(&cmd.args, args); + + if (start_command(&cmd)) + return -1; + + out = xfdopen(cmd.out, "r"); + while (strbuf_getline(&buf, out) != EOF) { + struct object_id oid; + const char *rest; + + if (parse_oid_hex(buf.buf, &oid, &rest) || *rest) { + ret = error(_("invalid extra cruft tip: '%s'"), buf.buf); + break; + } + + oidset_insert(set, &oid); + } + + fclose(out); + ret |= finish_command(&cmd); + + strbuf_release(&buf); + return ret; +} + +static void load_gc_recent_objects(struct recent_data *data) +{ + const struct string_list *programs; + int ret = 0; + size_t i; + + data->extra_recent_oids_loaded = 1; + + if (git_config_get_string_multi("gc.recentobjectshook", &programs)) + return; + + for (i = 0; i < programs->nr; i++) { + ret = run_one_gc_recent_objects_hook(&data->extra_recent_oids, + programs->items[i].string); + if (ret) + die(_("unable to enumerate additional recent objects")); + } +} + +static int obj_is_recent(const struct object_id *oid, timestamp_t mtime, + struct recent_data *data) +{ + if (mtime > data->timestamp) + return 1; + + if (!data->extra_recent_oids_loaded) + load_gc_recent_objects(data); + return oidset_contains(&data->extra_recent_oids, oid); +} + static void add_recent_object(const struct object_id *oid, struct packed_git *pack, off_t offset, @@ -74,7 +149,7 @@ static void add_recent_object(const struct object_id *oid, struct object *obj; enum object_type type; - if (mtime <= data->timestamp) + if (!obj_is_recent(oid, mtime, data)) return; /* @@ -152,7 +227,8 @@ static int add_recent_loose(const struct object_id *oid, } static int add_recent_packed(const struct object_id *oid, - struct packed_git *p, uint32_t pos, + struct packed_git *p, + uint32_t pos, void *data) { struct object *obj; @@ -188,24 +264,32 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs, data.cb = cb; data.ignore_in_core_kept_packs = ignore_in_core_kept_packs; + oidset_init(&data.extra_recent_oids, 0); + data.extra_recent_oids_loaded = 0; + r = for_each_loose_object(add_recent_loose, &data, FOR_EACH_OBJECT_LOCAL_ONLY); if (r) - return r; + goto done; flags = FOR_EACH_OBJECT_LOCAL_ONLY | FOR_EACH_OBJECT_PACK_ORDER; if (ignore_in_core_kept_packs) flags |= FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS; - return for_each_packed_object(add_recent_packed, &data, flags); + r = for_each_packed_object(add_recent_packed, &data, flags); + +done: + oidset_clear(&data.extra_recent_oids); + + return r; } static int mark_object_seen(const struct object_id *oid, enum object_type type, - int exclude, - uint32_t name_hash, - struct packed_git *found_pack, - off_t found_offset) + int exclude UNUSED, + uint32_t name_hash UNUSED, + struct packed_git *found_pack UNUSED, + off_t found_offset UNUSED) { struct object *obj = lookup_object_by_type(the_repository, oid, type); if (!obj) |
