@atlaspack/cache 3.1.1-canary.41 → 3.1.1-canary.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/FSCache.js CHANGED
@@ -25,6 +25,20 @@ function _util() {
25
25
  };
26
26
  return data;
27
27
  }
28
+ function _rust() {
29
+ const data = require("@atlaspack/rust");
30
+ _rust = function () {
31
+ return data;
32
+ };
33
+ return data;
34
+ }
35
+ function _featureFlags() {
36
+ const data = require("@atlaspack/feature-flags");
37
+ _featureFlags = function () {
38
+ return data;
39
+ };
40
+ return data;
41
+ }
28
42
  function _logger() {
29
43
  const data = _interopRequireDefault(require("@atlaspack/logger"));
30
44
  _logger = function () {
@@ -62,6 +76,10 @@ class FSCache {
62
76
  await Promise.all(dirPromises);
63
77
  }
64
78
  _getCachePath(cacheId) {
79
+ if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
80
+ const cleanId = (0, _rust().hashString)(cacheId);
81
+ return _path().default.join(this.dir, cleanId.slice(0, 2), cleanId.slice(2));
82
+ }
65
83
  return _path().default.join(this.dir, cacheId.slice(0, 2), cacheId.slice(2));
66
84
  }
67
85
  getStream(key) {
@@ -91,6 +109,9 @@ class FSCache {
91
109
  }
92
110
  }
93
111
  #getFilePath(key, index) {
112
+ if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
113
+ return _path().default.join(this.dir, `${(0, _rust().hashString)(key)}-${index}`);
114
+ }
94
115
  return _path().default.join(this.dir, `${key}-${index}`);
95
116
  }
96
117
  async #unlinkChunks(key, index) {
@@ -70,6 +70,13 @@ function _fs2() {
70
70
  }
71
71
  var _package = _interopRequireDefault(require("../package.json"));
72
72
  var _FSCache = require("./FSCache");
73
+ function _logger() {
74
+ const data = require("@atlaspack/logger");
75
+ _logger = function () {
76
+ return data;
77
+ };
78
+ return data;
79
+ }
73
80
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
74
81
  // $FlowFixMe
75
82
  const ncpAsync = (0, _util().promisify)(_ncp().default);
@@ -121,9 +128,14 @@ function open(directory
121
128
  }
122
129
  const pipeline = (0, _util().promisify)(_stream().default.pipeline);
