Skip to content

Commit

Permalink
Add concurrentFsLimit option
Browse files Browse the repository at this point in the history
  • Loading branch information
nodkz committed Nov 15, 2024
1 parent dfe8f34 commit eb1fc3b
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ await repo.dispose();
- `'include'` or `true` (default) - process all packs
- `'exclude'` or `false` - exclude cruft packs from processing
- `'only'` - process cruft packs only
- `concurrentFsLimit` – number of concurrent file system operations (default: 50)

### Refs

Expand Down
24 changes: 14 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export async function createGitReader(gitdir: string, options?: GitReaderOptions
const normalizedOptions = normalizeOptions(options);
const resolvedGitDir = await resolveGitDir(gitdir);
const [refIndex, looseObjectIndex, packedObjectIndex] = await Promise.all([
createRefIndex(resolvedGitDir),
createLooseObjectIndex(resolvedGitDir),
createRefIndex(resolvedGitDir, normalizedOptions),
createLooseObjectIndex(resolvedGitDir, normalizedOptions),
createPackedObjectIndex(resolvedGitDir, normalizedOptions)
]);
const { readObjectHeaderByHash, readObjectByHash, readObjectHeaderByOid, readObjectByOid } =
Expand All @@ -38,20 +38,23 @@ export async function createGitReader(gitdir: string, options?: GitReaderOptions
async dispose() {
await Promise.all([looseObjectIndex.dispose(), packedObjectIndex.dispose()]);
},
stat: createStatMethod({
gitdir: resolvedGitDir,
refIndex,
looseObjectIndex,
packedObjectIndex
}),
stat: createStatMethod(
{
gitdir: resolvedGitDir,
refIndex,
looseObjectIndex,
packedObjectIndex
},
normalizedOptions
),

initTime: Date.now() - startInitTime
};
}

function normalizeOptions(options?: GitReaderOptions): NormalizedGitReaderOptions {
if (!options || options.cruftPacks === undefined) {
return { cruftPacks: 'include' };
return { cruftPacks: 'include', concurrentFsLimit: 50 };
}

return {
Expand All @@ -60,7 +63,8 @@ function normalizeOptions(options?: GitReaderOptions): NormalizedGitReaderOption
? validateCruftPackMode(options.cruftPacks)
: options.cruftPacks // expands true/false aliases
? 'include'
: 'exclude'
: 'exclude',
concurrentFsLimit: options.concurrentFsLimit ?? 50
};
}

Expand Down
12 changes: 8 additions & 4 deletions src/loose-object-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
GitObject,
InternalGitObjectContent,
InternalGitObjectHeader,
NormalizedGitReaderOptions,
ObjectsTypeStat,
PackedObjectType
} from './types.js';
Expand All @@ -15,13 +16,16 @@ import { promiseAllThreaded } from './utils/threads.js';
type LooseObjectMap = Map<string, string>;
type LooseObjectMapEntry = [oid: string, relpath: string];

