models.examples.case_studies.chord2.als Maven / Gradle / Ivy
module examples/case_studies/chord2
/*
* Models the chord distributed hash table lookup protocol.
*
* For a detailed description, see:
* http://www.pdos.lcs.mit.edu/papers/chord:sigcomm01/
*/
open util/relation as rel
sig Id {next: Id}
fact {all i: Id | Id in i.*next}
/**
* true iff i precedes j in the order starting at from
*/
pred less_than [from, i,j: Id] {
let next' = Id<:next - (Id->from) | j in i.^next' // if from=j, returns true if # nodes > 1
}
pred less_than_eq [from, i,j: Id] {
let next' = Id<:next - (Id->from) | j in i.*next'
}
sig Node {id: Id}
fact {all m,n: Node | m!=n => m.id != n.id}
sig NodeData {
prev, next: Node,
finger: Id -> lone Node,
closest_preceding_finger: Id -> one Node,
find_predecessor: Id -> one Node,
find_successor: Id -> one Node
}
sig State {
active: set Node,
data: active -> one NodeData
}
/**
* node n's next node is defined to be the m where n's finger table maps the id
* that follows n.id to m
* next holds the first entry of the finger table
*/
fact {all s: State | all n: s.active | n.(s.data).next = n.(s.data).finger[n.id.next]}
pred NextCorrect [s: State] {
all n: s.active {
-- no intervening node (ie, close enough)
no n': s.active - n | less_than [n.id, n'.id, n.(s.data).next.id]
-- can reach all other active nodes (ie, far enough)
-- need this because can't rule out case of next being node itself (because of 1-node ring)
-- s.active in n.*(s.data.next)
n.(s.data).next != n || #s.active = 1
}
}
/*
-- abortive attempt at simplifying next condition
fun NextCorrect" (s: State) {
all n: s.active | let nx = s.data.next {
s.active in n.*nx
less_than (n.id, n.id, n.nx.id)
}
}
*/
pred NextCorrect' [s: State] {
-- next seems to be correct for 1,2,3 nodes
all n: s.active | let nd = (s.data)[n] {
let next' = Id<:next - (Id -> nd.next.id) {
no n' : s.active { n'.id in n.id.^next' }
}}
}
assert Same1 {all s: State | NextCorrect[s] => NextCorrect'[s]}
//check Same1 for 3 but 1 State -- valid
assert Same2 {all s: State | s.active = Node => (NextCorrect'[s] => NextCorrect[s])}
//check Same2 for 3 but 1 State -- invalid if active condition removed
-- assert NextInFinger {all s: State | all n: s.active | some n.s.data.finger[n.id.next] }
/**
* says that finger entry maps an id to a node so that there are no intervening nodes
* between the id and the node
*/
pred FingersCorrect [s: State] {
all nd: s.active.(s.data) | all start:nd.finger.univ |
nd.finger[start] in s.active &&
(no n' : s.active | less_than [start, n'.id, nd.finger[start].id])
}
pred FingersCorrect' [s: State] {
all n: s.active | let nd = (s.data)[n] | all start: Node.~(nd.finger) {
nd.finger[start] in s.active &&
(let next' = Id<:next - (nd.finger[start].id -> Id) {
no n' : s.active - nd.finger[start] {
n'.id in start.*next'
}})}
}
assert SameFC {all s: State | FingersCorrect [s] iff FingersCorrect'[s]}
//check SameFC for 3 but 1 State
pred ShowMeFC {
all s : State | s.active = Node && FingersCorrect[s]
}
//run ShowMeFC for 2 but 1 State
/*
fun ClosestPrecedingFinger(s: State) {
all n: s.active | let nd = n.s.data |
all i: Id | let cpf = nd.closest_preceding_finger[i] {
no n': nd.finger[Id] | less_than (cpf.id, n'.id, i)
cpf in nd.finger[Id] + n
less_than (n.id, cpf.id, i)
}
}
*/
pred ClosestPrecedingFinger_SAVE [s: State] {
all n: s.active | let nd = n.(s.data) |
all i: Id | let cpf = nd.closest_preceding_finger[i] {
no n': (nd.finger[Id] + n) - cpf | less_than [cpf.id, n'.id, i]
cpf in nd.finger[Id] + n
cpf.id != i || # s.active = 1
//less_than (n.id, cpf.id, i)
}
}
pred CPFBody [s: State, n: Node, nd: NodeData, i: Id, cpf: Node] {
no n': (nd.finger[Id] + n) - cpf | less_than [cpf.id, n'.id, i]
cpf in nd.finger[Id] + n
cpf.id != i || # s.active = 1
}
pred ClosestPrecedingFinger[s: State] {
all n: s.active | let nd = n.(s.data) |
all i: Id |
some cpf: Node | CPFBody [s,n,nd,i,cpf] => CPFBody [s,n,nd,i,nd.closest_preceding_finger[i]]
}
pred ClosestPrecedingFinger'[s: State] {
all n: s.active | let nd = (s.data)[n] | all i: Id {
let next' = Id<:next - (Id -> i) {
nd.next.id in n.id.^next' =>
// nd.closest_preceding_finger[i] = nd.next,
(some n1: nd.finger[Id] {
nd.closest_preceding_finger[i] = n1
//n1 in nd.finger[Id]
n1.id in n.id.^next'
no n2: nd.finger[Id] | n2.id in n1.id.^next'
}) else
nd.closest_preceding_finger[i] = n
}}
}
assert SameCPF {all s: State | FingersCorrect[s] => (ClosestPrecedingFinger [s] iff ClosestPrecedingFinger' [s])}
assert SameCPF1 {all s: State | FingersCorrect[s] => (ClosestPrecedingFinger [s] => ClosestPrecedingFinger' [s])}
assert SameCPF2 {
all s: State | ((s.active = Node && FingersCorrect[s] && ClosestPrecedingFinger' [s])
=> ClosestPrecedingFinger [s]) }
//check SameCPF for 3 but 1 State
//check SameCPF1 for 2 but 1 State
//check SameCPF2 for 3 but 1 State
pred ShowMeCPF {
all s : State | s.active = Node && FingersCorrect[s] &&
// not ClosestPrecedingFinger(s) && ClosestPrecedingFinger'(s)
ClosestPrecedingFinger[s]
//all s : State | all nd : s.active.s.data | nd.finger[Id] = Node
# Node = 2
# State = 1
}
//run ShowMeCPF for 2 but 1 State
pred FindPredecessor[s: State] {
all n: s.active | let nd = n.(s.data) | all i: Id {
nd.find_predecessor[i] =
((less_than_eq [n.id, i, nd.next.id] && (n.id != i || # s.active = 1))
=> n
else (nd.closest_preceding_finger[i].(s.data).find_predecessor)[i])
}
}
-- problem : could return node that's inactive ???
assert FPisActive {
all s: State | FingersCorrect[s] && ClosestPrecedingFinger[s] && FindPredecessor[s]
=> (all n: s.active | all nd: n.(s.data) | nd.find_predecessor[Id] in s.active)
}
//check FPisActive for 3 but 1 State
pred FindPredecessor'[s: State] {
all n: s.active | let nd = (s.data)[n] | all i: Id {
let next' = Id<:next - (nd.next.id -> Id) {
one s.active or i in n.id.^next' =>
nd.find_predecessor[i] = n else
nd.find_predecessor[i] =
((s.data)[nd.closest_preceding_finger[i]]).find_predecessor[i]
}}
}
assert SameFP {all s: State | FingersCorrect[s] && s.active = Node
=> (FindPredecessor [s] iff FindPredecessor' [s])}
assert SameFP1 {
all s: State | FingersCorrect[s] && s.active = Node
=> (FindPredecessor [s] => FindPredecessor' [s])}
assert SameFP2 {
all s: State | FingersCorrect[s] && s.active = Node
=> (FindPredecessor' [s] => FindPredecessor [s])}
//check SameFP for 3 but 1 State
//check SameFP1 for 3 but 1 State
//check SameFP2 for 3 but 1 State
pred FindSuccessor[s: State] {
all n: s.active | let nd = (s.data)[n] | all i: Id {
nd.find_successor[i] = ((s.data)[nd.find_predecessor[i]]).next
}}
fact { all s : State {
ClosestPrecedingFinger[s]
FindPredecessor[s]
FindSuccessor[s]
}}
// should be able to //check that closest_p_f, etc returns
// only active nodes if FingersCorrect.
pred ShowMe1Node {
#Node = 1
all s : State | NextCorrect[s]
State.active = Node
}
//run ShowMe1Node for 2 but 1 State, 1 Node
-- does the expected correct thing for 1 node.
pred ShowMe1 {
#Node = 2
#State = 1
all s : State | NextCorrect[s]
State.active = Node
}
pred ShowMe2 {
#Node = 3
#State = 1
all s : State | NextCorrect[s] && FingersCorrect[s]
State.active = Node
//all n: NodeData | one n.finger[Id]
}
assert OK1 {
#Node = 3 &&
#State = 1 &&
(all s : State | NextCorrect[s] && FingersCorrect[s]) &&
State.active = Node
}
assert FindSuccessorWorks {
all s: State, i: Id |
let nd = s.active.(s.data) |
let succ = nd.find_successor [i] |
FingersCorrect [s]
=> {
no n': s.active | less_than [i, n'.id, succ.id]
succ in s.active
}
}
check FindSuccessorWorks for 4 but 1 State, 3 Node, 3 NodeData expect 0
© 2015 - 2025 Weber Informatics LLC | Privacy Policy