fix(swingset): fix refcounts for messages queued to a promise #3270
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
As described in #3264, we were not maintaining correct reference counts when
messages get queued to an unresolved promise.
In the new approach, the lifetime of a message is:
during
doSend
, as beforetype: 'send'
event to the run-queuesend
event is pulled off the run-queue, all krefs aredecrefed (as before)
kernelKeeper.addMessageToPromiseQueue
increfs all krefsaddMessageToPromiseQueue
did not change therefcounts)
laterally from the promise queue to
send
events on the run-queue, withoutchanging their refcounts
doSend
, whichincremented the refcounts)
send
event is removed from therun-queue, as usual
The result is the same number of increments and decrements as before, but the
increment is done earlier, so messages on a promise queue will maintain a
refcount on all their krefs (target, args, and any result). This protects
objects and promises which would otherwise have been eligible for collection
while they sat on the promise queue.
Strictly speaking we don't need to maintain a refcount on the target (which
is also kind of redundant: everything on the queue for promise
kp1
obviously has
target: 'kp1'
), since that will always be additionally heldby the c-list of the decider (at least). But by making all promise queues do
the same thing as the main run-queue, we can laterally transfer messages from
promise- to run-queue without DB churn (decrementing then immediately
incrementing the counts).
This change moves the responsibility for the lateral transfer from
notifySubscribersAndQueue
in kernel.js tokernelKeeper.resolveKernelPromise()
, deleting the former entirely andmerging the subscription loop into
doResolve
.closes #3264
(reviewer note: consider examining each commit separately; they don't overlap much, but are logically separate)