123
130
  class LMDBLiteCache {
131
+ /**
132
+ * Directory where we store raw files.
133
+ */
134
+
124
135
  constructor(cacheDir) {
125
136
  this.fs = new (_fs2().NodeFS)();
126
137
  this.dir = cacheDir;
138
+ this.cacheFilesDirectory = _path().default.join(cacheDir, 'files');
127
139
  this.fsCache = new _FSCache.FSCache(this.fs, cacheDir);
128
140
  this.store = open(cacheDir, {
129
141
  name: 'parcel-cache',
@@ -142,6 +154,7 @@ class LMDBLiteCache {
142
154
  if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
143
155
  await this.fsCache.ensure();
144
156
  }
157
+ await this.fs.mkdirp(this.cacheFilesDirectory);
145
158
  return Promise.resolve();
146
159
  }
147
160
  serialize() {
@@ -166,10 +179,20 @@ class LMDBLiteCache {
166
179
  await this.setBlob(key, (0, _buildCache().serialize)(value));
167
180
  }
168
181
  getStream(key) {
169
- return this.fs.createReadStream(_path().default.join(this.dir, key));
182
+ if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
183
+ return this.fs.createReadStream(_path().default.join(this.dir, key));
184
+ }
185
+ return _fs().default.createReadStream(this.getFileKey(key));
170
186
  }
171
- setStream(key, stream) {
172
- return pipeline(stream, this.fs.createWriteStream(_path().default.join(this.dir, key)));
187
+ async setStream(key, stream) {
188
+ if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
189
+ return pipeline(stream, this.fs.createWriteStream(_path().default.join(this.dir, key)));
190
+ }
191
+ const filePath = this.getFileKey(key);
192
+ await _fs().default.promises.mkdir(_path().default.dirname(filePath), {
193
+ recursive: true
194
+ });
195
+ return pipeline(stream, _fs().default.createWriteStream(filePath));
173
196
  }
174
197
 
175
198
  // eslint-disable-next-line require-await
@@ -189,34 +212,27 @@ class LMDBLiteCache {
189
212
  getBuffer(key) {
190
213
  return Promise.resolve(this.store.get(key));
191
214
  }
192
- #getFilePath(key, index) {
193
- return _path().default.join(this.dir, `${key}-${index}`);
194
- }
195
215
  hasLargeBlob(key) {
196
216
  if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
197
217
  return this.fsCache.hasLargeBlob(key);
198
218
  }
199
- return this.has(key);
219
+ return _fs().default.promises.access(this.getFileKey(key), _fs().default.constants.F_OK).then(() => true).catch(() => false);
200
220
  }
201
-
202
- /**
203
- * @deprecated Use getBlob instead.
204
- */
205
221
  getLargeBlob(key) {
206
222
  if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
207
223
  return this.fsCache.getLargeBlob(key);
208
224
  }
209
- return Promise.resolve(this.getBlobSync(key));
225
+ return _fs().default.promises.readFile(this.getFileKey(key));
210
226
  }
211
-
212
- /**
213
- * @deprecated Use setBlob instead.
214
- */
215
- setLargeBlob(key, contents, options) {
227
+ async setLargeBlob(key, contents, options) {
216
228
  if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
217
229
  return this.fsCache.setLargeBlob(key, contents, options);
218
230
  }
219
- return this.setBlob(key, contents);
231
+ const targetPath = this.getFileKey(key);
232
+ await _fs().default.promises.mkdir(_path().default.dirname(targetPath), {
233
+ recursive: true
234
+ });
235
+ return _fs().default.promises.writeFile(targetPath, contents);
220
236
  }
221
237
 
222
238
  /**
@@ -247,6 +263,37 @@ class LMDBLiteCache {
247
263
  this.store.compact(_path().default.join(targetPath, 'data.mdb'));
248
264
  }
249
265
  refresh() {}
266
+
267
+ /**
268
+ * Streams, packages are stored in files instead of LMDB.
269
+ *
270
+ * On this case, if a cache key happens to have a parent traversal, ../..
271
+ * it is treated specially
272
+ *
273
+ * That is, something/../something and something are meant to be different
274
+ * keys.
275
+ *
276
+ * Plus we do not want to store values outside of the cache directory.
277
+ */
278
+ getFileKey(key) {
279
+ const cleanKey = key.split('/').map(part => {
280
+ if (part === '..') {
281
+ return '$$__parent_dir$$';
282
+ }
283
+ return part;
284
+ }).join('/');
285
+ return _path().default.join(this.cacheFilesDirectory, cleanKey);
286
+ }
287
+ async clear() {
288
+ await (0, _logger().instrumentAsync)('LMDBLiteCache::clear', async () => {
289
+ const keys = await this.keys();
290
+ for (const key of keys) {
291
+ await this.store.delete(key);
292
+ }
293
+ await this.fs.rimraf(this.cacheFilesDirectory);
294
+ await this.fs.mkdirp(this.cacheFilesDirectory);
295
+ });
296
+ }
250
297
  }
251
298
  exports.LMDBLiteCache = LMDBLiteCache;
252
299
  (0, _buildCache().registerSerializableClass)(`${_package.default.version}:LMDBLiteCache`, LMDBLiteCache);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atlaspack/cache",
3
3
  "description": "Interface for defining caches and file-system, IDB and LMDB implementations.",
