Marine Library  1.0
C++ library for Linux Networking Development
consistent_hash.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Zhao DAI <daidodo@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or any
7  * later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see accompanying file LICENSE.txt
16  * or <http://www.gnu.org/licenses/>.
17  */
18 
26 #ifndef DOZERG_CONSISTENT_HASH_H_20131127
27 #define DOZERG_CONSISTENT_HASH_H_20131127
28 
29 #include <stdint.h>
30 #include <cassert>
31 #include <map>
32 #include <vector>
33 #include "template.hh" //CHashFn
34 
35 NS_SERVER_BEGIN
36 
68 template<
69  class Key,
70  template<typename>class HashKey = CHashFn
72 {
73  //typedefs
75 public:
76  typedef Key key_type;
77  typedef uint32_t value_type;
78  typedef HashKey<key_type> hasher;
79 private:
80  typedef std::map<value_type, value_type> __Map; //pos -> value
81  struct __Node{
82  value_type last_;
83  std::vector<value_type> pos_;
84  size_t weight() const{return pos_.size();}
85  };
86  typedef std::map<value_type, __Node> __Values; //value -> node
87 public:
88  //functions
94  value_type hash(const key_type & key) const{
95  assert(!ring_.empty());
96  const value_type h = hasher()(key);
97  typename __Map::const_iterator wh = ring_.lower_bound(h);
98  if(ring_.end() == wh)
99  wh = ring_.begin();
100  return wh->second;
101  }
107  void setValue(value_type value, size_t weight = 1000){
108  if(weight){
109  __Node & n = values_[value];
110  if(n.weight() > weight){
111  removeNode(value, weight, n);
112  }else if(n.weight() < weight)
113  insertNode(value, weight, n);
114  }else{
115  typename __Values::iterator wh = values_.find(value);
116  if(values_.end() != wh){
117  removeNode(value, 0, wh->second);
118  values_.erase(wh);
119  }
120  }
121  }
122 #ifdef UNIT_TEST
123  // These are test APIs.
124 public:
125  void actualWeight(std::vector<std::pair<value_type, value_type> > & results) const{
126  assert(!ring_.empty());
127  value_type last = 0;
128  for(typename __Map::const_iterator it = ring_.begin();it != ring_.end();++it){
129  addWeight(it->second, it->first - last, results);
130  last = it->first;
131  }
132  addWeight(ring_.begin()->second, value_type(-1) - last, results);
133  }
134  void vnodes(std::vector<std::pair<value_type, value_type> > & results) const{
135  results.resize(ring_.size());
136  std::copy(ring_.begin(), ring_.end(), results.begin());
137  }
138  static void addWeight(value_type value, value_type weight, std::vector<std::pair<value_type, value_type> > & results){
139  typedef std::vector<std::pair<value_type, value_type> > __Ret;
140  for(__Ret::iterator it = results.begin();it != results.end();++it)
141  if(it->first == value){
142  it->second += weight;
143  return;
144  }
145  results.push_back(std::make_pair(value, weight));
146  }
147 #endif
148 private:
149  void insertNode(value_type value, size_t weight, __Node & n){
150  while(n.weight() < weight){
151  n.last_ = hashValue(value, n.weight(), n.last_);
152  std::pair<typename __Map::iterator, bool> ret = ring_.insert(std::make_pair(n.last_, value));
153  if(ret.second)
154  n.pos_.push_back(n.last_);
155  }
156  }
157  void removeNode(value_type value, size_t weight, __Node & n){
158  while(n.weight() > weight){
159  ring_.erase(n.pos_.back());
160  n.pos_.pop_back();
161  n.last_ = (n.pos_.empty() ? 0 : n.pos_.back());
162  }
163  }
164  static value_type hashValue(value_type key, size_t index, value_type last){
165  return u32Hash(key + last + (index << 16) + (index >> 16));
166  }
167  static value_type u32Hash(value_type val){
168  val = ((val >> 16) ^ val) * 0x45d9f3b + 1;
169  val = ((val >> 16) ^ val) * 0x45d9f3b + 3;
170  val = ((val >> 16) ^ val);
171  return val;
172  }
173  //fields
174  __Values values_;
175  __Map ring_;
176 };
177 
178 NS_SERVER_END
179 
180 #endif
181 
A lightweight implementation of Consistent Hashng algorithm.
Definition: consistent_hash.hh:71
value_type hash(const key_type &key) const
Get consistent hash result of a key.
Definition: consistent_hash.hh:94
void setValue(value_type value, size_t weight=1000)
Add, remove or modify weight of a value.
Definition: consistent_hash.hh:107
Definition: template.hh:174