Skip to content

Commit bb542e4

Browse files
lukecotterisomorphic-git-bot
authored andcommitted
feat: perf: cache git config (statusMatrix ~20% faster) (#2023)
* perf: avoid stat call when savedStats is null * perf: combine two map function calls * fix: ensure isSection is set when config is updated * fix: handle num + bool already being primitives * perf: locally cache git config after first read * perf: read gitConfig once * docs: add @lukecotter as a contributor * test: add case to ensure git config is reread correctly when calling walk multiple times * refactor: avoid extra call to entry.content() * refactor: avoid extra object creation * Revert "refactor: avoid extra object creation" This reverts commit 36090f820c1c5635f6342f6f40929d6d5cf85e58. * Revert "refactor: avoid extra call to entry.content()" This reverts commit 9dc82cd3d910175789c447543f60320320ed08c6. * Revert "perf: combine two map function calls" This reverts commit 63c3b12b48e8990607ef23f85978bcbec552df1d. * Revert "perf: avoid stat call when savedStats is null" This reverts commit 00a43da7b4337db39d1015f62102b303e2718bf7. * refactor: rename me to self
1 parent f577f87 commit bb542e4

File tree

6 files changed

+71
-14
lines changed

6 files changed

+71
-14
lines changed

js/isomorphic-git/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
374374
<td align="center"><a href="http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=62372"><img src="https://avatars.githubusercontent.com/u/865809?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Modesty Zhang</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=modesty" title="Code">💻</a> <a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=modesty" title="Documentation">📖</a> <a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=modesty" title="Tests">⚠️</a></td>
375375
<td align="center"><a href="https://github.com/amrc-benmorrow"><img src="https://avatars.githubusercontent.com/u/120477944?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Ben Morrow</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=amrc-benmorrow" title="Code">💻</a></td>
376376
</tr>
377-
<tr>
377+
<tr>
378378
<td align="center"><a href="https://github.com/jayree"><img src="https://avatars.githubusercontent.com/u/14836154?v=4?s=60" width="60px;" alt=""/><br /><sub><b>jayree</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=jayree" title="Code">💻</a> <a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=jayree" title="Tests">⚠️</a></td>
379379
<td align="center"><a href="https://github.com/lsegurado"><img src="https://avatars.githubusercontent.com/u/27731047?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Lucas Martin Segurado</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=lsegurado" title="Documentation">📖</a> <a href="https://github.com/isomorphic-git/isomorphic-git/issues?q=author%3Alsegurado" title="Bug reports">🐛</a></td>
380380
<td align="center"><a href="https://github.com/limond"><img src="https://avatars.githubusercontent.com/u/1025682?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Leon Kaucher</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=limond" title="Code">💻</a> <a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=limond" title="Tests">⚠️</a></td>
@@ -383,6 +383,9 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
383383
<td align="center"><a href="https://github.com/Vinzent03"><img src="https://avatars.githubusercontent.com/u/63981639?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Vinzent</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=Vinzent03" title="Code">💻</a></td>
384384
<td align="center"><a href="https://github.com/LokiMidgard"><img src="https://avatars.githubusercontent.com/u/389101?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Patrick Kranz</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=LokiMidgard" title="Code">💻</a> <a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=LokiMidgard" title="Documentation">📖</a> <a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=LokiMidgard" title="Tests">⚠️</a></td>
385385
</tr>
386+
<tr>
387+
<td align="center"><a href="https://github.com/lukecotter"><img src="https://avatars.githubusercontent.com/u/4013877?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Luke Cotter</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=lukecotter" title="Code">💻</a></td>
388+
</tr>
386389
</table>
387390

388391
<!-- markdownlint-restore -->

js/isomorphic-git/index.cjs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,10 @@ function compareRefNames(a, b) {
14891489

14901490
// This is straight from parse_unit_factor in config.c of canonical git
14911491
const num = val => {
1492+
if (typeof val === 'number') {
1493+
return val
1494+
}
1495+
14921496
val = val.toLowerCase();
14931497
let n = parseInt(val);
14941498
if (val.endsWith('k')) n *= 1024;
@@ -1499,6 +1503,10 @@ const num = val => {
14991503

15001504
// This is straight from git_parse_maybe_bool_text in config.c of canonical git
15011505
const bool = val => {
1506+
if (typeof val === 'boolean') {
1507+
return val
1508+
}
1509+
15021510
val = val.trim().toLowerCase();
15031511
if (val === 'true' || val === 'yes' || val === 'on') return true
15041512
if (val === 'false' || val === 'no' || val === 'off') return false
@@ -1614,6 +1622,7 @@ const normalizePath = path => {
16141622
name,
16151623
path: getPath(section, subsection, name),
16161624
sectionPath: getPath(section, subsection, null),
1625+
isSection: !!section,
16171626
}
16181627
};
16191628

@@ -1674,7 +1683,7 @@ class GitConfig {
16741683

16751684
async getSubsections(section) {
16761685
return this.parsedConfig
1677-
.filter(config => config.section === section && config.isSection)
1686+
.filter(config => config.isSection && config.section === section)
16781687
.map(config => config.subsection)
16791688
}
16801689

@@ -1696,7 +1705,9 @@ class GitConfig {
16961705
name,
16971706
path: normalizedPath,
16981707
sectionPath,
1708+
isSection,
16991709
} = normalizePath(path);
1710+
17001711
const configIndex = findLastIndex(
17011712
this.parsedConfig,
17021713
config => config.path === normalizedPath
@@ -1738,6 +1749,7 @@ class GitConfig {
17381749
} else {
17391750
// Add a new section
17401751
const newSection = {
1752+
isSection,
17411753
section,
17421754
subsection,
17431755
modified: true,
@@ -4124,6 +4136,8 @@ class GitWalkerFs {
41244136
this.cache = cache;
41254137
this.dir = dir;
41264138
this.gitdir = gitdir;
4139+
4140+
this.config = null;
41274141
const walker = this;
41284142
this.ConstructEntry = class WorkdirEntry {
41294143
constructor(fullpath) {
@@ -4210,7 +4224,7 @@ class GitWalkerFs {
42104224
if ((await entry.type()) === 'tree') {
42114225
entry._content = undefined;
42124226
} else {
4213-
const config = await GitConfigManager.get({ fs, gitdir });
4227+
const config = await this._getGitConfig(fs, gitdir);
42144228
const autocrlf = await config.get('core.autocrlf');
42154229
const content = await fs.read(`${dir}/${entry._fullpath}`, { autocrlf });
42164230
// workaround for a BrowserFS edge case
@@ -4226,6 +4240,7 @@ class GitWalkerFs {
42264240

42274241
async oid(entry) {
42284242
if (entry._oid === false) {
4243+
const self = this;
42294244
const { fs, gitdir, cache } = this;
42304245
let oid;
42314246
// See if we can use the SHA1 hash in the index.
@@ -4234,7 +4249,7 @@ class GitWalkerFs {
42344249
) {
42354250
const stage = index.entriesMap.get(entry._fullpath);
42364251
const stats = await entry.stat();
4237-
const config = await GitConfigManager.get({ fs, gitdir });
4252+
const config = await self._getGitConfig(fs, gitdir);
42384253
const filemode = await config.get('core.filemode');
42394254
const trustino =
42404255
typeof process !== 'undefined'
@@ -4273,6 +4288,14 @@ class GitWalkerFs {
42734288
}
42744289
return entry._oid
42754290
}
4291+
4292+
async _getGitConfig(fs, gitdir) {
4293+
if (this.config) {
4294+
return this.config
4295+
}
4296+
this.config = await GitConfigManager.get({ fs, gitdir });
4297+
return this.config
4298+
}
42764299
}
42774300

42784301
// @ts-check
@@ -5066,6 +5089,8 @@ async function add({
50665089

50675090
const fs = new FileSystem(_fs);
50685091
await GitIndexManager.acquire({ fs, gitdir, cache }, async index => {
5092+
const config = await GitConfigManager.get({ fs, gitdir });
5093+
const autocrlf = await config.get('core.autocrlf');
50695094
return addToIndex({
50705095
dir,
50715096
gitdir,
@@ -5074,6 +5099,7 @@ async function add({
50745099
index,
50755100
force,
50765101
parallel,
5102+
autocrlf,
50775103
})
50785104
});
50795105
} catch (err) {
@@ -5090,6 +5116,7 @@ async function addToIndex({
50905116
index,
50915117
force,
50925118
parallel,
5119+
autocrlf,
50935120
}) {
50945121
// TODO: Should ignore UNLESS it's already in the index.
50955122
filepath = Array.isArray(filepath) ? filepath : [filepath];
@@ -5118,6 +5145,7 @@ async function addToIndex({
51185145
index,
51195146
force,
51205147
parallel,
5148+
autocrlf,
51215149
})
51225150
);
51235151
await Promise.all(promises);
@@ -5131,12 +5159,11 @@ async function addToIndex({
51315159
index,
51325160
force,
51335161
parallel,
5162+
autocrlf,
51345163
});
51355164
}
51365165
}
51375166
} else {
5138-
const config = await GitConfigManager.get({ fs, gitdir });
5139-
const autocrlf = await config.get('core.autocrlf');
51405167
const object = stats.isSymbolicLink()
51415168
? await fs.readlink(pathBrowserify.join(dir, currentFilepath)).then(posixifyPathBuffer)
51425169
: await fs.read(pathBrowserify.join(dir, currentFilepath), { autocrlf });

js/isomorphic-git/index.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,10 @@ function compareRefNames(a, b) {
14831483

14841484
// This is straight from parse_unit_factor in config.c of canonical git
14851485
const num = val => {
1486+
if (typeof val === 'number') {
1487+
return val
1488+
}
1489+
14861490
val = val.toLowerCase();
14871491
let n = parseInt(val);
14881492
if (val.endsWith('k')) n *= 1024;
@@ -1493,6 +1497,10 @@ const num = val => {
14931497

14941498
// This is straight from git_parse_maybe_bool_text in config.c of canonical git
14951499
const bool = val => {
1500+
if (typeof val === 'boolean') {
1501+
return val
1502+
}
1503+
14961504
val = val.trim().toLowerCase();
14971505
if (val === 'true' || val === 'yes' || val === 'on') return true
14981506
if (val === 'false' || val === 'no' || val === 'off') return false
@@ -1608,6 +1616,7 @@ const normalizePath = path => {
16081616
name,
16091617
path: getPath(section, subsection, name),
16101618
sectionPath: getPath(section, subsection, null),
1619+
isSection: !!section,
16111620
}
16121621
};
16131622

@@ -1668,7 +1677,7 @@ class GitConfig {
16681677

16691678
async getSubsections(section) {
16701679
return this.parsedConfig
1671-
.filter(config => config.section === section && config.isSection)
1680+
.filter(config => config.isSection && config.section === section)
16721681
.map(config => config.subsection)
16731682
}
16741683

@@ -1690,7 +1699,9 @@ class GitConfig {
16901699
name,
16911700
path: normalizedPath,
16921701
sectionPath,
1702+
isSection,
16931703
} = normalizePath(path);
1704+
16941705
const configIndex = findLastIndex(
16951706
this.parsedConfig,
16961707
config => config.path === normalizedPath
@@ -1732,6 +1743,7 @@ class GitConfig {
17321743
} else {
17331744
// Add a new section
17341745
const newSection = {
1746+
isSection,
17351747
section,
17361748
subsection,
17371749
modified: true,
@@ -4118,6 +4130,8 @@ class GitWalkerFs {
41184130
this.cache = cache;
41194131
this.dir = dir;
41204132
this.gitdir = gitdir;
4133+
4134+
this.config = null;
41214135
const walker = this;
41224136
this.ConstructEntry = class WorkdirEntry {
41234137
constructor(fullpath) {
@@ -4204,7 +4218,7 @@ class GitWalkerFs {
42044218
if ((await entry.type()) === 'tree') {
42054219
entry._content = undefined;
42064220
} else {
4207-
const config = await GitConfigManager.get({ fs, gitdir });
4221+
const config = await this._getGitConfig(fs, gitdir);
42084222
const autocrlf = await config.get('core.autocrlf');
42094223
const content = await fs.read(`${dir}/${entry._fullpath}`, { autocrlf });
42104224
// workaround for a BrowserFS edge case
@@ -4220,6 +4234,7 @@ class GitWalkerFs {
42204234

42214235
async oid(entry) {
42224236
if (entry._oid === false) {
4237+
const self = this;
42234238
const { fs, gitdir, cache } = this;
42244239
let oid;
42254240
// See if we can use the SHA1 hash in the index.
@@ -4228,7 +4243,7 @@ class GitWalkerFs {
42284243
) {
42294244
const stage = index.entriesMap.get(entry._fullpath);
42304245
const stats = await entry.stat();
4231-
const config = await GitConfigManager.get({ fs, gitdir });
4246+
const config = await self._getGitConfig(fs, gitdir);
42324247
const filemode = await config.get('core.filemode');
42334248
const trustino =
42344249
typeof process !== 'undefined'
@@ -4267,6 +4282,14 @@ class GitWalkerFs {
42674282
}
42684283
return entry._oid
42694284
}
4285+
4286+
async _getGitConfig(fs, gitdir) {
4287+
if (this.config) {
4288+
return this.config
4289+
}
4290+
this.config = await GitConfigManager.get({ fs, gitdir });
4291+
return this.config
4292+
}
42704293
}
42714294

42724295
// @ts-check
@@ -5060,6 +5083,8 @@ async function add({
50605083

50615084
const fs = new FileSystem(_fs);
50625085
await GitIndexManager.acquire({ fs, gitdir, cache }, async index => {
5086+
const config = await GitConfigManager.get({ fs, gitdir });
5087+
const autocrlf = await config.get('core.autocrlf');
50635088
return addToIndex({
50645089
dir,
50655090
gitdir,
@@ -5068,6 +5093,7 @@ async function add({
50685093
index,
50695094
force,
50705095
parallel,
5096+
autocrlf,
50715097
})
50725098
});
50735099
} catch (err) {
@@ -5084,6 +5110,7 @@ async function addToIndex({
50845110
index,
50855111
force,
50865112
parallel,
5113+
autocrlf,
50875114
}) {
50885115
// TODO: Should ignore UNLESS it's already in the index.
50895116
filepath = Array.isArray(filepath) ? filepath : [filepath];
@@ -5112,6 +5139,7 @@ async function addToIndex({
51125139
index,
51135140
force,
51145141
parallel,
5142+
autocrlf,
51155143
})
51165144
);
51175145
await Promise.all(promises);
@@ -5125,12 +5153,11 @@ async function addToIndex({
51255153
index,
51265154
force,
51275155
parallel,
5156+
autocrlf,
51285157
});
51295158
}
51305159
}
51315160
} else {
5132-
const config = await GitConfigManager.get({ fs, gitdir });
5133-
const autocrlf = await config.get('core.autocrlf');
51345161
const object = stats.isSymbolicLink()
51355162
? await fs.readlink(join(dir, currentFilepath)).then(posixifyPathBuffer)
51365163
: await fs.read(join(dir, currentFilepath), { autocrlf });

js/isomorphic-git/index.umd.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/isomorphic-git/index.umd.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/isomorphic-git/size_report.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)