4
- "version": "3.1.1-canary.41+212de35c7",
4
+ "version": "3.1.1-canary.43+0e0458eed",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "type": "commonjs",
7
7
  "publishConfig": {
@@ -23,12 +23,12 @@
23
23
  "check-ts": "tsc --noEmit index.d.ts"
24
24
  },
25
25
  "dependencies": {
26
- "@atlaspack/build-cache": "2.13.3-canary.109+212de35c7",
27
- "@atlaspack/feature-flags": "2.14.1-canary.109+212de35c7",
28
- "@atlaspack/fs": "2.14.5-canary.41+212de35c7",
29
- "@atlaspack/logger": "2.14.5-canary.41+212de35c7",
30
- "@atlaspack/rust": "3.2.1-canary.41+212de35c7",
31
- "@atlaspack/utils": "2.14.5-canary.41+212de35c7",
26
+ "@atlaspack/build-cache": "2.13.3-canary.111+0e0458eed",
27
+ "@atlaspack/feature-flags": "2.14.1-canary.111+0e0458eed",
28
+ "@atlaspack/fs": "2.14.5-canary.43+0e0458eed",
29
+ "@atlaspack/logger": "2.14.5-canary.43+0e0458eed",
30
+ "@atlaspack/rust": "3.2.1-canary.43+0e0458eed",
31
+ "@atlaspack/utils": "2.14.5-canary.43+0e0458eed",
32
32
  "ncp": "^2.0.0"
33
33
  },
34
34
  "devDependencies": {
@@ -37,5 +37,5 @@
37
37
  "browser": {
38
38
  "./src/IDBCache.js": "./src/IDBCache.browser.js"
39
39
  },
40
- "gitHead": "212de35c70ca46b0510c94fbda916892b667692c"
40
+ "gitHead": "0e0458eedab6e398b375b073439f27f8bcd0b490"
41
41
  }
package/src/FSCache.js CHANGED
@@ -9,6 +9,8 @@ import stream from 'stream';
9
9
  import path from 'path';
10
10
  import {promisify} from 'util';
11
11
 
12
+ import {hashString} from '@atlaspack/rust';
13
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
12
14
  import logger from '@atlaspack/logger';
13
15
  import {
14
16
  deserialize,
@@ -51,6 +53,10 @@ export class FSCache implements Cache {
51
53
  }
52
54
 
53
55
  _getCachePath(cacheId: string): FilePath {
56
+ if (getFeatureFlag('cachePerformanceImprovements')) {
57
+ const cleanId = hashString(cacheId);
58
+ return path.join(this.dir, cleanId.slice(0, 2), cleanId.slice(2));
59
+ }
54
60
  return path.join(this.dir, cacheId.slice(0, 2), cacheId.slice(2));
55
61
  }
56
62
 
@@ -90,6 +96,9 @@ export class FSCache implements Cache {
90
96
  }
91
97
 
92
98
  #getFilePath(key: string, index: number): string {
99
+ if (getFeatureFlag('cachePerformanceImprovements')) {
100
+ return path.join(this.dir, `${hashString(key)}-${index}`);
101
+ }
93
102
  return path.join(this.dir, `${key}-${index}`);
94
103
  }
95
104
 
@@ -19,6 +19,7 @@ import {NodeFS} from '@atlaspack/fs';
19
19
  // $FlowFixMe
20
20
  import packageJson from '../package.json';
21
21
  import {FSCache} from './FSCache';
22
+ import {instrumentAsync} from '@atlaspack/logger';
22
23
 
23
24
  const ncpAsync = promisify(ncp);
24
25
 
