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

swingset: auto-subscribe all vats to hear about promise resolution #745

Closed
warner opened this issue Mar 19, 2020 · 1 comment
Closed

swingset: auto-subscribe all vats to hear about promise resolution #745

warner opened this issue Mar 19, 2020 · 1 comment
Labels
SwingSet package: SwingSet

Comments

@warner
Copy link
Member

warner commented Mar 19, 2020

To help #675 (prune resolved promises from kernel tables), we'd like to accelerate the retirement of all Promises in the system. Currently, if a Vat is told about a Promise (as the argument in a message or resolution, or as the result of a message), the kernel will only notify that vat about the Promise's resolution if the Vat first subscribes to hear about it. The vat must do a syscall.subscribe to be added to the subscribers list, which is kept in the kernel promise table. The dispatch.notifyResolve* messages are sent to all vats in the subscription list, and to any vat which subscribes while the promise is in a resolved state.

I built it this way because I was anticipating a performance benefit from avoiding unwanted resolution messages. I imagined that a common use case would be to receive a promise, use it as the target of messages, or to pass on to others, but not to call .then on it. In this case, the vat holding the promise doesn't really care about when it becomes resolved. I also imagined that some day we would have some fancy hooks on Javascript Promise objects (maybe involving the HandledPromise extension that we use for promise-pipelining), which would allow us to detect when .then was called. Lacking such a hook, I had the vat (in the liveSlots layer) automatically subscribe to any promise that it heard about. So the kernel API could support not subscribing, but the Vat side didn't take advantage of this ability.

This design adds some small complexity and one extra message per .then'ed promise, to avoid sending one message per non-.then'ed promise. @dtribble 's position is that this is not actually a win, and I'm starting to agree. For two local vats interacting, the messages don't cost very much. When the vats are separated by a comms layer and run on different machines, the messages cost a lot more. But the round trip time is the really expensive part. By requiring the receiving vat to send a subscribe, we introduce an extra RTT to deliver a resolve promise and its resolution: A sends (already resolved) promise to B, B sends subscribe to A, A sends notifyResolve* message.

So his recommendation is to have the kernel automatically subscribe any vat which learns about the Promise, the first time it hears about it (when we allocate a new P-nn entry in its c-list).

This also provides a performance improvement in the context of #675. We can't delete a row from the kernel promise table until all references to it have been dropped. Some of these references will come from the kernel/vat c-list tables. The first phase of #675 is to delete the c-list entries immediately after sending a dispatch.notifyResolve* message into the vat. But if we're using explicit subscriptions, and the vat doesn't subscribe to hear about these notifications, we'll never send in a notifyResolve*, and we won't have an opportunity to delete the c-list entry. This would keep the kernel promise around forever, just in case the vat still has a reference and chooses to use it.

So the task here is to automatically subscribe vats to hear about resolution when the kernel promise identifier is added to their c-list. We currently manage the subscriptions in one place (the kernel promise table), and the c-lists in a different place. But with some clever data structures, we could maybe find a way to query all the c-lists for the presence of entries with a given kernel promise identifier (kpid in, set of vatids out). We could then use the c-lists as the canonical location for this data, and remove the subscription list from the kernel promise table.

We must remember to handle the case where a previously-resolved promise is sent into a vat for the first time. When the kpid is added to the c-list, we must enqueue a notifyResolve* to that same vat with the resolution value. An open question (in my mind) is whether the notifyResolve* should be delivered immediately (i.e. put it at the front of the kernel run queue), or after all other pending messages (i.e. add it to the back of the queue). I suspect there are some important differences between the two approaches, but I don't currently know which one would be correct.

@FUDCo
Copy link
Contributor

FUDCo commented May 20, 2020

Closing. We are not doing it this way.

@FUDCo FUDCo closed this as completed May 20, 2020
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

No branches or pull requests

2 participants