[e-lang] Fixing the sealed persistence protocol (was Newbie questions about persistence)
Kevin Reid
kpreid at mac.com
Sat Sep 19 12:32:31 EDT 2009
On Sep 19, 2009, at 11:42, Mark Miller wrote:
> On Mon, Sep 14, 2009 at 3:43 PM, Kevin Reid <kpreid at mac.com> 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/>
More information about the e-lang
mailing list