async function createLooseObjectMap(gitdir: string): Promise<LooseObjectMap> {
async function createLooseObjectMap(
gitdir: string,
{ concurrentFsLimit }: NormalizedGitReaderOptions
): Promise<LooseObjectMap> {
const objectsPath = pathJoin(gitdir, 'objects');
const looseDirs = (await fsPromises.readdir(objectsPath)).filter((p) =>
/^[0-9a-f]{2}$/.test(p)
);

const objectDirs = await promiseAllThreaded(20, looseDirs, (dir) =>
const objectDirs = await promiseAllThreaded(concurrentFsLimit, looseDirs, (dir) =>
fsPromises
.readdir(pathJoin(objectsPath, dir))
.then((files) =>
Expand Down Expand Up @@ -76,8 +80,8 @@ function parseLooseObject(buffer: Buffer): InternalGitObjectContent {
};
}

export async function createLooseObjectIndex(gitdir: string) {
const looseObjectMap = await createLooseObjectMap(gitdir);
export async function createLooseObjectIndex(gitdir: string, options: NormalizedGitReaderOptions) {
const looseObjectMap = await createLooseObjectMap(gitdir, options);
const { fanoutTable, binaryNames, names } = indexObjectNames([...looseObjectMap.keys()]);

const getOidFromHash = (hash: Buffer) => {
Expand Down
4 changes: 2 additions & 2 deletions src/packed-object-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const PACKDIR = 'objects/pack';
*/
export async function createPackedObjectIndex(
gitdir: string,
{ cruftPacks }: NormalizedGitReaderOptions
{ cruftPacks, concurrentFsLimit }: NormalizedGitReaderOptions
) {
function readObjectHeaderByHash(
hash: Buffer,
Expand Down Expand Up @@ -76,7 +76,7 @@ export async function createPackedObjectIndex(
: !cruftPackFilenames.includes(filename);
});

const packFiles = await promiseAllThreaded(20, packFilenames, async (filename) =>
const packFiles = await promiseAllThreaded(concurrentFsLimit, packFilenames, async (filename) =>
readPackFile(gitdir, `${PACKDIR}/${filename}`, readObjectHeaderByHash, readObjectByHash)
);

Expand Down
14 changes: 10 additions & 4 deletions src/resolve-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { promises as fsPromises, existsSync } from 'fs';
import { join as pathJoin, basename, sep as pathSep } from 'path';
import { promiseAllThreaded } from './utils/threads.js';
import { scanFs } from '@discoveryjs/scan-fs';
import { NormalizedGitReaderOptions } from './types.js';

type Ref = {
name: string;
Expand Down Expand Up @@ -50,7 +51,10 @@ function isOid(value: unknown) {
return typeof value === 'string' && value.length === 40 && /^[0-9a-f]{40}$/.test(value);
}

export async function createRefIndex(gitdir: string) {
export async function createRefIndex(
gitdir: string,
{ concurrentFsLimit }: NormalizedGitReaderOptions
) {
const refResolver = await createRefResolver(gitdir);

// expand a ref into a full form
Expand Down Expand Up @@ -137,7 +141,7 @@ export async function createRefIndex(gitdir: string) {
let cachedRefsWithOid = listRefsWithOidCache.get(prefix);

if (cachedRefsWithOid === undefined) {
const oids = await promiseAllThreaded(20, cachedRefs, (name) =>
const oids = await promiseAllThreaded(50, cachedRefs, (name) =>
refResolver.resolveOid(prefix + name)
);

Expand Down Expand Up @@ -211,8 +215,10 @@ export async function createRefIndex(gitdir: string) {

async stat() {
const remotes = listRemotes();
const branchesByRemote = await promiseAllThreaded(20, remotes, (remote) =>
listRemoteBranches(remote)
const branchesByRemote = await promiseAllThreaded(
concurrentFsLimit,
remotes,
(remote) => listRemoteBranches(remote)
);

return {
Expand Down
28 changes: 16 additions & 12 deletions src/stat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@ import { promiseAllThreaded } from './utils/threads.js';
import { createRefIndex } from './resolve-ref.js';
import { createLooseObjectIndex } from './loose-object-index.js';
import { createPackedObjectIndex } from './packed-object-index.js';
import { NormalizedGitReaderOptions } from './types.js';

export function createStatMethod({
gitdir,
refIndex,
looseObjectIndex,
packedObjectIndex
}: {
gitdir: string;
refIndex: Awaited<ReturnType<typeof createRefIndex>>;
looseObjectIndex: Awaited<ReturnType<typeof createLooseObjectIndex>>;
packedObjectIndex: Awaited<ReturnType<typeof createPackedObjectIndex>>;
}) {
export function createStatMethod(
{
gitdir,
refIndex,
looseObjectIndex,
packedObjectIndex
}: {
gitdir: string;
refIndex: Awaited<ReturnType<typeof createRefIndex>>;
looseObjectIndex: Awaited<ReturnType<typeof createLooseObjectIndex>>;
packedObjectIndex: Awaited<ReturnType<typeof createPackedObjectIndex>>;
},
{ concurrentFsLimit }: NormalizedGitReaderOptions
) {
return async function () {
const [refs, looseObjects, packedObjects, { files }] = await Promise.all([
refIndex.stat(),
Expand All @@ -26,7 +30,7 @@ export function createStatMethod({
scanFs(gitdir)
]);

const fileStats = await promiseAllThreaded(20, files, (file) =>
const fileStats = await promiseAllThreaded(concurrentFsLimit, files, (file) =>
fsPromises.stat(path.join(gitdir, file.path))
);

Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,14 @@ export interface GitReaderOptions {
* @default 'include'
*/
cruftPacks?: CruftPackMode | boolean;
/**
* Maximum number of concurrent file system operations.
* @default 50
*/
concurrentFsLimit?: number;
}

export interface NormalizedGitReaderOptions {
cruftPacks: CruftPackMode;
concurrentFsLimit: number;
}

0 comments on commit eb1fc3b

Please sign in to comment.