-
Notifications
You must be signed in to change notification settings - Fork 0
/
Chord.fsx
185 lines (150 loc) · 6.32 KB
/
Chord.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#r "nuget: Akka"
open Akka.Actor
open System
open System.Collections.Generic
open System.Threading
// Function to generate a unique random number and update the set
let generateUniqueRandomNumber (maxValue: int) (mutableSet: HashSet<int>) =
let random = Random()
let mutable randomNumber = random.Next(1, maxValue + 1)
// Generate a random number until it is not in the integerSet
while mutableSet.Contains(randomNumber) do
randomNumber <- random.Next(1, maxValue + 1)
// Add the generated number to the integerSet
mutableSet.Add(randomNumber) |> ignore
randomNumber
let m = 20
let maxvalue = int32 (pown 2 m - 1) // Maximum range of values allowed for a node
let keyList = List<int>()
let mutableSet = HashSet<int>() // Used to store and determine if a random number has already been used
let myList = LinkedList<int>() // Used to store Node keys
let mutable numberOfNodes = 0
let mutable numberOfRequests = 0
let args = System.Environment.GetCommandLineArgs()
if args.Length >= 3 then
numberOfNodes <- int args.[2] // Number of nodes
numberOfRequests <- int args.[3] // Number of requests
else
printfn "Please provide two command-line arguments: NumberOfNodes and NumberOfRequests."
// Create a CountdownEvent to coordinate starting and waiting for requests
let requestsCountdown = CountdownEvent(numberOfNodes)
for k=1 to numberOfRequests-1 do
keyList.Add(generateUniqueRandomNumber maxvalue mutableSet)
type chord_Node =
{ ID: IActorRef
FingerTable: Dictionary<int, int>
key: int
mutable Next: chord_Node option }
// Define a global variable of type CircularListNode
let mutable globalHead : int = -1
// Dictionary to store circular linked list nodes
let mutable nodeList = Dictionary<int, chord_Node>()
let mutable nodeData = List<int>()
// Function to create a circular linked list node
let calculateNumberOfHops (startNodeKey: int) (lookupKey: int) =
let rec loop currentNodeKey hops =
if currentNodeKey = lookupKey then hops
else
let node = nodeList.[currentNodeKey]
let mutable closestPrecedingNodeKey = currentNodeKey
for keyValue in node.FingerTable.Keys do
let fingerValue = node.FingerTable.[keyValue]
if (currentNodeKey < keyValue) && (keyValue <= lookupKey) && (fingerValue > closestPrecedingNodeKey) then
closestPrecedingNodeKey <- fingerValue
if closestPrecedingNodeKey = currentNodeKey then
// The key doesn't exist in the network or something went wrong
hops
else
loop closestPrecedingNodeKey (hops + 1)
loop startNodeKey 0
let mutable hopCount = 0
// Class for actors
type MyActor(requestsCountdown: CountdownEvent) =
inherit ReceiveActor()
override this.PreStart() =
let selfRef = this.Self
async {
// Start the request loop only after all actors are created
let mutable counter = 0
while counter < numberOfRequests do
do! Async.Sleep(1000) // Sleep for 1 second
let nodeValue = int selfRef.Path.Name
let key = calculateNumberOfHops nodeValue keyList[counter]
hopCount <- hopCount + key
counter <- counter + 1
printfn "%s has finished all requests" (selfRef.Path.Name)
if requestsCountdown.Signal() then
printfn "The average number of hops is %f" (float hopCount / float (numberOfNodes * numberOfRequests))
Environment.Exit(0)
} |> Async.Start
// Function to create an actor with a custom name
let createActor (actorSystem: ActorSystem) (name: string) =
let actorref = actorSystem.ActorOf(Props.Create(fun () -> MyActor(requestsCountdown)), name)
actorref
for i = 1 to numberOfRequests do
let key = generateUniqueRandomNumber maxvalue mutableSet
keyList.Add(key)
let getSuccesor (key: int32) =
let mutable successor = -1
for k = 0 to nodeData.Count - 2 do
if key > nodeData.[k] && key <= nodeData.[k + 1] && successor = -1 then
successor <- nodeData.[k + 1]
if successor = -1 then
successor <- nodeData.[0]
successor
let UpdateFingerTable (id: int) =
for k = 1 to m do
let key1 = id + int32 (pown 2 (k - 1))
let value1 = getSuccesor (key1 % (int32 (pown 2 m)))
nodeList.[id].FingerTable[key1] <- value1
let create (actor: IActorRef) (data: int) =
// Create a circular linked list node with the actor's name as ID
let node = { ID = actor; FingerTable = new Dictionary<int, int>(); key = data; Next = None }
// Add the node to the dictionary with its ID as the key
nodeList.[node.key] <- node
node.Next <- Some node
globalHead <- node.key
nodeData <- List<int> nodeList.Keys
for k in nodeData do
UpdateFingerTable k
// Function to join a new node to the circular linked list
let join (name: IActorRef) (data: int) =
let newNode =
{
ID = name
FingerTable = new Dictionary<int32, int32>()
key = data
Next = None
}
nodeList.[newNode.key] <- newNode
if data < nodeData[0] || data > nodeData[nodeData.Count-1] then
let temp = nodeList[nodeData[nodeData.Count-1]].Next
newNode.Next <- temp
nodeList[nodeData[nodeData.Count-1]].Next <- Some newNode
if data < nodeData[0] then
nodeData.Insert(0, data)
else
nodeData.Add(data)
else
let mutable temp1 = true
for i = 1 to nodeData.Count - 1 do
if temp1 && nodeData[i - 1] < data && data < nodeData[i] then
let temp = nodeList[nodeData[i - 1]].Next
newNode.Next <- temp
nodeList[nodeData[i - 1]].Next <- Some newNode
nodeData.Insert(i, data)
temp1 <- false
for k in nodeData do
UpdateFingerTable k
// Create the ActorSystem
let system = ActorSystem.Create("ChordSystem")
for i in 1 .. numberOfNodes do
let uniqueNumber = generateUniqueRandomNumber maxvalue mutableSet
let actorName = string uniqueNumber
let actor = createActor system actorName
if i = 1 then
create actor uniqueNumber
else
join actor uniqueNumber
// Wait for all actors to finish their requests
requestsCountdown.Wait()