Commit 44e8af8f by Edward Thomson Committed by GitHub

Merge pull request #3892 from mitesch/shared_buffer

Use a shared buffer in calls of git_treebuilder_write to avoid heap contention
parents 3b4eb107 87aaefe2
...@@ -375,6 +375,19 @@ GIT_EXTERN(void) git_treebuilder_filter( ...@@ -375,6 +375,19 @@ GIT_EXTERN(void) git_treebuilder_filter(
GIT_EXTERN(int) git_treebuilder_write( GIT_EXTERN(int) git_treebuilder_write(
git_oid *id, git_treebuilder *bld); 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 */ /** Callback for the tree traversal method */
typedef int (*git_treewalk_cb)( typedef int (*git_treewalk_cb)(
......
...@@ -520,7 +520,8 @@ static int write_tree( ...@@ -520,7 +520,8 @@ static int write_tree(
git_repository *repo, git_repository *repo,
git_index *index, git_index *index,
const char *dirname, const char *dirname,
size_t start) size_t start,
git_buf *shared_buf)
{ {
git_treebuilder *bld = NULL; git_treebuilder *bld = NULL;
size_t i, entries = git_index_entrycount(index); size_t i, entries = git_index_entrycount(index);
...@@ -573,7 +574,7 @@ static int write_tree( ...@@ -573,7 +574,7 @@ static int write_tree(
GITERR_CHECK_ALLOC(subdir); GITERR_CHECK_ALLOC(subdir);
/* Write out the subtree */ /* 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) { if (written < 0) {
git__free(subdir); git__free(subdir);
goto on_error; goto on_error;
...@@ -605,7 +606,7 @@ static int write_tree( ...@@ -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; goto on_error;
git_treebuilder_free(bld); git_treebuilder_free(bld);
...@@ -621,6 +622,7 @@ int git_tree__write_index( ...@@ -621,6 +622,7 @@ int git_tree__write_index(
{ {
int ret; int ret;
git_tree *tree; git_tree *tree;
git_buf shared_buf = GIT_BUF_INIT;
bool old_ignore_case = false; bool old_ignore_case = false;
assert(oid && index && repo); assert(oid && index && repo);
...@@ -646,7 +648,8 @@ int git_tree__write_index( ...@@ -646,7 +648,8 @@ int git_tree__write_index(
git_index__set_ignore_case(index, false); 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) if (old_ignore_case)
git_index__set_ignore_case(index, true); git_index__set_ignore_case(index, true);
...@@ -802,19 +805,36 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename) ...@@ -802,19 +805,36 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename)
int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) 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; int error = 0;
size_t i, entrycount; size_t i, entrycount;
git_buf tree = GIT_BUF_INIT;
git_odb *odb; git_odb *odb;
git_tree_entry *entry; git_tree_entry *entry;
git_vector entries; git_vector entries;
assert(bld); assert(bld);
assert(tree);
git_buf_clear(tree);
entrycount = git_strmap_num_entries(bld->map); entrycount = git_strmap_num_entries(bld->map);
if (git_vector_init(&entries, entrycount, entry_sort_cmp) < 0) if (git_vector_init(&entries, entrycount, entry_sort_cmp) < 0)
return -1; return -1;
if (tree->asize == 0 &&
(error = git_buf_grow(tree, entrycount * 72)) < 0)
return error;
git_strmap_foreach_value(bld->map, entry, { git_strmap_foreach_value(bld->map, entry, {
if (git_vector_insert(&entries, entry) < 0) if (git_vector_insert(&entries, entry) < 0)
return -1; return -1;
...@@ -822,26 +842,21 @@ int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) ...@@ -822,26 +842,21 @@ int git_treebuilder_write(git_oid *oid, git_treebuilder *bld)
git_vector_sort(&entries); 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) { for (i = 0; i < entries.length && !error; ++i) {
git_tree_entry *entry = git_vector_get(&entries, i); git_tree_entry *entry = git_vector_get(&entries, i);
git_buf_printf(&tree, "%o ", entry->attr); git_buf_printf(tree, "%o ", entry->attr);
git_buf_put(&tree, entry->filename, entry->filename_len + 1); git_buf_put(tree, entry->filename, entry->filename_len + 1);
git_buf_put(&tree, (char *)entry->oid->id, GIT_OID_RAWSZ); git_buf_put(tree, (char *)entry->oid->id, GIT_OID_RAWSZ);
if (git_buf_oom(&tree)) if (git_buf_oom(tree))
error = -1; error = -1;
} }
if (!error && if (!error &&
!(error = git_repository_odb__weakptr(&odb, bld->repo))) !(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); git_vector_free(&entries);
return error; return error;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment