Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 337b2b0

Browse files
committed
Merge pull request libgit2#3508 from libgit2/cmn/tree-parse-speed
Improvements to tree parsing speed
2 parents a589f22 + 95ae352 commit 337b2b0

File tree

2 files changed

+55
-17
lines changed

2 files changed

+55
-17
lines changed

src/tree.c

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,26 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
8181
git__strncasecmp);
8282
}
8383

84-
static git_tree_entry *alloc_entry(const char *filename)
84+
/**
85+
* Allocate either from the pool or from the system allocator
86+
*/
87+
static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, size_t filename_len)
8588
{
8689
git_tree_entry *entry = NULL;
87-
size_t filename_len = strlen(filename), tree_len;
90+
size_t tree_len;
91+
92+
if (filename_len > UINT16_MAX) {
93+
giterr_set(GITERR_INVALID, "tree entry is over UINT16_MAX in length");
94+
return NULL;
95+
}
8896

8997
if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
90-
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) ||
91-
!(entry = git__malloc(tree_len)))
98+
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1))
99+
return NULL;
100+
101+
entry = pool ? git_pool_malloc(pool, tree_len) :
102+
git__malloc(tree_len);
103+
if (!entry)
92104
return NULL;
93105

94106
memset(entry, 0x0, sizeof(git_tree_entry));
@@ -99,9 +111,31 @@ static git_tree_entry *alloc_entry(const char *filename)
99111
return entry;
100112
}
101113

114+
/**
115+
* Allocate a tree entry, using the poolin the tree which owns
116+
* it. This is useful when reading trees, so we don't allocate a ton
117+
* of small strings but can use the pool.
118+
*/
119+
static git_tree_entry *alloc_entry_pooled(git_pool *pool, const char *filename, size_t filename_len)
120+
{
121+
git_tree_entry *entry = NULL;
122+
123+
if (!(entry = alloc_entry_base(pool, filename, filename_len)))
124+
return NULL;
125+
126+
entry->pooled = true;
127+
128+
return entry;
129+
}
130+
131+
static git_tree_entry *alloc_entry(const char *filename)
132+
{
133+
return alloc_entry_base(NULL, filename, strlen(filename));
134+
}
135+
102136
struct tree_key_search {
103137
const char *filename;
104-
size_t filename_len;
138+
uint16_t filename_len;
105139
};
106140

107141
static int homing_search_cmp(const void *key, const void *array_member)
@@ -198,7 +232,7 @@ static int tree_key_search(
198232

199233
void git_tree_entry_free(git_tree_entry *entry)
200234
{
201-
if (entry == NULL)
235+
if (entry == NULL || entry->pooled)
202236
return;
203237

204238
git__free(entry);
@@ -233,6 +267,7 @@ void git_tree__free(void *_tree)
233267
git_tree_entry_free(e);
234268

235269
git_vector_free(&tree->entries);
270+
git_pool_clear(&tree->pool);
236271
git__free(tree);
237272
}
238273

@@ -385,11 +420,14 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
385420
const char *buffer = git_odb_object_data(odb_obj);
386421
const char *buffer_end = buffer + git_odb_object_size(odb_obj);
387422

423+
git_pool_init(&tree->pool, 1);
388424
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0)
389425
return -1;
390426

391427
while (buffer < buffer_end) {
392428
git_tree_entry *entry;
429+
size_t filename_len;
430+
const char *nul;
393431
int attr;
394432

395433
if (git__strtol32(&attr, buffer, &buffer, 8) < 0 || !buffer)
@@ -398,26 +436,23 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
398436
if (*buffer++ != ' ')
399437
return tree_error("Failed to parse tree. Object is corrupted", NULL);
400438

401-
if (memchr(buffer, 0, buffer_end - buffer) == NULL)
439+
if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL)
402440
return tree_error("Failed to parse tree. Object is corrupted", NULL);
403441

442+
filename_len = nul - buffer;
404443
/** Allocate the entry and store it in the entries vector */
405444
{
406-
entry = alloc_entry(buffer);
445+
entry = alloc_entry_pooled(&tree->pool, buffer, filename_len);
407446
GITERR_CHECK_ALLOC(entry);
408447

409-
if (git_vector_insert(&tree->entries, entry) < 0) {
410-
git__free(entry);
448+
if (git_vector_insert(&tree->entries, entry) < 0)
411449
return -1;
412-
}
413450

414451
entry->attr = attr;
415452
}
416453

417-
while (buffer < buffer_end && *buffer != 0)
418-
buffer++;
419-
420-
buffer++;
454+
/* Advance to the ID just after the path */
455+
buffer += filename_len + 1;
421456

422457
git_oid_fromraw(&entry->oid, (const unsigned char *)buffer);
423458
buffer += GIT_OID_RAWSZ;

src/tree.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,20 @@
1212
#include "odb.h"
1313
#include "vector.h"
1414
#include "strmap.h"
15+
#include "pool.h"
1516

1617
struct git_tree_entry {
1718
uint16_t attr;
19+
uint16_t filename_len;
1820
git_oid oid;
19-
size_t filename_len;
20-
char filename[1];
21+
bool pooled;
22+
char filename[GIT_FLEX_ARRAY];
2123
};
2224

2325
struct git_tree {
2426
git_object object;
2527
git_vector entries;
28+
git_pool pool;
2629
};
2730

2831
struct git_treebuilder {

0 commit comments

Comments
 (0)