@atlaspack/cache 3.1.1-canary.14 → 3.1.1-canary.141
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 +161 -0
- package/lib/FSCache.d.ts +27 -0
- package/lib/FSCache.js +35 -3
- package/lib/IDBCache.browser.d.ts +22 -0
- package/lib/IDBCache.browser.js +7 -6
- package/lib/IDBCache.d.ts +4 -0
- package/lib/IDBCache.js +1 -1
- package/lib/LMDBLiteCache.d.ts +78 -0
- package/lib/LMDBLiteCache.js +71 -41
- package/lib/constants.d.ts +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/types.d.ts +1 -1
- package/package.json +13 -14
- package/src/{FSCache.js → FSCache.ts} +30 -15
- package/src/{IDBCache.browser.js → IDBCache.browser.ts} +8 -10
- package/src/{IDBCache.js → IDBCache.ts} +1 -2
- package/src/{LMDBLiteCache.js → LMDBLiteCache.ts} +80 -39
- package/src/{constants.js → constants.ts} +0 -2
- package/src/{index.js → index.ts} +0 -2
- package/src/{types.js → types.ts} +0 -1
- package/test/LMDBLiteCache.test.ts +241 -0
- package/test/workerThreadsTest.js +42 -0
- package/tsconfig.json +4 -0
- package/index.d.ts +0 -12
- package/test/LMDBLiteCache.test.js +0 -69
@@ -0,0 +1,241 @@
|
|
1
|
+
import * as fs from 'fs';
|
2
|
+
import * as path from 'path';
|
3
|
+
import {tmpdir} from 'os';
|
4
|
+
import {LMDBLiteCache} from '../src/index';
|
5
|
+
import {deserialize, serialize} from 'v8';
|
6
|
+
import assert from 'assert';
|
7
|
+
import {Worker} from 'worker_threads';
|
8
|
+
import {initializeMonitoring} from '@atlaspack/rust';
|
9
|
+
|
10
|
+
const cacheDir = path.join(tmpdir(), 'lmdb-lite-cache-tests');
|
11
|
+
|
12
|
+
describe('LMDBLiteCache', () => {
|
13
|
+
let cache: any;
|
14
|
+
|
15
|
+
beforeEach(async () => {
|
16
|
+
await fs.promises.rm(cacheDir, {recursive: true, force: true});
|
17
|
+
});
|
18
|
+
|
19
|
+
it('can be constructed', async () => {
|
20
|
+
cache = new LMDBLiteCache(cacheDir);
|
21
|
+
await cache.ensure();
|
22
|
+
});
|
23
|
+
|
24
|
+
it('can retrieve keys', async () => {
|
25
|
+
cache = new LMDBLiteCache(cacheDir);
|
26
|
+
await cache.ensure();
|
27
|
+
await cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
28
|
+
const buffer = await cache.getBlob('key');
|
29
|
+
const result = deserialize(buffer);
|
30
|
+
assert.equal(result.value, 42);
|
31
|
+
});
|
32
|
+
|
33
|
+
it('can retrieve keys synchronously', async () => {
|
34
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'retrieve_keys_test'));
|
35
|
+
await cache.ensure();
|
36
|
+
await cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
37
|
+
const buffer = cache.getBlobSync('key');
|
38
|
+
const result = deserialize(buffer);
|
39
|
+
assert.equal(result.value, 42);
|
40
|
+
});
|
41
|
+
|
42
|
+
it('can iterate over keys', async () => {
|
43
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'keys_test'));
|
44
|
+
await cache.ensure();
|
45
|
+
await cache.setBlob('key1', Buffer.from(serialize({value: 42})));
|
46
|
+
await cache.setBlob('key2', Buffer.from(serialize({value: 43})));
|
47
|
+
const keys = cache.keys();
|
48
|
+
assert.deepEqual(Array.from(keys), ['key1', 'key2']);
|
49
|
+
});
|
50
|
+
|
51
|
+
it('can compact databases', async () => {
|
52
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'compact_test'));
|
53
|
+
await cache.ensure();
|
54
|
+
await cache.setBlob('key1', Buffer.from(serialize({value: 42})));
|
55
|
+
await cache.setBlob('key2', Buffer.from(serialize({value: 43})));
|
56
|
+
await cache.compact(path.join(cacheDir, 'compact_test_compacted'));
|
57
|
+
|
58
|
+
cache = new LMDBLiteCache(path.join(cacheDir, 'compact_test_compacted'));
|
59
|
+
await cache.ensure();
|
60
|
+
const keys = cache.keys();
|
61
|
+
assert.deepEqual(Array.from(keys), ['key1', 'key2']);
|
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 = new LMDBLiteCache(path.join(cacheDir, 'close_and_reopen_test'));
|
88
|
+
await cache.ensure();
|
89
|
+
const buffer = await cache.getBlob('key');
|
90
|
+
const result = deserialize(buffer);
|
91
|
+
assert.equal(result.value, 42);
|
92
|
+
});
|
93
|
+
|
94
|
+
it('should NOT fail when trying to open the same database twice', async () => {
|
95
|
+
const testDir = path.join(cacheDir, 'double_open_test');
|
96
|
+
const cache1 = new LMDBLiteCache(testDir);
|
97
|
+
await cache1.ensure();
|
98
|
+
|
99
|
+
assert.doesNotThrow(() => {
|
100
|
+
new LMDBLiteCache(testDir);
|
101
|
+
});
|
102
|
+
});
|
103
|
+
|
104
|
+
it('should NOT fail when trying to open after GC', async () => {
|
105
|
+
const testDir = path.join(cacheDir, 'gc_test');
|
106
|
+
|
107
|
+
let cache1 = new LMDBLiteCache(testDir);
|
108
|
+
await cache1.ensure();
|
109
|
+
await cache1.setBlob('key', Buffer.from(serialize({value: 42})));
|
110
|
+
|
111
|
+
cache1 = null;
|
112
|
+
|
113
|
+
if (global.gc) {
|
114
|
+
global.gc();
|
115
|
+
}
|
116
|
+
|
117
|
+
assert.doesNotThrow(() => {
|
118
|
+
new LMDBLiteCache(testDir);
|
119
|
+
});
|
120
|
+
});
|
121
|
+
|
122
|
+
it('should handle rapid open/close cycles', async () => {
|
123
|
+
const testDir = path.join(cacheDir, 'rapid_cycles_test');
|
124
|
+
|
125
|
+
for (let i = 0; i < 10; i++) {
|
126
|
+
const cache = new LMDBLiteCache(testDir);
|
127
|
+
await cache.ensure();
|
128
|
+
await cache.setBlob(`key${i}`, Buffer.from(serialize({value: i})));
|
129
|
+
|
130
|
+
await new Promise((resolve: any) => setTimeout(resolve, 10));
|
131
|
+
}
|
132
|
+
|
133
|
+
const finalCache = new LMDBLiteCache(testDir);
|
134
|
+
await finalCache.ensure();
|
135
|
+
const buffer = await finalCache.getBlob('key9');
|
136
|
+
const result = deserialize(buffer);
|
137
|
+
assert.equal(result.value, 9);
|
138
|
+
});
|
139
|
+
|
140
|
+
it('should work when there are multiple node.js worker threads accessing the same database', async function () {
|
141
|
+
this.timeout(40000);
|
142
|
+
|
143
|
+
try {
|
144
|
+
initializeMonitoring();
|
145
|
+
} catch (error: any) {
|
146
|
+
/* empty */
|
147
|
+
}
|
148
|
+
|
149
|
+
const testDir = path.join(cacheDir, 'worker_threads_test');
|
150
|
+
|
151
|
+
let cache = new LMDBLiteCache(testDir);
|
152
|
+
await cache.set('main_thread_key', {
|
153
|
+
mainThreadId: 0,
|
154
|
+
hello: 'world',
|
155
|
+
});
|
156
|
+
setTimeout(() => {
|
157
|
+
cache = null;
|
158
|
+
|
159
|
+
if (global.gc) {
|
160
|
+
global.gc();
|
161
|
+
}
|
162
|
+
}, Math.random() * 300);
|
163
|
+
|
164
|
+
const numWorkers = 10;
|
165
|
+
|
166
|
+
const workers: Array<any> = [];
|
167
|
+
const responsePromises: Array<any> = [];
|
168
|
+
for (let i = 0; i < numWorkers; i++) {
|
169
|
+
const worker = new Worker(path.join(__dirname, 'workerThreadsTest.js'), {
|
170
|
+
workerData: {
|
171
|
+
cacheDir: testDir,
|
172
|
+
},
|
173
|
+
});
|
174
|
+
workers.push(worker);
|
175
|
+
|
176
|
+
const responsePromise = new Promise((resolve: any, reject: any) => {
|
177
|
+
worker.addListener('error', (error: Error) => {
|
178
|
+
reject(error);
|
179
|
+
});
|
180
|
+
worker.addListener('message', (message: any) => {
|
181
|
+
resolve(message);
|
182
|
+
});
|
183
|
+
});
|
184
|
+
|
185
|
+
worker.addListener('message', (message: any) => {
|
186
|
+
// eslint-disable-next-line no-console
|
187
|
+
console.log('Worker message', message);
|
188
|
+
});
|
189
|
+
worker.addListener('online', () => {
|
190
|
+
worker.postMessage({
|
191
|
+
type: 'go',
|
192
|
+
});
|
193
|
+
});
|
194
|
+
|
195
|
+
responsePromises.push(responsePromise);
|
196
|
+
}
|
197
|
+
|
198
|
+
// eslint-disable-next-line no-console
|
199
|
+
console.log('Waiting for responses');
|
200
|
+
const responses = await Promise.all(responsePromises);
|
201
|
+
|
202
|
+
// eslint-disable-next-line no-console
|
203
|
+
console.log('Responses received');
|
204
|
+
for (const [index, response] of responses.entries()) {
|
205
|
+
const worker = workers[index];
|
206
|
+
|
207
|
+
assert.deepEqual(
|
208
|
+
response,
|
209
|
+
{
|
210
|
+
mainThreadData: {
|
211
|
+
mainThreadId: 0,
|
212
|
+
hello: 'world',
|
213
|
+
},
|
214
|
+
workerId: worker.threadId,
|
215
|
+
},
|
216
|
+
`worker_${index} - Worker ${worker.threadId} should have received the correct data`,
|
217
|
+
);
|
218
|
+
}
|
219
|
+
|
220
|
+
// eslint-disable-next-line no-console
|
221
|
+
console.log('Getting main thread key');
|
222
|
+
cache = new LMDBLiteCache(testDir);
|
223
|
+
const data = await cache?.get('main_thread_key');
|
224
|
+
assert.deepEqual(data, {
|
225
|
+
mainThreadId: 0,
|
226
|
+
hello: 'world',
|
227
|
+
});
|
228
|
+
|
229
|
+
// eslint-disable-next-line no-console
|
230
|
+
console.log('Getting worker keys');
|
231
|
+
for (const worker of workers) {
|
232
|
+
const data = await cache?.get(`worker_key/${worker.threadId}`);
|
233
|
+
assert.deepEqual(data, {
|
234
|
+
workerId: worker.threadId,
|
235
|
+
});
|
236
|
+
|
237
|
+
await new Promise((resolve: any) => setTimeout(resolve, 500));
|
238
|
+
worker.terminate();
|
239
|
+
}
|
240
|
+
});
|
241
|
+
});
|
@@ -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
|
+
}
|
package/tsconfig.json
ADDED
package/index.d.ts
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
import type {FilePath} from '@atlaspack/types';
|
2
|
-
import type {Cache} from './lib/types';
|
3
|
-
|
4
|
-
export type {Cache} from './lib/types';
|
5
|
-
|
6
|
-
export const FSCache: {
|
7
|
-
new (cacheDir: FilePath): Cache;
|
8
|
-
};
|
9
|
-
|
10
|
-
export const LMDBLiteCache: {
|
11
|
-
new (cacheDir: FilePath): Cache;
|
12
|
-
};
|
@@ -1,69 +0,0 @@
|
|
1
|
-
// @flow
|
2
|
-
|
3
|
-
import * as fs from 'fs';
|
4
|
-
import * as path from 'path';
|
5
|
-
import {tmpdir} from 'os';
|
6
|
-
import {LMDBLiteCache} from '../src/index';
|
7
|
-
import {deserialize, serialize} from 'v8';
|
8
|
-
import assert from 'assert';
|
9
|
-
|
10
|
-
const cacheDir = path.join(tmpdir(), 'lmdb-lite-cache-tests');
|
11
|
-
|
12
|
-
describe('LMDBLiteCache', () => {
|
13
|
-
let cache;
|
14
|
-
|
15
|
-
beforeEach(async () => {
|
16
|
-
await fs.promises.rm(cacheDir, {recursive: true, force: true});
|
17
|
-
});
|
18
|
-
|
19
|
-
afterEach(() => {
|
20
|
-
cache.getNativeRef().close();
|
21
|
-
});
|
22
|
-
|
23
|
-
it('can be constructed', async () => {
|
24
|
-
cache = new LMDBLiteCache(cacheDir);
|
25
|
-
await cache.ensure();
|
26
|
-
});
|
27
|
-
|
28
|
-
it('can retrieve keys', async () => {
|
29
|
-
cache = new LMDBLiteCache(cacheDir);
|
30
|
-
await cache.ensure();
|
31
|
-
await cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
32
|
-
const buffer = await cache.getBlob('key');
|
33
|
-
const result = deserialize(buffer);
|
34
|
-
assert.equal(result.value, 42);
|
35
|
-
});
|
36
|
-
|
37
|
-
it('can retrieve keys synchronously', async () => {
|
38
|
-
cache = new LMDBLiteCache(path.join(cacheDir, 'retrieve_keys_test'));
|
39
|
-
await cache.ensure();
|
40
|
-
await cache.setBlob('key', Buffer.from(serialize({value: 42})));
|
41
|
-
const buffer = cache.getBlobSync('key');
|
42
|
-
const result = deserialize(buffer);
|
43
|
-
assert.equal(result.value, 42);
|
44
|
-
});
|
45
|
-
|
46
|
-
it('can iterate over keys', async () => {
|
47
|
-
cache = new LMDBLiteCache(path.join(cacheDir, 'keys_test'));
|
48
|
-
await cache.ensure();
|
49
|
-
await cache.setBlob('key1', Buffer.from(serialize({value: 42})));
|
50
|
-
await cache.setBlob('key2', Buffer.from(serialize({value: 43})));
|
51
|
-
const keys = cache.keys();
|
52
|
-
assert.deepEqual(Array.from(keys), ['key1', 'key2']);
|
53
|
-
});
|
54
|
-
|
55
|
-
it('can compact databases', async () => {
|
56
|
-
cache = new LMDBLiteCache(path.join(cacheDir, 'compact_test'));
|
57
|
-
await cache.ensure();
|
58
|
-
await cache.setBlob('key1', Buffer.from(serialize({value: 42})));
|
59
|
-
await cache.setBlob('key2', Buffer.from(serialize({value: 43})));
|
60
|
-
await cache.compact(path.join(cacheDir, 'compact_test_compacted'));
|
61
|
-
|
62
|
-
cache.getNativeRef().close();
|
63
|
-
|
64
|
-
cache = new LMDBLiteCache(path.join(cacheDir, 'compact_test_compacted'));
|
65
|
-
await cache.ensure();
|
66
|
-
const keys = cache.keys();
|
67
|
-
assert.deepEqual(Array.from(keys), ['key1', 'key2']);
|
68
|
-
});
|
69
|
-
});
|