@@ -107,10 +108,15 @@ export class LMDBLiteCache implements Cache {
107
108
  dir: FilePath;
108
109
  store: LmdbWrapper;
109
110
  fsCache: FSCache;
111
+ /**
112
+ * Directory where we store raw files.
113
+ */
114
+ cacheFilesDirectory: FilePath;
110
115
 
111
116
  constructor(cacheDir: FilePath) {
112
117
  this.fs = new NodeFS();
113
118
  this.dir = cacheDir;
119
+ this.cacheFilesDirectory = path.join(cacheDir, 'files');
114
120
  this.fsCache = new FSCache(this.fs, cacheDir);
115
121
 
116
122
  this.store = open(cacheDir, {
@@ -131,6 +137,7 @@ export class LMDBLiteCache implements Cache {
131
137
  if (!getFeatureFlag('cachePerformanceImprovements')) {
132
138
  await this.fsCache.ensure();
133
139
  }
140
+ await this.fs.mkdirp(this.cacheFilesDirectory);
134
141
  return Promise.resolve();
135
142
  }
136
143
 
@@ -162,14 +169,24 @@ export class LMDBLiteCache implements Cache {
162
169
  }
163
170
 
164
171
  getStream(key: string): Readable {
165
- return this.fs.createReadStream(path.join(this.dir, key));
172
+ if (!getFeatureFlag('cachePerformanceImprovements')) {
173
+ return this.fs.createReadStream(path.join(this.dir, key));
174
+ }
175
+
176
+ return fs.createReadStream(this.getFileKey(key));
166
177
  }
167
178
 
168
- setStream(key: string, stream: Readable): Promise<void> {
169
- return pipeline(
170
- stream,
171
- this.fs.createWriteStream(path.join(this.dir, key)),
172
- );
179
+ async setStream(key: string, stream: Readable): Promise<void> {
180
+ if (!getFeatureFlag('cachePerformanceImprovements')) {
181
+ return pipeline(
182
+ stream,
183
+ this.fs.createWriteStream(path.join(this.dir, key)),
184
+ );
185
+ }
186
+
187
+ const filePath = this.getFileKey(key);
188
+ await fs.promises.mkdir(path.dirname(filePath), {recursive: true});
189
+ return pipeline(stream, fs.createWriteStream(filePath));
173
190
  }
174
191
 
175
192
  // eslint-disable-next-line require-await
@@ -193,31 +210,25 @@ export class LMDBLiteCache implements Cache {
193
210
  return Promise.resolve(this.store.get(key));
194
211
  }
195
212
 
196
- #getFilePath(key: string, index: number): string {
197
- return path.join(this.dir, `${key}-${index}`);
198
- }
199
-
200
213
  hasLargeBlob(key: string): Promise<boolean> {
201
214
  if (!getFeatureFlag('cachePerformanceImprovements')) {
202
215
  return this.fsCache.hasLargeBlob(key);
203
216
  }
204
- return this.has(key);
217
+
218
+ return fs.promises
219
+ .access(this.getFileKey(key), fs.constants.F_OK)
220
+ .then(() => true)
221
+ .catch(() => false);
205
222
  }
206
223
 
207
- /**
208
- * @deprecated Use getBlob instead.
209
- */
210
224
  getLargeBlob(key: string): Promise<Buffer> {
211
225
  if (!getFeatureFlag('cachePerformanceImprovements')) {
212
226
  return this.fsCache.getLargeBlob(key);
213
227
  }
214
- return Promise.resolve(this.getBlobSync(key));
228
+ return fs.promises.readFile(this.getFileKey(key));
215
229
  }
216
230
 
217
- /**
218
- * @deprecated Use setBlob instead.
219
- */
220
- setLargeBlob(
231
+ async setLargeBlob(
221
232
  key: string,
222
233
  contents: Buffer | string,
223
234
  options?: {|signal?: AbortSignal|},
@@ -225,7 +236,10 @@ export class LMDBLiteCache implements Cache {
225
236
  if (!getFeatureFlag('cachePerformanceImprovements')) {
226
237
  return this.fsCache.setLargeBlob(key, contents, options);
227
238
  }
228
- return this.setBlob(key, contents);
239
+
240
+ const targetPath = this.getFileKey(key);
241
+ await fs.promises.mkdir(path.dirname(targetPath), {recursive: true});
242
+ return fs.promises.writeFile(targetPath, contents);
229
243
  }
230
244
 
231
245
  /**
@@ -262,6 +276,42 @@ export class LMDBLiteCache implements Cache {
262
276
  }
263
277
 
264
278
  refresh(): void {}
279
+
280
+ /**
281
+ * Streams, packages are stored in files instead of LMDB.
282
+ *
283
+ * On this case, if a cache key happens to have a parent traversal, ../..
284
+ * it is treated specially
285
+ *
286
+ * That is, something/../something and something are meant to be different
287
+ * keys.
288
+ *
289
+ * Plus we do not want to store values outside of the cache directory.
290
+ */
291
+ getFileKey(key: string): string {
292
+ const cleanKey = key
293
+ .split('/')
294
+ .map((part) => {
295
+ if (part === '..') {
296
+ return '$$__parent_dir$$';
297
+ }
298
+ return part;
299
+ })
300
+ .join('/');
301
+ return path.join(this.cacheFilesDirectory, cleanKey);
302
+ }
303
+
304
+ async clear(): Promise<void> {
305
+ await instrumentAsync('LMDBLiteCache::clear', async () => {
306
+ const keys = await this.keys();
307
+ for (const key of keys) {
308
+ await this.store.delete(key);
309
+ }
310
+
311
+ await this.fs.rimraf(this.cacheFilesDirectory);
312
+ await this.fs.mkdirp(this.cacheFilesDirectory);
313
+ });
314
+ }
265
315
  }
266
316
 
267
317
  registerSerializableClass(
@@ -16,10 +16,6 @@ describe('LMDBLiteCache', () => {
16
16
  await fs.promises.rm(cacheDir, {recursive: true, force: true});
17
17
  });
18
18
 
19
- afterEach(() => {
20
- cache.getNativeRef().close();
21
- });
22
-
23
19
  it('can be constructed', async () => {
24
20
  cache = new LMDBLiteCache(cacheDir);
25
21
  await cache.ensure();
@@ -59,11 +55,40 @@ describe('LMDBLiteCache', () => {
59
55
  await cache.setBlob('key2', Buffer.from(serialize({value: 43})));
60
56
  await cache.compact(path.join(cacheDir, 'compact_test_compacted'));
61
57
 
62
- cache.getNativeRef().close();
63
-
64
58
  cache = new LMDBLiteCache(path.join(cacheDir, 'compact_test_compacted'));
65
59
  await cache.ensure();
66
60
  const keys = cache.keys();
67
61
  assert.deepEqual(Array.from(keys), ['key1', 'key2']);
68
62
  });
63
+
64
+ describe('getFileKey', () => {
65
+ it('should return the correct key', () => {
66
+ const target = path.join(cacheDir, 'test-file-keys');
67
+ const cache = new LMDBLiteCache(target);
68
+ const key = cache.getFileKey('key');
69
+ assert.equal(key, path.join(target, 'files', 'key'));
70
+ });
71
+
72
+ it('should return the correct key for a key with a parent traversal', () => {
73
+ const target = path.join(cacheDir, 'test-parent-keys');
74
+ cache = new LMDBLiteCache(target);
75
+ const key = cache.getFileKey('../../key');
76
+ assert.equal(
77
+ key,
78
+ path.join(target, 'files', '$$__parent_dir$$/$$__parent_dir$$/key'),
79
+ );
80
+ });
81
+ });
82
+
83
+ it('can be closed and re-opened', async () => {
84
+ cache = new LMDBLiteCache(path.join(cacheDir, 'close_and_reopen_test'));
85
+ await cache.ensure();
86
+ await cache.setBlob('key', Buffer.from(serialize({value: 42})));
87
+ cache.getNativeRef().close();
88
+ cache = new LMDBLiteCache(path.join(cacheDir, 'close_and_reopen_test'));
89
+ await cache.ensure();
90
+ const buffer = await cache.getBlob('key');
91
+ const result = deserialize(buffer);
92
+ assert.equal(result.value, 42);
93
+ });
69
94
  });