/* */ #include "BNode.h" #include #include #include "DHTBucket.h" #include "DHTNode.h" namespace aria2 { BNode::BNode(const SharedHandle& bucket): bucket_(bucket), up_(0), left_(0), right_(0) {} BNode::~BNode() { delete left_; delete right_; } void BNode::setLeft(BNode* left) { left_ = left; left_->up_ = this; } void BNode::setRight(BNode* right) { right_ = right; right_->up_ = this; } void BNode::setUp(BNode* up) { up_ = up; } void BNode::setBucket(const SharedHandle& bucket) { bucket_ = bucket; } bool BNode::isInRange(const unsigned char* key) const { if(bucket_.isNull()) { return left_->isInRange(key) || right_->isInRange(key); } else { return bucket_->isInRange(key); } } BNode* BNode::findBNodeFor(BNode* b, const unsigned char* key) { if(!b->isInRange(key)) { return 0; } while(1) { if(!b->getBucket().isNull()) { return b; } // we assume key fits in either left or right bucket range. if(b->getLeft()->isInRange(key)) { b = b->getLeft(); } else { b = b->getRight(); } } // for properly configured BNode tree, here is unreachable. return 0; } SharedHandle BNode::findBucketFor(BNode* b, const unsigned char* key) { BNode* bnode = findBNodeFor(b, key); if(bnode) { return bnode->getBucket(); } else { return SharedHandle(); } } void BNode::findClosestKNodes(std::vector >& nodes, BNode* b, const unsigned char* key) { BNode* bnode = findBNodeFor(b, key); if(!bnode) { return; } { SharedHandle bucket = bnode->getBucket(); bucket->getGoodNodes(nodes); } if(nodes.size() >= DHTBucket::K) { return; } std::vector visited; visited.push_back(bnode); BNode* up = bnode->getUp(); if(!up) { return; } bool leftFirst = false; if(up->getLeft() == bnode) { leftFirst = true; } bnode = up; std::const_mem_fun_t firstfunc = leftFirst?std::mem_fun(&BNode::getLeft):std::mem_fun(&BNode::getRight); std::const_mem_fun_t secondfunc = leftFirst?std::mem_fun(&BNode::getRight):std::mem_fun(&BNode::getLeft); while(nodes.size() < DHTBucket::K) { if(!bnode->getLeft() && !bnode->getRight()) { bnode = bnode->getUp(); } else { if(std::find(visited.begin(), visited.end(), firstfunc(bnode)) == visited.end()) { bnode = firstfunc(bnode); } else if(std::find(visited.begin(), visited.end(), secondfunc(bnode)) == visited.end()) { bnode = secondfunc(bnode); } else { bnode = bnode->getUp(); } } if(!bnode) { break; } visited.push_back(bnode); { SharedHandle bucket = bnode->getBucket(); if(!bucket.isNull()) { std::vector > goodNodes; bucket->getGoodNodes(goodNodes); size_t r = DHTBucket::K-nodes.size(); if(goodNodes.size() <= r) { nodes.insert(nodes.end(), goodNodes.begin(), goodNodes.end()); } else { nodes.insert(nodes.end(), goodNodes.begin(), goodNodes.begin()+r); } } } } } void BNode::enumerateBucket(std::vector >& buckets, const BNode* b) { std::vector visited; visited.push_back(b); while(1) { if(!b) { break; } if(!b->getBucket().isNull()) { buckets.push_back(b->getBucket()); b = b->getUp(); } else if(std::find(visited.begin(), visited.end(), b->getLeft()) == visited.end()) { b = b->getLeft(); visited.push_back(b); } else if(std::find(visited.begin(), visited.end(), b->getRight()) == visited.end()) { b = b->getRight(); visited.push_back(b); } else { b = b->getUp(); } } return; } } // namespace aria2