-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Persistent vat state relies on a synchronous vatstore, which has thus far been elusive due to (1) the asynchronous nature of the kernel<->vat boundary (obstructing the kernel from implementing the vatstore components of the liveslots syscall API, which, despite the fact that the kernel itself does have synchronous access to persistent storage (see issue #76), are predicated on a synchronous kernel<->vat relationship (see comments on PR #317)), and (2) the fact that all the persistent storage options that are available to vats running in an iframe are asynchronous.
Thus far our plan of record has been to accept that most vats will be ephemeral (which we judged acceptable for many plausible use cases) while allowing a small number of vats to instead run in web workers where they could use OPFS in synchronous mode (see issue #332). However, this strategy is proving challenging in part because synchronous OPFS access from extension web workers appears to be less straightforward than we initially believed.
An alternative strategy is to load the entire contents of a vat's persistent store into in-memory data structures prior to processing a message delivery, synchronously service vatstore accesses from those data structures while processing the message, then save the entire state once message processing is completed. This will work because the necessarily asynchronous load and store operations can take place outside the window during which data access must be synchronous
I had initial intuitions that this strategy was probably not practical due to concerns about memory footprint and performance hiccups stemming from large data transfers between the kernel and the vats. However, upon further reflection it may be the case that this strategy is much more viable that I had previously considered. The data load step is only required when a vat iframe is initially being created, either when the vat itself is being created (which should be quick because at that point in the vat's lifecycle it has no state to speak of) or when the vat is being restored after a browser restart (which, hopefully, should be relatively infrequent). The save phase need only checkpoint those portions of the vat's persistent state which have been altered during message processing, which should typically be a small amount of data.
This strategy does sacrifice the option to exploit liveslots' virtual object machinery to enable a vat to support data volumes that exceed available memory, but I believe the main value for this option lies in server-side vats, since they potentially may be providing services to a very large number of clients. However, server-side vats (once we implement them) will be perfectly capable of accessing persistent storage directly since they are not subject to the bizarre minefield of limitations that in-browser code is prey to. The amount of data that can be held in memory in an iframe in modern computers is still quite substantial, and I suspect that use cases for browser vats should generally not be subject to the same kinds of scaling concerns that a server must contend with.
With the foregoing considerations in mind, let's implement the full-state load/store strategy for vats. A rough outline of the implementation is:
-
Add a kernel request that a vat can use to (asynchronously) fetch the complete contents of its vatstore in bulk with an efficient encoding.
-
Add
VatSupervisorcode to employ (1) as part of vat startup in cases where the vat is not being started for the first time (alternatively, this step and (1) could be folded into the existingVatSupervisor.initVatoperation). -
Implement a
Map-based in-memory form of the vatstore that uses aMapto hold the state, fronted by a synchronous vatstore object that reads and writes this map AND keeps a record of the keys that have been set or deleted. -
Add a kernel request to update persistent vatstore state by transmitting a bundle of updated key-value settings and key deletions recorded by (3), for use at the completion of processing a vat delivery (plausibly this could be folded into the delivery response that is sent back to the kernel at that time rather than by adding a new kernel request per se). (And the
VatSupervisorshould also flush the contents of thesetanddeleterecords at this time, to prepare for the next delivery).