Skip to content

Commit a849735

Browse files
jamillgitster
authored andcommitted
block alloc: add lifecycle APIs for cache_entry structs
It has been observed that the time spent loading an index with a large number of entries is partly dominated by malloc() calls. This change is in preparation for using memory pools to reduce the number of malloc() calls made to allocate cahce entries when loading an index. Add an API to allocate and discard cache entries, abstracting the details of managing the memory backing the cache entries. This commit does actually change how memory is managed - this will be done in a later commit in the series. This change makes the distinction between cache entries that are associated with an index and cache entries that are not associated with an index. A main use of cache entries is with an index, and we can optimize the memory management around this. We still have other cases where a cache entry is not persisted with an index, and so we need to handle the "transient" use case as well. To keep the congnitive overhead of managing the cache entries, there will only be a single discard function. This means there must be enough information kept with the cache entry so that we know how to discard them. A summary of the main functions in the API is: make_cache_entry: create cache entry for use in an index. Uses specified parameters to populate cache_entry fields. make_empty_cache_entry: Create an empty cache entry for use in an index. Returns cache entry with empty fields. make_transient_cache_entry: create cache entry that is not used in an index. Uses specified parameters to populate cache_entry fields. make_empty_transient_cache_entry: create cache entry that is not used in an index. Returns cache entry with empty fields. discard_cache_entry: A single function that knows how to discard a cache entry regardless of how it was allocated. Signed-off-by: Jameson Miller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 825ed4d commit a849735

File tree

13 files changed

+165
-92
lines changed

13 files changed

+165
-92
lines changed

apply.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4090,12 +4090,12 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
40904090
return error(_("sha1 information is lacking or useless "
40914091
"(%s)."), name);
40924092

4093-
ce = make_cache_entry(patch->old_mode, &oid, name, 0, 0);
4093+
ce = make_cache_entry(&result, patch->old_mode, &oid, name, 0, 0);
40944094
if (!ce)
40954095
return error(_("make_cache_entry failed for path '%s'"),
40964096
name);
40974097
if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
4098-
free(ce);
4098+
discard_cache_entry(ce);
40994099
return error(_("could not add %s to temporary index"),
41004100
name);
41014101
}
@@ -4263,12 +4263,11 @@ static int add_index_file(struct apply_state *state,
42634263
struct stat st;
42644264
struct cache_entry *ce;
42654265
int namelen = strlen(path);
4266-
unsigned ce_size = cache_entry_size(namelen);
42674266

42684267
if (!state->update_index)
42694268
return 0;
42704269

4271-
ce = xcalloc(1, ce_size);
4270+
ce = make_empty_cache_entry(&the_index, namelen);
42724271
memcpy(ce->name, path, namelen);
42734272
ce->ce_mode = create_ce_mode(mode);
42744273
ce->ce_flags = create_ce_flags(0);
@@ -4278,27 +4277,27 @@ static int add_index_file(struct apply_state *state,
42784277

42794278
if (!skip_prefix(buf, "Subproject commit ", &s) ||
42804279
get_oid_hex(s, &ce->oid)) {
4281-
free(ce);
4282-
return error(_("corrupt patch for submodule %s"), path);
4280+
discard_cache_entry(ce);
4281+
return error(_("corrupt patch for submodule %s"), path);
42834282
}
42844283
} else {
42854284
if (!state->cached) {
42864285
if (lstat(path, &st) < 0) {
4287-
free(ce);
4286+
discard_cache_entry(ce);
42884287
return error_errno(_("unable to stat newly "
42894288
"created file '%s'"),
42904289
path);
42914290
}
42924291
fill_stat_cache_info(ce, &st);
42934292
}
42944293
if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
4295-
free(ce);
4294+
discard_cache_entry(ce);
42964295
return error(_("unable to create backing store "
42974296
"for newly created file %s"), path);
42984297
}
42994298
}
43004299
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
4301-
free(ce);
4300+
discard_cache_entry(ce);
43024301
return error(_("unable to add cache entry for %s"), path);
43034302
}
43044303

