DHTBucketTree.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2010 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "DHTBucketTree.h"
  36. #include <cstring>
  37. #include <algorithm>
  38. #include "DHTBucket.h"
  39. #include "DHTNode.h"
  40. namespace aria2 {
  41. DHTBucketTreeNode::DHTBucketTreeNode
  42. (DHTBucketTreeNode* left,
  43. DHTBucketTreeNode* right)
  44. : parent_(0),
  45. left_(left),
  46. right_(right)
  47. {
  48. resetRelation();
  49. }
  50. DHTBucketTreeNode::DHTBucketTreeNode(const SharedHandle<DHTBucket>& bucket)
  51. : parent_(0),
  52. left_(0),
  53. right_(0),
  54. bucket_(bucket)
  55. {
  56. memcpy(minId_, bucket_->getMinID(), DHT_ID_LENGTH);
  57. memcpy(maxId_, bucket_->getMaxID(), DHT_ID_LENGTH);
  58. }
  59. DHTBucketTreeNode::~DHTBucketTreeNode()
  60. {
  61. delete left_;
  62. delete right_;
  63. }
  64. void DHTBucketTreeNode::resetRelation()
  65. {
  66. left_->setParent(this);
  67. right_->setParent(this);
  68. memcpy(minId_, left_->getMinId(), DHT_ID_LENGTH);
  69. memcpy(maxId_, right_->getMaxId(), DHT_ID_LENGTH);
  70. }
  71. DHTBucketTreeNode* DHTBucketTreeNode::dig(const unsigned char* key)
  72. {
  73. if(leaf()) {
  74. return 0;
  75. }
  76. if(left_->isInRange(key)) {
  77. return left_;
  78. } else {
  79. return right_;
  80. }
  81. }
  82. bool DHTBucketTreeNode::isInRange(const unsigned char* key) const
  83. {
  84. return
  85. !std::lexicographical_compare(&key[0], &key[DHT_ID_LENGTH],
  86. &minId_[0], &minId_[DHT_ID_LENGTH]) &&
  87. !std::lexicographical_compare(&maxId_[0], &maxId_[DHT_ID_LENGTH],
  88. &key[0], &key[DHT_ID_LENGTH]);
  89. }
  90. void DHTBucketTreeNode::split()
  91. {
  92. SharedHandle<DHTBucket> leftBucket = bucket_->split();
  93. left_ = new DHTBucketTreeNode(leftBucket);
  94. right_ = new DHTBucketTreeNode(bucket_);
  95. bucket_.reset();
  96. resetRelation();
  97. }
  98. namespace dht {
  99. DHTBucketTreeNode* findTreeNodeFor
  100. (DHTBucketTreeNode* root, const unsigned char* key)
  101. {
  102. if(root->leaf()) {
  103. return root;
  104. } else {
  105. return findTreeNodeFor(root->dig(key), key);
  106. }
  107. }
  108. SharedHandle<DHTBucket> findBucketFor
  109. (DHTBucketTreeNode* root, const unsigned char* key)
  110. {
  111. DHTBucketTreeNode* leaf = findTreeNodeFor(root, key);
  112. return leaf->getBucket();
  113. }
  114. namespace {
  115. void collectNodes
  116. (std::vector<SharedHandle<DHTNode> >& nodes,
  117. const SharedHandle<DHTBucket>& bucket)
  118. {
  119. std::vector<SharedHandle<DHTNode> > goodNodes;
  120. bucket->getGoodNodes(goodNodes);
  121. nodes.insert(nodes.end(), goodNodes.begin(), goodNodes.end());
  122. }
  123. } // namespace
  124. namespace {
  125. void collectDownwardLeftFirst
  126. (std::vector<SharedHandle<DHTNode> >& nodes, DHTBucketTreeNode* tnode)
  127. {
  128. if(tnode->leaf()) {
  129. collectNodes(nodes, tnode->getBucket());
  130. } else {
  131. collectDownwardLeftFirst(nodes, tnode->getLeft());
  132. if(nodes.size() < DHTBucket::K) {
  133. collectDownwardLeftFirst(nodes, tnode->getRight());
  134. }
  135. }
  136. }
  137. } //namespace
  138. namespace {
  139. void collectDownwardRightFirst
  140. (std::vector<SharedHandle<DHTNode> >& nodes, DHTBucketTreeNode* tnode)
  141. {
  142. if(tnode->leaf()) {
  143. collectNodes(nodes, tnode->getBucket());
  144. } else {
  145. collectDownwardRightFirst(nodes, tnode->getRight());
  146. if(nodes.size() < DHTBucket::K) {
  147. collectDownwardRightFirst(nodes, tnode->getLeft());
  148. }
  149. }
  150. }
  151. } //namespace
  152. namespace {
  153. void collectUpward
  154. (std::vector<SharedHandle<DHTNode> >& nodes, DHTBucketTreeNode* from)
  155. {
  156. while(1) {
  157. DHTBucketTreeNode* parent = from->getParent();
  158. if(!parent) {
  159. break;
  160. }
  161. if(parent->getLeft() == from) {
  162. collectNodes(nodes, parent->getRight()->getBucket());
  163. } else {
  164. collectNodes(nodes, parent->getLeft()->getBucket());
  165. }
  166. from = parent;
  167. parent = parent->getParent();
  168. if(DHTBucket::K <= nodes.size()) {
  169. break;
  170. }
  171. }
  172. }
  173. } // namespace
  174. void findClosestKNodes
  175. (std::vector<SharedHandle<DHTNode> >& nodes,
  176. DHTBucketTreeNode* root,
  177. const unsigned char* key)
  178. {
  179. size_t nodesSize = nodes.size();
  180. if(DHTBucket::K <= nodesSize) {
  181. return;
  182. }
  183. DHTBucketTreeNode* leaf = findTreeNodeFor(root, key);
  184. if(leaf == root) {
  185. collectNodes(nodes, leaf->getBucket());
  186. } else {
  187. DHTBucketTreeNode* parent = leaf->getParent();
  188. if(parent->getLeft() == leaf) {
  189. collectDownwardLeftFirst(nodes, parent);
  190. } else {
  191. collectDownwardRightFirst(nodes, parent);
  192. }
  193. if(nodes.size() < DHTBucket::K) {
  194. collectUpward(nodes, parent);
  195. }
  196. }
  197. if(DHTBucket::K < nodes.size()) {
  198. nodes.erase(nodes.begin()+DHTBucket::K, nodes.end());
  199. }
  200. }
  201. void enumerateBucket
  202. (std::vector<SharedHandle<DHTBucket> >& buckets, DHTBucketTreeNode* root)
  203. {
  204. if(root->leaf()) {
  205. buckets.push_back(root->getBucket());
  206. } else {
  207. enumerateBucket(buckets, root->getLeft());
  208. enumerateBucket(buckets, root->getRight());
  209. }
  210. }
  211. } // namespace dht
  212. } // namespace aria2