mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-10 03:56:58 +00:00
Merge pull request #3508 from libgit2/cmn/tree-parse-speed
Improvements to tree parsing speed
This commit is contained in:
commit
337b2b08f4
65
src/tree.c
65
src/tree.c
@ -81,14 +81,26 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
|
|||||||
git__strncasecmp);
|
git__strncasecmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static git_tree_entry *alloc_entry(const char *filename)
|
/**
|
||||||
|
* Allocate either from the pool or from the system allocator
|
||||||
|
*/
|
||||||
|
static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, size_t filename_len)
|
||||||
{
|
{
|
||||||
git_tree_entry *entry = NULL;
|
git_tree_entry *entry = NULL;
|
||||||
size_t filename_len = strlen(filename), tree_len;
|
size_t tree_len;
|
||||||
|
|
||||||
|
if (filename_len > UINT16_MAX) {
|
||||||
|
giterr_set(GITERR_INVALID, "tree entry is over UINT16_MAX in length");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
|
if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
|
||||||
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) ||
|
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1))
|
||||||
!(entry = git__malloc(tree_len)))
|
return NULL;
|
||||||
|
|
||||||
|
entry = pool ? git_pool_malloc(pool, tree_len) :
|
||||||
|
git__malloc(tree_len);
|
||||||
|
if (!entry)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memset(entry, 0x0, sizeof(git_tree_entry));
|
memset(entry, 0x0, sizeof(git_tree_entry));
|
||||||
@ -99,9 +111,31 @@ static git_tree_entry *alloc_entry(const char *filename)
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a tree entry, using the poolin the tree which owns
|
||||||
|
* it. This is useful when reading trees, so we don't allocate a ton
|
||||||
|
* of small strings but can use the pool.
|
||||||
|
*/
|
||||||
|
static git_tree_entry *alloc_entry_pooled(git_pool *pool, const char *filename, size_t filename_len)
|
||||||
|
{
|
||||||
|
git_tree_entry *entry = NULL;
|
||||||
|
|
||||||
|
if (!(entry = alloc_entry_base(pool, filename, filename_len)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
entry->pooled = true;
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static git_tree_entry *alloc_entry(const char *filename)
|
||||||
|
{
|
||||||
|
return alloc_entry_base(NULL, filename, strlen(filename));
|
||||||
|
}
|
||||||
|
|
||||||
struct tree_key_search {
|
struct tree_key_search {
|
||||||
const char *filename;
|
const char *filename;
|
||||||
size_t filename_len;
|
uint16_t filename_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int homing_search_cmp(const void *key, const void *array_member)
|
static int homing_search_cmp(const void *key, const void *array_member)
|
||||||
@ -198,7 +232,7 @@ static int tree_key_search(
|
|||||||
|
|
||||||
void git_tree_entry_free(git_tree_entry *entry)
|
void git_tree_entry_free(git_tree_entry *entry)
|
||||||
{
|
{
|
||||||
if (entry == NULL)
|
if (entry == NULL || entry->pooled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
git__free(entry);
|
git__free(entry);
|
||||||
@ -233,6 +267,7 @@ void git_tree__free(void *_tree)
|
|||||||
git_tree_entry_free(e);
|
git_tree_entry_free(e);
|
||||||
|
|
||||||
git_vector_free(&tree->entries);
|
git_vector_free(&tree->entries);
|
||||||
|
git_pool_clear(&tree->pool);
|
||||||
git__free(tree);
|
git__free(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,11 +420,14 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
|||||||
const char *buffer = git_odb_object_data(odb_obj);
|
const char *buffer = git_odb_object_data(odb_obj);
|
||||||
const char *buffer_end = buffer + git_odb_object_size(odb_obj);
|
const char *buffer_end = buffer + git_odb_object_size(odb_obj);
|
||||||
|
|
||||||
|
git_pool_init(&tree->pool, 1);
|
||||||
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0)
|
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (buffer < buffer_end) {
|
while (buffer < buffer_end) {
|
||||||
git_tree_entry *entry;
|
git_tree_entry *entry;
|
||||||
|
size_t filename_len;
|
||||||
|
const char *nul;
|
||||||
int attr;
|
int attr;
|
||||||
|
|
||||||
if (git__strtol32(&attr, buffer, &buffer, 8) < 0 || !buffer)
|
if (git__strtol32(&attr, buffer, &buffer, 8) < 0 || !buffer)
|
||||||
@ -398,26 +436,23 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
|||||||
if (*buffer++ != ' ')
|
if (*buffer++ != ' ')
|
||||||
return tree_error("Failed to parse tree. Object is corrupted", NULL);
|
return tree_error("Failed to parse tree. Object is corrupted", NULL);
|
||||||
|
|
||||||
if (memchr(buffer, 0, buffer_end - buffer) == NULL)
|
if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL)
|
||||||
return tree_error("Failed to parse tree. Object is corrupted", NULL);
|
return tree_error("Failed to parse tree. Object is corrupted", NULL);
|
||||||
|
|
||||||
|
filename_len = nul - buffer;
|
||||||
/** Allocate the entry and store it in the entries vector */
|
/** Allocate the entry and store it in the entries vector */
|
||||||
{
|
{
|
||||||
entry = alloc_entry(buffer);
|
entry = alloc_entry_pooled(&tree->pool, buffer, filename_len);
|
||||||
GITERR_CHECK_ALLOC(entry);
|
GITERR_CHECK_ALLOC(entry);
|
||||||
|
|
||||||
if (git_vector_insert(&tree->entries, entry) < 0) {
|
if (git_vector_insert(&tree->entries, entry) < 0)
|
||||||
git__free(entry);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
entry->attr = attr;
|
entry->attr = attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (buffer < buffer_end && *buffer != 0)
|
/* Advance to the ID just after the path */
|
||||||
buffer++;
|
buffer += filename_len + 1;
|
||||||
|
|
||||||
buffer++;
|
|
||||||
|
|
||||||
git_oid_fromraw(&entry->oid, (const unsigned char *)buffer);
|
git_oid_fromraw(&entry->oid, (const unsigned char *)buffer);
|
||||||
buffer += GIT_OID_RAWSZ;
|
buffer += GIT_OID_RAWSZ;
|
||||||
|
@ -12,17 +12,20 @@
|
|||||||
#include "odb.h"
|
#include "odb.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "strmap.h"
|
#include "strmap.h"
|
||||||
|
#include "pool.h"
|
||||||
|
|
||||||
struct git_tree_entry {
|
struct git_tree_entry {
|
||||||
uint16_t attr;
|
uint16_t attr;
|
||||||
|
uint16_t filename_len;
|
||||||
git_oid oid;
|
git_oid oid;
|
||||||
size_t filename_len;
|
bool pooled;
|
||||||
char filename[1];
|
char filename[GIT_FLEX_ARRAY];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct git_tree {
|
struct git_tree {
|
||||||
git_object object;
|
git_object object;
|
||||||
git_vector entries;
|
git_vector entries;
|
||||||
|
git_pool pool;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct git_treebuilder {
|
struct git_treebuilder {
|
||||||
|
Loading…
Reference in New Issue
Block a user