All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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