Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor dispatch to be a function, not an object #2674

Closed
wants to merge 7 commits into from

Conversation

warner
Copy link
Member

@warner warner commented Mar 18, 2021

Previously, the low-level vat interface was defined by a dispatch object,
with methods like .deliver and .notify. Now, it is defined by a
dispatch() function, which takes a vatDeliveryObject that has the exact
same form as the data sent in the kernel-vat protocol.

This reduces the size of the manager/supervisor code and reduces the
redundancy somewhat.

refs #2671

@warner warner self-assigned this Mar 18, 2021
@warner warner added the SwingSet package: SwingSet label Mar 18, 2021
@warner warner changed the base branch from master to 2660-add-weakref March 18, 2021 07:54
@warner
Copy link
Member Author

warner commented Mar 18, 2021

Can anyone help me with the type annotations? https://github.com/Agoric/agoric-sdk/pull/2674/checks?check_run_id=2137783731#step:7:98 says that

is unhappy because Argument of type 'unknown' is not assignable to parameter of type 'Tagged'. I see that Tagged is defined as a 1+-length array of unknowns; in this case the type is always a string, and if that string is syscall then the second (and only) other element is a vatSyscallObject, which is again a 1+-length array where the first is a string and the rest depends upon the first. I don't know typescript well enough to know to cast the const vatSyscallObject = into something with more information than the unknown that it gets from args.

@warner warner force-pushed the 2671-refactor-dispatch branch 2 times, most recently from 87fb514 to 89e1324 Compare March 21, 2021 09:21
@warner warner marked this pull request as ready for review March 21, 2021 18:23
@warner warner requested review from FUDCo and dckc March 21, 2021 18:23
@warner
Copy link
Member Author

warner commented Mar 21, 2021

This does a number of other cleanups and refactorings to align the four different worker types. The overall diff is kind of big, but each individual commit is pretty small and self-contained, so I'd recommend reviewing each commit separately and sequentially.

Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

My eyes did glaze over some parts... especially the non-XS vat managers and the tests in 9214adf . So it may be best to keep @FUDCo 's review in the critical path.

*
* @typedef { [tag: 'message', target: string, msg: Message]} VatDeliveryMessage
* @typedef { [tag: 'notify', resolutions: string[] ]} VatDeliveryNotify
* @typedef { [tag: 'dropExports', vrefs: string[] ]} VatDeliveryDropExports
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay! types! but...

Names such as VatDeliveryDropExports don't seem to get reused anywhere. I suspect the VatDeliveryObject and VatSyscallObject types would be more clear if the options were inlined.

minor style issue. not critical.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't know how to do that. Would it be something like:

/**
 * @typedef { [tag: 'message', target: string, msg: Message] |
 *            [tag: 'notify', resolutions: string[]] |
 *            [tag: 'dropExports', vrefs: string[]] } VatDeliveryObject
 */

?

(note to self/chip, that notify signature isn't correct, I'll fix that)

At some point soon, we're going to have a function in liveslots which switches on tag and then calls one of three different functions. Would the typedefs on those three functions be a reason to retain the VatDeliveryMessage/etc subtypes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be something like: ... ?

yes.

Would the typedefs on those three functions be a reason to retain the VatDeliveryMessage/etc subtypes?

yes.

packages/SwingSet/src/kernel/liveSlots.js Show resolved Hide resolved
import { assert, details as X } from '@agoric/assert';
import { insistMessage } from '../../message';
/** @type { (delivery: VatDeliveryObject, prefix: string) => string } */
function summarizeDelivery(vatDeliveryObject, prefix = 'vat') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange name for something that always returns a ... failed message.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's really a "make a message to log just in case it fails" function, but that name seemed expedient.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

failureMessage?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

summarizeDeliveryFailure maybe?

const dispatchArgs = dispatchRecord.slice(1);
transcriptManager.startDispatch(dispatchRecord);
await runAndWait(() => dispatch[dispatchOp](...dispatchArgs), errmsg);
// vatDeliveryObject is one of:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to keep this comment here? It duplicates a lot of info that's now in types; move the prose to the type declaration? Also: cite the .md doc?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree. Keep the prose here. It's more informative and more legible than the type declaration.

return doProcess(['dropExports', vrefs], errmsg);
}

// vatDeliverObject is:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise... move prose to type declaration and remove?

workerLog(`doProcess done`);
/** @type { Tagged } */
const vatDeliveryResults = harden(['ok']);
return vatDeliveryResults;
}

