summaryrefslogtreecommitdiff
path: root/diffcore-rename.c
diff options
context:
space:
mode:
Diffstat (limited to 'diffcore-rename.c')
-rw-r--r--diffcore-rename.c68
1 files changed, 59 insertions, 9 deletions
diff --git a/diffcore-rename.c b/diffcore-rename.c
index c95857b51f..bebd4ed6a4 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -317,10 +317,11 @@ static int find_identical_files(struct hashmap *srcs,
}
static void insert_file_table(struct repository *r,
+ struct mem_pool *pool,
struct hashmap *table, int index,
struct diff_filespec *filespec)
{
- struct file_similarity *entry = xmalloc(sizeof(*entry));
+ struct file_similarity *entry = mem_pool_alloc(pool, sizeof(*entry));
entry->index = index;
entry->filespec = filespec;
@@ -336,7 +337,8 @@ static void insert_file_table(struct repository *r,
* and then during the second round we try to match
* cache-dirty entries as well.
*/
-static int find_exact_renames(struct diff_options *options)
+static int find_exact_renames(struct diff_options *options,
+ struct mem_pool *pool)
{
int i, renames = 0;
struct hashmap file_table;
@@ -346,7 +348,7 @@ static int find_exact_renames(struct diff_options *options)
*/
hashmap_init(&file_table, NULL, NULL, rename_src_nr);
for (i = rename_src_nr-1; i >= 0; i--)
- insert_file_table(options->repo,
+ insert_file_table(options->repo, pool,
&file_table, i,
rename_src[i].p->one);
@@ -354,8 +356,8 @@ static int find_exact_renames(struct diff_options *options)
for (i = 0; i < rename_dst_nr; i++)
renames += find_identical_files(&file_table, i, options);
- /* Free the hash data structure and entries */
- hashmap_clear_and_free(&file_table, struct file_similarity, entry);
+ /* Free the hash data structure (entries will be freed with the pool) */
+ hashmap_clear(&file_table);
return renames;
}
@@ -1330,7 +1332,47 @@ static void handle_early_known_dir_renames(struct dir_rename_info *info,
rename_src_nr = new_num_src;
}
+static void free_filespec_data(struct diff_filespec *spec)
+{
+ if (!--spec->count)
+ diff_free_filespec_data(spec);
+}
+
+static void pool_free_filespec(struct mem_pool *pool,
+ struct diff_filespec *spec)
+{
+ if (!pool) {
+ free_filespec(spec);
+ return;
+ }
+
+ /*
+ * Similar to free_filespec(), but only frees the data. The spec
+ * itself was allocated in the pool and should not be individually
+ * freed.
+ */
+ free_filespec_data(spec);
+}
+
+void pool_diff_free_filepair(struct mem_pool *pool,
+ struct diff_filepair *p)
+{
+ if (!pool) {
+ diff_free_filepair(p);
+ return;
+ }
+
+ /*
+ * Similar to diff_free_filepair() but only frees the data from the
+ * filespecs; not the filespecs or the filepair which were
+ * allocated from the pool.
+ */
+ free_filespec_data(p->one);
+ free_filespec_data(p->two);
+}
+
void diffcore_rename_extended(struct diff_options *options,
+ struct mem_pool *pool,
struct strintmap *relevant_sources,
struct strintmap *dirs_removed,
struct strmap *dir_rename_count,
@@ -1345,6 +1387,7 @@ void diffcore_rename_extended(struct diff_options *options,
int num_destinations, dst_cnt;
int num_sources, want_copies;
struct progress *progress = NULL;
+ struct mem_pool local_pool;
struct dir_rename_info info;
struct diff_populate_filespec_options dpf_options = {
.check_binary = 0,
@@ -1413,11 +1456,18 @@ void diffcore_rename_extended(struct diff_options *options,
goto cleanup; /* nothing to do */
trace2_region_enter("diff", "exact renames", options->repo);
+ mem_pool_init(&local_pool, 32*1024);
/*
* We really want to cull the candidates list early
* with cheap tests in order to avoid doing deltas.
*/
- rename_count = find_exact_renames(options);
+ rename_count = find_exact_renames(options, &local_pool);
+ /*
+ * Discard local_pool immediately instead of at "cleanup:" in order
+ * to reduce maximum memory usage; inexact rename detection uses up
+ * a fair amount of memory, and mem_pools can too.
+ */
+ mem_pool_discard(&local_pool, 0);
trace2_region_leave("diff", "exact renames", options->repo);
/* Did we only want exact renames? */
@@ -1636,7 +1686,7 @@ void diffcore_rename_extended(struct diff_options *options,
pair_to_free = p;
if (pair_to_free)
- diff_free_filepair(pair_to_free);
+ pool_diff_free_filepair(pool, pair_to_free);
}
diff_debug_queue("done copying original", &outq);
@@ -1646,7 +1696,7 @@ void diffcore_rename_extended(struct diff_options *options,
for (i = 0; i < rename_dst_nr; i++)
if (rename_dst[i].filespec_to_free)
- free_filespec(rename_dst[i].filespec_to_free);
+ pool_free_filespec(pool, rename_dst[i].filespec_to_free);
cleanup_dir_rename_info(&info, dirs_removed, dir_rename_count != NULL);
FREE_AND_NULL(rename_dst);
@@ -1663,5 +1713,5 @@ void diffcore_rename_extended(struct diff_options *options,
void diffcore_rename(struct diff_options *options)
{
- diffcore_rename_extended(options, NULL, NULL, NULL, NULL);
+ diffcore_rename_extended(options, NULL, NULL, NULL, NULL, NULL);
}