Fixing the sealed persistence protocol (was Newbie questions about persistence)
Kevin Reid <[email protected]>
| Newsgroups | gmane.comp.lang.e.general |
|---|---|
| Message-ID | <[email protected]> |
On Sep 19, 2009, at 11:42, Mark Miller wrote: > On Mon, Sep 14, 2009 at 3:43 PM, Kevin Reid <[email protected]> wrote: >> IMO, ScopeSetup should directly get the sealer from the >> PersistentKeyHolder, rather than having E-level code do it. There may >> be a reason to have more configurability than that though. >> >> MarkM, is there any reason the persistence sealer should not be >> widely >> available? > > An oversight. This is a good plan. Thomas, feel free to submit a > patch. Kevin, feel free to make a commitment along the lines you > explain above. Commitment? Do you mean commit? I'm not sure what exactly you mean -- that I should revise and commit Thomas's patch, or ...? >> But as a workaround, you can define the proxy as you describe. I >> would >> recommend making it part of the implementation of the oneShot, and >> not >> exposing its existence to the user. (One way to do it would be to >> have >> your oneShot serialize, not as its current state, but rather the slot >> of the used flag: def uncall := [makeOneShot, "withFlagSlot", >> [&used]]. Then the 'used' slot object serves as the un-duplicatable >> object. >> >> But this seems like a kludge, and I think we should fix the >> persistence protocol. Thanks for spotting this. >> >> MarkM, do you agree this is an excessively surprising problem? > > This is indeed excessively surprising. I'm not sure whether or not the > slot solution is a kludge. The persistence of var-slots needs to be > fixed regardless. The slot solution is a kludge because: - nontrivial objects may have state which is not naturally expressed *across upgrades* as one or more var slots. - it means the object may be constructed with its internal shared with other parties: this could violate invariants. - it is not a natural style to program in and creates additional visual noise in the program. - the maker provides degrees of freedom which are unrelated to the actual application. - the need for it IS unnecessarily surprising -- programmers will write accidentally insecure programs by not doing it. Let's think about how to fix the persistence protocol. What we want to achieve is that an object (henceforth referred to as the oneShot, even though this is general) may reveal a portrayal to the persistence subsystem, and thus be persistent, but with the guarantee that it will only be instantiated at most once in any given future vat incarnation. The problem with just returning a portrayal in a sealed box from __optSealedDispatch is that any other object can proxy its __optSealedDispatch to the oneShot and thus revive as a duplicate of it. So one fix would be to stuff the identity in the box and check it: # from org.erights.e.extern.persist.initTimeMachine def persistUncaller { to optUncall(obj) :nullOk[__Portrayal] { if (Ref.isNear(obj) && pUnsealer.amplify(obj) =~ \ [[==(makeTraversalKey(obj)), portrayal]]) { return portrayal } else { return null } } } def oneShot { to __optSealedDispatch(brand) { switch (brand) { match ==persistBrand { return persistSealer.seal(makeTraversalKey(oneShot), [makeOneShot, ...]) } }} } An oddball variation of this would be to put the object in the box and use it instead if the identities don't match: this would permit proxying __optSealedDispatch but change the behavior such that the proxying object is revived as the lone oneShot rather than a duplicate of it. def persistUncaller { to optUncall(obj) :nullOk[__Portrayal] { if (Ref.isNear(obj) && pUnsealer.amplify(obj) =~ [[objForIdentity, portrayal]]) { if (obj == objForIdentity) { return portrayal } else { return [__identityFunc, "run", objForIdentity] } } else { return null } } } def oneShot { to __optSealedDispatch(brand) { switch (brand) { match ==persistBrand { return persistSealer.seal(oneShot, [makeOneShot, ...]) } }} } Also, I note that org.erights.e.extern.persist.initTimeMachine's persistUncaller is currently equivalent to makeAmplifier in org.erights.e.elib.serial.makeAnUncaller except for requiring nearness. - Should all amplifying uncallers work in this same way? I have not considered the matter, but I would think this issue is likely to crop up similarly in other applications. - The nearness restriction should be dropped and the uncall made through Ref.optSealedDispatch. If a Proxy-ref wants to be persistent, let it. Given both of these changes, the persistUncaller is just makeAnUncaller.makeAmplifier(pUnsealer). -- Kevin Reid <http://switchb.org/kpreid/>