Thread (17 messages) flat view 17 messages, 4 authors, 15d ago
COLD15d

[PATCH v2 0/2] builtin/maintenance: improve heuristic for "rerere gc"

From: Patrick Steinhardt <hidden>
Date: 2026-09-04 07:03:28

Hi,

as reported and discussed in [1]. Thanks!

Changes in v2:
  - Restore `prune_one()`.
  - Handle "maintenance.rerere-gc.auto" values explicitly.
  - Rename `rerere_gc_estimate()` to `rerere_gc_needed()`.
  - Link to v1: https://patch.msgid.link/20260903-b4-pks-maintenance-rerere-gc-heuristic-v1-0-9929c45a9788@pks.im

Patrick

[1]: [ref]

---
Patrick Steinhardt (2):
      rerere: extract logic to determine whether entries are stale
      builtin/maintenance: improve heuristic for "rerere gc"

 Documentation/config/maintenance.adoc |  8 +--
 builtin/gc.c                          | 28 +++--------
 rerere.c                              | 94 ++++++++++++++++++++++++++++++-----
 rerere.h                              |  6 +++
 t/t7900-maintenance.sh                | 61 +++++++++++++++++------
 5 files changed, 144 insertions(+), 53 deletions(-)

Range-diff versus v1:

1:  343dbf1c0c ! 1:  1b0b7a7b9a rerere: extract logic to determine whether entries are stale
    @@ rerere.c: static void unlink_rr_item(struct rerere_id *id)
      		cutoff = cutoff_noresolve;
      	}
     -	if (then < cutoff)
    --		unlink_rr_item(id);
     +
     +	return then < cutoff;
    ++}
    ++
    ++static void prune_one(struct rerere_id *id,
    ++		      timestamp_t cutoff_resolve, timestamp_t cutoff_noresolve)
    ++{
    ++	if (rerere_id_is_stale(id, cutoff_resolve, cutoff_noresolve))
    + 		unlink_rr_item(id);
      }
      
    - /* Does the basename in "path" look plausibly like an rr-cache entry? */
     @@ rerere.c: void rerere_gc(struct repository *r, struct string_list *rr)
      	DIR *dir;
      	struct dirent *e;
    @@ rerere.c: void rerere_gc(struct repository *r, struct string_list *rr)
      	repo_config(the_repository, git_default_config, NULL);
      	dir = opendir(repo_git_path_replace(the_repository, &buf, "rr-cache"));
      	if (!dir)
    -@@ rerere.c: void rerere_gc(struct repository *r, struct string_list *rr)
    - 		for (id.variant = 0, id.collection = rr_dir;
    - 		     id.variant < id.collection->status_nr;
    - 		     id.variant++) {
    --			prune_one(&id, cutoff_resolve, cutoff_noresolve);
    -+			if (rerere_id_is_stale(&id, cutoff_resolve, cutoff_noresolve))
    -+				unlink_rr_item(&id);
    - 			if (id.collection->status[id.variant])
    - 				now_empty = 0;
    - 		}
2:  c8a52f0663 ! 2:  1ceb798cdf builtin/maintenance: improve heuristic for "rerere gc"
    @@ builtin/gc.c: static int maintenance_task_rerere_gc(struct maintenance_run_opts
     -	if (!dir)
     -		goto out;
     -	should_gc = !!readdir_skip_dot_and_dotdot(dir);
    -+	if (limit <= 0)
    -+		return limit < 0;
    ++	if (!limit)
    ++		return 0; /* never prune */
    ++	if (limit < 0)
    ++		return 1; /* always prune */
      
     -out:
     -	strbuf_release(&path);
     -	if (dir)
     -		closedir(dir);
     -	return should_gc;
    -+	return rerere_gc_estimate(the_repository, limit) >= (size_t)limit;
    ++	return rerere_gc_needed(the_repository, (size_t)limit);
      }
      
      #define OPTIMIZE_FIELDS_FROM_GC_CONFIG(cfg, aggressive) \
    @@ rerere.c: static int is_rr_cache_dirname(const char *path)
      	return !parse_oid_hex(path, &oid, &end) && !*end;
      }
      
    -+size_t rerere_gc_estimate(struct repository *r, size_t limit)
    ++bool rerere_gc_needed(struct repository *r, size_t limit)
     +{
     +	timestamp_t cutoff_resolve, cutoff_noresolve;
     +	struct strbuf buf = STRBUF_INIT;
    ++	bool needed = false;
     +	struct dirent *e;
     +	size_t count = 0;
     +	DIR *dir;
    @@ rerere.c: static int is_rr_cache_dirname(const char *path)
     +			if (rerere_id_is_stale(&id, cutoff_resolve,
     +					       cutoff_noresolve)) {
     +				count += 256;
    -+				if (count >= limit)
    ++				if (count >= limit) {
    ++					needed = true;
     +					goto out;
    ++				}
     +			}
     +		}
     +	}
    @@ rerere.c: static int is_rr_cache_dirname(const char *path)
     +		closedir(dir);
     +	free_rerere_dirs();
     +	strbuf_release(&buf);
    -+	return count;
    ++	return needed;
     +}
     +
      void rerere_gc(struct repository *r, struct string_list *rr)
    @@ rerere.h: int rerere_remaining(struct repository *, struct string_list *);
      void rerere_gc(struct repository *, struct string_list *);
      
     +/*
    -+ * Estimate the number of stale entries that a run of "git rerere gc"
    -+ * would prune.
    ++ * Check whether garbage collection for rerere entries is needed, which is
    ++ * the case when there's at least `limit` stale entries that would be pruned.
     + */
    -+size_t rerere_gc_estimate(struct repository *r, size_t limit);
    ++bool rerere_gc_needed(struct repository *r, size_t limit);
     +
      #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
      	N_("update the index with reused conflict resolution if possible"))

---
base-commit: 3cb9185f65410273787f74333cc027d2ea5daada
change-id: 20260903-b4-pks-maintenance-rerere-gc-heuristic-763b0a9a50d2
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help