@@ -4422,27 +4421,26 @@ static int add_conflicted_stages_file(struct apply_state *state,
44224421
struct patch *patch)
44234422
{
44244423
int stage, namelen;
4425-
unsigned ce_size, mode;
4424+
unsigned mode;
44264425
struct cache_entry *ce;
44274426

44284427
if (!state->update_index)
44294428
return 0;
44304429
namelen = strlen(patch->new_name);
4431-
ce_size = cache_entry_size(namelen);
44324430
mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
44334431

44344432
remove_file_from_cache(patch->new_name);
44354433
for (stage = 1; stage < 4; stage++) {
44364434
if (is_null_oid(&patch->threeway_stage[stage - 1]))
44374435
continue;
4438-
ce = xcalloc(1, ce_size);
4436+
ce = make_empty_cache_entry(&the_index, namelen);
44394437
memcpy(ce->name, patch->new_name, namelen);
44404438
ce->ce_mode = create_ce_mode(mode);
44414439
ce->ce_flags = create_ce_flags(stage);
44424440
ce->ce_namelen = namelen;
44434441
oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
44444442
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
4445-
free(ce);
4443+
discard_cache_entry(ce);
44464444
return error(_("unable to add cache entry for %s"),
44474445
patch->new_name);
44484446
}

blame.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
154154
struct strbuf buf = STRBUF_INIT;
155155
const char *ident;
156156
time_t now;
157-
int size, len;
157+
int len;
158158
struct cache_entry *ce;
159159
unsigned mode;
160160
struct strbuf msg = STRBUF_INIT;
@@ -252,8 +252,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
252252
/* Let's not bother reading from HEAD tree */
253253
mode = S_IFREG | 0644;
254254
}
255-
size = cache_entry_size(len);
256-
ce = xcalloc(1, size);
255+
ce = make_empty_cache_entry(&the_index, len);
257256
oidcpy(&ce->oid, &origin->blob_oid);
258257
memcpy(ce->name, path, len);
259258
ce->ce_flags = create_ce_flags(0);

builtin/checkout.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
7777
return READ_TREE_RECURSIVE;
7878

7979
len = base->len + strlen(pathname);
80-
ce = xcalloc(1, cache_entry_size(len));
80+
ce = make_empty_cache_entry(&the_index, len);
8181
oidcpy(&ce->oid, oid);
8282
memcpy(ce->name, base->buf, base->len);
8383
memcpy(ce->name + base->len, pathname, len - base->len);
@@ -96,7 +96,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
9696
if (ce->ce_mode == old->ce_mode &&
9797
!oidcmp(&ce->oid, &old->oid)) {
9898
old->ce_flags |= CE_UPDATE;
99-
free(ce);
99+
discard_cache_entry(ce);
100100
return 0;
101101
}
102102
}
@@ -230,11 +230,11 @@ static int checkout_merged(int pos, const struct checkout *state)
230230
if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
231231
die(_("Unable to add merge result for '%s'"), path);
232232
free(result_buf.ptr);
233-
ce = make_cache_entry(mode, &oid, path, 2, 0);
233+
ce = make_transient_cache_entry(mode, &oid, path, 2);
234234
if (!ce)
235235
die(_("make_cache_entry failed for path '%s'"), path);
236236
status = checkout_entry(ce, state, NULL);
237-
free(ce);
237+
discard_cache_entry(ce);
238238
return status;
239239
}
240240

builtin/difftool.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,10 @@ static int checkout_path(unsigned mode, struct object_id *oid,
321321
struct cache_entry *ce;
322322
int ret;
323323

324-
ce = make_cache_entry(mode, oid, path, 0, 0);
324+
ce = make_transient_cache_entry(mode, oid, path, 0);
325325
ret = checkout_entry(ce, state, NULL);
326326

327-
free(ce);
327+
discard_cache_entry(ce);
328328
return ret;
329329
}
330330

@@ -488,7 +488,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
488488
* index.
489489
*/
490490
struct cache_entry *ce2 =
491-
make_cache_entry(rmode, &roid,
491+
make_cache_entry(&wtindex, rmode, &roid,
492492
dst_path, 0, 0);
493493

494494
add_index_entry(&wtindex, ce2,

builtin/reset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
134134
continue;
135135
}
136136

137-
ce = make_cache_entry(one->mode, &one->oid, one->path,
137+
ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
138138
0, 0);
139139
if (!ce)
140140
die(_("make_cache_entry failed for path '%s'"),

builtin/update-index.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,14 @@ static int process_lstat_error(const char *path, int err)
268268

269269
static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
270270
{
271-
int option, size;
271+
int option;
272272
struct cache_entry *ce;
273273

274274
/* Was the old index entry already up-to-date? */
275275
if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
276276
return 0;
277277

278-
size = cache_entry_size(len);
279-
ce = xcalloc(1, size);
278+
ce = make_empty_cache_entry(&the_index, len);
280279
memcpy(ce->name, path, len);
281280
ce->ce_flags = create_ce_flags(0);
282281
ce->ce_namelen = len;
@@ -285,13 +284,13 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
285284

286285
if (index_path(&ce->oid, path, st,
287286
info_only ? 0 : HASH_WRITE_OBJECT)) {
288-
free(ce);
287+
discard_cache_entry(ce);
289288
return -1;
290289
}
291290
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
292291
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
293292
if (add_cache_entry(ce, option)) {
294-
free(ce);
293+
discard_cache_entry(ce);
295294
return error("%s: cannot add to the index - missing --add option?", path);
296295
}
297296
return 0;
@@ -402,15 +401,14 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
402401
static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
403402
const char *path, int stage)
404403
{
405-
int size, len, option;
404+
int len, option;
406405
struct cache_entry *ce;
407406

408407
if (!verify_path(path, mode))
409408
return error("Invalid path '%s'", path);
410409

411410
len = strlen(path);
412-
size = cache_entry_size(len);
413-
ce = xcalloc(1, size);
411+
ce = make_empty_cache_entry(&the_index, len);
414412

415413
oidcpy(&ce->oid, oid);
416414
memcpy(ce->name, path, len);
@@ -599,7 +597,6 @@ static struct cache_entry *read_one_ent(const char *which,
599597
{
600598
unsigned mode;
601599
struct object_id oid;
602-
int size;
603600
struct cache_entry *ce;
604601

605602
if (get_tree_entry(ent, path, &oid, &mode)) {
@@ -612,8 +609,7 @@ static struct cache_entry *read_one_ent(const char *which,
612609
error("%s: not a blob in %s branch.", path, which);
613610
return NULL;
614611
}
615-
size = cache_entry_size(namelen);
616-
ce = xcalloc(1, size);
612+
ce = make_empty_cache_entry(&the_index, namelen);
617613

618614
oidcpy(&ce->oid, &oid);
619615
memcpy(ce->name, path, namelen);
@@ -690,8 +686,8 @@ static int unresolve_one(const char *path)
690686
error("%s: cannot add their version to the index.", path);
691687
ret = -1;
692688
free_return:
693-
free(ce_2);
694-
free(ce_3);
689+
discard_cache_entry(ce_2);
690+
discard_cache_entry(ce_3);
695691
return ret;
696692
}
697693

@@ -758,7 +754,7 @@ static int do_reupdate(int ac, const char **av,
758754
ce->name, ce_namelen(ce), 0);
759755
if (old && ce->ce_mode == old->ce_mode &&
760756
!oidcmp(&ce->oid, &old->oid)) {
761-
free(old);
757+
discard_cache_entry(old);
762758
continue; /* unchanged */
763759
}
764760
/* Be careful. The working tree may not have the
@@ -769,7 +765,7 @@ static int do_reupdate(int ac, const char **av,
769765
path = xstrdup(ce->name);
770766
update_one(path);
771767
free(path);
772-
free(old);
768+
discard_cache_entry(old);
773769
if (save_nr != active_nr)
774770
goto redo;
775771
}

cache.h

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,40 @@ extern void remove_name_hash(struct index_state *istate, struct cache_entry *ce)
339339
extern void free_name_hash(struct index_state *istate);
340340

341341

342+
/* Cache entry creation and cleanup */
343+
344+
/*
345+
* Create cache_entry intended for use in the specified index. Caller
346+
* is responsible for discarding the cache_entry with
347+
* `discard_cache_entry`.
348+
*/
349+
struct cache_entry *make_cache_entry(struct index_state *istate,
350+
unsigned int mode,
351+
const struct object_id *oid,
352+
const char *path,
353+
int stage,
354+
unsigned int refresh_options);
355+
356+
struct cache_entry *make_empty_cache_entry(struct index_state *istate,
357+
size_t name_len);
358+
359+
/*
360+
* Create a cache_entry that is not intended to be added to an index.
361+
* Caller is responsible for discarding the cache_entry
362+
* with `discard_cache_entry`.
363+
*/
364+
struct cache_entry *make_transient_cache_entry(unsigned int mode,
365+
const struct object_id *oid,
366+
const char *path,
367+
int stage);
368+
369+
struct cache_entry *make_empty_transient_cache_entry(size_t name_len);
370+
371+
/*
372+
* Discard cache entry.
373+
*/
374+
void discard_cache_entry(struct cache_entry *ce);
375+
342376
#ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
343377
#define active_cache (the_index.cache)
344378
#define active_nr (the_index.cache_nr)
@@ -698,12 +732,6 @@ extern int remove_file_from_index(struct index_state *, const char *path);
698732
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
699733
extern int add_file_to_index(struct index_state *, const char *path, int flags);
700734

701-
extern struct cache_entry *make_cache_entry(unsigned int mode,
702-
const struct object_id *oid,
703-
const char *path,
704-
int stage,
705-
unsigned int refresh_options);
706-
707735
extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
708736
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
709737
extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);

merge-recursive.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,
315315
struct cache_entry *ce;
316316
int ret;
317317

318-
ce = make_cache_entry(mode, oid ? oid : &null_oid, path, stage, 0);
318+
ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0);
319319
if (!ce)
320320
return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path);
321321

0 commit comments

Comments
 (0)