一致性哈希的实现理解
1 namespace
2 {
3
4 class StringifyException
5 {
6 };
7
8 template <class T>
9 std::string Stringify(const T& t)
10 {
11 std::ostringstream os;
12 if (!(os << t))
13 {
14 throw StringifyException();
15 }
16 return os.str();
17 }
18
19 template <>
20 std::string Stringify(const std::string& str)
21 {
22 return str;
23 }
24
25 template <>
26 std::string Stringify(const char* const& str)
27 {
28 return str;
29 }
30 }
31
32 namespace Consistent
33 {
34
35 class EmptyRingException
36 {
37 };
38
39 template <class Node, class Data, class Hash = HASH_NAMESPACE::hash<const char*> >
40 class HashRing
41 {
42 public:
43 typedef std::map<size_t, Node> NodeMap;
44
45 HashRing(unsigned int replicas)
46 : replicas_(replicas), hash_(HASH_NAMESPACE::hash<const char*>())
47 {
48 }
49
50 HashRing(unsigned int replicas, const Hash& hash)
51 : replicas_(replicas), hash_(hash)
52 {
53 }
54
55 size_t AddNode(const Node& node);
56 void RemoveNode(const Node& node);
57 const Node& GetNode(const Data& data) const;
58
59 private:
60 NodeMap ring_;
61 const unsigned int replicas_;
62 Hash hash_;
63 };
64
65 template <class Node, class Data, class Hash>
66 size_t HashRing<Node, Data, Hash>::AddNode(const Node& node)
67 {
68 size_t hash;
69 std::string nodestr = Stringify(node);
70 for (unsigned int r = 0; r < replicas_; r++)
71 {
72 hash = hash_((nodestr + Stringify(r)).c_str());
73 ring_[hash] = node;
74 }
75 return hash;
76 }
77
78 template <class Node, class Data, class Hash>
79 void HashRing<Node, Data, Hash>::RemoveNode(const Node& node)
80 {
81 std::string nodestr = Stringify(node);
82 for (unsigned int r = 0; r < replicas_; r++)
83 {
84 size_t hash = hash_((nodestr + Stringify(r)).c_str());
85 ring_.erase(hash);
86 }
87 }
88
89 template <class Node, class Data, class Hash>
90 const Node& HashRing<Node, Data, Hash>::GetNode(const Data& data) const
91 {
92 if (ring_.empty())
93 throw EmptyRingException();
94
95 size_t hash = hash_(Stringify(data).c_str());
96 typename NodeMap::const_iterator it;
97 // Look for the first node >= hash
98 it = ring_.lower_bound(hash);
99 if (it == ring_.end())
100 {
101 // Wrapped around; get the first node
102 it = ring_.begin();
103 }
104 return it->second;
105 }
106 }