Proto
ยค
This is the top-level server description
"ref" is the reference object "me" is the server's id net is the network
include table
include delmap
module sht_protocol(me,ref,trans,id,key,data,shard) = {
action set(k:key.t,d:data) returns(tx:ref.txid)
action get(k:key.t) returns(tx:ref.txid)
action answer(k:key.t,d:data,tx:ref.txid)
action delegate_(dst:id, lo:key.iter.t, hi:key.iter.t) returns(ok:bool)
object spec = {
before set {
tx := ref.begin(me,ref.write,k,d)
}
before get {
tx := ref.begin(me,ref.read,k,0)
}
before answer {
assert ref.data_(tx) = d;
call ref.end(tx)
}
before delegate_ {
assert dst ~= me;
assert lo < hi;
assert key.iter.between(lo,K,hi) -> impl.dm.map(K,me)
}
}
object req = {
type t = struct {
src : id,
rkey : key.t,
rtype : ref.otype,
rdata : data,
rtxid : ref.txid
}
}
object impl = {
instance hash : hash_table(key,data,shard)
instance dm : delegation_map(key,id)
action handle_request(rq:req.t) returns(ok:bool) = {
local src:id, k:key.t, op:ref.otype, d:data, tx:ref.txid, ow:id {
src := req.src(rq);
k := req.rkey(rq);
op := req.rtype(rq);
d := req.rdata(rq);
tx := req.rtxid(rq);
ow := dm.get(k);
if ow = me {
call ref.commit(tx); # this is ghost!
if op = ref.read {
req.rdata(rq) := hash.get(k)
}
else {
call hash.set(k,d)
};
ok := trans.send_reply(me, src, rq)
} else {
ok := trans.send_request(me, ow, rq) # forward request
}
}
}
implement set {
local rq:req.t {
req.src(rq) := me;
req.rkey(rq) := k;
req.rtype(rq) := ref.write;
req.rdata(rq) := d;
req.rtxid(rq) := tx;
local ok:bool {
ok := handle_request(rq)
}
}
}
implement get {
local rq:req.t {
req.src(rq) := me;
req.rkey(rq) := k;
req.rtype(rq) := ref.read;
req.rtxid(rq) := tx;
local ok:bool {
ok := handle_request(rq)
}
}
}
implement delegate_ {
call dm.set(lo,hi,dst);
ok := trans.send_delegate(me,dst,hash.extract_(lo,hi))
}
implement trans.recv_request(rq:req.t) {
local ok : bool {
ok := handle_request(rq)
}
}
implement trans.recv_reply(rq:req.t) {
call answer(req.rkey(rq),req.rdata(rq),req.rtxid(rq))
}
implement trans.recv_delegate(s:shard.t) {
call dm.set(shard.lo(s),shard.hi(s),me);
call hash.incorporate(s)
}
conjecture impl.dm.map(K,me) -> hash.hash(K) = ref.map(K)
conjecture impl.dm.map(K,me) & X ~= me -> ~proto.impl.dm(X).map(K,X)
conjecture impl.dm.map(K,me) -> ~(trans.delegated(X,S) & key.iter.between(shard.lo(S),K,shard.hi(S)))
conjecture trans.delegated(X,S) & key.iter.between(shard.lo(S),K,shard.hi(S))
& trans.delegated(X1,S1) & key.iter.between(shard.lo(S1),K,shard.hi(S1))
-> X = X1 & S = S1
conjecture trans.requested(D,R) & L = req.rtxid(R)->
(req.rkey(R) = ref.key_(L) &
req.rtype(R) = ref.type_(L) &
(req.rtype(R) = ref.write -> req.rdata(R) = ref.data_(L)))
conjecture trans.replied(D,R) & L = req.rtxid(R)->
(req.rkey(R) = ref.key_(L) &
req.rtype(R) = ref.type_(L) &
req.rdata(R) = ref.data_(L))
conjecture trans.requested(D,R) -> ref.generated(req.rtxid(R)) & ~ref.committed(req.rtxid(R))
conjecture trans.replied(D,R) -> ref.generated(req.rtxid(R)) & ref.committed(req.rtxid(R))
conjecture trans.requested(D1,R1) & trans.requested(D2,R2) & req.rtxid(R1) = req.rtxid(R2)
-> D1 = D2 & R1 = R2
conjecture trans.replied(D1,R1) & trans.replied(D2,R2) & req.rtxid(R1) = req.rtxid(R2)
-> D1 = D2 & R1 = R2
conjecture trans.delegated(X,S) & key.iter.between(shard.lo(S),K,shard.hi(S)) -> shard.value(S,K) = ref.map(K)
conjecture trans.delegated(D,S) -> shard.valid(S)
}
}