perf: don't random ID to temp file names (#6817)

This commit is contained in:
Zoltan Kochan
2023-07-17 11:35:34 +03:00
committed by GitHub
parent 250f7e9fe9
commit e958707b2d
13 changed files with 52 additions and 38 deletions

View File

@@ -0,0 +1,8 @@
---
"@pnpm/package-requester": patch
"@pnpm/fs.indexed-pkg-importer": patch
"@pnpm/npm-resolver": patch
"@pnpm/cafs": patch
---
Improve performance by removing cryptographically generated id from temporary file names.

View File

@@ -23,7 +23,7 @@
"make-empty-dir": "^2.0.0",
"p-limit": "^3.1.0",
"path-exists": "^4.0.0",
"path-temp": "^2.0.0",
"path-temp": "^2.1.0",
"rename-overwrite": "^4.0.3",
"sanitize-filename": "^1.6.3"
},

View File

@@ -5,7 +5,7 @@ import { globalWarn, logger } from '@pnpm/logger'
import rimraf from '@zkochan/rimraf'
import sanitizeFilename from 'sanitize-filename'
import makeEmptyDir from 'make-empty-dir'
import pathTemp from 'path-temp'
import { fastPathTemp as pathTemp } from 'path-temp'
import renameOverwrite from 'rename-overwrite'
const filenameConflictsLogger = logger('_filename-conflicts')
@@ -20,7 +20,7 @@ export async function importIndexedDir (
keepModulesDir?: boolean
}
) {
const stage = pathTemp(path.dirname(newDir))
const stage = pathTemp(newDir)
try {
await tryImportIndexedDir(importFile, stage, filenames)
if (opts.keepModulesDir) {

View File

@@ -19,7 +19,7 @@ jest.mock('@pnpm/graceful-fs', () => {
default: fsMock,
}
})
jest.mock('path-temp', () => (dir: string) => path.join(dir, '_tmp'))
jest.mock('path-temp', () => ({ fastPathTemp: (file: string) => `${file}_tmp` }))
jest.mock('rename-overwrite', () => jest.fn())
jest.mock('fs-extra', () => ({
copy: jest.fn(),
@@ -48,12 +48,12 @@ test('packageImportMethod=auto: clone files by default', async () => {
})).toBe('clone')
expect(gfs.copyFile).toBeCalledWith(
path.join('hash1'),
path.join('project', '_tmp', 'package.json'),
path.join('project', 'package_tmp', 'package.json'),
fs.constants.COPYFILE_FICLONE_FORCE
)
expect(gfs.copyFile).toBeCalledWith(
path.join('hash2'),
path.join('project', '_tmp', 'index.js'),
path.join('project', 'package_tmp', 'index.js'),
fs.constants.COPYFILE_FICLONE_FORCE
)
})
@@ -71,8 +71,8 @@ test('packageImportMethod=auto: link files if cloning fails', async () => {
force: false,
fromStore: false,
})).toBe('hardlink')
expect(gfs.link).toBeCalledWith(path.join('hash1'), path.join('project', '_tmp', 'package.json'))
expect(gfs.link).toBeCalledWith(path.join('hash2'), path.join('project', '_tmp', 'index.js'))
expect(gfs.link).toBeCalledWith(path.join('hash1'), path.join('project', 'package_tmp', 'package.json'))
expect(gfs.link).toBeCalledWith(path.join('hash2'), path.join('project', 'package_tmp', 'index.js'))
expect(gfs.copyFile).toBeCalled()
;(gfs.copyFile as jest.Mock).mockClear()
@@ -86,8 +86,8 @@ test('packageImportMethod=auto: link files if cloning fails', async () => {
fromStore: false,
})).toBe('hardlink')
expect(gfs.copyFile).not.toBeCalled()
expect(gfs.link).toBeCalledWith(path.join('hash1'), path.join('project2', '_tmp', 'package.json'))
expect(gfs.link).toBeCalledWith(path.join('hash2'), path.join('project2', '_tmp', 'index.js'))
expect(gfs.link).toBeCalledWith(path.join('hash1'), path.join('project2', 'package_tmp', 'package.json'))
expect(gfs.link).toBeCalledWith(path.join('hash2'), path.join('project2', 'package_tmp', 'index.js'))
})
test('packageImportMethod=auto: link files if cloning fails and even hard linking fails but not with EXDEV error', async () => {
@@ -109,7 +109,7 @@ test('packageImportMethod=auto: link files if cloning fails and even hard linkin
force: false,
fromStore: false,
})).toBe('hardlink')
expect(gfs.link).toBeCalledWith(path.join('hash2'), path.join('project', '_tmp', 'index.js'))
expect(gfs.link).toBeCalledWith(path.join('hash2'), path.join('project', 'package_tmp', 'index.js'))
expect(gfs.link).toBeCalledTimes(2)
expect(gfs.copyFile).toBeCalledTimes(1)
})
@@ -131,7 +131,7 @@ test('packageImportMethod=auto: chooses copying if cloning and hard linking is n
force: false,
fromStore: false,
})).toBe('copy')
expect(gfs.copyFile).toBeCalledWith(path.join('hash2'), path.join('project', '_tmp', 'index.js'))
expect(gfs.copyFile).toBeCalledWith(path.join('hash2'), path.join('project', 'package_tmp', 'index.js'))
expect(gfs.copyFile).toBeCalledTimes(2)
})
@@ -154,8 +154,8 @@ test('packageImportMethod=hardlink: fall back to copying if hardlinking fails',
})).toBe('hardlink')
expect(gfs.link).toBeCalledTimes(3)
expect(gfs.copyFile).toBeCalledTimes(2) // One time the target already exists, so it won't be copied
expect(gfs.copyFile).toBeCalledWith(path.join('hash1'), path.join('project', '_tmp', 'package.json'))
expect(gfs.copyFile).toBeCalledWith(path.join('hash2'), path.join('project', '_tmp', 'index.js'))
expect(gfs.copyFile).toBeCalledWith(path.join('hash1'), path.join('project', 'package_tmp', 'package.json'))
expect(gfs.copyFile).toBeCalledWith(path.join('hash2'), path.join('project', 'package_tmp', 'index.js'))
})
test('packageImportMethod=hardlink does not relink package from store if package.json is linked from the store', async () => {

View File

@@ -52,7 +52,7 @@
"p-limit": "^3.1.0",
"p-map-values": "^1.0.0",
"p-queue": "^6.6.2",
"path-temp": "^2.0.0",
"path-temp": "^2.1.0",
"promise-share": "^1.0.0",
"ramda": "npm:@pnpm/ramda@0.28.1",
"rename-overwrite": "^4.0.3",

View File

@@ -48,7 +48,7 @@ import pMapValues from 'p-map-values'
import PQueue from 'p-queue'
import loadJsonFile from 'load-json-file'
import pDefer from 'p-defer'
import pathTemp from 'path-temp'
import { fastPathTemp as pathTemp } from 'path-temp'
import pShare from 'promise-share'
import pick from 'ramda/src/pick'
import renameOverwrite from 'rename-overwrite'
@@ -656,7 +656,7 @@ async function writeJsonFile (filePath: string, data: unknown) {
// There is actually no need to create the directory in 99% of cases.
// So by using cafs API, we'll improve performance.
await fs.mkdir(targetDir, { recursive: true })
const temp = pathTemp(targetDir)
const temp = pathTemp(filePath)
await gfs.writeFile(temp, JSON.stringify(data))
await renameOverwrite(temp, filePath)
}

32
pnpm-lock.yaml generated
View File

@@ -1704,8 +1704,8 @@ importers:
specifier: ^4.0.0
version: 4.0.0
path-temp:
specifier: ^2.0.0
version: 2.0.0
specifier: ^2.1.0
version: 2.1.0
rename-overwrite:
specifier: ^4.0.3
version: 4.0.3
@@ -3631,8 +3631,8 @@ importers:
specifier: ^6.6.2
version: 6.6.2
path-temp:
specifier: ^2.0.0
version: 2.0.0
specifier: ^2.1.0
version: 2.1.0
promise-share:
specifier: ^1.0.0
version: 1.0.0
@@ -4945,8 +4945,8 @@ importers:
specifier: ^3.0.0
version: 3.0.0
path-temp:
specifier: ^2.0.0
version: 2.0.0
specifier: ^2.1.0
version: 2.1.0
ramda:
specifier: npm:@pnpm/ramda@0.28.1
version: /@pnpm/ramda@0.28.1
@@ -5495,8 +5495,8 @@ importers:
specifier: ^3.1.0
version: 3.1.0
path-temp:
specifier: ^2.0.0
version: 2.0.0
specifier: ^2.1.0
version: 2.1.0
rename-overwrite:
specifier: ^4.0.3
version: 4.0.3
@@ -5577,8 +5577,8 @@ importers:
specifier: ^8.1.1
version: 8.1.1
path-temp:
specifier: ^2.0.0
version: 2.0.0
specifier: ^2.1.0
version: 2.1.0
ramda:
specifier: npm:@pnpm/ramda@0.28.1
version: /@pnpm/ramda@0.28.1
@@ -5965,8 +5965,8 @@ importers:
specifier: ^1.0.1
version: 1.0.1
path-temp:
specifier: ^2.0.0
version: 2.0.0
specifier: ^2.1.0
version: 2.1.0
root-link-target:
specifier: ^3.1.0
version: 3.1.0
@@ -15167,6 +15167,13 @@ packages:
dependencies:
unique-string: 2.0.0
/path-temp@2.1.0:
resolution: {integrity: sha512-cMMJTAZlion/RWRRC48UbrDymEIt+/YSD/l8NqjneyDw2rDOBQcP5yRkMB4CYGn47KMhZvbblBP7Z79OsMw72w==}
engines: {node: '>=8.15'}
dependencies:
unique-string: 2.0.0
dev: false
/path-to-regexp@0.1.7:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
@@ -17979,7 +17986,6 @@ time:
/path-absolute@1.0.1: '2018-11-28T20:25:53.253Z'
/path-exists@4.0.0: '2019-04-04T03:29:16.887Z'
/path-name@1.0.0: '2016-10-20T18:43:50.780Z'
/path-temp@2.0.0: '2019-05-04T14:35:52.401Z'
/pidtree@0.6.0: '2022-06-05T18:35:44.206Z'
/preferred-pm@3.0.3: '2021-02-09T01:16:52.150Z'
/pretty-bytes@5.6.0: '2021-02-21T14:04:35.036Z'

View File

@@ -49,7 +49,7 @@
"p-limit": "^3.1.0",
"p-memoize": "4.0.1",
"parse-npm-tarball-url": "^3.0.0",
"path-temp": "^2.0.0",
"path-temp": "^2.1.0",
"ramda": "npm:@pnpm/ramda@0.28.1",
"rename-overwrite": "^4.0.3",
"semver": "^7.5.4",

View File

@@ -9,7 +9,7 @@ import { type PackageManifest } from '@pnpm/types'
import getRegistryName from 'encode-registry'
import loadJsonFile from 'load-json-file'
import pLimit from 'p-limit'
import pathTemp from 'path-temp'
import { fastPathTemp as pathTemp } from 'path-temp'
import pick from 'ramda/src/pick'
import renameOverwrite from 'rename-overwrite'
import { toRaw } from './toRaw'
@@ -272,7 +272,7 @@ async function saveMeta (pkgMirror: string, meta: PackageMeta): Promise<void> {
await fs.mkdir(dir, { recursive: true })
createdDirs.add(dir)
}
const temp = pathTemp(dir)
const temp = pathTemp(pkgMirror)
await gfs.writeFile(temp, JSON.stringify(meta))
await renameOverwrite(temp, pkgMirror)
}

View File

@@ -24,7 +24,7 @@
"get-stream": "^6.0.1",
"gunzip-maybe": "1.4.2",
"p-limit": "^3.1.0",
"path-temp": "^2.0.0",
"path-temp": "^2.1.0",
"rename-overwrite": "^4.0.3",
"safe-promise-defer": "^1.0.1",
"ssri": "10.0.4",

View File

@@ -2,7 +2,7 @@ import { promises as fs, type Stats } from 'fs'
import path from 'path'
import type { FileWriteResult, PackageFileInfo } from '@pnpm/cafs-types'
import getStream from 'get-stream'
import pathTemp from 'path-temp'
import { fastPathTemp as pathTemp } from 'path-temp'
import renameOverwrite from 'rename-overwrite'
import ssri from 'ssri'
import { addFilesFromDir } from './addFilesFromDir'
@@ -108,7 +108,7 @@ async function writeBufferToCafs (
//
// If we don't allow --no-verify-store-integrity then we probably can write
// to the final file directly.
const temp = pathTemp(path.dirname(fileDest))
const temp = pathTemp(fileDest)
await writeFile(temp, buffer, mode)
// Unfortunately, "birth time" (time of file creation) is available not on all filesystems.
// We log the creation time ourselves and save it in the package index file.

View File

@@ -20,7 +20,7 @@
"@pnpm/fs.indexed-pkg-importer": "workspace:*",
"@pnpm/store-controller-types": "workspace:*",
"mem": "^8.1.1",
"path-temp": "^2.0.0",
"path-temp": "^2.1.0",
"ramda": "npm:@pnpm/ramda@0.28.1"
},
"devDependencies": {

View File

@@ -33,7 +33,7 @@
"@zkochan/rimraf": "^2.1.2",
"can-link": "^2.0.0",
"path-absolute": "^1.0.1",
"path-temp": "^2.0.0",
"path-temp": "^2.1.0",
"root-link-target": "^3.1.0",
"touch": "3.1.0"
},