(This page shows only cooperative revocation. For an explanation of uncooperative revocation, see The Membrane Pattern.) The distributed capability paradigm is surprising faithful to the properties of the single-machine capability paradigm. One of the differences between the two is that single-machine capabilities are "reliable", meaning that they work perfectly for as long as their universe exists. Distributed capabilities can be at most fail-stop, since one side can fail without the other, or a partition can separate them. Usually, this fails safe, since an inability to exercise authority is a lack of service, but not a breach. The revokable forwarder is a nice counter-example to this pleasant principle. def makeRevoker(var myPrecious) :any { def revoker { to pass(verb, args) :any { E.send(myPrecious, verb, args) } to revoke(problem) { myPrecious := Ref.broken(problem) } } def forwarder { to __printOn(out) { myPrecious.__printOn(out) } match [verb, args] { revoker.pass(verb, args) } } [forwarder, revoker] } If the holder of the revoker is remote, then a partition can prevent them from sending a revoke message, leaving the holder of the wrapper with too much authority. To solve this, we turn the revoker into a "DeadManSwitch" as follows: def revoker { to pass(verb, args) :any { E.send(myPrecious, verb, args) } to revoke(problem) { # myPrecious <- __reactToLostClient(problem) [see below] myPrecious := Ref.broken(problem) } to __reactToLostClient(problem) { revoker.revoke(problem) } }
__reactToLostClient is a MirandaMethod explained as: In practice, one would also add a __reactToLostClient method to the forwarder, to forward this message to myPrecious: def forwarder { to __printOn(out) { myPrecious.__printOn(out) } to __reactToLostClient(problem) { myPrecious.__reactToLostClient(problem) } match [verb, args] { revoker.pass(verb, args) } } This allows a revocable forwarder to a DeadManSwitch to itself be a DeadManSwitch, whose ability to trigger the underlying DeadManSwitch is revocable. This raises an interesting design choice: Should the revoker send a __reactToLostClient messages to the underlying object during a revoke(), in case the underlying is also a DeadManSwitch? How should we think about revoking rights to revoke? Should we consider this a loss to the underlying of a client? |
||||||||||||
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
|