Software /
code /
prosody
Comparison
util/hashring.lua @ 10005:409ff72c501c
util.hashring: Implementation of hashring data structure
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Mon, 13 May 2019 10:03:46 +0100 |
child | 11208:96429946a742 |
comparison
equal
deleted
inserted
replaced
10004:e057e8318130 | 10005:409ff72c501c |
---|---|
1 local function generate_ring(nodes, num_replicas, hash) | |
2 local new_ring = {}; | |
3 for _, node_name in ipairs(nodes) do | |
4 for replica = 1, num_replicas do | |
5 local replica_hash = hash(node_name..":"..replica); | |
6 new_ring[replica_hash] = node_name; | |
7 table.insert(new_ring, replica_hash); | |
8 end | |
9 end | |
10 table.sort(new_ring); | |
11 return new_ring; | |
12 end | |
13 | |
14 local hashring_methods = {}; | |
15 local hashring_mt = { | |
16 __index = function (self, k) | |
17 -- Automatically build self.ring if it's missing | |
18 if k == "ring" then | |
19 local ring = generate_ring(self.nodes, self.num_replicas, self.hash); | |
20 rawset(self, "ring", ring); | |
21 return ring; | |
22 end | |
23 return rawget(hashring_methods, k); | |
24 end | |
25 }; | |
26 | |
27 local function new(num_replicas, hash_function) | |
28 return setmetatable({ nodes = {}, num_replicas = num_replicas, hash = hash_function }, hashring_mt); | |
29 end; | |
30 | |
31 function hashring_methods:add_node(name) | |
32 self.ring = nil; | |
33 self.nodes[name] = true; | |
34 table.insert(self.nodes, name); | |
35 return true; | |
36 end | |
37 | |
38 function hashring_methods:add_nodes(nodes) | |
39 self.ring = nil; | |
40 for _, node_name in ipairs(nodes) do | |
41 if not self.nodes[node_name] then | |
42 self.nodes[node_name] = true; | |
43 table.insert(self.nodes, node_name); | |
44 end | |
45 end | |
46 return true; | |
47 end | |
48 | |
49 function hashring_methods:remove_node(node_name) | |
50 self.ring = nil; | |
51 if self.nodes[node_name] then | |
52 for i, stored_node_name in ipairs(self.nodes) do | |
53 if node_name == stored_node_name then | |
54 self.nodes[node_name] = nil; | |
55 table.remove(self.nodes, i); | |
56 return true; | |
57 end | |
58 end | |
59 end | |
60 return false; | |
61 end | |
62 | |
63 function hashring_methods:remove_nodes(nodes) | |
64 self.ring = nil; | |
65 for _, node_name in ipairs(nodes) do | |
66 self:remove_node(node_name); | |
67 end | |
68 end | |
69 | |
70 function hashring_methods:clone() | |
71 local clone_hashring = new(self.num_replicas, self.hash); | |
72 clone_hashring:add_nodes(self.nodes); | |
73 return clone_hashring; | |
74 end | |
75 | |
76 function hashring_methods:get_node(key) | |
77 local key_hash = self.hash(key); | |
78 for _, replica_hash in ipairs(self.ring) do | |
79 if key_hash < replica_hash then | |
80 return self.ring[replica_hash]; | |
81 end | |
82 end | |
83 return self.ring[self.ring[1]]; | |
84 end | |
85 | |
86 return { | |
87 new = new; | |
88 } |