mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-10-31 00:16:35 +00:00 
			
		
		
		
	Merge pull request #3892 from mitesch/shared_buffer
Use a shared buffer in calls of git_treebuilder_write to avoid heap contention
This commit is contained in:
		
						commit
						44e8af8f29
					
				| @ -375,6 +375,19 @@ GIT_EXTERN(void) git_treebuilder_filter( | ||||
| GIT_EXTERN(int) git_treebuilder_write( | ||||
| 	git_oid *id, git_treebuilder *bld); | ||||
| 
 | ||||
| /**
 | ||||
|  * Write the contents of the tree builder as a tree object | ||||
|  * using a shared git_buf. | ||||
|  * | ||||
|  * @see git_treebuilder_write | ||||
|  * | ||||
|  * @param id Pointer to store the OID of the newly written tree | ||||
|  * @param bld Tree builder to write | ||||
|  * @param tree Shared buffer for writing the tree. Will be grown as necessary. | ||||
|  * @return 0 or an error code | ||||
|  */ | ||||
| GIT_EXTERN(int) git_treebuilder_write_with_buffer( | ||||
| 	git_oid *oid, git_treebuilder *bld, git_buf *tree); | ||||
| 
 | ||||
| /** Callback for the tree traversal method */ | ||||
| typedef int (*git_treewalk_cb)( | ||||
|  | ||||
							
								
								
									
										45
									
								
								src/tree.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								src/tree.c
									
									
									
									
									
								
							| @ -520,7 +520,8 @@ static int write_tree( | ||||
| 	git_repository *repo, | ||||
| 	git_index *index, | ||||
| 	const char *dirname, | ||||
| 	size_t start) | ||||
| 	size_t start, | ||||
| 	git_buf *shared_buf) | ||||
| { | ||||
| 	git_treebuilder *bld = NULL; | ||||
| 	size_t i, entries = git_index_entrycount(index); | ||||
| @ -573,7 +574,7 @@ static int write_tree( | ||||
| 			GITERR_CHECK_ALLOC(subdir); | ||||
| 
 | ||||
| 			/* Write out the subtree */ | ||||
| 			written = write_tree(&sub_oid, repo, index, subdir, i); | ||||
| 			written = write_tree(&sub_oid, repo, index, subdir, i, shared_buf); | ||||
| 			if (written < 0) { | ||||
| 				git__free(subdir); | ||||
| 				goto on_error; | ||||
| @ -605,7 +606,7 @@ static int write_tree( | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (git_treebuilder_write(oid, bld) < 0) | ||||
| 	if (git_treebuilder_write_with_buffer(oid, bld, shared_buf) < 0) | ||||
| 		goto on_error; | ||||
| 
 | ||||
| 	git_treebuilder_free(bld); | ||||
| @ -621,6 +622,7 @@ int git_tree__write_index( | ||||
| { | ||||
| 	int ret; | ||||
| 	git_tree *tree; | ||||
| 	git_buf shared_buf = GIT_BUF_INIT; | ||||
| 	bool old_ignore_case = false; | ||||
| 
 | ||||
| 	assert(oid && index && repo); | ||||
| @ -646,7 +648,8 @@ int git_tree__write_index( | ||||
| 		git_index__set_ignore_case(index, false); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = write_tree(oid, repo, index, "", 0); | ||||
| 	ret = write_tree(oid, repo, index, "", 0, &shared_buf); | ||||
| 	git_buf_free(&shared_buf); | ||||
| 
 | ||||
| 	if (old_ignore_case) | ||||
| 		git_index__set_ignore_case(index, true); | ||||
| @ -801,20 +804,37 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename) | ||||
| } | ||||
| 
 | ||||
| int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) | ||||
| { | ||||
| 	int error; | ||||
| 	git_buf buffer = GIT_BUF_INIT; | ||||
| 
 | ||||
| 	error = git_treebuilder_write_with_buffer(oid, bld, &buffer); | ||||
| 
 | ||||
| 	git_buf_free(&buffer); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *tree) | ||||
| { | ||||
| 	int error = 0; | ||||
| 	size_t i, entrycount; | ||||
| 	git_buf tree = GIT_BUF_INIT; | ||||
| 	git_odb *odb; | ||||
| 	git_tree_entry *entry; | ||||
| 	git_vector entries; | ||||
| 
 | ||||
| 	assert(bld); | ||||
| 	assert(tree); | ||||
| 
 | ||||
| 	git_buf_clear(tree); | ||||
| 
 | ||||
| 	entrycount = git_strmap_num_entries(bld->map); | ||||
| 	if (git_vector_init(&entries, entrycount, entry_sort_cmp) < 0) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	if (tree->asize == 0 && | ||||
| 		(error = git_buf_grow(tree, entrycount * 72)) < 0) | ||||
| 		return error; | ||||
| 
 | ||||
| 	git_strmap_foreach_value(bld->map, entry, { | ||||
| 		if (git_vector_insert(&entries, entry) < 0) | ||||
| 			return -1; | ||||
| @ -822,26 +842,21 @@ int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) | ||||
| 
 | ||||
| 	git_vector_sort(&entries); | ||||
| 
 | ||||
| 	/* Grow the buffer beforehand to an estimated size */ | ||||
| 	error = git_buf_grow(&tree, entrycount * 72); | ||||
| 
 | ||||
| 	for (i = 0; i < entries.length && !error; ++i) { | ||||
| 		git_tree_entry *entry = git_vector_get(&entries, i); | ||||
| 
 | ||||
| 		git_buf_printf(&tree, "%o ", entry->attr); | ||||
| 		git_buf_put(&tree, entry->filename, entry->filename_len + 1); | ||||
| 		git_buf_put(&tree, (char *)entry->oid->id, GIT_OID_RAWSZ); | ||||
| 		git_buf_printf(tree, "%o ", entry->attr); | ||||
| 		git_buf_put(tree, entry->filename, entry->filename_len + 1); | ||||
| 		git_buf_put(tree, (char *)entry->oid->id, GIT_OID_RAWSZ); | ||||
| 
 | ||||
| 		if (git_buf_oom(&tree)) | ||||
| 		if (git_buf_oom(tree)) | ||||
| 			error = -1; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (!error && | ||||
| 		!(error = git_repository_odb__weakptr(&odb, bld->repo))) | ||||
| 		error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE); | ||||
| 		error = git_odb_write(oid, odb, tree->ptr, tree->size, GIT_OBJ_TREE); | ||||
| 
 | ||||
| 	git_buf_free(&tree); | ||||
| 	git_vector_free(&entries); | ||||
| 
 | ||||
| 	return error; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Edward Thomson
						Edward Thomson