models.examples.case_studies.chord.als Maven / Gradle / Ivy
module examples/case_studies/chord
/*
* 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
}
}
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' }
}}
}
// valid
assert Same1 {all s: State | NextCorrect[s] => NextCorrect'[s]}
check Same1 for 3 but 1 State expect 0
// valid unless active condition removed
assert Same2 {all s: State | s.active = Node => (NextCorrect'[s] => NextCorrect[s])}
check Same2 for 3 but 1 State expect 0
-- 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 expect 0
pred ShowMeFC {
all s : State | s.active = Node && FingersCorrect[s]
}
run ShowMeFC for 2 but 1 State expect 1
pred 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] + 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 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 expect 0
check SameCPF1 for 2 but 1 State expect 0
check SameCPF2 for 3 but 1 State expect 0
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 expect 1
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])
}
}
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 expect 1
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' => // *next' -> ^next' 1/8/02
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 expect 1
check SameFP1 for 3 but 1 State expect 0
check SameFP2 for 3 but 1 State expect 0
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
}}
// 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 expect 1
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
}
run ShowMe1 for 3 expect 1
run ShowMe2 for 3 expect 1
assert InjectiveIds {all i, j: Id | i!=j => i.next != j.next}
check InjectiveIds for 5 expect 0
assert FindSuccessorWorks {
all s: State, i: Id |
let nd = s.active.(s.data) |
let succ = nd.find_successor [i] |
FingersCorrect [s] // && s.active = Node
=> (no n': s.active | less_than [i, n'.id, succ.id])
}
check FindSuccessorWorks for 3 but 1 State expect 1
© 2015 - 2025 Weber Informatics LLC | Privacy Policy