From d7951b070228cd7f30e104b95ade806e365910e2 Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Sat, 9 Mar 2024 11:53:20 -0800 Subject: [PATCH] refactor!(daemon): Rename mutex to serial-jobs Renames the daemon's `Mutex` to `SerialJobs`, which better reflects its purpose. Also removes `lock()` and `unlock()` from its interface. --- packages/daemon/src/daemon-node-powers.js | 10 ++--- packages/daemon/src/daemon.js | 24 +++++++---- .../daemon/src/{mutex.js => serial-jobs.js} | 6 +-- packages/daemon/src/types.d.ts | 4 +- .../{test-mutex.js => test-serial-jobs.js} | 40 +++++++++---------- 5 files changed, 44 insertions(+), 40 deletions(-) rename packages/daemon/src/{mutex.js => serial-jobs.js} (82%) rename packages/daemon/test/{test-mutex.js => test-serial-jobs.js} (56%) diff --git a/packages/daemon/src/daemon-node-powers.js b/packages/daemon/src/daemon-node-powers.js index 42073b6641..bb3813ff84 100644 --- a/packages/daemon/src/daemon-node-powers.js +++ b/packages/daemon/src/daemon-node-powers.js @@ -9,7 +9,7 @@ import { makeReaderRef } from './reader-ref.js'; import { makePetStoreMaker } from './pet-store.js'; import { servePrivatePortHttp } from './serve-private-port-http.js'; import { servePrivatePath } from './serve-private-path.js'; -import { makeMutex } from './mutex.js'; +import { makeSerialJobs } from './serial-jobs.js'; const { quote: q } = assert; @@ -355,7 +355,7 @@ export const makeNetworkPowers = ({ http, ws, net }) => { }; export const makeFilePowers = ({ fs, path: fspath }) => { - const writeLock = makeMutex(); + const writeJobs = makeSerialJobs(); /** * @param {string} path @@ -379,7 +379,7 @@ export const makeFilePowers = ({ fs, path: fspath }) => { * @param {string} text */ const writeFileText = async (path, text) => { - await writeLock.enqueue(async () => { + await writeJobs.enqueue(async () => { await fs.promises.writeFile(path, text); }); }; @@ -423,13 +423,13 @@ export const makeFilePowers = ({ fs, path: fspath }) => { * @param {string} path */ const removePath = async path => { - await writeLock.enqueue(async () => { + await writeJobs.enqueue(async () => { return fs.promises.rm(path); }); }; const renamePath = async (source, target) => { - await writeLock.enqueue(async () => { + await writeJobs.enqueue(async () => { return fs.promises.rename(source, target); }); }; diff --git a/packages/daemon/src/daemon.js b/packages/daemon/src/daemon.js index 205bc5559b..dd5217e627 100644 --- a/packages/daemon/src/daemon.js +++ b/packages/daemon/src/daemon.js @@ -17,7 +17,7 @@ import { parseFormulaIdentifier, serializeFormulaIdentifier, } from './formula-identifier.js'; -import { makeMutex } from './mutex.js'; +import { makeSerialJobs } from './serial-jobs.js'; import { makeWeakMultimap } from './weak-multimap.js'; import { makeLoopbackNetwork } from './networks/loopback.js'; @@ -101,7 +101,15 @@ const makeDaemonCore = async ( } = powers; const { randomHex512 } = cryptoPowers; const contentStore = persistencePowers.makeContentSha512Store(); - const formulaGraphMutex = makeMutex(); + /** + * Mutations of the formula graph must be serialized through this queue. + * "Mutations" include: + * - Creation + * - Removal + * - Incarnation + * - Cancellation + */ + const formulaGraphJobs = makeSerialJobs(); // This is the id of the node that is hosting the values. // This will likely get replaced with a public key in the future. const ownNodeIdentifier = getDerivedId( @@ -835,7 +843,7 @@ const makeDaemonCore = async ( /** @type {import('./types.js').DaemonCore['cancelValue']} */ const cancelValue = async (formulaIdentifier, reason) => { - await formulaGraphMutex.enqueue(); + await formulaGraphJobs.enqueue(); const controller = provideControllerForFormulaIdentifier(formulaIdentifier); console.log('Cancelled:'); return controller.context.cancel(reason); @@ -983,7 +991,7 @@ const makeDaemonCore = async ( * @type {import('./types.js').DaemonCore['incarnateWorker']} */ const incarnateWorker = async () => { - const formulaNumber = await formulaGraphMutex.enqueue(randomHex512); + const formulaNumber = await formulaGraphJobs.enqueue(randomHex512); return incarnateNumberedWorker(formulaNumber); }; @@ -1068,7 +1076,7 @@ const makeDaemonCore = async ( /** @type {import('./types.js').DaemonCore['incarnateGuest']} */ const incarnateGuest = async (hostFormulaIdentifier, deferredTasks) => { return incarnateNumberedGuest( - await formulaGraphMutex.enqueue(async () => { + await formulaGraphJobs.enqueue(async () => { const identifiers = await incarnateGuestDependencies( hostFormulaIdentifier, ); @@ -1116,7 +1124,7 @@ const makeDaemonCore = async ( workerFormulaIdentifier, endowmentFormulaIdentifiers, evalFormulaNumber, - } = await formulaGraphMutex.enqueue(async () => { + } = await formulaGraphJobs.enqueue(async () => { const ownFormulaNumber = await randomHex512(); const ownFormulaIdentifier = serializeFormulaIdentifier({ type: 'eval', @@ -1261,7 +1269,7 @@ const makeDaemonCore = async ( powersFormulaIdentifier, capletFormulaNumber, workerFormulaIdentifier, - } = await formulaGraphMutex.enqueue(() => + } = await formulaGraphJobs.enqueue(() => incarnateCapletDependencies( 'make-unconfined', hostFormulaIdentifier, @@ -1297,7 +1305,7 @@ const makeDaemonCore = async ( powersFormulaIdentifier, capletFormulaNumber, workerFormulaIdentifier, - } = await formulaGraphMutex.enqueue(() => + } = await formulaGraphJobs.enqueue(() => incarnateCapletDependencies( 'make-bundle', hostFormulaIdentifier, diff --git a/packages/daemon/src/mutex.js b/packages/daemon/src/serial-jobs.js similarity index 82% rename from packages/daemon/src/mutex.js rename to packages/daemon/src/serial-jobs.js index 44fdad7bd4..fc2783abf8 100644 --- a/packages/daemon/src/mutex.js +++ b/packages/daemon/src/serial-jobs.js @@ -1,9 +1,9 @@ import { makeQueue } from '@endo/stream'; /** - * @returns {import('./types.js').Mutex} + * @returns {import('./types.js').SerialJobs} */ -export const makeMutex = () => { +export const makeSerialJobs = () => { /** @type {import('@endo/stream').AsyncQueue} */ const queue = makeQueue(); const lock = () => { @@ -15,8 +15,6 @@ export const makeMutex = () => { unlock(); return { - lock, - unlock, enqueue: async (asyncFn = /** @type {any} */ (async () => {})) => { await lock(); try { diff --git a/packages/daemon/src/types.d.ts b/packages/daemon/src/types.d.ts index 99b238b3f0..240e122f1b 100644 --- a/packages/daemon/src/types.d.ts +++ b/packages/daemon/src/types.d.ts @@ -813,9 +813,7 @@ export interface DaemonCore { makeDirectoryNode: MakeDirectoryNode; } -export type Mutex = { - lock: () => Promise; - unlock: () => void; +export type SerialJobs = { enqueue: (asyncFn?: () => Promise) => Promise; }; diff --git a/packages/daemon/test/test-mutex.js b/packages/daemon/test/test-serial-jobs.js similarity index 56% rename from packages/daemon/test/test-mutex.js rename to packages/daemon/test/test-serial-jobs.js index 62ac3a6129..9744975121 100644 --- a/packages/daemon/test/test-mutex.js +++ b/packages/daemon/test/test-serial-jobs.js @@ -4,24 +4,24 @@ import '@endo/init/debug.js'; import rawTest from 'ava'; import { wrapTest } from '@endo/ses-ava'; -import { makeMutex } from '../src/mutex.js'; +import { makeSerialJobs } from '../src/serial-jobs.js'; const test = wrapTest(rawTest); const delay = () => new Promise(resolve => setTimeout(resolve, 1)); -test('releases lock in expected order (sync functions)', async t => { - const mutex = makeMutex(); +test('performs operations in expected order (sync functions)', async t => { + const serialJobs = makeSerialJobs(); const results = []; await Promise.all([ - mutex.enqueue(() => { + serialJobs.enqueue(() => { results.push(1); }), - mutex.enqueue(() => { + serialJobs.enqueue(() => { results.push(2); }), - mutex.enqueue(() => { + serialJobs.enqueue(() => { results.push(3); }), ]); @@ -29,18 +29,18 @@ test('releases lock in expected order (sync functions)', async t => { t.deepEqual(results, [1, 2, 3]); }); -test('releases lock in expected order (async functions)', async t => { - const mutex = makeMutex(); +test('performs operations in expected order (async functions)', async t => { + const serialJobs = makeSerialJobs(); const results = []; await Promise.all([ - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { results.push(1); }), - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { results.push(2); }), - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { results.push(3); }), ]); @@ -48,20 +48,20 @@ test('releases lock in expected order (async functions)', async t => { t.deepEqual(results, [1, 2, 3]); }); -test('releases lock in expected order (async functions with await)', async t => { - const mutex = makeMutex(); +test('performs operations in expected order (async functions with await)', async t => { + const serialJobs = makeSerialJobs(); const results = []; await Promise.all([ - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { await delay(); results.push(1); }), - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { await delay(); results.push(2); }), - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { await delay(); results.push(3); }), @@ -71,20 +71,20 @@ test('releases lock in expected order (async functions with await)', async t => }); test('immediately releases the lock to the awaiter', async t => { - const mutex = makeMutex(); + const serialJobs = makeSerialJobs(); const results = []; await Promise.all([ - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { await delay(); results.push(2); }), (async () => { results.push(1); - await mutex.enqueue(() => delay()); + await serialJobs.enqueue(() => delay()); results.push(3); })(), - mutex.enqueue(async () => { + serialJobs.enqueue(async () => { results.push(4); }), ]);