/** @type { (ts: unknown, msg: any) => Promise<Tagged> } */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yay! deleting code!

const slot = args.slots[qnode.index];
insistVatType('device', slot);
function dispatch(vatDeliverObject) {
const { method, args } = extractMessage(vatDeliverObject);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reads nicely.

return [[promiseID, rejected, data]];
}

function buildSyscall() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah... so we had already written buildSyscall() but not exported it. Cool.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah there are a bunch of little helpers in various tests that finally hit my threshold for factoring them out into something common

Copy link
Contributor

@FUDCo FUDCo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine. Getting rid of some of the extraneous, additional, and unnecessary redundancy and duplication is especially good.

You can probably expect some minor complications merging test-comms.js.

const dispatchArgs = dispatchRecord.slice(1);
transcriptManager.startDispatch(dispatchRecord);
await runAndWait(() => dispatch[dispatchOp](...dispatchArgs), errmsg);
// vatDeliveryObject is one of:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree. Keep the prose here. It's more informative and more legible than the type declaration.

import { assert, details as X } from '@agoric/assert';
import { insistMessage } from '../../message';
/** @type { (delivery: VatDeliveryObject, prefix: string) => string } */
function summarizeDelivery(vatDeliveryObject, prefix = 'vat') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

summarizeDeliveryFailure maybe?

assert(
dispatch && dispatch.deliver,
`vat failed to return a 'dispatch' with .deliver: ${dispatch}`,
assert.equal(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason here not to use assert.typeof ?

This was a false start on the GC task. Previously we thought vat-side
finalizers would call a vat-specific `decref` function at spontaneous times,
and the kernel would accumulate the dropped references for later processing.
Now we have liveslots collect the finalizer results and perform a
non-transcript-enforced syscall.dropImports at the end of crank.

This removes `testTrackDecref` from `kernelOptions`.
This changes the protocol used to speak to the three remote vat
workers (nodeworker, subprocess-node, subprocess-xsnap) slightly. Previously
we unpacked the VatSyscallObject (a tagged array of `[syscallTag,
...syscallArgs]`) when constructing a remote message (which has its own tag),
giving us something like `['syscall', syscallTag, ...syscallArgs]`. Now we
leave the VatSyscallObject intact, giving us `['syscall', [syscallTag,
...syscallArgs]]`. This should be a bit simpler. It changes the protocol in
an incompatible way, but the child thread/process never outlives the kernel
process, so the incompatibility shouldn't be observable.
message.js acquired insistVatDeliveryObject() and insistVatSyscallObject(),
which are type guard functions that match.

Also rename CapDataS to SwingSetCapData.
This changes the protocol used to speak to the three remote vat
workers (nodeworker, subprocess-node, subprocess-xsnap) slightly, by leaving
the VatDeliveryObject intact (rather than merging it with the outer frame).
This object starts each crank by either delivering a 'message', a 'notify',
or a 'dropExports' operation.
This changes the protocol used to speak to two of the remote vat
workers (nodeworker, subprocess-node) slightly, by leaving the
VatDeliveryResults intact (rather than merging it with the outer frame).

The subprocess-xsnap protocol has its own return-value framing and wasn't
merging this object into it.
These two worker types were lagging behind the others, and weren't recording
dispatches into their transcripts. Any vats using them would fail to replay
after a host restart, because their transcripts would be empty.
Previously, the lowest level of a vat was defined by an object named
`dispatch`, which had three methods: `{ deliver, notify, dropExports }`. Now
we define `dispatch()` to be a *function*, which takes a
`VatDeliveryObject` (of which there are three flavors). This simplifies the
supervisor code and removes a lot of redundant boilerplate, and prepares for
later phase where `dispatch()` becomes `async dispatch()`.

refs #2671
@dckc
Copy link
Member

dckc commented Mar 31, 2021

@warner are you holding off on this for any particular reason? It would be nice to have in the vatWarehouse work #2277 .

@warner
Copy link
Member Author

warner commented Mar 31, 2021

Alas this is based upon PR #2667 (the 2660-add-weakref branch) which has been abandoned because of our late discovery of a design flaw (#2724 has details), which would have introduced non-determinism into any Zoe/ERTP pattern that uses a Presence in a WeakMap. I saw intermittent test failures locally when it was fully enabled.

I'm going to have to re-do the refactorings without the WeakRef tracking. It will be shaped a lot like this branch, but it won't be this branch, and it won't target 2660-add-weakref, so I'm going to close this PR without landing.

@warner warner closed this Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
SwingSet package: SwingSet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants