delta-islands: free island-related data after use

On my use case involving 771 islands of Linux on kernel.org, this reduces memory usage by around 25MB. The bulk of that comes from free_remote_islands, since free_config_regexes only saves around 40k. This memory is saved early in the memory-intensive pack process, making it available for the remainder of the long process. Signed-off-by: Eric Wong <e@80x24.org> Co-authored-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Taylor Blau <me@ttaylorr.com>

Eric Wong committed Nov 17, 2022 at 23:06 UTC 7025f54c40672f5253969e17ad81b1f511fbb04b
1 file changed +51 -20
delta-islands.c
+51 -20
@@ -26,8 +26,6 @@ static kh_oid_map_t *island_marks;
26 static unsigned island_counter;
27 static unsigned island_counter_core;
28
29 -static kh_str_t *remote_islands;
30 -
29 struct remote_island {
30 uint64_t hash;
31 struct oid_array oids;
@@ -312,29 +310,55 @@ void resolve_tree_islands(struct repository *r,
310 free(todo);
311 }
312
315 -static regex_t *island_regexes;
316 -static unsigned int island_regexes_alloc, island_regexes_nr;
313 +struct island_load_data {
314 + kh_str_t *remote_islands;
315 + regex_t *rx;
316 + size_t nr;
317 + size_t alloc;
318 +};
319 static const char *core_island_name;
320
319 -static int island_config_callback(const char *k, const char *v, void *cb UNUSED)
321 +static void free_config_regexes(struct island_load_data *ild)
322 {
323 + for (size_t i = 0; i < ild->nr; i++)
324 + regfree(&ild->rx[i]);
325 + free(ild->rx);
326 +}
327 +
328 +static void free_remote_islands(kh_str_t *remote_islands)
329 +{
330 + const char *island_name;
331 + struct remote_island *rl;
332 +
333 + kh_foreach(remote_islands, island_name, rl, {
334 + free((void *)island_name);
335 + oid_array_clear(&rl->oids);
336 + free(rl);
337 + });
338 + kh_destroy_str(remote_islands);
339 +}
340 +
341 +static int island_config_callback(const char *k, const char *v, void *cb)
342 +{
343 + struct island_load_data *ild = cb;
344 +
345 if (!strcmp(k, "pack.island")) {
346 struct strbuf re = STRBUF_INIT;
347
348 if (!v)
349 return config_error_nonbool(k);
350
327 - ALLOC_GROW(island_regexes, island_regexes_nr + 1, island_regexes_alloc);
351 + ALLOC_GROW(ild->rx, ild->nr + 1, ild->alloc);
352
353 if (*v != '^')
354 strbuf_addch(&re, '^');
355 strbuf_addstr(&re, v);
356
333 - if (regcomp(&island_regexes[island_regexes_nr], re.buf, REG_EXTENDED))
357 + if (regcomp(&ild->rx[ild->nr], re.buf, REG_EXTENDED))
358 die(_("failed to load island regex for '%s': %s"), k, re.buf);
359
360 strbuf_release(&re);
337 - island_regexes_nr++;
361 + ild->nr++;
362 return 0;
363 }
364
@@ -344,7 +368,8 @@ static int island_config_callback(const char *k, const char *v, void *cb UNUSED)
368 return 0;
369 }
370
347 -static void add_ref_to_island(const char *island_name, const struct object_id *oid)
371 +static void add_ref_to_island(kh_str_t *remote_islands, const char *island_name,
372 + const struct object_id *oid)
373 {
374 uint64_t sha_core;
375 struct remote_island *rl = NULL;
@@ -365,8 +390,10 @@ static void add_ref_to_island(const char *island_name, const struct object_id *o
390 }
391
392 static int find_island_for_ref(const char *refname, const struct object_id *oid,
368 - int flags UNUSED, void *data UNUSED)
393 + int flags UNUSED, void *cb)
394 {
395 + struct island_load_data *ild = cb;
396 +
397 /*
398 * We should advertise 'ARRAY_SIZE(matches) - 2' as the max,
399 * so we can diagnose below a config with more capture groups
@@ -377,8 +404,8 @@ static int find_island_for_ref(const char *refname, const struct object_id *oid,
404 struct strbuf island_name = STRBUF_INIT;
405
406 /* walk backwards to get last-one-wins ordering */
380 - for (i = island_regexes_nr - 1; i >= 0; i--) {
381 - if (!regexec(&island_regexes[i], refname,
407 + for (i = ild->nr - 1; i >= 0; i--) {
408 + if (!regexec(&ild->rx[i], refname,
409 ARRAY_SIZE(matches), matches, 0))
410 break;
411 }
@@ -403,12 +430,12 @@ static int find_island_for_ref(const char *refname, const struct object_id *oid,
430 strbuf_add(&island_name, refname + match->rm_so, match->rm_eo - match->rm_so);
431 }
432
406 - add_ref_to_island(island_name.buf, oid);
433 + add_ref_to_island(ild->remote_islands, island_name.buf, oid);
434 strbuf_release(&island_name);
435 return 0;
436 }
437
411 -static struct remote_island *get_core_island(void)
438 +static struct remote_island *get_core_island(kh_str_t *remote_islands)
439 {
440 if (core_island_name) {
441 khiter_t pos = kh_get_str(remote_islands, core_island_name);
@@ -419,7 +446,7 @@ static struct remote_island *get_core_island(void)
446 return NULL;
447 }
448
422 -static void deduplicate_islands(struct repository *r)
449 +static void deduplicate_islands(kh_str_t *remote_islands, struct repository *r)
450 {
451 struct remote_island *island, *core = NULL, **list;
452 unsigned int island_count, dst, src, ref, i = 0;
@@ -445,7 +472,7 @@ static void deduplicate_islands(struct repository *r)
472 }
473
474 island_bitmap_size = (island_count / 32) + 1;
448 - core = get_core_island();
475 + core = get_core_island(remote_islands);
476
477 for (i = 0; i < island_count; ++i) {
478 mark_remote_island_1(r, list[i], core && list[i]->hash == core->hash);
@@ -456,12 +483,16 @@ static void deduplicate_islands(struct repository *r)
483
484 void load_delta_islands(struct repository *r, int progress)
485 {
486 + struct island_load_data ild = { 0 };
487 +
488 island_marks = kh_init_oid_map();
460 - remote_islands = kh_init_str();
489
462 - git_config(island_config_callback, NULL);
463 - for_each_ref(find_island_for_ref, NULL);
464 - deduplicate_islands(r);
490 + git_config(island_config_callback, &ild);
491 + ild.remote_islands = kh_init_str();
492 + for_each_ref(find_island_for_ref, &ild);
493 + free_config_regexes(&ild);
494 + deduplicate_islands(ild.remote_islands, r);
495 + free_remote_islands(ild.remote_islands);
496
497 if (progress)
498 fprintf(stderr, _("Marked %d islands, done.\n"), island_counter);