Skip to content

Commit 41da4e1

Browse files
committed
Cache the parsed submodule config when diffing
This change makes that anything that calls `git_diff__from_iterators` (any of the `git_diff_xxx` functions) only need to parse the `.gitmodules` file once. This can be avoided by calling `git_repository_submodule_cache_all(...)`, but we can do that safely for the user with no change in semantics. Fixes: libgit2#5725
1 parent 03ea04b commit 41da4e1

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

src/diff_generate.c

Lines changed: 34 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,37 @@ 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+
/* Cache the submodule information to avoid having to parse it for every submodule. */
713+
if (git_strmap_new(&info->submodule_cache) == 0) {
714+
if (git_submodule__map(diff->base.repo, info->submodule_cache) < 0) {
715+
/* If the caching failed for whatever reason, bail out and clean up. */
716+
git_submodule *sm = NULL;
717+
git_strmap_foreach_value(info->submodule_cache, sm, {
718+
git_submodule_free(sm);
719+
});
720+
git_strmap_free(info->submodule_cache);
721+
info->submodule_cache = NULL;
722+
}
723+
}
724+
}
725+
submodule_cache = info->submodule_cache;
726+
}
727+
728+
if ((error = git_submodule__lookup_with_cache(
729+
&sub, diff->base.repo, info->nitem->path, submodule_cache)) < 0) {
706730

707731
/* GIT_EEXISTS means dir with .git in it was found - ignore it */
708732
if (error == GIT_EEXISTS) {
@@ -1192,7 +1216,7 @@ int git_diff__from_iterators(
11921216
const git_diff_options *opts)
11931217
{
11941218
git_diff_generated *diff;
1195-
diff_in_progress info;
1219+
diff_in_progress info = {0};
11961220
int error = 0;
11971221

11981222
*out = NULL;
@@ -1260,6 +1284,13 @@ int git_diff__from_iterators(
12601284
*out = &diff->base;
12611285
else
12621286
git_diff_free(&diff->base);
1287+
if (info.submodule_cache) {
1288+
git_submodule *sm = NULL;
1289+
git_strmap_foreach_value(info.submodule_cache, sm, {
1290+
git_submodule_free(sm);
1291+
});
1292+
git_strmap_free(info.submodule_cache);
1293+
}
12631294

12641295
return error;
12651296
}

src/submodule.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ int git_submodule_lookup(
253253
git_submodule **out, /* NULL if user only wants to test existence */
254254
git_repository *repo,
255255
const char *name) /* trailing slash is allowed */
256+
{
257+
return git_submodule__lookup_with_cache(out, repo, name, repo->submodule_cache);
258+
}
259+
260+
int git_submodule__lookup_with_cache(
261+
git_submodule **out, /* NULL if user only wants to test existence */
262+
git_repository *repo,
263+
const char *name, /* trailing slash is allowed */
264+
git_strmap *cache)
256265
{
257266
int error;
258267
unsigned int location;
@@ -266,8 +275,8 @@ int git_submodule_lookup(
266275
return -1;
267276
}
268277

269-
if (repo->submodule_cache != NULL) {
270-
if ((sm = git_strmap_get(repo->submodule_cache, name)) != NULL) {
278+
if (cache != NULL) {
279+
if ((sm = git_strmap_get(cache, name)) != NULL) {
271280
if (out) {
272281
*out = sm;
273282
GIT_REFCOUNT_INC(*out);

src/submodule.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ enum {
122122
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
123123
((S) & ~(0xFFFFFFFFu << 20))
124124

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);
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)