@@ -317,10 +317,11 @@ static int find_identical_files(struct hashmap *srcs,
317317}
318318
319319static void insert_file_table (struct repository * r ,
320+ struct mem_pool * pool ,
320321 struct hashmap * table , int index ,
321322 struct diff_filespec * filespec )
322323{
323- struct file_similarity * entry = xmalloc ( sizeof (* entry ));
324+ struct file_similarity * entry = mem_pool_alloc ( pool , sizeof (* entry ));
324325
325326 entry -> index = index ;
326327 entry -> filespec = filespec ;
@@ -336,7 +337,8 @@ static void insert_file_table(struct repository *r,
336337 * and then during the second round we try to match
337338 * cache-dirty entries as well.
338339 */
339- static int find_exact_renames (struct diff_options * options )
340+ static int find_exact_renames (struct diff_options * options ,
341+ struct mem_pool * pool )
340342{
341343 int i , renames = 0 ;
342344 struct hashmap file_table ;
@@ -346,16 +348,16 @@ static int find_exact_renames(struct diff_options *options)
346348 */
347349 hashmap_init (& file_table , NULL , NULL , rename_src_nr );
348350 for (i = rename_src_nr - 1 ; i >= 0 ; i -- )
349- insert_file_table (options -> repo ,
351+ insert_file_table (options -> repo , pool ,
350352 & file_table , i ,
351353 rename_src [i ].p -> one );
352354
353355 /* Walk the destinations and find best source match */
354356 for (i = 0 ; i < rename_dst_nr ; i ++ )
355357 renames += find_identical_files (& file_table , i , options );
356358
357- /* Free the hash data structure and entries */
358- hashmap_clear_and_free (& file_table , struct file_similarity , entry );
359+ /* Free the hash data structure ( entries will be freed with the pool) */
360+ hashmap_clear (& file_table );
359361
360362 return renames ;
361363}
@@ -1330,7 +1332,47 @@ static void handle_early_known_dir_renames(struct dir_rename_info *info,
13301332 rename_src_nr = new_num_src ;
13311333}
13321334
1335+ static void free_filespec_data (struct diff_filespec * spec )
1336+ {
1337+ if (!-- spec -> count )
1338+ diff_free_filespec_data (spec );
1339+ }
1340+
1341+ static void pool_free_filespec (struct mem_pool * pool ,
1342+ struct diff_filespec * spec )
1343+ {
1344+ if (!pool ) {
1345+ free_filespec (spec );
1346+ return ;
1347+ }
1348+
1349+ /*
1350+ * Similar to free_filespec(), but only frees the data. The spec
1351+ * itself was allocated in the pool and should not be individually
1352+ * freed.
1353+ */
1354+ free_filespec_data (spec );
1355+ }
1356+
1357+ void pool_diff_free_filepair (struct mem_pool * pool ,
1358+ struct diff_filepair * p )
1359+ {
1360+ if (!pool ) {
1361+ diff_free_filepair (p );
1362+ return ;
1363+ }
1364+
1365+ /*
1366+ * Similar to diff_free_filepair() but only frees the data from the
1367+ * filespecs; not the filespecs or the filepair which were
1368+ * allocated from the pool.
1369+ */
1370+ free_filespec_data (p -> one );
1371+ free_filespec_data (p -> two );
1372+ }
1373+
13331374void diffcore_rename_extended (struct diff_options * options ,
1375+ struct mem_pool * pool ,
13341376 struct strintmap * relevant_sources ,
13351377 struct strintmap * dirs_removed ,
13361378 struct strmap * dir_rename_count ,
@@ -1345,6 +1387,7 @@ void diffcore_rename_extended(struct diff_options *options,
13451387 int num_destinations , dst_cnt ;
13461388 int num_sources , want_copies ;
13471389 struct progress * progress = NULL ;
1390+ struct mem_pool local_pool ;
13481391 struct dir_rename_info info ;
13491392 struct diff_populate_filespec_options dpf_options = {
13501393 .check_binary = 0 ,
@@ -1413,11 +1456,18 @@ void diffcore_rename_extended(struct diff_options *options,
14131456 goto cleanup ; /* nothing to do */
14141457
14151458 trace2_region_enter ("diff" , "exact renames" , options -> repo );
1459+ mem_pool_init (& local_pool , 32 * 1024 );
14161460 /*
14171461 * We really want to cull the candidates list early
14181462 * with cheap tests in order to avoid doing deltas.
14191463 */
1420- rename_count = find_exact_renames (options );
1464+ rename_count = find_exact_renames (options , & local_pool );
1465+ /*
1466+ * Discard local_pool immediately instead of at "cleanup:" in order
1467+ * to reduce maximum memory usage; inexact rename detection uses up
1468+ * a fair amount of memory, and mem_pools can too.
1469+ */
1470+ mem_pool_discard (& local_pool , 0 );
14211471 trace2_region_leave ("diff" , "exact renames" , options -> repo );
14221472
14231473 /* Did we only want exact renames? */
@@ -1636,7 +1686,7 @@ void diffcore_rename_extended(struct diff_options *options,
16361686 pair_to_free = p ;
16371687
16381688 if (pair_to_free )
1639- diff_free_filepair ( pair_to_free );
1689+ pool_diff_free_filepair ( pool , pair_to_free );
16401690 }
16411691 diff_debug_queue ("done copying original" , & outq );
16421692
@@ -1646,7 +1696,7 @@ void diffcore_rename_extended(struct diff_options *options,
16461696
16471697 for (i = 0 ; i < rename_dst_nr ; i ++ )
16481698 if (rename_dst [i ].filespec_to_free )
1649- free_filespec ( rename_dst [i ].filespec_to_free );
1699+ pool_free_filespec ( pool , rename_dst [i ].filespec_to_free );
16501700
16511701 cleanup_dir_rename_info (& info , dirs_removed , dir_rename_count != NULL );
16521702 FREE_AND_NULL (rename_dst );
@@ -1663,5 +1713,5 @@ void diffcore_rename_extended(struct diff_options *options,
16631713
16641714void diffcore_rename (struct diff_options * options )
16651715{
1666- diffcore_rename_extended (options , NULL , NULL , NULL , NULL );
1716+ diffcore_rename_extended (options , NULL , NULL , NULL , NULL , NULL );
16671717}
0 commit comments