@atlaspack/cache 3.1.1-canary.0 → 3.1.1-canary.100
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/CHANGELOG.md +117 -0
- package/lib/FSCache.js +21 -0
- package/lib/LMDBLiteCache.js +120 -39
- package/package.json +9 -8
- package/src/FSCache.js +9 -0
- package/src/LMDBLiteCache.js +112 -37
- package/test/LMDBLiteCache.test.js +214 -4
- package/test/workerThreadsTest.js +42 -0
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,122 @@
|
|
1
1
|
# @atlaspack/cache
|
2
2
|
|
3
|
+
## 3.2.10
|
4
|
+
|
5
|
+
### Patch Changes
|
6
|
+
|
7
|
+
- Updated dependencies [[`5ded263`](https://github.com/atlassian-labs/atlaspack/commit/5ded263c7f11b866e8885b81c73e20dd060b25be)]:
|
8
|
+
- @atlaspack/feature-flags@2.18.3
|
9
|
+
- @atlaspack/fs@2.15.10
|
10
|
+
- @atlaspack/utils@2.15.3
|
11
|
+
|
12
|
+
## 3.2.9
|
13
|
+
|
14
|
+
### Patch Changes
|
15
|
+
|
16
|
+
- Updated dependencies [[`644b157`](https://github.com/atlassian-labs/atlaspack/commit/644b157dee72a871acc2d0facf0b87b8eea51956)]:
|
17
|
+
- @atlaspack/feature-flags@2.18.2
|
18
|
+
- @atlaspack/fs@2.15.9
|
19
|
+
- @atlaspack/utils@2.15.2
|
20
|
+
|
21
|
+
## 3.2.8
|
22
|
+
|
23
|
+
### Patch Changes
|
24
|
+
|
25
|
+
- Updated dependencies [[`ef3d622`](https://github.com/atlassian-labs/atlaspack/commit/ef3d6228f4e006702198a19c61e051d194d325cb), [`26aa9c5`](https://github.com/atlassian-labs/atlaspack/commit/26aa9c599d2be45ce1438a74c5fa22f39b9b554b), [`0501255`](https://github.com/atlassian-labs/atlaspack/commit/05012550da35b05ce7d356a8cc29311e7f9afdca)]:
|
26
|
+
- @atlaspack/logger@2.14.11
|
27
|
+
- @atlaspack/feature-flags@2.18.1
|
28
|
+
- @atlaspack/fs@2.15.8
|
29
|
+
- @atlaspack/utils@2.15.1
|
30
|
+
|
31
|
+
## 3.2.7
|
32
|
+
|
33
|
+
### Patch Changes
|
34
|
+
|
35
|
+
- Updated dependencies [[`10fbcfb`](https://github.com/atlassian-labs/atlaspack/commit/10fbcfbfa49c7a83da5d7c40983e36e87f524a75), [`85c52d3`](https://github.com/atlassian-labs/atlaspack/commit/85c52d3f7717b3c84a118d18ab98cfbfd71dcbd2), [`e39c6cf`](https://github.com/atlassian-labs/atlaspack/commit/e39c6cf05f7e95ce5420dbcea66f401b1cbd397c)]:
|
36
|
+
- @atlaspack/feature-flags@2.18.0
|
37
|
+
- @atlaspack/utils@2.15.0
|
38
|
+
- @atlaspack/fs@2.15.7
|
39
|
+
|
40
|
+
## 3.2.6
|
41
|
+
|
42
|
+
### Patch Changes
|
43
|
+
|
44
|
+
- Updated dependencies [[`73ea3c4`](https://github.com/atlassian-labs/atlaspack/commit/73ea3c4d85d4401fdd15abcbf988237e890e7ad3), [`b1b3693`](https://github.com/atlassian-labs/atlaspack/commit/b1b369317c66f8a431c170df2ebba4fa5b2e38ef)]:
|
45
|
+
- @atlaspack/feature-flags@2.17.0
|
46
|
+
- @atlaspack/fs@2.15.6
|
47
|
+
- @atlaspack/utils@2.14.11
|
48
|
+
|
49
|
+
## 3.2.5
|
50
|
+
|
51
|
+
### Patch Changes
|
52
|
+
|
53
|
+
- Updated dependencies [[`0999fb7`](https://github.com/atlassian-labs/atlaspack/commit/0999fb78da519a6c7582d212883e515fcf6c1252), [`35fdd4b`](https://github.com/atlassian-labs/atlaspack/commit/35fdd4b52da0af20f74667f7b8adfb2f90279b7c), [`6dd4ccb`](https://github.com/atlassian-labs/atlaspack/commit/6dd4ccb753541de32322d881f973d571dd57e4ca)]:
|
54
|
+
- @atlaspack/fs@2.15.5
|
55
|
+
- @atlaspack/rust@3.3.5
|
56
|
+
- @atlaspack/logger@2.14.10
|
57
|
+
- @atlaspack/utils@2.14.10
|
58
|
+
|
59
|
+
## 3.2.4
|
60
|
+
|
61
|
+
### Patch Changes
|
62
|
+
|
63
|
+
- [#583](https://github.com/atlassian-labs/atlaspack/pull/583) [`124b7ff`](https://github.com/atlassian-labs/atlaspack/commit/124b7fff44f71aac9fbad289a9a9509b3dfc9aaa) Thanks [@yamadapc](https://github.com/yamadapc)! - Fix problem where cache writes could start to fail during a V3 build
|
64
|
+
|
65
|
+
- Updated dependencies [[`124b7ff`](https://github.com/atlassian-labs/atlaspack/commit/124b7fff44f71aac9fbad289a9a9509b3dfc9aaa), [`e052521`](https://github.com/atlassian-labs/atlaspack/commit/e0525210850ed1606146eb86991049cf567c5dec), [`15c6d70`](https://github.com/atlassian-labs/atlaspack/commit/15c6d7000bd89da876bc590aa75b17a619a41896), [`e4d966c`](https://github.com/atlassian-labs/atlaspack/commit/e4d966c3c9c4292c5013372ae65b10d19d4bacc6), [`209692f`](https://github.com/atlassian-labs/atlaspack/commit/209692ffb11eae103a0d65c5e1118a5aa1625818), [`42a775d`](https://github.com/atlassian-labs/atlaspack/commit/42a775de8eec638ad188f3271964170d8c04d84b), [`29c2f10`](https://github.com/atlassian-labs/atlaspack/commit/29c2f106de9679adfb5afa04e1910471dc65a427), [`f4da1e1`](https://github.com/atlassian-labs/atlaspack/commit/f4da1e120e73eeb5e8b8927f05e88f04d6148c7b), [`1ef91fc`](https://github.com/atlassian-labs/atlaspack/commit/1ef91fcc863fdd2831511937083dbbc1263b3d9d)]:
|
66
|
+
- @atlaspack/rust@3.3.4
|
67
|
+
- @atlaspack/fs@2.15.4
|
68
|
+
- @atlaspack/feature-flags@2.16.0
|
69
|
+
- @atlaspack/logger@2.14.9
|
70
|
+
- @atlaspack/utils@2.14.9
|
71
|
+
|
72
|
+
## 3.2.3
|
73
|
+
|
74
|
+
### Patch Changes
|
75
|
+
|
76
|
+
- Updated dependencies [[`30f6017`](https://github.com/atlassian-labs/atlaspack/commit/30f60175ba4d272c5fc193973c63bc298584775b), [`3a3e8e7`](https://github.com/atlassian-labs/atlaspack/commit/3a3e8e7be9e2dffd7304436d792f0f595d59665a), [`1ab0a27`](https://github.com/atlassian-labs/atlaspack/commit/1ab0a275aeca40350415e2b03e7440d1dddc6228), [`b8a4ae8`](https://github.com/atlassian-labs/atlaspack/commit/b8a4ae8f83dc0a83d8b145c5f729936ce52080a3)]:
|
77
|
+
- @atlaspack/feature-flags@2.15.1
|
78
|
+
- @atlaspack/fs@2.15.3
|
79
|
+
- @atlaspack/rust@3.3.3
|
80
|
+
- @atlaspack/utils@2.14.8
|
81
|
+
- @atlaspack/logger@2.14.8
|
82
|
+
|
83
|
+
## 3.2.2
|
84
|
+
|
85
|
+
### Patch Changes
|
86
|
+
|
87
|
+
- Updated dependencies [[`a1773d2`](https://github.com/atlassian-labs/atlaspack/commit/a1773d2a62d0ef7805ac7524621dcabcc1afe929), [`556d6ab`](https://github.com/atlassian-labs/atlaspack/commit/556d6ab8ede759fa7f37fcd3f4da336ef1c55e8f)]:
|
88
|
+
- @atlaspack/feature-flags@2.15.0
|
89
|
+
- @atlaspack/logger@2.14.7
|
90
|
+
- @atlaspack/rust@3.3.2
|
91
|
+
- @atlaspack/fs@2.15.2
|
92
|
+
- @atlaspack/utils@2.14.7
|
93
|
+
|
94
|
+
## 3.2.1
|
95
|
+
|
96
|
+
### Patch Changes
|
97
|
+
|
98
|
+
- Updated dependencies [[`e0f5337`](https://github.com/atlassian-labs/atlaspack/commit/e0f533757bd1019dbd108a04952c87da15286e09)]:
|
99
|
+
- @atlaspack/feature-flags@2.14.4
|
100
|
+
- @atlaspack/rust@3.3.1
|
101
|
+
- @atlaspack/fs@2.15.1
|
102
|
+
- @atlaspack/utils@2.14.6
|
103
|
+
- @atlaspack/logger@2.14.6
|
104
|
+
|
105
|
+
## 3.2.0
|
106
|
+
|
107
|
+
### Minor Changes
|
108
|
+
|
109
|
+
- [#531](https://github.com/atlassian-labs/atlaspack/pull/531) [`d2c50c2`](https://github.com/atlassian-labs/atlaspack/commit/d2c50c2c020888b33bb25b8690d9320c2b69e2a6) Thanks [@yamadapc](https://github.com/yamadapc)! - Add way to iterate LMDB cache keys
|
110
|
+
|
111
|
+
### Patch Changes
|
112
|
+
|
113
|
+
- Updated dependencies [[`11d6f16`](https://github.com/atlassian-labs/atlaspack/commit/11d6f16b6397dee2f217167e5c98b39edb63f7a7), [`e2ba0f6`](https://github.com/atlassian-labs/atlaspack/commit/e2ba0f69702656f3d1ce95ab1454e35062b13b39), [`d2c50c2`](https://github.com/atlassian-labs/atlaspack/commit/d2c50c2c020888b33bb25b8690d9320c2b69e2a6), [`46a90dc`](https://github.com/atlassian-labs/atlaspack/commit/46a90dccd019a26b222c878a92d23acc75dc67c5), [`4c17141`](https://github.com/atlassian-labs/atlaspack/commit/4c1714103dab2aa9039c488f381551d2b65d1d01)]:
|
114
|
+
- @atlaspack/feature-flags@2.14.3
|
115
|
+
- @atlaspack/rust@3.3.0
|
116
|
+
- @atlaspack/fs@2.15.0
|
117
|
+
- @atlaspack/utils@2.14.5
|
118
|
+
- @atlaspack/logger@2.14.5
|
119
|
+
|
3
120
|
## 3.1.0
|
4
121
|
|
5
122
|
### Minor Changes
|
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) {
|
package/lib/LMDBLiteCache.js
CHANGED
@@ -26,16 +26,16 @@ function _rust() {
|
|
26
26
|
};
|
27
27
|
return data;
|
28
28
|
}
|
29
|
-
function
|
30
|
-
const data = _interopRequireDefault(require("
|
31
|
-
|
29
|
+
function _fs() {
|
30
|
+
const data = _interopRequireDefault(require("fs"));
|
31
|
+
_fs = function () {
|
32
32
|
return data;
|
33
33
|
};
|
34
34
|
return data;
|
35
35
|
}
|
36
|
-
function
|
37
|
-
const data = _interopRequireDefault(require("
|
38
|
-
|
36
|
+
function _ncp() {
|
37
|
+
const data = _interopRequireDefault(require("ncp"));
|
38
|
+
_ncp = function () {
|
39
39
|
return data;
|
40
40
|
};
|
41
41
|
return data;
|
@@ -47,25 +47,42 @@ function _util() {
|
|
47
47
|
};
|
48
48
|
return data;
|
49
49
|
}
|
50
|
-
function
|
50
|
+
function _stream() {
|
51
|
+
const data = _interopRequireDefault(require("stream"));
|
52
|
+
_stream = function () {
|
53
|
+
return data;
|
54
|
+
};
|
55
|
+
return data;
|
56
|
+
}
|
57
|
+
function _path() {
|
58
|
+
const data = _interopRequireDefault(require("path"));
|
59
|
+
_path = function () {
|
60
|
+
return data;
|
61
|
+
};
|
62
|
+
return data;
|
63
|
+
}
|
64
|
+
function _fs2() {
|
51
65
|
const data = require("@atlaspack/fs");
|
52
|
-
|
66
|
+
_fs2 = function () {
|
53
67
|
return data;
|
54
68
|
};
|
55
69
|
return data;
|
56
70
|
}
|
57
71
|
var _package = _interopRequireDefault(require("../package.json"));
|
58
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
|
+
}
|
59
80
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
60
81
|
// $FlowFixMe
|
82
|
+
const ncpAsync = (0, _util().promisify)(_ncp().default);
|
61
83
|
class LmdbWrapper {
|
62
84
|
constructor(lmdb) {
|
63
85
|
this.lmdb = lmdb;
|
64
|
-
|
65
|
-
// $FlowFixMe
|
66
|
-
this[Symbol.dispose] = () => {
|
67
|
-
this.lmdb.close();
|
68
|
-
};
|
69
86
|
}
|
70
87
|
has(key) {
|
71
88
|
return this.lmdb.hasSync(key);
|
@@ -80,7 +97,19 @@ class LmdbWrapper {
|
|
80
97
|
const buffer = typeof value === 'string' ? Buffer.from(value) : value;
|
81
98
|
await this.lmdb.put(key, buffer);
|
82
99
|
}
|
83
|
-
|
100
|
+
*keys() {
|
101
|
+
const PAGE_SIZE = 10000000;
|
102
|
+
let currentKeys = this.lmdb.keysSync(0, PAGE_SIZE);
|
103
|
+
while (currentKeys.length > 0) {
|
104
|
+
for (const key of currentKeys) {
|
105
|
+
yield key;
|
106
|
+
}
|
107
|
+
currentKeys = this.lmdb.keysSync(currentKeys.length, PAGE_SIZE);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
compact(targetPath) {
|
111
|
+
this.lmdb.compact(targetPath);
|
112
|
+
}
|
84
113
|
}
|
85
114
|
exports.LmdbWrapper = LmdbWrapper;
|
86
115
|
function open(directory
|
@@ -94,9 +123,14 @@ function open(directory
|
|
94
123
|
}
|
95
124
|
const pipeline = (0, _util().promisify)(_stream().default.pipeline);
|
96
125
|
class LMDBLiteCache {
|
126
|
+
/**
|
127
|
+
* Directory where we store raw files.
|
128
|
+
*/
|
129
|
+
|
97
130
|
constructor(cacheDir) {
|
98
|
-
this.fs = new (
|
131
|
+
this.fs = new (_fs2().NodeFS)();
|
99
132
|
this.dir = cacheDir;
|
133
|
+
this.cacheFilesDirectory = _path().default.join(cacheDir, 'files');
|
100
134
|
this.fsCache = new _FSCache.FSCache(this.fs, cacheDir);
|
101
135
|
this.store = open(cacheDir, {
|
102
136
|
name: 'parcel-cache',
|
@@ -115,6 +149,7 @@ class LMDBLiteCache {
|
|
115
149
|
if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
116
150
|
await this.fsCache.ensure();
|
117
151
|
}
|
152
|
+
await this.fs.mkdirp(this.cacheFilesDirectory);
|
118
153
|
return Promise.resolve();
|
119
154
|
}
|
120
155
|
serialize() {
|
@@ -139,10 +174,20 @@ class LMDBLiteCache {
|
|
139
174
|
await this.setBlob(key, (0, _buildCache().serialize)(value));
|
140
175
|
}
|
141
176
|
getStream(key) {
|
142
|
-
|
177
|
+
if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
178
|
+
return this.fs.createReadStream(_path().default.join(this.dir, key));
|
179
|
+
}
|
180
|
+
return _fs().default.createReadStream(this.getFileKey(key));
|
143
181
|
}
|
144
|
-
setStream(key, stream) {
|
145
|
-
|
182
|
+
async setStream(key, stream) {
|
183
|
+
if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
184
|
+
return pipeline(stream, this.fs.createWriteStream(_path().default.join(this.dir, key)));
|
185
|
+
}
|
186
|
+
const filePath = this.getFileKey(key);
|
187
|
+
await _fs().default.promises.mkdir(_path().default.dirname(filePath), {
|
188
|
+
recursive: true
|
189
|
+
});
|
190
|
+
return pipeline(stream, _fs().default.createWriteStream(filePath));
|
146
191
|
}
|
147
192
|
|
148
193
|
// eslint-disable-next-line require-await
|
@@ -162,34 +207,27 @@ class LMDBLiteCache {
|
|
162
207
|
getBuffer(key) {
|
163
208
|
return Promise.resolve(this.store.get(key));
|
164
209
|
}
|
165
|
-
#getFilePath(key, index) {
|
166
|
-
return _path().default.join(this.dir, `${key}-${index}`);
|
167
|
-
}
|
168
210
|
hasLargeBlob(key) {
|
169
211
|
if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
170
212
|
return this.fsCache.hasLargeBlob(key);
|
171
213
|
}
|
172
|
-
return this.
|
214
|
+
return _fs().default.promises.access(this.getFileKey(key), _fs().default.constants.F_OK).then(() => true).catch(() => false);
|
173
215
|
}
|
174
|
-
|
175
|
-
/**
|
176
|
-
* @deprecated Use getBlob instead.
|
177
|
-
*/
|
178
216
|
getLargeBlob(key) {
|
179
217
|
if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
180
218
|
return this.fsCache.getLargeBlob(key);
|
181
219
|
}
|
182
|
-
return
|
220
|
+
return _fs().default.promises.readFile(this.getFileKey(key));
|
183
221
|
}
|
184
|
-
|
185
|
-
/**
|
186
|
-
* @deprecated Use setBlob instead.
|
187
|
-
*/
|
188
|
-
setLargeBlob(key, contents, options) {
|
222
|
+
async setLargeBlob(key, contents, options) {
|
189
223
|
if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
190
224
|
return this.fsCache.setLargeBlob(key, contents, options);
|
191
225
|
}
|
192
|
-
|
226
|
+
const targetPath = this.getFileKey(key);
|
227
|
+
await _fs().default.promises.mkdir(_path().default.dirname(targetPath), {
|
228
|
+
recursive: true
|
229
|
+
});
|
230
|
+
return _fs().default.promises.writeFile(targetPath, contents);
|
193
231
|
}
|
194
232
|
|
195
233
|
/**
|
@@ -201,12 +239,55 @@ class LMDBLiteCache {
|
|
201
239
|
}
|
202
240
|
return this.store.delete(key);
|
203
241
|
}
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
242
|
+
keys() {
|
243
|
+
return this.store.keys();
|
244
|
+
}
|
245
|
+
async compact(targetPath) {
|
246
|
+
await _fs().default.promises.mkdir(targetPath, {
|
247
|
+
recursive: true
|
248
|
+
});
|
249
|
+
const files = await _fs().default.promises.readdir(this.dir);
|
250
|
+
// copy all files except data.mdb and lock.mdb to the target path (recursive)
|
251
|
+
for (const file of files) {
|
252
|
+
const filePath = _path().default.join(this.dir, file);
|
253
|
+
if (file === 'data.mdb' || file === 'lock.mdb') {
|
254
|
+
continue;
|
255
|
+
}
|
256
|
+
await ncpAsync(filePath, _path().default.join(targetPath, file));
|
257
|
+
}
|
258
|
+
this.store.compact(_path().default.join(targetPath, 'data.mdb'));
|
259
|
+
}
|
260
|
+
refresh() {}
|
261
|
+
|
262
|
+
/**
|
263
|
+
* Streams, packages are stored in files instead of LMDB.
|
264
|
+
*
|
265
|
+
* On this case, if a cache key happens to have a parent traversal, ../..
|
266
|
+
* it is treated specially
|
267
|
+
*
|
268
|
+
* That is, something/../something and something are meant to be different
|
269
|
+
* keys.
|
270
|
+
*
|
271
|
+
* Plus we do not want to store values outside of the cache directory.
|
272
|
+
*/
|
273
|
+
getFileKey(key) {
|
274
|
+
const cleanKey = key.split('/').map(part => {
|
275
|
+
if (part === '..') {
|
276
|
+
return '$$__parent_dir$$';
|
277
|
+
}
|
278
|
+
return part;
|
279
|
+
}).join('/');
|
280
|
+
return _path().default.join(this.cacheFilesDirectory, cleanKey);
|
281
|
+
}
|
282
|
+
async clear() {
|
283
|
+
await (0, _logger().instrumentAsync)('LMDBLiteCache::clear', async () => {
|
284
|
+
const keys = await this.keys();
|
285
|
+
for (const key of keys) {
|
286
|
+
await this.store.delete(key);
|
287
|
+
}
|
288
|
+
await this.fs.rimraf(this.cacheFilesDirectory);
|
289
|
+
await this.fs.mkdirp(this.cacheFilesDirectory);
|
290
|
+
});
|
210
291
|
}
|
211
292
|
}
|
212
293
|
exports.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.
|
4
|
+
"version": "3.1.1-canary.100+f609bf49f",
|
5
5
|
"license": "(MIT OR Apache-2.0)",
|
6
6
|
"type": "commonjs",
|
7
7
|
"publishConfig": {
|
@@ -23,12 +23,13 @@
|
|
23
23
|
"check-ts": "tsc --noEmit index.d.ts"
|
24
24
|
},
|
25
25
|
"dependencies": {
|
26
|
-
"@atlaspack/build-cache": "2.13.3-canary.
|
27
|
-
"@atlaspack/feature-flags": "2.14.1-canary.
|
28
|
-
"@atlaspack/fs": "2.14.5-canary.
|
29
|
-
"@atlaspack/logger": "2.14.5-canary.
|
30
|
-
"@atlaspack/rust": "3.2.1-canary.
|
31
|
-
"@atlaspack/utils": "2.14.5-canary.
|
26
|
+
"@atlaspack/build-cache": "2.13.3-canary.168+f609bf49f",
|
27
|
+
"@atlaspack/feature-flags": "2.14.1-canary.168+f609bf49f",
|
28
|
+
"@atlaspack/fs": "2.14.5-canary.100+f609bf49f",
|
29
|
+
"@atlaspack/logger": "2.14.5-canary.100+f609bf49f",
|
30
|
+
"@atlaspack/rust": "3.2.1-canary.100+f609bf49f",
|
31
|
+
"@atlaspack/utils": "2.14.5-canary.100+f609bf49f",
|
32
|
+
"ncp": "^2.0.0"
|
32
33
|
},
|
33
34
|
"devDependencies": {
|
34
35
|
"idb": "^5.0.8"
|
@@ -36,5 +37,5 @@
|
|
36
37
|
"browser": {
|
37
38
|
"./src/IDBCache.js": "./src/IDBCache.browser.js"
|
38
39
|
},
|
39
|
-
"gitHead": "
|
40
|
+
"gitHead": "f609bf49ffa3984c0ff81d4853a5c850aaee5fce"
|
40
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
|
|
package/src/LMDBLiteCache.js
CHANGED
@@ -10,17 +10,18 @@ import {Lmdb} from '@atlaspack/rust';
|
|
10
10
|
import type {FilePath} from '@atlaspack/types';
|
11
11
|
import type {Cache} from './types';
|
12
12
|
import type {Readable, Writable} from 'stream';
|
13
|
-
|
13
|
+
import fs from 'fs';
|
14
|
+
import ncp from 'ncp';
|
15
|
+
import {promisify} from 'util';
|
14
16
|
import stream from 'stream';
|
15
17
|
import path from 'path';
|
16
|
-
import {promisify} from 'util';
|
17
|
-
|
18
18
|
import {NodeFS} from '@atlaspack/fs';
|
19
|
-
|
20
19
|
// $FlowFixMe
|
21
20
|
import packageJson from '../package.json';
|
22
|
-
|
23
21
|
import {FSCache} from './FSCache';
|
22
|
+
import {instrumentAsync} from '@atlaspack/logger';
|
23
|
+
|
24
|
+
const ncpAsync = promisify(ncp);
|
24
25
|
|
25
26
|
interface DBOpenOptions {
|
26
27
|
name: string;
|
@@ -35,11 +36,6 @@ export class LmdbWrapper {
|
|
35
36
|
|
36
37
|
constructor(lmdb: Lmdb) {
|
37
38
|
this.lmdb = lmdb;
|
38
|
-
|
39
|
-
// $FlowFixMe
|
40
|
-
this[Symbol.dispose] = () => {
|
41
|
-
this.lmdb.close();
|
42
|
-
};
|
43
39
|
}
|
44
40
|
|
45
41
|
has(key: string): boolean {
|
@@ -60,7 +56,21 @@ export class LmdbWrapper {
|
|
60
56
|
await this.lmdb.put(key, buffer);
|
61
57
|
}
|
62
58
|
|
63
|
-
|
59
|
+
*keys(): Iterable<string> {
|
60
|
+
const PAGE_SIZE = 10000000;
|
61
|
+
|
62
|
+
let currentKeys = this.lmdb.keysSync(0, PAGE_SIZE);
|
63
|
+
while (currentKeys.length > 0) {
|
64
|
+
for (const key of currentKeys) {
|
65
|
+
yield key;
|
66
|
+
}
|
67
|
+
currentKeys = this.lmdb.keysSync(currentKeys.length, PAGE_SIZE);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
compact(targetPath: string) {
|
72
|
+
this.lmdb.compact(targetPath);
|
73
|
+
}
|
64
74
|
}
|
65
75
|
|
66
76
|
export function open(
|
@@ -93,10 +103,15 @@ export class LMDBLiteCache implements Cache {
|
|
93
103
|
dir: FilePath;
|
94
104
|
store: LmdbWrapper;
|
95
105
|
fsCache: FSCache;
|
106
|
+
/**
|
107
|
+
* Directory where we store raw files.
|
108
|
+
*/
|
109
|
+
cacheFilesDirectory: FilePath;
|
96
110
|
|
97
111
|
constructor(cacheDir: FilePath) {
|
98
112
|
this.fs = new NodeFS();
|
99
113
|
this.dir = cacheDir;
|
114
|
+
this.cacheFilesDirectory = path.join(cacheDir, 'files');
|
100
115
|
this.fsCache = new FSCache(this.fs, cacheDir);
|
101
116
|
|
102
117
|
this.store = open(cacheDir, {
|
@@ -117,6 +132,7 @@ export class LMDBLiteCache implements Cache {
|
|
117
132
|
if (!getFeatureFlag('cachePerformanceImprovements')) {
|
118
133
|
await this.fsCache.ensure();
|
119
134
|
}
|
135
|
+
await this.fs.mkdirp(this.cacheFilesDirectory);
|
120
136
|
return Promise.resolve();
|
121
137
|
}
|
122
138
|
|
@@ -148,14 +164,24 @@ export class LMDBLiteCache implements Cache {
|
|
148
164
|
}
|
149
165
|
|
150
166
|
getStream(key: string): Readable {
|
151
|
-
|
167
|
+
if (!getFeatureFlag('cachePerformanceImprovements')) {
|
168
|
+
return this.fs.createReadStream(path.join(this.dir, key));
|
169
|
+
}
|
170
|
+
|
171
|
+
return fs.createReadStream(this.getFileKey(key));
|
152
172
|
}
|
153
173
|
|
154
|
-
setStream(key: string, stream: Readable): Promise<void> {
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
174
|
+
async setStream(key: string, stream: Readable): Promise<void> {
|
175
|
+
if (!getFeatureFlag('cachePerformanceImprovements')) {
|
176
|
+
return pipeline(
|
177
|
+
stream,
|
178
|
+
this.fs.createWriteStream(path.join(this.dir, key)),
|
179
|
+
);
|
180
|
+
}
|
181
|
+
|
182
|
+
const filePath = this.getFileKey(key);
|
183
|
+
await fs.promises.mkdir(path.dirname(filePath), {recursive: true});
|
184
|
+
return pipeline(stream, fs.createWriteStream(filePath));
|
159
185
|
}
|
160
186
|
|
161
187
|
// eslint-disable-next-line require-await
|
@@ -179,31 +205,25 @@ export class LMDBLiteCache implements Cache {
|
|
179
205
|
return Promise.resolve(this.store.get(key));
|
180
206
|
}
|
181
207
|
|
182
|
-
#getFilePath(key: string, index: number): string {
|
183
|
-
return path.join(this.dir, `${key}-${index}`);
|
184
|
-
}
|
185
|
-
|
186
208
|
hasLargeBlob(key: string): Promise<boolean> {
|
187
209
|
if (!getFeatureFlag('cachePerformanceImprovements')) {
|
188
210
|
return this.fsCache.hasLargeBlob(key);
|
189
211
|
}
|
190
|
-
|
212
|
+
|
213
|
+
return fs.promises
|
214
|
+
.access(this.getFileKey(key), fs.constants.F_OK)
|
215
|
+
.then(() => true)
|
216
|
+
.catch(() => false);
|
191
217
|
}
|
192
218
|
|
193
|
-
/**
|
194
|
-
* @deprecated Use getBlob instead.
|
195
|
-
*/
|
196
219
|
getLargeBlob(key: string): Promise<Buffer> {
|
197
220
|
if (!getFeatureFlag('cachePerformanceImprovements')) {
|
198
221
|
return this.fsCache.getLargeBlob(key);
|
199
222
|
}
|
200
|
-
return
|
223
|
+
return fs.promises.readFile(this.getFileKey(key));
|
201
224
|
}
|
202
225
|
|
203
|
-
|
204
|
-
* @deprecated Use setBlob instead.
|
205
|
-
*/
|
206
|
-
setLargeBlob(
|
226
|
+
async setLargeBlob(
|
207
227
|
key: string,
|
208
228
|
contents: Buffer | string,
|
209
229
|
options?: {|signal?: AbortSignal|},
|
@@ -211,7 +231,10 @@ export class LMDBLiteCache implements Cache {
|
|
211
231
|
if (!getFeatureFlag('cachePerformanceImprovements')) {
|
212
232
|
return this.fsCache.setLargeBlob(key, contents, options);
|
213
233
|
}
|
214
|
-
|
234
|
+
|
235
|
+
const targetPath = this.getFileKey(key);
|
236
|
+
await fs.promises.mkdir(path.dirname(targetPath), {recursive: true});
|
237
|
+
return fs.promises.writeFile(targetPath, contents);
|
215
238
|
}
|
216
239
|
|
217
240
|
/**
|
@@ -225,12 +248,64 @@ export class LMDBLiteCache implements Cache {
|
|
225
248
|
return this.store.delete(key);
|
226
249
|
}
|
227
250
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
251
|
+
keys(): Iterable<string> {
|
252
|
+
return this.store.keys();
|
253
|
+
}
|
254
|
+
|
255
|
+
async compact(targetPath: string): Promise<void> {
|
256
|
+
await fs.promises.mkdir(targetPath, {recursive: true});
|
257
|
+
|
258
|
+
const files = await fs.promises.readdir(this.dir);
|
259
|
+
// copy all files except data.mdb and lock.mdb to the target path (recursive)
|
260
|
+
for (const file of files) {
|
261
|
+
const filePath = path.join(this.dir, file);
|
262
|
+
|
263
|
+
if (file === 'data.mdb' || file === 'lock.mdb') {
|
264
|
+
continue;
|
265
|
+
}
|
266
|
+
|
267
|
+
await ncpAsync(filePath, path.join(targetPath, file));
|
268
|
+
}
|
269
|
+
|
270
|
+
this.store.compact(path.join(targetPath, 'data.mdb'));
|
271
|
+
}
|
272
|
+
|
273
|
+
refresh(): void {}
|
274
|
+
|
275
|
+
/**
|
276
|
+
* Streams, packages are stored in files instead of LMDB.
|
277
|
+
*
|
278
|
+
* On this case, if a cache key happens to have a parent traversal, ../..
|
279
|
+
* it is treated specially
|
280
|
+
*
|
281
|
+
* That is, something/../something and something are meant to be different
|
282
|
+
* keys.
|
283
|
+
*
|
284
|
+
* Plus we do not want to store values outside of the cache directory.
|
285
|
+
*/
|
286
|
+
getFileKey(key: string): string {
|
287
|
+
const cleanKey = key
|
288
|
+
.split('/')
|
289
|
+
.map((part) => {
|
290
|
+
if (part === '..') {
|
291
|
+
return '$$__parent_dir$$';
|
292
|
+
}
|
293
|
+
return part;
|
294
|
+
})
|
295
|
+
.join('/');
|
296
|
+
return path.join(this.cacheFilesDirectory, cleanKey);
|
297
|
+
}
|
298
|
+
|
299
|
+
async clear(): Promise<void> {
|
300
|
+
await instrumentAsync('LMDBLiteCache::clear', async () => {
|
301
|
+
const keys = await this.keys();
|
302
|
+
for (const key of keys) {
|
303
|
+
await this.store.delete(key);
|
304
|
+
}
|
305
|
+
|
306
|
+
await this.fs.rimraf(this.cacheFilesDirectory);
|
307
|
+
await this.fs.mkdirp(this.cacheFilesDirectory);
|
308
|
+
});
|
234
309
|
}
|
235
310
|
}
|
236
311
|
|
@@ -1,20 +1,30 @@
|
|
1
1
|
// @flow
|
2
|
+
|
3
|
+
import * as fs from 'fs';
|
2
4
|
import * as path from 'path';
|
3
5
|
import {tmpdir} from 'os';
|
4
6
|
import {LMDBLiteCache} from '../src/index';
|
5
7
|
import {deserialize, serialize} from 'v8';
|
6
8
|
import assert from 'assert';
|
9
|
+
import {Worker} from 'worker_threads';
|
10
|
+
import {initializeMonitoring} from '@atlaspack/rust';
|
7
11
|
|
8
12
|
const cacheDir = path.join(tmpdir(), 'lmdb-lite-cache-tests');
|
9
13
|
|
10
14
|
describe('LMDBLiteCache', () => {
|
15
|
+
let cache;
|
16
|
+
|
17
|
+
beforeEach(async () => {
|
18
|
+
await fs.promises.rm(cacheDir, {recursive: true, force: true});
|
19
|
+
});
|
20
|
+
|
11
21
|
it('can be constructed', async () => {
|
12
|
-
|
22
|
+
cache = new LMDBLiteCache(cacheDir);
|
13
23
|
await cache.ensure();
|
14
24
|
});
|
15
25
|
|
16
26
|
it('can retrieve keys', async () => {
|
17
|
-
|
27
|
+
cache = new LMDBLiteCache(cacheDir);
|
18
28
|
await cache.ensure();
|
19
29
|
await cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
20
30
|
const buffer = await cache.getBlob('key');
|
@@ -23,11 +33,211 @@ describe('LMDBLiteCache', () => {
|
|
23
33
|
});
|
24
34
|
|
25
35
|
it('can retrieve keys synchronously', async () => {
|
26
|
-
|
36
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'retrieve_keys_test'));
|
27
37
|
await cache.ensure();
|
28
|
-
cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
38
|
+
await cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
29
39
|
const buffer = cache.getBlobSync('key');
|
30
40
|
const result = deserialize(buffer);
|
31
41
|
assert.equal(result.value, 42);
|
32
42
|
});
|
43
|
+
|
44
|
+
it('can iterate over keys', async () => {
|
45
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'keys_test'));
|
46
|
+
await cache.ensure();
|
47
|
+
await cache.setBlob('key1', Buffer.from(serialize({value: 42})));
|
48
|
+
await cache.setBlob('key2', Buffer.from(serialize({value: 43})));
|
49
|
+
const keys = cache.keys();
|
50
|
+
assert.deepEqual(Array.from(keys), ['key1', 'key2']);
|
51
|
+
});
|
52
|
+
|
53
|
+
it('can compact databases', async () => {
|
54
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'compact_test'));
|
55
|
+
await cache.ensure();
|
56
|
+
await cache.setBlob('key1', Buffer.from(serialize({value: 42})));
|
57
|
+
await cache.setBlob('key2', Buffer.from(serialize({value: 43})));
|
58
|
+
await cache.compact(path.join(cacheDir, 'compact_test_compacted'));
|
59
|
+
|
60
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'compact_test_compacted'));
|
61
|
+
await cache.ensure();
|
62
|
+
const keys = cache.keys();
|
63
|
+
assert.deepEqual(Array.from(keys), ['key1', 'key2']);
|
64
|
+
});
|
65
|
+
|
66
|
+
describe('getFileKey', () => {
|
67
|
+
it('should return the correct key', () => {
|
68
|
+
const target = path.join(cacheDir, 'test-file-keys');
|
69
|
+
const cache = new LMDBLiteCache(target);
|
70
|
+
const key = cache.getFileKey('key');
|
71
|
+
assert.equal(key, path.join(target, 'files', 'key'));
|
72
|
+
});
|
73
|
+
|
74
|
+
it('should return the correct key for a key with a parent traversal', () => {
|
75
|
+
const target = path.join(cacheDir, 'test-parent-keys');
|
76
|
+
cache = new LMDBLiteCache(target);
|
77
|
+
const key = cache.getFileKey('../../key');
|
78
|
+
assert.equal(
|
79
|
+
key,
|
80
|
+
path.join(target, 'files', '$$__parent_dir$$/$$__parent_dir$$/key'),
|
81
|
+
);
|
82
|
+
});
|
83
|
+
});
|
84
|
+
|
85
|
+
it('can be closed and re-opened', async () => {
|
86
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'close_and_reopen_test'));
|
87
|
+
await cache.ensure();
|
88
|
+
await cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
89
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'close_and_reopen_test'));
|
90
|
+
await cache.ensure();
|
91
|
+
const buffer = await cache.getBlob('key');
|
92
|
+
const result = deserialize(buffer);
|
93
|
+
assert.equal(result.value, 42);
|
94
|
+
});
|
95
|
+
|
96
|
+
it('should NOT fail when trying to open the same database twice', async () => {
|
97
|
+
const testDir = path.join(cacheDir, 'double_open_test');
|
98
|
+
const cache1 = new LMDBLiteCache(testDir);
|
99
|
+
await cache1.ensure();
|
100
|
+
|
101
|
+
assert.doesNotThrow(() => {
|
102
|
+
new LMDBLiteCache(testDir);
|
103
|
+
});
|
104
|
+
});
|
105
|
+
|
106
|
+
it('should NOT fail when trying to open after GC', async () => {
|
107
|
+
const testDir = path.join(cacheDir, 'gc_test');
|
108
|
+
|
109
|
+
let cache1 = new LMDBLiteCache(testDir);
|
110
|
+
await cache1.ensure();
|
111
|
+
await cache1.setBlob('key', Buffer.from(serialize({value: 42})));
|
112
|
+
|
113
|
+
cache1 = null;
|
114
|
+
|
115
|
+
if (global.gc) {
|
116
|
+
global.gc();
|
117
|
+
}
|
118
|
+
|
119
|
+
assert.doesNotThrow(() => {
|
120
|
+
new LMDBLiteCache(testDir);
|
121
|
+
});
|
122
|
+
});
|
123
|
+
|
124
|
+
it('should handle rapid open/close cycles', async () => {
|
125
|
+
const testDir = path.join(cacheDir, 'rapid_cycles_test');
|
126
|
+
|
127
|
+
for (let i = 0; i < 10; i++) {
|
128
|
+
const cache = new LMDBLiteCache(testDir);
|
129
|
+
await cache.ensure();
|
130
|
+
await cache.setBlob(`key${i}`, Buffer.from(serialize({value: i})));
|
131
|
+
|
132
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
133
|
+
}
|
134
|
+
|
135
|
+
const finalCache = new LMDBLiteCache(testDir);
|
136
|
+
await finalCache.ensure();
|
137
|
+
const buffer = await finalCache.getBlob('key9');
|
138
|
+
const result = deserialize(buffer);
|
139
|
+
assert.equal(result.value, 9);
|
140
|
+
});
|
141
|
+
|
142
|
+
it('should work when there are multiple node.js worker threads accessing the same database', async function () {
|
143
|
+
this.timeout(40000);
|
144
|
+
|
145
|
+
try {
|
146
|
+
initializeMonitoring();
|
147
|
+
} catch (error) {
|
148
|
+
/* empty */
|
149
|
+
}
|
150
|
+
|
151
|
+
const testDir = path.join(cacheDir, 'worker_threads_test');
|
152
|
+
|
153
|
+
let cache = new LMDBLiteCache(testDir);
|
154
|
+
await cache.set('main_thread_key', {
|
155
|
+
mainThreadId: 0,
|
156
|
+
hello: 'world',
|
157
|
+
});
|
158
|
+
setTimeout(() => {
|
159
|
+
cache = null;
|
160
|
+
|
161
|
+
if (global.gc) {
|
162
|
+
global.gc();
|
163
|
+
}
|
164
|
+
}, Math.random() * 300);
|
165
|
+
|
166
|
+
const numWorkers = 10;
|
167
|
+
|
168
|
+
const workers = [];
|
169
|
+
const responsePromises = [];
|
170
|
+
for (let i = 0; i < numWorkers; i++) {
|
171
|
+
const worker = new Worker(path.join(__dirname, 'workerThreadsTest.js'), {
|
172
|
+
workerData: {
|
173
|
+
cacheDir: testDir,
|
174
|
+
},
|
175
|
+
});
|
176
|
+
workers.push(worker);
|
177
|
+
|
178
|
+
const responsePromise = new Promise((resolve, reject) => {
|
179
|
+
worker.addListener('error', (error: Error) => {
|
180
|
+
reject(error);
|
181
|
+
});
|
182
|
+
worker.addListener('message', (message) => {
|
183
|
+
resolve(message);
|
184
|
+
});
|
185
|
+
});
|
186
|
+
|
187
|
+
worker.addListener('message', (message) => {
|
188
|
+
// eslint-disable-next-line no-console
|
189
|
+
console.log('Worker message', message);
|
190
|
+
});
|
191
|
+
worker.addListener('online', () => {
|
192
|
+
worker.postMessage({
|
193
|
+
type: 'go',
|
194
|
+
});
|
195
|
+
});
|
196
|
+
|
197
|
+
responsePromises.push(responsePromise);
|
198
|
+
}
|
199
|
+
|
200
|
+
// eslint-disable-next-line no-console
|
201
|
+
console.log('Waiting for responses');
|
202
|
+
const responses = await Promise.all(responsePromises);
|
203
|
+
|
204
|
+
// eslint-disable-next-line no-console
|
205
|
+
console.log('Responses received');
|
206
|
+
for (const [index, response] of responses.entries()) {
|
207
|
+
const worker = workers[index];
|
208
|
+
|
209
|
+
assert.deepEqual(
|
210
|
+
response,
|
211
|
+
{
|
212
|
+
mainThreadData: {
|
213
|
+
mainThreadId: 0,
|
214
|
+
hello: 'world',
|
215
|
+
},
|
216
|
+
workerId: worker.threadId,
|
217
|
+
},
|
218
|
+
`worker_${index} - Worker ${worker.threadId} should have received the correct data`,
|
219
|
+
);
|
220
|
+
}
|
221
|
+
|
222
|
+
// eslint-disable-next-line no-console
|
223
|
+
console.log('Getting main thread key');
|
224
|
+
cache = new LMDBLiteCache(testDir);
|
225
|
+
const data = await cache?.get('main_thread_key');
|
226
|
+
assert.deepEqual(data, {
|
227
|
+
mainThreadId: 0,
|
228
|
+
hello: 'world',
|
229
|
+
});
|
230
|
+
|
231
|
+
// eslint-disable-next-line no-console
|
232
|
+
console.log('Getting worker keys');
|
233
|
+
for (const worker of workers) {
|
234
|
+
const data = await cache?.get(`worker_key/${worker.threadId}`);
|
235
|
+
assert.deepEqual(data, {
|
236
|
+
workerId: worker.threadId,
|
237
|
+
});
|
238
|
+
|
239
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
240
|
+
worker.terminate();
|
241
|
+
}
|
242
|
+
});
|
33
243
|
});
|
@@ -0,0 +1,42 @@
|
|
1
|
+
/* eslint-disable no-inner-declarations */
|
2
|
+
|
3
|
+
require('@atlaspack/babel-register');
|
4
|
+
const {
|
5
|
+
workerData,
|
6
|
+
threadId,
|
7
|
+
parentPort,
|
8
|
+
isMainThread,
|
9
|
+
} = require('worker_threads');
|
10
|
+
const {LMDBLiteCache} = require('../src/index');
|
11
|
+
|
12
|
+
if (!isMainThread) {
|
13
|
+
const cache = new LMDBLiteCache(workerData.cacheDir);
|
14
|
+
|
15
|
+
async function onMessage() {
|
16
|
+
try {
|
17
|
+
cache.set(`worker_key/${threadId}`, {
|
18
|
+
workerId: threadId,
|
19
|
+
});
|
20
|
+
|
21
|
+
const data = await cache.get('main_thread_key');
|
22
|
+
|
23
|
+
parentPort.postMessage({
|
24
|
+
mainThreadData: data,
|
25
|
+
workerId: threadId,
|
26
|
+
});
|
27
|
+
|
28
|
+
setTimeout(() => {
|
29
|
+
parentPort.postMessage({
|
30
|
+
type: 'close',
|
31
|
+
workerId: threadId,
|
32
|
+
});
|
33
|
+
}, Math.random() * 200);
|
34
|
+
} catch (error) {
|
35
|
+
parentPort.postMessage({
|
36
|
+
error: error.message,
|
37
|
+
});
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
parentPort.on('message', onMessage);
|
42
|
+
}
|