Skip to content

Commit

Permalink
copy comms protocol notes from #3306
Browse files Browse the repository at this point in the history
  • Loading branch information
warner committed Jun 13, 2021
1 parent eb88d51 commit bd50389
Showing 1 changed file with 41 additions and 1 deletion.
42 changes: 41 additions & 1 deletion packages/SwingSet/docs/garbage-collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,47 @@ The `dropImports`, `retireImports`, and `retireExports` syscalls/deliveries only

(TODO): describe the code which tracks REACHABLE/RECOGNIZABLE for all objects the the comms object table, the "reachable" flag in each c-list entry, the code that computes the overall reachability state, and the creation and processing of remote-side `dropImports`/etc messages.

Note that the comms tracking code is not yet implemented. Until then, the comms vat will retain a strong reference to all passing objects forever.
Note that the comms tracking code is not yet implemented. Until then, the comms vat will retain a strong reference to all passing objects forever. See #3306 for current progress.

The following are some quick protocol notes.


* incoming drop/retire messages are either "informed" if the sender was fully aware of any cross-on-the-wire re-introductions, or "ignorant" if not
* comms-kernel messages are always informed
* comms-comms messages are informed if the inbound message's acknum is equal or greater than the outbound clist record of the last reintroduction, else they are ignorant
* comms will add an `isReachable` flag to all clist entries
* on import entries, this describes the state of the importer
* on export entries, it merely records whether we've sent a drop or not, and might not actually be necessary
* comms will add a (reachable, recognizable) refcount tuple to all comms object table entries
* just like the kernel does:
* `reachable` is the sum of the `isReachable` flags from all importers, plus one for each resolved promise or auxdata that references the object
* `recognizable` is the count of all importing clist entries, plus resolved promises and auxdata
* when comms receives an informed `dropExport`, it clears the `isReachable` flag for that importer's clist, which decrements the `reachable` refcount
* if `reachable` hits zero, comms sends a `dropExport` to the exporter and clears the `isReachable` flag on the exporter's clist entry (again, maybe not really necessary)
* when comms receives an informed `retireExport`, it deletes the importer's clist entry, which decrements the `recognizable` refcount
* if `recognizable` hits zero, comms sends a `retireExport` to the exporter and deletes the clist entry
* when comms receives an informed(??) `dropImport` (which will always be from an exporter):
* comms translates the `dropImport` from sender-space to local (comms) space, then deletes the exporting c-list entry
* the `reachable` count must already be zero, else the sender of `dropImport` did something wrong
* comms locates all importers, then deletes the object table entry
* comms translates a `dropImport` to each importer, then deletes their clist entry
* comms sends the translated `dropImport` to the importer

If comms receives a `retireExport` or `retireImport` for a ref that is not in the c-list, it should just ignore it. There are two reasons/phases where this might happen. The "normal" one is during a race between the importer sending `retireExport` and the exporter sending `retireImport`. We could choose to track this race in the same way we handle the retirement of promises:
* importer sends `retireExport`, and tracks the (sent seqnum, rref) pair in an ordered list
* if a message arrives that effectively acks that seqnum, delete the pair: the window for a race has closed
* if a re-introduction arrives before that point, delete the pair: the race has been superceded by a replacement object
* if a `retireImport` arrives before that point, ignore it: there was a race, no big deal
* if a `retireImport` arrives after that point (i.e. neither the clist nor the ordered `retireExport`-sent list knows the rref): this is the weird case, we might decide to kill the connection, or log-but-ignore, or just ignore
* follow the same pattern when the exporter sends `retireImport`

The algorithm for comms is mostly simpler than the kernel because:
* there are no queued messages: no run-queue, and no per-promise message queues (because everything is immediately pipelined)
* we aren't trying to spread GC actions out among multiple cranks, so we don't need to record the upcoming work in a durable fashion: the equivalents of `maybeFreeKrefs` and the durable `gcActions` set can both be ephemeral
* drops and retires appear in separate messages, so we don't need the `processNextGCAction` code that prioritizes one over the other, and actions won't be negated by an earlier re-introduction

However it's slightly more complex because of the need to distinguish between informed and ignorant inbound messages, and the possibility that we choose to log or kill-connection when a `retireImport`/`retireExport` arrives after we know the race window has closed.


# Cross-Vat (kernel) Tracking

Expand Down

0 comments on commit bd50389

Please sign in to comment.