-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutils.ex
159 lines (151 loc) · 4.48 KB
/
utils.ex
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
defmodule Utils do
# node's pid is passed and then converted to a string
# that string is then hashed using SHA-1 ans trucated to 2^20 bits
def hash_modulus(node_name) do
str_num = Atom.to_string(node_name)
num = :crypto.hash(:sha, str_num) |> Base.encode16
{int_num, _} = Integer.parse(num, 16)
id = rem(int_num, :math.pow(2,20) |> trunc)
check_id(id)
end
# makes sure all the ids are unique
def check_id(id) do
node_list = Chief.get(MyChief)
if (id in node_list) do
id = id + :rand.uniform(100)
check_id(id)
else
id
end
end
# checks if x node exists between the nodes a and b (excluding a and b)
def check_range_excl(x, a, b) do
node_list = Chief.get(MyChief)
cond do
a == nil || b == nil || x == nil ->
false
a not in node_list || b not in node_list ->
false
a == b ->
false
a < b ->
index_a = Enum.find_index(node_list, fn i -> i == a end)
index_b = Enum.find_index(node_list, fn i -> i == b end)
check_list = Enum.slice(node_list, index_a + 1, index_b - index_a - 1)
x in check_list
a > b ->
index_a = Enum.find_index(node_list, fn i -> i == a end)
index_b = Enum.find_index(node_list, fn i -> i == b end)
last_index = length(node_list) - 1
checklist_1 = Enum.slice(node_list, index_a + 1, last_index)
checklist_2 = Enum.slice(node_list, 0, index_b)
x in checklist_1 || x in checklist_2
end
end
# check_range_excl real_deal_inclusion
# checks if x node exists between the nodes a and b (excluding a and including b)
def check_range_incl(x, a, b) do
node_list = Chief.get(MyChief)
cond do
x == nil ->
false
a == b ->
false
a < b ->
index_a = Enum.find_index(node_list, fn i -> i == a end)
index_b = Enum.find_index(node_list, fn i -> i == b end)
check_list = Enum.slice(node_list, index_a + 1, index_b - index_a)
x in check_list
a > b ->
index_a = Enum.find_index(node_list, fn i -> i == a end)
index_b = Enum.find_index(node_list, fn i -> i == b end)
last_index = length(node_list) - 1
checklist_1 = Enum.slice(node_list, index_a + 1, last_index)
checklist_2 = Enum.slice(node_list, 0, index_b + 1)
x in checklist_1 || x in checklist_2
end
end
# real_succ_incl key_in_range_incl
# check if x in between (a, b]
def key_in_range_incl(x, a, b) do
node_list = Chief.get(MyChief)
cond do
a == nil || b == nil || x == nil ->
false
a == b ->
if(x == a) do
true
else
false
end
a < b ->
x in (a + 1)..b
a > b ->
x in 0..b || x in (a + 1)..(:math.pow(2, 20) |> trunc)
end
end
# real_succ_excl key_in_range_excl
# check if x in between (a, b)
def key_in_range_excl(x, a, b) do
node_list = Chief.get(MyChief)
cond do
a == nil || b == nil || x == nil ->
false
a == b ->
if(x == a) do
true
else
false
end
a < b ->
x in (a + 1)..(b - 1)
a > b ->
last_index = length(node_list) - 1
x in 0..(b - 1) || x in (a + 1)..(:math.pow(2, 20) |> trunc)
end
end
# to find succ for current node n
def find_succ(n, id, data) do
[{_, state}] = :ets.lookup(data, n)
if(Utils.key_in_range_incl(id, state[:id], state[:succ])) do
state[:succ]
else
n_dash = closest_preceding_node(id, state)
if(n_dash == n) do
n
else
find_succ(n_dash, id, data)
end
end
end
# count number of hops for lookups
def find_succ_acc(n, id, data, acc) do
[{_, state}] = :ets.lookup(data, n)
if(Utils.key_in_range_incl(id, state[:id], state[:succ])) do
acc
else
n_dash = closest_preceding_node(id, state)
find_succ_acc(n_dash, id, data, acc + 1)
end
end
# returns the closest preceding node of id
def closest_preceding_node(id, state) do
finger = state[:finger_table]
size = Enum.count(Map.keys(finger))
list_m = Enum.reverse(1..size)
finger_list =
Enum.map(list_m, fn i ->
if(Utils.key_in_range_excl(finger[i], state[:id], id)) do
finger[i]
end
end)
# ensuring no duplicate entries
finger_list = Enum.uniq(finger_list)
if(finger_list == [nil]) do
state[:id]
else
finger_list = finger_list -- [nil]
Enum.fetch!(finger_list, 0)
end
end
end