/* Split a bucket into two equal parts. */ bool RoutingTable::split(const RoutingTable::iterator& b) { InfoHash new_id; try { new_id = middle(b); } catch (const std::out_of_range& e) { return false; } // Insert new bucket insert(std::next(b), Bucket {b->af, new_id, b->time}); // Re-assign nodes std::list<Sp<Node>> nodes {}; nodes.splice(nodes.begin(), b->nodes); while (!nodes.empty()) { auto n = nodes.begin(); auto b = findBucket((*n)->id); if (b == end()) nodes.erase(n); else b->nodes.splice(b->nodes.begin(), nodes, n); } return true; }
bool RoutingTable::onNewNode(const Sp<Node>& node, int confirm, const time_point& now, const InfoHash& myid, net::NetworkEngine& ne) { auto b = findBucket(node->id); if (b == end()) return false; if (confirm == 2) b->time = now; for (auto& n : b->nodes) { if (n == node) return false; } bool mybucket = contains(b, myid); if (mybucket) { grow_time = now; //scheduler.edit(nextNodesConfirmation, now); } if (b->nodes.size() >= TARGET_NODES) { /* Try to get rid of an expired node. */ for (auto& n : b->nodes) if (n->isExpired()) { n = node; return true; } /* Bucket full. Ping a dubious node */ bool dubious = false; for (auto& n : b->nodes) { /* Pick the first dubious node that we haven't pinged in the last 9 seconds. This gives nodes the time to reply, but tends to concentrate on the same nodes, so that we get rid of bad nodes fast. */ if (not n->isGood(now)) { dubious = true; if (not n->isPendingMessage()) { //DHT_LOG.d(n->id, "[node %s] sending ping to dubious node", n->toString().c_str()); ne.sendPing(n, nullptr, nullptr); break; } } } if ((mybucket || (is_client and depth(b) < 6)) && (!dubious || size() == 1)) { //DHT_LOG.d("Splitting from depth %u", depth(b)); b->sendCachedPing(ne); split(b); return onNewNode(node, confirm, now, myid, ne); } /* No space for this node. Cache it away for later. */ if (confirm or not b->cached) b->cached = node; } else { /* Create a new node. */ b->nodes.emplace_front(node); } return true; }
bool exists(const int p, const prevPlanes &pp) const { if (p>0 && (pp[0] < min0 || pp[0] > ranges->max(0))) return false; if (p>1 && (pp[1] < min1 || pp[1] > ranges->max(1))) return false; ColorVal rmin, rmax; ColorVal v=pp[p]; ranges->snap(p,pp,rmin,rmax,v); if (v != pp[p]) return false; // bucket empty because of original range constraints const ColorBucket b = findBucket(p,pp); //if (b.min > b.max) return false; if (b.snapColor_slow(pp[p]) != pp[p]) return false; return true; }
void NodeTree::removeNode( NodeSPtr address ) { if (!address.get()) throw std::invalid_argument("Node is not set"); std::lock_guard<std::mutex> lock(mutex); BucketContainer::const_iterator bucket_it = findBucket(*address); BucketContainer::key_type bucket = *bucket_it; assert(bucket->inBounds(address)); bucket->remove(*address); }
/** Updates the value in a certain date range.<br> * This will create a new bucket if required. */ DECLARE_EXPORT void Calendar::setValue(Date start, Date end, const double v) { CalendarBucket* x = static_cast<CalendarBucket*>(findBucket(start)); if (x && x->getStart() == start && x->getEnd() <= end) // We can update an existing bucket: it has the same start date // and ends before the new effective period ends. x->setEnd(end); else { // Creating a new bucket x = new CalendarBucket(); x->setStart(start); x->setEnd(end); x->setCalendar(this); } x->setValue(v); x->setPriority(lowestPriority()-1); }
// This method will not return the exact 8 closest, but fetches the nodes from // three buckets, the right one and the 2 adjacent ones. // In case we have a lot of nodes it will be precise, if not then we can't // expect to have a precise result anyway. const std::list<NodeSPtr> NodeTree::getClosestNodes( const NodeData& data) const { std::list<NodeSPtr> nodes; std::lock_guard<std::mutex> lock(mutex); std::set<NodeSPtr,std::function<bool(const NodeSPtr&,const NodeSPtr&)> > knownNodes( [&data]( const NodeSPtr& x, const NodeSPtr& y) { return (*x ^ data) <= (*y ^ data); }); // find bucket auto bucket_it = findBucket(data); // check if we have a perfect match const Bucket::const_iterator perfect_match = std::find_if( (*bucket_it)->cbegin(),(*bucket_it)->cend(), [&data](const NodeSPtr& a) { return *a == data; } ); if ( perfect_match != (*bucket_it)->cend() ) { nodes.push_back(*perfect_match); return nodes; } // in case a perfect match is not found the closest nodes are returned if (bucket_it != _buckets.begin()) --bucket_it; // put it at the left bucket for( int i = 0; i < 3 && bucket_it != _buckets.end(); ++i, ++bucket_it ) { for( auto it = (*bucket_it)->cbegin(); it != (*bucket_it)->cend(); ++it) { knownNodes.insert(*it); } } auto it = knownNodes.begin(); for( size_t __i = 0; __i < knownNodes.size() && __i < DHT_FIND_NODE_COUNT; ++__i, ++it ) { nodes.push_back(*it); } return nodes; }
std::vector<Sp<Node>> RoutingTable::findClosestNodes(const InfoHash id, time_point now, size_t count) const { std::vector<Sp<Node>> nodes; nodes.reserve(count); auto bucket = findBucket(id); if (bucket == end()) { return nodes; } auto sortedBucketInsert = [&](const Bucket &b) { for (auto n : b.nodes) { if (not n->isGood(now)) continue; auto here = std::find_if(nodes.begin(), nodes.end(), [&id,&n](Sp<Node> &node) { return id.xorCmp(n->id, node->id) < 0; } ); nodes.insert(here, n); } }; auto itn = bucket; auto itp = (bucket == begin()) ? end() : std::prev(bucket); while (nodes.size() < count && (itn != end() || itp != end())) { if (itn != end()) { sortedBucketInsert(*itn); itn = std::next(itn); } if (itp != end()) { sortedBucketInsert(*itp); itp = (itp == begin()) ? end() : std::prev(itp); } } // shrink to the count closest nodes. if (nodes.size() > count) { nodes.resize(count); } return nodes; }
bool NodeTree::addNode( NodeSPtr address ) { if (!address.get()) throw std::invalid_argument("Node is not set"); std::lock_guard<std::mutex> lock(mutex); BucketContainer::const_iterator bucket_it = findBucket(*address); assert(bucket_it != _buckets.end()); BucketContainer::key_type bucket = *bucket_it; assert(bucket->inBounds(address)); bool isAdded = bucket->add(address); if ( !isAdded && bucket->inBounds(_node) ) { MaybeBuckets maybe_split_buckets = split(bucket_it); // unsplittable, ignore it if (!maybe_split_buckets) return false; BucketSPtrPair& split_buckets = *maybe_split_buckets; assert(split_buckets.first->inBounds(address) || split_buckets.second->inBounds(address)); if (split_buckets.first->inBounds(address)) { isAdded = split_buckets.first->add(address); } else { assert(split_buckets.second->inBounds(address)); isAdded = split_buckets.second->add(address); } return isAdded; } return isAdded; }
void addColor(const std::vector<ColorVal> &pixel) { for (unsigned int p=0; p < pixel.size(); p++) { findBucket(p, pixel).addColor(pixel[p],max_per_colorbucket[p]); } }
const boost::optional<NodeSPtr> NodeTree::getNode( const NodeData& data ) const noexcept { return (*findBucket(data))->find(data); }