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
|
local it = require "prosody.util.iterators";
local function generate_ring(nodes, num_replicas, hash)
local new_ring = {};
for _, node_name in ipairs(nodes) do
for replica = 1, num_replicas do
local replica_hash = hash(node_name..":"..replica);
new_ring[replica_hash] = node_name;
table.insert(new_ring, replica_hash);
end
end
table.sort(new_ring);
return new_ring;
end
local hashring_methods = {};
local hashring_mt = {
__index = function (self, k)
-- Automatically build self.ring if it's missing
if k == "ring" then
local ring = generate_ring(self.nodes, self.num_replicas, self.hash);
rawset(self, "ring", ring);
return ring;
end
return rawget(hashring_methods, k);
end
};
local function new(num_replicas, hash_function)
return setmetatable({ nodes = {}, num_replicas = num_replicas, hash = hash_function }, hashring_mt);
end;
function hashring_methods:add_node(name, value)
self.ring = nil;
self.nodes[name] = value == nil and true or value;
table.insert(self.nodes, name);
return true;
end
function hashring_methods:add_nodes(nodes)
self.ring = nil;
local iter = pairs;
if nodes[1] then -- simple array?
iter = it.values;
end
for node_name, node_value in iter(nodes) do
if self.nodes[node_name] == nil then
self.nodes[node_name] = node_value == nil and true or node_value;
table.insert(self.nodes, node_name);
end
end
return true;
end
function hashring_methods:remove_node(node_name)
self.ring = nil;
if self.nodes[node_name] ~= nil then
for i, stored_node_name in ipairs(self.nodes) do
if node_name == stored_node_name then
self.nodes[node_name] = nil;
table.remove(self.nodes, i);
return true;
end
end
end
return false;
end
function hashring_methods:remove_nodes(nodes)
self.ring = nil;
for _, node_name in ipairs(nodes) do
self:remove_node(node_name);
end
end
function hashring_methods:clone()
local clone_hashring = new(self.num_replicas, self.hash);
for node_name, node_value in pairs(self.nodes) do
clone_hashring.nodes[node_name] = node_value;
end
clone_hashring.ring = nil;
return clone_hashring;
end
function hashring_methods:get_node(key)
local node;
local key_hash = self.hash(key);
for _, replica_hash in ipairs(self.ring) do
if key_hash < replica_hash then
node = self.ring[replica_hash];
break;
end
end
if not node then
node = self.ring[self.ring[1]];
end
return node, self.nodes[node];
end
return {
new = new;
}
|