|
1 | 1 | // @ts-check
|
2 |
| -import fs from 'fs'; |
3 |
| -import path from 'path'; |
4 |
| -import Readlines from 'n-readlines'; |
5 |
| - |
6 | 2 | import { assert, details as X, q } from '@agoric/assert';
|
7 | 3 |
|
8 | 4 | /**
|
@@ -35,29 +31,14 @@ import { assert, details as X, q } from '@agoric/assert';
|
35 | 31 | * }} SwingStore
|
36 | 32 | */
|
37 | 33 |
|
38 |
| -function safeUnlink(filePath) { |
39 |
| - try { |
40 |
| - fs.unlinkSync(filePath); |
41 |
| - } catch (e) { |
42 |
| - if (e.code !== 'ENOENT') { |
43 |
| - throw e; |
44 |
| - } |
45 |
| - } |
46 |
| -} |
| 34 | +const streamPeek = new WeakMap(); // for tests to get raw access to the streams |
47 | 35 |
|
48 | 36 | /**
|
49 |
| - * Create a new instance of a RAM-based implementation of the Storage API. |
50 |
| - * |
51 |
| - * The "Storage API" is a set of functions { has, getKeys, get, set, delete } |
52 |
| - * that work on string keys and accept string values. A lot of kernel-side |
53 |
| - * code expects to get an object that implements the Storage API. |
| 37 | + * Do the work of `initSwingStore` and `openSwingStore`. |
54 | 38 | *
|
55 |
| - * @returns {{ |
56 |
| - * kvStore: KVStore, // the storage API object itself |
57 |
| - * state: any, // the underlying map that holds the state in memory |
58 |
| - * }} |
| 39 | + * @returns {SwingStore} |
59 | 40 | */
|
60 |
| -function makeStorageInMemory() { |
| 41 | +function makeSwingStore() { |
61 | 42 | const state = new Map();
|
62 | 43 |
|
63 | 44 | /**
|
@@ -153,78 +134,6 @@ function makeStorageInMemory() {
|
153 | 134 | delete: del,
|
154 | 135 | };
|
155 | 136 |
|
156 |
| - return harden({ kvStore, state }); |
157 |
| -} |
158 |
| - |
159 |
| -const streamPeek = new WeakMap(); // for tests to get raw access to the streams |
160 |
| - |
161 |
| -/** |
162 |
| - * Do the work of `initSwingStore` and `openSwingStore`. |
163 |
| - * |
164 |
| - * @param {string} [dirPath] Path to a directory in which database files may be kept, or |
165 |
| - * null. |
166 |
| - * @param {boolean} [forceReset] If true, initialize the database to an empty state |
167 |
| - * |
168 |
| - * @returns {SwingStore} |
169 |
| - */ |
170 |
| -function makeSwingStore(dirPath, forceReset = false) { |
171 |
| - const { kvStore, state } = makeStorageInMemory(); |
172 |
| - |
173 |
| - let storeFile; |
174 |
| - if (dirPath) { |
175 |
| - fs.mkdirSync(dirPath, { recursive: true }); |
176 |
| - storeFile = path.resolve(dirPath, 'swingset-kernel-state.jsonlines'); |
177 |
| - if (forceReset) { |
178 |
| - safeUnlink(storeFile); |
179 |
| - } else { |
180 |
| - let lines; |
181 |
| - try { |
182 |
| - lines = new Readlines(storeFile); |
183 |
| - } catch (e) { |
184 |
| - // storeFile will be missing the first time we try to use it. That's OK; |
185 |
| - // commit will create it. |
186 |
| - if (e.code !== 'ENOENT') { |
187 |
| - throw e; |
188 |
| - } |
189 |
| - } |
190 |
| - if (lines) { |
191 |
| - let line = lines.next(); |
192 |
| - while (line) { |
193 |
| - // @ts-ignore JSON.parse can take a Buffer |
194 |
| - const [key, value] = JSON.parse(line); |
195 |
| - kvStore.set(key, value); |
196 |
| - line = lines.next(); |
197 |
| - } |
198 |
| - } |
199 |
| - } |
200 |
| - } |
201 |
| - |
202 |
| - /** |
203 |
| - * Commit unsaved changes. |
204 |
| - */ |
205 |
| - function commit() { |
206 |
| - if (dirPath) { |
207 |
| - const tempFile = `${storeFile}.tmp`; |
208 |
| - const fd = fs.openSync(tempFile, 'w'); |
209 |
| - |
210 |
| - for (const [key, value] of state.entries()) { |
211 |
| - const line = JSON.stringify([key, value]); |
212 |
| - fs.writeSync(fd, line); |
213 |
| - fs.writeSync(fd, '\n'); |
214 |
| - } |
215 |
| - fs.closeSync(fd); |
216 |
| - fs.renameSync(tempFile, storeFile); |
217 |
| - } |
218 |
| - } |
219 |
| - |
220 |
| - /** |
221 |
| - * Close the "database", abandoning any changes made since the last commit |
222 |
| - * (if you want to save them, call commit() first). |
223 |
| - */ |
224 |
| - function close() { |
225 |
| - // Nothing to do here. |
226 |
| - } |
227 |
| - |
228 | 137 | /** @type {Map<string, Array<string>>} */
|
229 | 138 | const streams = new Map();
|
230 | 139 | /** @type {Map<string, string>} */
|
@@ -336,53 +245,75 @@ function makeSwingStore(dirPath, forceReset = false) {
|
336 | 245 | return harden({ itemCount: position.itemCount + 1 });
|
337 | 246 | }
|
338 | 247 |
|
339 |
| - const streamStore = harden({ |
| 248 | + const streamStore = { |
340 | 249 | readStream,
|
341 | 250 | writeStreamItem,
|
342 | 251 | closeStream,
|
343 | 252 | STREAM_START,
|
344 |
| - }); |
| 253 | + }; |
| 254 | + |
| 255 | + /** |
| 256 | + * Commit unsaved changes. |
| 257 | + */ |
| 258 | + function commit() { |
| 259 | + // Nothing to do here. |
| 260 | + } |
| 261 | + |
| 262 | + /** |
| 263 | + * Close the "database", abandoning any changes made since the last commit |
| 264 | + * (if you want to save them, call commit() first). |
| 265 | + */ |
| 266 | + function close() { |
| 267 | + // Nothing to do here. |
| 268 | + } |
345 | 269 |
|
346 | 270 | streamPeek.set(streamStore, streams);
|
347 | 271 |
|
348 | 272 | return harden({ kvStore, streamStore, commit, close });
|
349 | 273 | }
|
350 | 274 |
|
351 | 275 | /**
|
352 |
| - * Create a swingset store that is an in-memory map, normally backed by JSON |
353 |
| - * serialized to a text file. If there is an existing store at the given |
354 |
| - * `dirPath`, it will be reinitialized to an empty state. |
| 276 | + * Create a swingset store that is an in-memory map. |
355 | 277 | *
|
356 |
| - * @param {string=} dirPath Path to a directory in which database files may be kept. |
357 |
| - * This directory need not actually exist yet (if it doesn't it will be |
358 |
| - * created) but it is reserved (by the caller) for the exclusive use of this |
359 |
| - * swing store instance. If this is nullish, the swing store created will |
360 |
| - * have no backing store and thus be non-persistent. |
| 278 | + * @param {string=} dirPath Optional path to a directory in which database files |
| 279 | + * might be kept, if this were a persistent form of swingset store. If a path |
| 280 | + * is provided, a warning will be output to the console. This parameter is |
| 281 | + * provided so that the in-memory store may be substituted for a persistent |
| 282 | + * store for testing or debugging purposes without needing to change the |
| 283 | + * client. |
361 | 284 | *
|
362 | 285 | * @returns {SwingStore}
|
363 | 286 | */
|
364 | 287 | export function initSwingStore(dirPath) {
|
365 |
| - if (dirPath !== null && dirPath !== undefined && `${dirPath}` !== dirPath) { |
366 |
| - throw new Error('dirPath must be a string or nullish'); |
| 288 | + if (dirPath) { |
| 289 | + console.log( |
| 290 | + `Warning: initSwingStore ignoring dirPath, simpleStore is memory only`, |
| 291 | + ); |
367 | 292 | }
|
368 |
| - return makeSwingStore(dirPath, true); |
| 293 | + return makeSwingStore(); |
369 | 294 | }
|
370 | 295 |
|
371 | 296 | /**
|
372 |
| - * Open a swingset store that is an in-memory map, backed by JSON serialized to |
373 |
| - * a text file. If there is no existing store at the given `dirPath`, a new, |
374 |
| - * empty store will be created. |
| 297 | + * Open a swingset store that is an in-memory map. Note that "open" is a |
| 298 | + * misnomer here, because you will always get a fresh, empty store. This entry |
| 299 | + * point is provided for testing purposes only. |
375 | 300 | *
|
376 |
| - * @param {string} dirPath Path to a directory in which database files may be kept. |
377 |
| - * This directory need not actually exist yet (if it doesn't it will be |
378 |
| - * created) but it is reserved (by the caller) for the exclusive use of this |
379 |
| - * swing store instance. |
| 301 | + * @param {string=} dirPath Optional path to a directory in which database files |
| 302 | + * might be kept, if this were a persistent form of swingset store. If a path |
| 303 | + * is provided, a warning will be output to the console. This parameter is |
| 304 | + * provided so that the in-memory store may be substituted for a persistent |
| 305 | + * store for testing or debugging purposes without needing to change the |
| 306 | + * client. |
380 | 307 | *
|
381 | 308 | * @returns {SwingStore}
|
382 | 309 | */
|
383 | 310 | export function openSwingStore(dirPath) {
|
384 |
| - assert.typeof(dirPath, 'string'); |
385 |
| - return makeSwingStore(dirPath, false); |
| 311 | + if (dirPath) { |
| 312 | + console.log( |
| 313 | + `Warning: openSwingStore ignoring dirPath, simpleStore is memory only`, |
| 314 | + ); |
| 315 | + } |
| 316 | + return makeSwingStore(); |
386 | 317 | }
|
387 | 318 |
|
388 | 319 | /**
|
@@ -445,25 +376,3 @@ export function setAllState(swingStore, stuff) {
|
445 | 376 | streamStore.closeStream(streamName);
|
446 | 377 | }
|
447 | 378 | }
|
448 |
| - |
449 |
| -/** |
450 |
| - * Is this directory a compatible swing store? |
451 |
| - * |
452 |
| - * @param {string} dirPath Path to a directory in which database files might be present. |
453 |
| - * This directory need not actually exist |
454 |
| - * |
455 |
| - * @returns {boolean} |
456 |
| - * If the directory is present and contains the files created by initSwingStore |
457 |
| - * or openSwingStore, returns true. Else returns false. |
458 |
| - * |
459 |
| - */ |
460 |
| -export function isSwingStore(dirPath) { |
461 |
| - assert.typeof(dirPath, 'string'); |
462 |
| - if (fs.existsSync(dirPath)) { |
463 |
| - const storeFile = path.resolve(dirPath, 'swingset-kernel-state.jsonlines'); |
464 |
| - if (fs.existsSync(storeFile)) { |
465 |
| - return true; |
466 |
| - } |
467 |
| - } |
468 |
| - return false; |
469 |
| -} |
0 commit comments