/* */ #include "BNode.h" #include "DHTBucket.h" #include "DHTNode.h" #include #include namespace aria2 { BNode::BNode(const SharedHandle& bucket): _bucket(bucket), _up(0), _left(0), _right(0) {} BNode::~BNode() { delete _left; delete _right; } SharedHandle BNode::getBucket() const { return _bucket; } BNode* BNode::getLeft() const { return _left; } BNode* BNode::getRight() const { return _right; } BNode* BNode::getUp() const { return _up; } 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::deque >& 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::deque 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::deque > 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::deque >& buckets, const BNode* b) { std::deque 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