sparse-index: introduce partially-sparse indexes

A future change will present a temporary, in-memory mode where the index can both contain sparse directory entries but also not be completely collapsed to the smallest possible sparse directories. This will be necessary for modifying the sparse-checkout definition while using a sparse index. For now, convert the single-bit member 'sparse_index' in 'struct index_state' to be a an 'enum sparse_index_mode' with three modes: * INDEX_EXPANDED (0): No sparse directories exist. This is always the case for repositories that do not use cone-mode sparse-checkout. * INDEX_COLLAPSED: Sparse directories may exist. Files outside the sparse-checkout cone are reduced to sparse directory entries whenever possible. * INDEX_PARTIALLY_SPARSE: Sparse directories may exist. Some file entries outside the sparse-checkout cone may exist. Running convert_to_sparse() may further reduce those files to sparse directory entries. The main reason to store this extra information is to allow convert_to_sparse() to short-circuit when the index is already in INDEX_EXPANDED mode but to actually do the necessary work when in INDEX_PARTIALLY_SPARSE mode. The INDEX_PARTIALLY_SPARSE mode will be used in an upcoming change. Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed May 23, 2022 at 13:48 UTC 9fadb373dd4a670e761776560d3c40f6fcc80360
4 files changed +32 -15
builtin/sparse-checkout.c
+1 -1
@@ -128,7 +128,7 @@ static void clean_tracked_sparse_directories(struct repository *r)
128 * sparse index will not delete directories that contain
129 * conflicted entries or submodules.
130 */
131 - if (!r->index->sparse_index) {
131 + if (r->index->sparse_index == INDEX_EXPANDED) {
132 /*
133 * If something, such as a merge conflict or other concern,
134 * prevents us from converting to a sparse index, then do
cache.h
+25 -8
@@ -310,6 +310,29 @@ struct untracked_cache;
310 struct progress;
311 struct pattern_list;
312
313 +enum sparse_index_mode {
314 + /*
315 + * There are no sparse directories in the index at all.
316 + *
317 + * Repositories that don't use cone-mode sparse-checkout will
318 + * always have their indexes in this mode.
319 + */
320 + INDEX_EXPANDED = 0,
321 +
322 + /*
323 + * The index has already been collapsed to sparse directories
324 + * whereever possible.
325 + */
326 + INDEX_COLLAPSED,
327 +
328 + /*
329 + * The sparse directories that exist are outside the
330 + * sparse-checkout boundary, but it is possible that some file
331 + * entries could collapse to sparse directory entries.
332 + */
333 + INDEX_PARTIALLY_SPARSE,
334 +};
335 +
336 struct index_state {
337 struct cache_entry **cache;
338 unsigned int version;
@@ -323,14 +346,8 @@ struct index_state {
346 drop_cache_tree : 1,
347 updated_workdir : 1,
348 updated_skipworktree : 1,
326 - fsmonitor_has_run_once : 1,
327 -
328 - /*
329 - * sparse_index == 1 when sparse-directory
330 - * entries exist. Requires sparse-checkout
331 - * in cone mode.
332 - */
333 - sparse_index : 1;
349 + fsmonitor_has_run_once : 1;
350 + enum sparse_index_mode sparse_index;
351 struct hashmap name_hash;
352 struct hashmap dir_hash;
353 struct object_id oid;
read-cache.c
+3 -3
@@ -112,7 +112,7 @@ static const char *alternate_index_output;
112 static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
113 {
114 if (S_ISSPARSEDIR(ce->ce_mode))
115 - istate->sparse_index = 1;
115 + istate->sparse_index = INDEX_COLLAPSED;
116
117 istate->cache[nr] = ce;
118 add_name_hash(istate, ce);
@@ -1856,7 +1856,7 @@ static int read_index_extension(struct index_state *istate,
1856 break;
1857 case CACHE_EXT_SPARSE_DIRECTORIES:
1858 /* no content, only an indicator */
1859 - istate->sparse_index = 1;
1859 + istate->sparse_index = INDEX_COLLAPSED;
1860 break;
1861 default:
1862 if (*ext < 'A' || 'Z' < *ext)
@@ -3149,7 +3149,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
3149 unsigned flags)
3150 {
3151 int ret;
3152 - int was_full = !istate->sparse_index;
3152 + int was_full = istate->sparse_index == INDEX_EXPANDED;
3153
3154 ret = convert_to_sparse(istate, 0);
3155
sparse-index.c
+3 -3
@@ -173,7 +173,7 @@ int convert_to_sparse(struct index_state *istate, int flags)
173 * If the index is already sparse, empty, or otherwise
174 * cannot be converted to sparse, do not convert.
175 */
176 - if (istate->sparse_index || !istate->cache_nr ||
176 + if (istate->sparse_index == INDEX_COLLAPSED || !istate->cache_nr ||
177 !is_sparse_index_allowed(istate, flags))
178 return 0;
179
@@ -214,7 +214,7 @@ int convert_to_sparse(struct index_state *istate, int flags)
214 FREE_AND_NULL(istate->fsmonitor_dirty);
215 FREE_AND_NULL(istate->fsmonitor_last_update);
216
217 - istate->sparse_index = 1;
217 + istate->sparse_index = INDEX_COLLAPSED;
218 trace2_region_leave("index", "convert_to_sparse", istate->repo);
219 return 0;
220 }
@@ -259,7 +259,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
259 * If the index is already full, then keep it full. We will convert
260 * it to a sparse index on write, if possible.
261 */
262 - if (!istate || !istate->sparse_index)
262 + if (!istate || istate->sparse_index == INDEX_EXPANDED)
263 return;
264
265 /*