Comparison

util/hashring.lua @ 12795:87424cbedc55

util.hashring: Support associating arbitrary data with nodes In this API, a 'node' is always a simple text string. Sometimes the caller may have a more complex structure representing a node, but the hash ring is really only concerned with the node's name. This API change allows :add_nodes() to take a table of `node_name = value` pairs, as well as the simple array of node names previously accepted. The 'value' of the selected node is returned as a new second result from :get_node(). If no value is passed when a node is added, it defaults to `true` (as before, but this was never previously exposed).
author Matthew Wild <mwild1@gmail.com>
date Fri, 02 Dec 2022 20:32:36 +0000
parent 11208:96429946a742
child 12975:d10957394a3c
comparison
equal deleted inserted replaced
12794:249b01adc54a 12795:87424cbedc55
1 local it = require "util.iterators";
2
1 local function generate_ring(nodes, num_replicas, hash) 3 local function generate_ring(nodes, num_replicas, hash)
2 local new_ring = {}; 4 local new_ring = {};
3 for _, node_name in ipairs(nodes) do 5 for _, node_name in ipairs(nodes) do
4 for replica = 1, num_replicas do 6 for replica = 1, num_replicas do
5 local replica_hash = hash(node_name..":"..replica); 7 local replica_hash = hash(node_name..":"..replica);
26 28
27 local function new(num_replicas, hash_function) 29 local function new(num_replicas, hash_function)
28 return setmetatable({ nodes = {}, num_replicas = num_replicas, hash = hash_function }, hashring_mt); 30 return setmetatable({ nodes = {}, num_replicas = num_replicas, hash = hash_function }, hashring_mt);
29 end; 31 end;
30 32
31 function hashring_methods:add_node(name) 33 function hashring_methods:add_node(name, value)
32 self.ring = nil; 34 self.ring = nil;
33 self.nodes[name] = true; 35 self.nodes[name] = value == nil and true or value;
34 table.insert(self.nodes, name); 36 table.insert(self.nodes, name);
35 return true; 37 return true;
36 end 38 end
37 39
38 function hashring_methods:add_nodes(nodes) 40 function hashring_methods:add_nodes(nodes)
39 self.ring = nil; 41 self.ring = nil;
40 for _, node_name in ipairs(nodes) do 42 local iter = pairs;
41 if not self.nodes[node_name] then 43 if nodes[1] then -- simple array?
42 self.nodes[node_name] = true; 44 iter = it.values;
45 end
46 for node_name, node_value in iter(nodes) do
47 if self.nodes[node_name] == nil then
48 self.nodes[node_name] = node_value == nil and true or node_value;
43 table.insert(self.nodes, node_name); 49 table.insert(self.nodes, node_name);
44 end 50 end
45 end 51 end
46 return true; 52 return true;
47 end 53 end
48 54
49 function hashring_methods:remove_node(node_name) 55 function hashring_methods:remove_node(node_name)
50 self.ring = nil; 56 self.ring = nil;
51 if self.nodes[node_name] then 57 if self.nodes[node_name] ~= nil then
52 for i, stored_node_name in ipairs(self.nodes) do 58 for i, stored_node_name in ipairs(self.nodes) do
53 if node_name == stored_node_name then 59 if node_name == stored_node_name then
54 self.nodes[node_name] = nil; 60 self.nodes[node_name] = nil;
55 table.remove(self.nodes, i); 61 table.remove(self.nodes, i);
56 return true; 62 return true;
67 end 73 end
68 end 74 end
69 75
70 function hashring_methods:clone() 76 function hashring_methods:clone()
71 local clone_hashring = new(self.num_replicas, self.hash); 77 local clone_hashring = new(self.num_replicas, self.hash);
72 clone_hashring:add_nodes(self.nodes); 78 for node_name, node_value in pairs(self.nodes) do
79 clone_hashring.nodes[node_name] = node_value;
80 end
81 clone_hashring.ring = nil;
73 return clone_hashring; 82 return clone_hashring;
74 end 83 end
75 84
76 function hashring_methods:get_node(key) 85 function hashring_methods:get_node(key)
86 local node;
77 local key_hash = self.hash(key); 87 local key_hash = self.hash(key);
78 for _, replica_hash in ipairs(self.ring) do 88 for _, replica_hash in ipairs(self.ring) do
79 if key_hash < replica_hash then 89 if key_hash < replica_hash then
80 return self.ring[replica_hash]; 90 node = self.ring[replica_hash];
91 break;
81 end 92 end
82 end 93 end
83 return self.ring[self.ring[1]]; 94 if not node then
95 node = self.ring[self.ring[1]];
96 end
97 return node, self.nodes[node];
84 end 98 end
85 99
86 return { 100 return {
87 new = new; 101 new = new;
88 } 102 }