diff options
author | Edward Thomson <ethomson@github.com> | 2017-01-21 22:51:50 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-21 22:51:50 +0000 |
commit | 44e8af8f290d91c32fe3814658f2b4cabe9447fc (patch) | |
tree | fd84221392426283f18078d805ecaf64347b44ff | |
parent | 3b4eb107c21eb855dd651bc2e5904c0b29ece9b7 (diff) | |
parent | 87aaefe20b2e2fad8f0b8b236d1c23ce9ec5340f (diff) | |
download | libgit2-44e8af8f290d91c32fe3814658f2b4cabe9447fc.tar.gz |
Merge pull request #3892 from mitesch/shared_buffer
Use a shared buffer in calls of git_treebuilder_write to avoid heap contention
-rw-r--r-- | include/git2/tree.h | 13 | ||||
-rw-r--r-- | src/tree.c | 45 |
2 files changed, 43 insertions, 15 deletions
diff --git a/include/git2/tree.h b/include/git2/tree.h index 2e4735c4b..a38215f9f 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -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)( diff --git a/src/tree.c b/src/tree.c index 783dca41f..26da296d5 100644 --- a/src/tree.c +++ b/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); @@ -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 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; |