Browse Source

Avoids unnecessary array to string conversion

main
Eric Amodio 2 years ago
parent
commit
0e796c1ab0
4 changed files with 78 additions and 52 deletions
  1. +8
    -9
      src/env/node/git/git.ts
  2. +29
    -32
      src/env/node/git/localGitProvider.ts
  3. +3
    -3
      src/git/parsers/logParser.ts
  4. +38
    -8
      src/system/string.ts

+ 8
- 9
src/env/node/git/git.ts View File

@ -874,18 +874,17 @@ export class Git {
);
}
async logStream(
async logStreamTo(
repoPath: string,
sha: string,
limit: number,
options?: { configs?: readonly string[]; stdin?: string },
...args: string[]
): Promise<[data: string, count: number]> {
const params = ['log'];
): Promise<[data: string[], count: number]> {
const params = ['log', ...args];
if (options?.stdin) {
params.push('--stdin');
}
params.push(...args);
const proc = await this.gitSpawn(
{ cwd: repoPath, configs: options?.configs ?? gitLogDefaultConfigs, stdin: options?.stdin },
@ -893,12 +892,12 @@ export class Git {
'--',
);
const shaRegex = new RegExp(`(^${sha}\x00)|(\x00\x00${sha}\x00)`);
const shaRegex = new RegExp(`(?:^|\x00\x00)${sha}\x00`);
let found = false;
let count = 0;
return new Promise<[data: string, count: number]>((resolve, reject) => {
return new Promise<[data: string[], count: number]>((resolve, reject) => {
const errData: string[] = [];
const data: string[] = [];
@ -915,13 +914,13 @@ export class Git {
reject(new Error(errData.join('')));
}
resolve([data.join(''), count]);
resolve([data, count]);
}
function onData(s: string) {
data.push(s);
// eslint-disable-next-line no-control-regex
count += (s.match(/\x00\x00[0-9a-f]{40}\x00/g)?.length ?? 0) + 1;
count += s.match(/(?:^|\x00\x00)[0-9a-f]{40}\x00/g)?.length ?? 0;
if (!found && shaRegex.test(s)) {
found = true;
@ -939,7 +938,7 @@ export class Git {
proc.stderr!.removeListener('data', onErrData);
proc.kill();
resolve([data.join(''), count]);
resolve([data, count]);
}
proc.on('error', onError);

+ 29
- 32
src/env/node/git/localGitProvider.ts View File

@ -1632,7 +1632,6 @@ export class LocalGitProvider implements GitProvider, Disposable {
this.getRemotes(repoPath),
]);
const limit = defaultLimit;
const remotes = getSettledValue(remotesResult);
const remoteMap = remotes != null ? new Map(remotes.map(r => [r.name, r])) : new Map();
const selectSha = first(refParser.parse(getSettledValue(refResult) ?? ''));
@ -1655,11 +1654,11 @@ export class LocalGitProvider implements GitProvider, Disposable {
async function getCommitsForGraphCore(
this: LocalGitProvider,
limit: number,
shaOrCursor?: string | { sha: string; skip?: number },
shaOrCursor?: string | { sha: string; skip: number },
): Promise<GitGraph> {
iterations++;
let cursor: { sha: string; skip?: number } | undefined;
let cursor: { sha: string; skip: number } | undefined;
let sha: string | undefined;
if (shaOrCursor != null) {
if (typeof shaOrCursor === 'string') {
@ -1669,7 +1668,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
}
let log: string | undefined;
let log: string | string[] | undefined;
let nextPageLimit = limit;
let size;
@ -1678,7 +1677,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
let data;
if (sha) {
[data, limit] = await this.git.logStream(
[data, limit] = await this.git.logStreamTo(
repoPath,
sha,
limit,
@ -1692,38 +1691,36 @@ export class LocalGitProvider implements GitProvider, Disposable {
}
data = await this.git.log2(repoPath, stdin ? { stdin: stdin } : undefined, ...args);
}
if (cursor || sha) {
const cursorIndex = data.startsWith(`${cursor?.sha ?? sha}\x00`)
? 0
: data.indexOf(`\x00\x00${cursor?.sha ?? sha}\x00`);
if (cursorIndex === -1) {
// If we didn't find any new commits, we must have them all so return that we have everything
if (size === data.length) return { repoPath: repoPath, ids: ids, rows: [] };
size = data.length;
nextPageLimit = (nextPageLimit === 0 ? defaultPageLimit : nextPageLimit) * 2;
if (cursor?.skip) {
if (cursor) {
const cursorIndex = data.startsWith(`${cursor.sha}\x00`)
? 0
: data.indexOf(`\x00\x00${cursor.sha}\x00`);
if (cursorIndex === -1) {
// If we didn't find any new commits, we must have them all so return that we have everything
if (size === data.length) return { repoPath: repoPath, ids: ids, rows: [] };
size = data.length;
nextPageLimit = (nextPageLimit === 0 ? defaultPageLimit : nextPageLimit) * 2;
cursor.skip -= Math.floor(cursor.skip * 0.1);
}
continue;
}
continue;
}
// if (cursorIndex > 0 && cursor != null) {
// const duplicates = data.substring(0, cursorIndex);
// if (data.length - duplicates.length < (size ?? data.length) / 4) {
// size = data.length;
// nextPageLimit = (nextPageLimit === 0 ? defaultPageLimit : nextPageLimit) * 2;
// continue;
// }
// if (cursorIndex > 0 && cursor != null) {
// const duplicates = data.substring(0, cursorIndex);
// if (data.length - duplicates.length < (size ?? data.length) / 4) {
// size = data.length;
// nextPageLimit = (nextPageLimit === 0 ? defaultPageLimit : nextPageLimit) * 2;
// continue;
// }
// // Substract out any duplicate commits (regex is faster than parsing and counting)
// nextPageLimit -= (duplicates.match(/\0\0[0-9a-f]{40}\0/g)?.length ?? 0) + 1;
// // Substract out any duplicate commits (regex is faster than parsing and counting)
// nextPageLimit -= (duplicates.match(/\0\0[0-9a-f]{40}\0/g)?.length ?? 0) + 1;
// data = data.substring(cursorIndex + 2);
// }
// data = data.substring(cursorIndex + 2);
// }
}
}
if (!data) return { repoPath: repoPath, ids: ids, rows: [] };
@ -1867,7 +1864,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
};
}
return getCommitsForGraphCore.call(this, limit, selectSha);
return getCommitsForGraphCore.call(this, defaultLimit, selectSha);
}
@log()

+ 3
- 3
src/git/parsers/logParser.ts View File

@ -68,7 +68,7 @@ interface LogEntry {
export type Parser<T> = {
arguments: string[];
parse: (data: string) => Generator<T>;
parse: (data: string | string[]) => Generator<T>;
};
type ParsedEntryFile = { status: string; path: string; originalPath?: string };
@ -142,7 +142,7 @@ export function createLogParser>(
args.push(...options.additionalArgs);
}
function* parse(data: string): Generator<T> {
function* parse(data: string | string[]): Generator<T> {
let entry: T = {} as any;
let fieldCount = 0;
let field;
@ -179,7 +179,7 @@ export function createLogParserSingle(field: string): Parser {
const format = field;
const args = ['-z', `--format=${format}`];
function* parse(data: string): Generator<string> {
function* parse(data: string | string[]): Generator<string> {
let field;
const fields = getLines(data, '\0');

+ 38
- 8
src/system/string.ts View File

@ -121,16 +121,46 @@ export function getDurationMilliseconds(start: [number, number]) {
return secs * 1000 + Math.floor(nanosecs / 1000000);
}
export function* getLines(s: string, char: string = '\n'): IterableIterator<string> {
let i = 0;
while (i < s.length) {
let j = s.indexOf(char, i);
if (j === -1) {
j = s.length;
export function* getLines(data: string | string[], char: string = '\n'): IterableIterator<string> {
if (typeof data === 'string') {
let i = 0;
while (i < data.length) {
let j = data.indexOf(char, i);
if (j === -1) {
j = data.length;
}
yield data.substring(i, j);
i = j + 1;
}
return;
}
let count = 0;
let leftover: string | undefined;
for (let s of data) {
count++;
if (leftover) {
s = leftover + s;
leftover = undefined;
}
yield s.substring(i, j);
i = j + 1;
let i = 0;
while (i < s.length) {
let j = s.indexOf(char, i);
if (j === -1) {
if (count === data.length) {
j = s.length;
} else {
leftover = s.substring(i);
break;
}
}
yield s.substring(i, j);
i = j + 1;
}
}
}

Loading…
Cancel
Save