Skip to content

Commit d185ab2

Browse files
authored
Merge pull request libgit2#5727 from lhchavez/make-git-diff-fast
Cache the parsed submodule config when diffing
2 parents 851e778 + 1ab2f57 commit d185ab2

File tree

4 files changed

+76
-33
lines changed

4 files changed

+76
-33
lines changed

src/diff_generate.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,8 @@ typedef struct {
680680
git_iterator *new_iter;
681681
const git_index_entry *oitem;
682682
const git_index_entry *nitem;
683+
git_strmap *submodule_cache;
684+
bool submodule_cache_initialized;
683685
} diff_in_progress;
684686

685687
#define MODE_BITS_MASK 0000777
@@ -694,15 +696,31 @@ static int maybe_modified_submodule(
694696
git_submodule *sub;
695697
unsigned int sm_status = 0;
696698
git_submodule_ignore_t ign = diff->base.opts.ignore_submodules;
699+
git_strmap *submodule_cache = NULL;
697700

698701
*status = GIT_DELTA_UNMODIFIED;
699702

700703
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_SUBMODULES) ||
701704
ign == GIT_SUBMODULE_IGNORE_ALL)
702705
return 0;
703706

704-
if ((error = git_submodule_lookup(
705-
&sub, diff->base.repo, info->nitem->path)) < 0) {
707+
if (diff->base.repo->submodule_cache != NULL) {
708+
submodule_cache = diff->base.repo->submodule_cache;
709+
} else {
710+
if (!info->submodule_cache_initialized) {
711+
info->submodule_cache_initialized = true;
712+
/*
713+
* Try to cache the submodule information to avoid having to parse it for
714+
* every submodule. It is okay if it fails, the cache will still be NULL
715+
* and the submodules will be attempted to be looked up individually.
716+
*/
717+
git_submodule_cache_init(&info->submodule_cache, diff->base.repo);
718+
}
719+
submodule_cache = info->submodule_cache;
720+
}
721+
722+
if ((error = git_submodule__lookup_with_cache(
723+
&sub, diff->base.repo, info->nitem->path, submodule_cache)) < 0) {
706724

707725
/* GIT_EEXISTS means dir with .git in it was found - ignore it */
708726
if (error == GIT_EEXISTS) {
@@ -1192,7 +1210,7 @@ int git_diff__from_iterators(
11921210
const git_diff_options *opts)
11931211
{
11941212
git_diff_generated *diff;
1195-
diff_in_progress info;
1213+
diff_in_progress info = {0};
11961214
int error = 0;
11971215

11981216
*out = NULL;
@@ -1260,6 +1278,8 @@ int git_diff__from_iterators(
12601278
*out = &diff->base;
12611279
else
12621280
git_diff_free(&diff->base);
1281+
if (info.submodule_cache)
1282+
git_submodule_cache_free(info.submodule_cache);
12631283

12641284
return error;
12651285
}

src/repository.c

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3055,30 +3055,16 @@ int git_repository_set_ident(git_repository *repo, const char *name, const char
30553055

30563056
int git_repository_submodule_cache_all(git_repository *repo)
30573057
{
3058-
int error;
3059-
30603058
GIT_ASSERT_ARG(repo);
3061-
3062-
if ((error = git_strmap_new(&repo->submodule_cache)))
3063-
return error;
3064-
3065-
error = git_submodule__map(repo, repo->submodule_cache);
3066-
return error;
3059+
return git_submodule_cache_init(&repo->submodule_cache, repo);
30673060
}
30683061

30693062
int git_repository_submodule_cache_clear(git_repository *repo)
30703063
{
3071-
git_submodule *sm;
3072-
3064+
int error = 0;
30733065
GIT_ASSERT_ARG(repo);
30743066

3075-
if (repo->submodule_cache == NULL) {
3076-
return 0;
3077-
}
3078-
git_strmap_foreach_value(repo->submodule_cache, sm, {
3079-
git_submodule_free(sm);
3080-
});
3081-
git_strmap_free(repo->submodule_cache);
3082-
repo->submodule_cache = 0;
3083-
return 0;
3067+
error = git_submodule_cache_free(repo->submodule_cache);
3068+
repo->submodule_cache = NULL;
3069+
return error;
30843070
}

src/submodule.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,47 @@ static int load_submodule_names(git_strmap **out, git_repository *repo, git_conf
249249
return error;
250250
}
251251

252+
int git_submodule_cache_init(git_strmap **out, git_repository *repo)
253+
{
254+
int error = 0;
255+
git_strmap *cache = NULL;
256+
GIT_ASSERT_ARG(out);
257+
GIT_ASSERT_ARG(repo);
258+
if ((error = git_strmap_new(&cache)) < 0)
259+
return error;
260+
if ((error = git_submodule__map(repo, cache)) < 0) {
261+
git_submodule_cache_free(cache);
262+
return error;
263+
}
264+
*out = cache;
265+
return error;
266+
}
267+
268+
int git_submodule_cache_free(git_strmap *cache)
269+
{
270+
git_submodule *sm = NULL;
271+
if (cache == NULL)
272+
return 0;
273+
git_strmap_foreach_value(cache, sm, {
274+
git_submodule_free(sm);
275+
});
276+
git_strmap_free(cache);
277+
return 0;
278+
}
279+
252280
int git_submodule_lookup(
253281
git_submodule **out, /* NULL if user only wants to test existence */
254282
git_repository *repo,
255283
const char *name) /* trailing slash is allowed */
284+
{
285+
return git_submodule__lookup_with_cache(out, repo, name, repo->submodule_cache);
286+
}
287+
288+
int git_submodule__lookup_with_cache(
289+
git_submodule **out, /* NULL if user only wants to test existence */
290+
git_repository *repo,
291+
const char *name, /* trailing slash is allowed */
292+
git_strmap *cache)
256293
{
257294
int error;
258295
unsigned int location;
@@ -266,8 +303,8 @@ int git_submodule_lookup(
266303
return -1;
267304
}
268305

269-
if (repo->submodule_cache != NULL) {
270-
if ((sm = git_strmap_get(repo->submodule_cache, name)) != NULL) {
306+
if (cache != NULL) {
307+
if ((sm = git_strmap_get(cache, name)) != NULL) {
271308
if (out) {
272309
*out = sm;
273310
GIT_REFCOUNT_INC(*out);

src/submodule.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,6 @@ struct git_submodule {
101101
git_oid wd_oid;
102102
};
103103

104-
/* Force revalidation of submodule data cache (alloc as needed) */
105-
extern int git_submodule_cache_refresh(git_repository *repo);
106-
107-
/* Release all submodules */
108-
extern void git_submodule_cache_free(git_repository *repo);
109-
110104
/* Additional flags on top of public GIT_SUBMODULE_STATUS values */
111105
enum {
112106
GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20),
@@ -122,9 +116,15 @@ enum {
122116
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
123117
((S) & ~(0xFFFFFFFFu << 20))
124118

125-
/* Internal lookup does not attempt to refresh cached data */
126-
extern int git_submodule__lookup(
127-
git_submodule **out, git_repository *repo, const char *path);
119+
/* Initialize an external submodule cache for the provided repo. */
120+
extern int git_submodule_cache_init(git_strmap **out, git_repository *repo);
121+
122+
/* Release the resources of the submodule cache. */
123+
extern int git_submodule_cache_free(git_strmap *cache);
124+
125+
/* Submodule lookup with an explicit cache */
126+
extern int git_submodule__lookup_with_cache(
127+
git_submodule **out, git_repository *repo, const char *path, git_strmap *cache);
128128

129129
/* Internal status fn returns status and optionally the various OIDs */
130130
extern int git_submodule__status(

0 commit comments

Comments
 (0)