split-index: add and use unshare_split_index()
When split-index is being used, we have two cache_entry arrays in index_state->cache[] and index_state->split_index->base->cache[]. index_state->cache[] may share the same entries with base->cache[] so we can quickly determine what entries are shared. This makes memory management tricky, we can't free base->cache[] until we know index_state->cache[] does not point to any of those entries. unshare_split_index() is added for this purpose, to find shared entries and either duplicate them in index_state->cache[], or discard them. Either way it should be safe to free base->cache[] after unshare_split_index(). Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
May 5, 2017 at 16:57 UTC
f9d7abec2ad2f9eb3d8873169cc28c34273df082
3 files changed
+47
-21
read-cache.c
+2
-8
@@ -1877,15 +1877,9 @@ int discard_index(struct index_state *istate)
1877
{
1878
int i;
1879
1880
- for (i = 0; i < istate->cache_nr; i++) {
1881
- if (istate->cache[i]->index &&
1882
- istate->split_index &&
1883
- istate->split_index->base &&
1884
- istate->cache[i]->index <= istate->split_index->base->cache_nr &&
1885
- istate->cache[i] == istate->split_index->base->cache[istate->cache[i]->index - 1])
1886
- continue;
1880
+ unshare_split_index(istate, 1);
1881
+ for (i = 0; i < istate->cache_nr; i++)
1882
free(istate->cache[i]);
1888
- }
1883
resolve_undo_clear_index(istate);
1884
istate->cache_nr = 0;
1885
istate->cache_changed = 0;
split-index.c
+44
-13
@@ -73,10 +73,17 @@ void move_cache_to_base_index(struct index_state *istate)
73
int i;
74
75
/*
76
- * do not delete old si->base, its index entries may be shared
77
- * with istate->cache[]. Accept a bit of leaking here because
78
- * this code is only used by short-lived update-index.
76
+ * If "si" is shared with another index_state (e.g. by
77
+ * unpack-trees code), we will need to duplicate split_index
78
+ * struct. It's not happening now though, luckily.
79
*/
80
+ assert(si->refcount <= 1);
81
+
82
+ unshare_split_index(istate, 0);
83
+ if (si->base) {
84
+ discard_index(si->base);
85
+ free(si->base);
86
+ }
87
si->base = xcalloc(1, sizeof(*si->base));
88
si->base->version = istate->version;
89
/* zero timestamp disables racy test in ce_write_index() */
@@ -275,11 +282,41 @@ void finish_writing_split_index(struct index_state *istate)
282
istate->cache_nr = si->saved_cache_nr;
283
}
284
285
+void unshare_split_index(struct index_state *istate, int discard)
286
+{
287
+ struct split_index *si = istate->split_index;
288
+ int i;
289
+
290
+ if (!si || !si->base)
291
+ return;
292
+
293
+ for (i = 0; i < istate->cache_nr; i++) {
294
+ struct cache_entry *ce = istate->cache[i];
295
+ struct cache_entry *new = NULL;
296
+
297
+ if (!ce->index ||
298
+ ce->index > si->base->cache_nr ||
299
+ ce != si->base->cache[ce->index - 1])
300
+ continue;
301
+
302
+ if (!discard) {
303
+ int len = ce_namelen(ce);
304
+ new = xcalloc(1, cache_entry_size(len));
305
+ copy_cache_entry(new, ce);
306
+ memcpy(new->name, ce->name, len);
307
+ new->index = 0;
308
+ }
309
+ istate->cache[i] = new;
310
+ }
311
+}
312
+
313
+
314
void discard_split_index(struct index_state *istate)
315
{
316
struct split_index *si = istate->split_index;
317
if (!si)
318
return;
319
+ unshare_split_index(istate, 0);
320
istate->split_index = NULL;
321
si->refcount--;
322
if (si->refcount)
@@ -328,14 +365,8 @@ void add_split_index(struct index_state *istate)
365
366
void remove_split_index(struct index_state *istate)
367
{
331
- if (istate->split_index) {
332
- /*
333
- * can't discard_split_index(&the_index); because that
334
- * will destroy split_index->base->cache[], which may
335
- * be shared with the_index.cache[]. So yeah we're
336
- * leaking a bit here.
337
- */
338
- istate->split_index = NULL;
339
- istate->cache_changed |= SOMETHING_CHANGED;
340
- }
368
+ if (!istate->split_index)
369
+ return;
370
+ discard_split_index(istate);
371
+ istate->cache_changed |= SOMETHING_CHANGED;
372
}
split-index.h
+1
@@ -33,5 +33,6 @@ void finish_writing_split_index(struct index_state *istate);
33
void discard_split_index(struct index_state *istate);
34
void add_split_index(struct index_state *istate);
35
void remove_split_index(struct index_state *istate);
36
+void unshare_split_index(struct index_state *istate, int discard);
37
38
#endif