tc_consistent_hash_new.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. * Tencent is pleased to support the open source community by making Tars available.
  3. *
  4. * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  7. * in compliance with the License. You may obtain a copy of the License at
  8. *
  9. * https://opensource.org/licenses/BSD-3-Clause
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed
  12. * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  13. * CONDITIONS OF ANY KIND, either express or implied. See the License for the
  14. * specific language governing permissions and limitations under the License.
  15. */
  16. #include "util/tc_consistent_hash_new.h"
  17. namespace tars
  18. {
  19. int32_t TC_KetamaHashAlg::hash(const char* sKey, size_t length)
  20. {
  21. vector<char> sMd5 = TC_MD5::md5bin(sKey, length);
  22. const char *p = (const char *) sMd5.data();
  23. int32_t hash = ((int32_t)(p[3] & 0xFF) << 24)
  24. | ((int32_t)(p[2] & 0xFF) << 16)
  25. | ((int32_t)(p[1] & 0xFF) << 8)
  26. | ((int32_t)(p[0] & 0xFF));
  27. return subTo32Bit(hash);
  28. }
  29. TC_HashAlgorithmType TC_KetamaHashAlg::getHashType()
  30. {
  31. return E_TC_CONHASH_KETAMAHASH;
  32. }
  33. int32_t TC_DefaultHashAlg::hash(const char* sKey, size_t length)
  34. {
  35. vector<char> sMd5 = TC_MD5::md5bin(sKey, length);
  36. const char *p = (const char *) sMd5.data();
  37. int32_t hash = (*(int*)(p)) ^ (*(int*)(p+4)) ^ (*(int*)(p+8)) ^ (*(int*)(p+12));
  38. return subTo32Bit(hash);
  39. }
  40. TC_HashAlgorithmType TC_DefaultHashAlg::getHashType()
  41. {
  42. return E_TC_CONHASH_DEFAULTHASH;
  43. }
  44. TC_HashAlgorithm *TC_HashAlgFactory::getHashAlg(TC_HashAlgorithmType hashType)
  45. {
  46. TC_HashAlgorithm *ptrHashAlg = NULL;
  47. switch(hashType)
  48. {
  49. case E_TC_CONHASH_KETAMAHASH:
  50. {
  51. ptrHashAlg = new TC_KetamaHashAlg();
  52. break;
  53. }
  54. case E_TC_CONHASH_DEFAULTHASH:
  55. default:
  56. {
  57. ptrHashAlg = new TC_DefaultHashAlg();
  58. break;
  59. }
  60. }
  61. return ptrHashAlg;
  62. }
  63. TC_ConsistentHashNew::TC_ConsistentHashNew()
  64. {
  65. _ptrHashAlg = TC_HashAlgFactory::getHashAlg(E_TC_CONHASH_DEFAULTHASH);
  66. }
  67. TC_ConsistentHashNew::TC_ConsistentHashNew(TC_HashAlgorithmType hashType)
  68. {
  69. _ptrHashAlg = TC_HashAlgFactory::getHashAlg(hashType);
  70. }
  71. /**
  72. * @brief 节点比较.
  73. *
  74. * @param m1 node_T_new类型的对象,比较节点之一
  75. * @param m2 node_T_new类型的对象,比较节点之一
  76. * @return less or not 比较结果,less返回ture,否则返回false
  77. */
  78. static bool less_hash(const TC_ConsistentHashNew::node_T_new & m1, const TC_ConsistentHashNew::node_T_new & m2)
  79. {
  80. return m1.iHashCode < m2.iHashCode;
  81. }
  82. void TC_ConsistentHashNew::sortNode()
  83. {
  84. sort(_vHashList.begin(), _vHashList.end(), less_hash);
  85. }
  86. void TC_ConsistentHashNew::printNode()
  87. {
  88. map<unsigned int, unsigned int> mapNode;
  89. size_t size = _vHashList.size();
  90. for (size_t i = 0; i < size; i++)
  91. {
  92. if (i == 0)
  93. {
  94. unsigned int value = 0xFFFFFFFF - _vHashList[size - 1].iHashCode + _vHashList[0].iHashCode;
  95. mapNode[_vHashList[0].iIndex] = value;
  96. }
  97. else
  98. {
  99. unsigned int value = _vHashList[i].iHashCode - _vHashList[i - 1].iHashCode;
  100. if (mapNode.find(_vHashList[i].iIndex) != mapNode.end())
  101. {
  102. value += mapNode[_vHashList[i].iIndex];
  103. }
  104. mapNode[_vHashList[i].iIndex] = value;
  105. }
  106. cout << "printNode: " << _vHashList[i].iHashCode << "|" << _vHashList[i].sNode << "|" << _vHashList[i].iIndex << "|" << mapNode[_vHashList[i].iIndex] << endl;
  107. }
  108. map<unsigned int, unsigned int>::iterator it = mapNode.begin();
  109. double avg = 100;
  110. double sum = 0;
  111. while (it != mapNode.end())
  112. {
  113. double tmp = it->second;
  114. cerr << "result: " << it->first << "|" << it->second << "|" << (tmp * 100 * mapNode.size() / 0xFFFFFFFF - avg) << endl;
  115. sum += (tmp * 100 * mapNode.size() / 0xFFFFFFFF - avg) * (tmp * 100 * mapNode.size() / 0xFFFFFFFF - avg);
  116. it++;
  117. }
  118. cerr << "variance: " << sum / mapNode.size() << ", size: " << _vHashList.size() << endl;
  119. }
  120. int TC_ConsistentHashNew::addNode(const string & node, unsigned int index, int weight)
  121. {
  122. if (_ptrHashAlg.get() == NULL)
  123. {
  124. return -1;
  125. }
  126. node_T_new stItem;
  127. stItem.sNode = node;
  128. stItem.iIndex = index;
  129. for (int j = 0; j < weight; j++)
  130. {
  131. string virtualNode = node + "_" + TC_Common::tostr<int>(j);
  132. // TODO: 目前写了2 种hash 算法,可以根据需要选择一种,
  133. // TODO: 其中KEMATA 为参考memcached client 的hash 算法,default 为原有的hash 算法,测试结论在表格里有
  134. if (_ptrHashAlg->getHashType() == E_TC_CONHASH_KETAMAHASH)
  135. {
  136. vector<char> sMd5 = TC_MD5::md5bin(virtualNode);
  137. char *p = (char *) sMd5.data();
  138. for (int i = 0; i < 4; i++)
  139. {
  140. stItem.iHashCode = ((int32_t)(p[i * 4 + 3] & 0xFF) << 24)
  141. | ((int32_t)(p[i * 4 + 2] & 0xFF) << 16)
  142. | ((int32_t)(p[i * 4 + 1] & 0xFF) << 8)
  143. | ((int32_t)(p[i * 4 + 0] & 0xFF));
  144. stItem.iIndex = index;
  145. _vHashList.push_back(stItem);
  146. }
  147. }
  148. else
  149. {
  150. stItem.iHashCode = _ptrHashAlg->hash(virtualNode.c_str(), virtualNode.length());
  151. _vHashList.push_back(stItem);
  152. }
  153. }
  154. return 0;
  155. }
  156. int TC_ConsistentHashNew::getIndex(const string & key, unsigned int & iIndex)
  157. {
  158. if(_ptrHashAlg.get() == NULL || _vHashList.size() == 0)
  159. {
  160. iIndex = 0;
  161. return -1;
  162. }
  163. vector<char> data = TC_MD5::md5bin(key);
  164. int32_t iCode = _ptrHashAlg->hash(data.data(), data.size());
  165. return getIndex(iCode, iIndex);
  166. }
  167. int TC_ConsistentHashNew::getIndex(int32_t hashcode, unsigned int & iIndex)
  168. {
  169. if(_ptrHashAlg.get() == NULL || _vHashList.size() == 0)
  170. {
  171. iIndex = 0;
  172. return -1;
  173. }
  174. // 只保留32位
  175. int32_t iCode = (hashcode & 0xFFFFFFFFL);
  176. int low = 0;
  177. int high = (int)_vHashList.size();
  178. if(iCode <= _vHashList[0].iHashCode || iCode > _vHashList[high-1].iHashCode)
  179. {
  180. iIndex = _vHashList[0].iIndex;
  181. return 0;
  182. }
  183. while (low < high - 1)
  184. {
  185. int mid = (low + high) / 2;
  186. if (_vHashList[mid].iHashCode > iCode)
  187. {
  188. high = mid;
  189. }
  190. else
  191. {
  192. low = mid;
  193. }
  194. }
  195. iIndex = _vHashList[low+1].iIndex;
  196. return 0;
  197. }
  198. int TC_ConsistentHashNew::getNodeName(const string & key, string & sNode)
  199. {
  200. if(_ptrHashAlg.get() == NULL || _vHashList.size() == 0)
  201. {
  202. sNode = "";
  203. return -1;
  204. }
  205. vector<char> data = TC_MD5::md5bin(key);
  206. int32_t iCode = _ptrHashAlg->hash(data.data(), data.size());
  207. return getNodeName(iCode, sNode);
  208. }
  209. int TC_ConsistentHashNew::getNodeName(int32_t hashcode, string & sNode)
  210. {
  211. if(_ptrHashAlg.get() == NULL || _vHashList.size() == 0)
  212. {
  213. sNode = "";
  214. return -1;
  215. }
  216. // 只保留32位
  217. int32_t iCode = (hashcode & 0xFFFFFFFFL);
  218. int low = 0;
  219. int high = (int)_vHashList.size();
  220. if(iCode <= _vHashList[0].iHashCode || iCode > _vHashList[high-1].iHashCode)
  221. {
  222. sNode = _vHashList[0].sNode;
  223. return 0;
  224. }
  225. while (low < high - 1)
  226. {
  227. int mid = (low + high) / 2;
  228. if (_vHashList[mid].iHashCode > iCode)
  229. {
  230. high = mid;
  231. }
  232. else
  233. {
  234. low = mid;
  235. }
  236. }
  237. sNode = _vHashList[low+1].sNode;
  238. return 0;
  239. }
  240. }