@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.
@@ -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
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../../tsconfig.json",
3
+ "include": ["src"]
4
+ }
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
- });