#include <PastryLeafSet.h>
This module contains the LeafSet of the Pastry implementation.
Public Member Functions | |
void | initializeSet (uint numberOfLeaves, double repairTimeout, const NodeHandle &owner, Pastry *overlay) |
Initializes the leaf set. | |
virtual const NodeHandle & | getDestinationNode (const OverlayKey &destination) |
gets the final node according to the Pastry routing scheme. | |
virtual const NodeHandle & | findCloserNode (const OverlayKey &destination, bool optimize=false) |
try to find a node numerically closer to a given key with the same shared prefix as the current node in the leaf set. | |
void | findCloserNodes (const OverlayKey &destination, NodeVector *nodes) |
virtual const TransportAddress & | failedNode (const TransportAddress &failed) |
tells the leafset that a node has failed | |
virtual const TransportAddress & | repair (const PastryStateMessage *msg, const PastryStateMsgProximity &prox) |
attempt to repair the leafset using a received REPAIR message | |
bool | isClosestNode (const OverlayKey &destination) const |
checks if we are the closest node to key destination in the overlay | |
virtual void | dumpToStateMessage (PastryStateMessage *msg) const |
dump content of the set to a PastryStateMessage | |
bool | mergeNode (const NodeHandle &node, simtime_t prox) |
merge a node into LeafSet | |
const NodeHandle & | getPredecessor (void) const |
return predecessor node for visualizing | |
const NodeHandle & | getSuccessor (void) const |
return successor node for visualizing | |
bool | isValid (void) const |
check if LeafSet knows at least one node to the left and to the right | |
virtual void | dumpToVector (std::vector< TransportAddress > &affected) const |
appends all leaf set entries to a given vector of TransportAddresses, needed to find all Nodes to be notified after joining. | |
NodeVector * | createSiblingVector (const OverlayKey &key, int numSiblings) const |
PastryNewLeafsMessage * | getNewLeafsMessage (void) |
generates a newLeafs-message if LeafSet changed since last call to this method. | |
Private Member Functions | |
virtual void | earlyInit (void) |
initialize watches etc. | |
const NodeHandle & | getBiggestNode (void) const |
return the node with the biggest key in the LeafSet or NodeHandle::UNSPECIFIED_NODE if LeafSet is empty | |
const OverlayKey & | getBiggestKey (void) const |
return the biggest key in the LeafSet or OverlayKey::UNSPECIFIED_KEY if LeafSet is empty | |
const NodeHandle & | getSmallestNode (void) const |
return the node with the smallest key in the LeafSet or NodeHandle::UNSPECIFIED_NODE if LeafSet is empty | |
const OverlayKey & | getSmallestKey (void) const |
return the smallest key in the LeafSet or OverlayKey::UNSPECIFIED_KEY if LeafSet is empty | |
bool | isLeft (const OverlayKey &key) const |
test if a given key should be placed on the left or on the right side of the leaf set | |
void | insertLeaf (std::vector< NodeHandle >::iterator &it, const NodeHandle &node) |
insert a leaf at a given position | |
bool | balanceLeafSet () |
Private Attributes | |
uint | numberOfLeaves |
double | repairTimeout |
Pastry * | overlay |
pointer to the main pastry module | |
std::vector< NodeHandle > | leaves |
std::vector < NodeHandle > ::iterator | smaller |
std::vector < NodeHandle > ::iterator | bigger |
std::map < TransportAddress, PLSRepairData > | awaitingRepair |
bool | newLeafs |
bool | isFull |
bool | wasFull |
void PastryLeafSet::initializeSet | ( | uint | numberOfLeaves, | |
double | repairTimeout, | |||
const NodeHandle & | owner, | |||
Pastry * | overlay | |||
) |
Initializes the leaf set.
This should be called on startup
numberOfLeaves | Pastry configuration parameter | |
repairTimeout | Pastry configuration parameter | |
owner | the node this table belongs to | |
overlay | pointer to the pastry main module |
00048 { 00049 if (numberOfLeaves % 2) throw "numberOfLeaves must be even."; 00050 00051 this->owner = owner; 00052 this->numberOfLeaves = numberOfLeaves; 00053 this->repairTimeout = repairTimeout; 00054 this->overlay = overlay; 00055 00056 if (!leaves.empty()) leaves.clear(); 00057 00058 // fill Set with unspecified node handles 00059 for (uint i = numberOfLeaves; i>0; i--) 00060 leaves.push_back(NodeHandle::UNSPECIFIED_NODE); 00061 00062 // initialize iterators to mark the beginning of bigger/smaller keys 00063 // in the set 00064 bigger = leaves.begin() + (numberOfLeaves >> 1); 00065 smaller = bigger - 1; 00066 00067 // reset repair marker: 00068 if (!awaitingRepair.empty()) awaitingRepair.clear(); 00069 00070 newLeafs = false; 00071 isFull = false; 00072 wasFull = false; 00073 }
const NodeHandle & PastryLeafSet::getDestinationNode | ( | const OverlayKey & | destination | ) | [virtual] |
gets the final node according to the Pastry routing scheme.
destination | the destination key |
Reimplemented from PastryStateObject.
00092 { 00093 std::vector<NodeHandle>::const_iterator i; 00094 const OverlayKey* smallest; 00095 const OverlayKey* biggest; 00096 const NodeHandle* ret = &NodeHandle::UNSPECIFIED_NODE; 00097 00098 // check whether destination is inside leafSet: 00099 00100 smallest = &(getSmallestKey()); 00101 biggest = &(getBiggestKey()); 00102 if (smallest->isUnspecified()) smallest = &(owner.key); 00103 if (biggest->isUnspecified()) biggest = &(owner.key); 00104 00105 if (!destination.isBetweenLR(*smallest, *biggest)) return *ret; 00106 00107 // find the closest node: 00108 00109 for (i = leaves.begin(); i != leaves.end(); i++) { 00110 if (i->isUnspecified()) continue; 00111 00112 // note for next line: 00113 // * dereferences iterator, & gets address of element. 00114 if (isCloser(*i, destination, *ret)) ret = &(*i); 00115 } 00116 00117 return *ret; 00118 }
const NodeHandle & PastryLeafSet::findCloserNode | ( | const OverlayKey & | destination, | |
bool | optimize = false | |||
) | [virtual] |
try to find a node numerically closer to a given key with the same shared prefix as the current node in the leaf set.
this method is to be called, when a regular next hop couldn't be found or wasn't reachable.
destination | the destination key | |
optimize | if set, check all nodes and return the best/closest one |
Implements PastryStateObject.
00393 { 00394 std::vector<NodeHandle>::const_iterator i; 00395 const NodeHandle* ret = &NodeHandle::UNSPECIFIED_NODE; 00396 00397 // this will only be called after getDestinationNode() returned 00398 // NodeHandle::UNSPECIFIED_NODE, so a closer Node can only be the biggest 00399 // or the smallest node in the LeafSet. 00400 00401 const NodeHandle& smallest = getSmallestNode(); 00402 const NodeHandle& biggest = getBiggestNode(); 00403 00404 if ((!smallest.isUnspecified()) && 00405 (specialCloserCondition(smallest, destination, *ret))) { 00406 if (optimize) ret = &smallest; 00407 else return smallest; 00408 } 00409 00410 if ((!biggest.isUnspecified()) && 00411 (specialCloserCondition(biggest, destination, *ret))) { 00412 if (optimize) ret = &biggest; 00413 else return biggest; 00414 } 00415 00416 return *ret; 00417 }
void PastryLeafSet::findCloserNodes | ( | const OverlayKey & | destination, | |
NodeVector * | nodes | |||
) | [virtual] |
Implements PastryStateObject.
00382 { 00383 std::vector<NodeHandle>::const_iterator it; 00384 00385 for (it = leaves.begin(); it != leaves.end(); it++) 00386 if (!it->isUnspecified()) 00387 nodes->add(*it); 00388 00389 }
const TransportAddress & PastryLeafSet::failedNode | ( | const TransportAddress & | failed | ) | [virtual] |
tells the leafset that a node has failed
failed | the failed node |
Implements PastryStateObject.
00421 { 00422 std::vector<NodeHandle>::iterator i; 00423 const TransportAddress* ask; 00424 bool left = true; 00425 00426 // search failed node in leafset: 00427 for (i = leaves.begin(); i != leaves.end(); i++) { 00428 if (i == bigger) left = false; 00429 if ((! i->isUnspecified()) && (i->ip == failed.ip)) break; 00430 } 00431 00432 // failed node not in leafset: 00433 if (i == leaves.end()) return TransportAddress::UNSPECIFIED_NODE; 00434 00435 overlay->callUpdate(*i, false); 00436 00437 // remove failed node: 00438 leaves.erase(i); 00439 newLeafs = true; 00440 00441 wasFull = isFull; 00442 isFull = false; 00443 00444 // insert UNSPECIFIED_NODE at front or back and return correct node 00445 // to ask for repair: 00446 if (left) { 00447 leaves.insert(leaves.begin(), NodeHandle::UNSPECIFIED_NODE); 00448 bigger = leaves.begin() + (numberOfLeaves >> 1); 00449 smaller = bigger - 1; 00450 ask = static_cast<const TransportAddress*>(&(getSmallestNode())); 00451 } else { 00452 leaves.push_back(NodeHandle::UNSPECIFIED_NODE); 00453 bigger = leaves.begin() + (numberOfLeaves >> 1); 00454 smaller = bigger - 1; 00455 ask = static_cast<const TransportAddress*>(&(getBiggestNode())); 00456 } 00457 00458 balanceLeafSet(); 00459 00460 if (! ask->isUnspecified()) 00461 awaitingRepair[*ask] = PLSRepairData(simTime(), left); 00462 00463 return *ask; 00464 }
const TransportAddress & PastryLeafSet::repair | ( | const PastryStateMessage * | msg, | |
const PastryStateMsgProximity & | prox | |||
) | [virtual] |
attempt to repair the leafset using a received REPAIR message
msg | the state message of type REPAIR | |
prox | record of proximity values matching the state message |
Reimplemented from PastryStateObject.
00468 { 00469 std::map<TransportAddress, PLSRepairData>::iterator it; 00470 const TransportAddress* ask; 00471 bool left; 00472 00473 simtime_t now = simTime(); 00474 00475 // first eliminate outdated entries in awaitingRepair: 00476 for (it = awaitingRepair.begin(); it != awaitingRepair.end();) { 00477 if (it->second.ts < (now - repairTimeout)) { 00478 //std::cout << "awaitingRepair.erase" << std::endl; 00479 awaitingRepair.erase(it++); 00480 } 00481 else it++; 00482 } 00483 00484 // don't expect any more repair messages: 00485 if (awaitingRepair.empty()) return TransportAddress::UNSPECIFIED_NODE; 00486 00487 // look for source node in our list: 00488 if ( (it = awaitingRepair.find(msg->getSender())) == awaitingRepair.end() ) 00489 return TransportAddress::UNSPECIFIED_NODE; 00490 00491 // which side of the LeafSet is affected: 00492 left = it->second.left; 00493 00494 // remove source node from list: 00495 awaitingRepair.erase(it); 00496 00497 // merge info from repair message: 00498 if (mergeState(msg, prox) || isFull || !wasFull) { 00499 EV << "Pastry: LeafSet repair was successful." << endl; 00500 return TransportAddress::UNSPECIFIED_NODE; 00501 } else { 00502 // repair did not succeed, try again: 00503 ask = &( left ? getSmallestNode() : getBiggestNode() ); 00504 if (ask->isUnspecified() || *ask == msg->getSender()) { 00505 EV << "Pastry: LeafSet giving up repair attempt." << endl; 00506 return TransportAddress::UNSPECIFIED_NODE; 00507 } else { 00508 awaitingRepair[*ask] = PLSRepairData(simTime(), left); 00509 } 00510 //assert(*ask != msg->getSender()); 00511 return *ask; 00512 } 00513 }
bool PastryLeafSet::isClosestNode | ( | const OverlayKey & | destination | ) | const |
checks if we are the closest node to key destination in the overlay
destination | the key to check |
00121 { 00122 // check for simple cases first 00123 if (owner.key == destination) { 00124 return true; 00125 } 00126 00127 if (bigger->isUnspecified() && smaller->isUnspecified()) { 00128 return true; 00129 } 00130 00131 // check if the next bigger or smaller node in the set is closer 00132 // than own node 00133 bool biggerIsCloser = false; 00134 bool smallerIsCloser = false; 00135 00136 if (! bigger->isUnspecified()) { 00137 biggerIsCloser = isCloser(*bigger, destination); 00138 } 00139 if (! smaller->isUnspecified()) { 00140 smallerIsCloser = isCloser(*smaller, destination); 00141 } 00142 00143 // return true if both are not closer 00144 return ((!biggerIsCloser) && (!smallerIsCloser)); 00145 }
void PastryLeafSet::dumpToStateMessage | ( | PastryStateMessage * | msg | ) | const [virtual] |
dump content of the set to a PastryStateMessage
msg | the PastryStateMessage to be filled with entries |
Implements PastryStateObject.
00148 { 00149 uint i = 0; 00150 std::vector<NodeHandle>::const_iterator it; 00151 00152 msg->setLeafSetArraySize(numberOfLeaves); 00153 for (it = leaves.begin(); it != leaves.end(); it++) 00154 msg->setLeafSet(i++, *it); 00155 }
bool PastryLeafSet::mergeNode | ( | const NodeHandle & | node, | |
simtime_t | prox | |||
) | [virtual] |
merge a node into LeafSet
node | the node to merge | |
prox | the proximity value of the node |
Implements PastryStateObject.
00203 { 00204 std::vector<NodeHandle>::iterator it, it_left, it_right; 00205 const OverlayKey* last_left = &(owner.key); 00206 const OverlayKey* last_right = &(owner.key); 00207 00208 it_left = smaller; 00209 it_right = bigger; 00210 00211 // avoid duplicates 00212 for (it = leaves.begin(); it != leaves.end(); ++it) { 00213 if (it->isUnspecified()) { 00214 isFull = false; 00215 continue; 00216 } 00217 if (it->key == node.key) return false; 00218 } 00219 00220 // look for correct position in left and right half of leafset 00221 while (true) { 00222 if(!isFull) { 00223 // both sides free 00224 if(it_left->key.isUnspecified() && 00225 it_right->key.isUnspecified()) { 00226 insertLeaf(it_left, node); 00227 return true; 00228 } 00229 if (it_left->key.isUnspecified() && 00230 !node.key.isBetween(*last_right, it_right->key)) { 00231 // end of smaller entries found 00232 insertLeaf(it_left, node); 00233 return true; 00234 } 00235 if (it_right->key.isUnspecified() && 00236 !node.key.isBetween(it_left->key, *last_left)) { 00237 // end of bigger entries found 00238 insertLeaf(it_right, node); 00239 return true; 00240 } 00241 } 00242 // left side 00243 if (node.key.isBetween(it_left->key, *last_left)) { 00244 // found correct position for inserting the new entry between 00245 // existing ones 00246 insertLeaf(it_left, node); 00247 return true; 00248 } 00249 // right side 00250 if (node.key.isBetween(*last_right, it_right->key)) { 00251 // found correct position for inserting the new entry between 00252 // existing ones 00253 insertLeaf(it_right, node); 00254 return true; 00255 } 00256 00257 last_right = &(it_right->key); 00258 ++it_right; 00259 00260 if (it_right == leaves.end()) break; 00261 00262 last_left = &(it_left->key); 00263 --it_left; 00264 } 00265 return false; 00266 }
const NodeHandle & PastryLeafSet::getPredecessor | ( | void | ) | const |
const NodeHandle & PastryLeafSet::getSuccessor | ( | void | ) | const |
bool PastryLeafSet::isValid | ( | void | ) | const |
void PastryLeafSet::dumpToVector | ( | std::vector< TransportAddress > & | affected | ) | const [virtual] |
appends all leaf set entries to a given vector of TransportAddresses, needed to find all Nodes to be notified after joining.
affected | the vector to fill with leaf set entries |
Implements PastryStateObject.
00348 { 00349 std::vector<NodeHandle>::const_iterator it; 00350 00351 for (it = leaves.begin(); it != leaves.end(); it++) 00352 if (!it->isUnspecified()) 00353 affected.push_back(*it); 00354 }
NodeVector * PastryLeafSet::createSiblingVector | ( | const OverlayKey & | key, | |
int | numSiblings | |||
) | const |
00159 { 00160 std::vector<NodeHandle>::const_iterator it; 00161 00162 // create temporary comparator 00163 KeyDistanceComparator<KeyRingMetric>* comp = 00164 new KeyDistanceComparator<KeyRingMetric>( key ); 00165 00166 // create result vector 00167 NodeVector* result = new NodeVector( numSiblings, comp ); 00168 00169 result->add(owner); 00170 00171 for (it = leaves.begin(); it != leaves.end(); it++) { 00172 if (!it->isUnspecified()) { 00173 result->add(*it); 00174 } 00175 } 00176 00177 delete comp; 00178 00179 // cout << "Siblings for key: " << key << " num: " << numSiblings << endl << *result << endl; 00180 00181 if (!isValid()) { 00182 return result; 00183 } 00184 00185 // if the leafset is not full, we could have a very small network 00186 // => return true (FIXME hack) 00187 if (leaves.front().isUnspecified() || leaves.back().isUnspecified()) { 00188 return result; 00189 } 00190 00191 if ( (result->contains(getBiggestKey())) 00192 || (result->contains(getSmallestKey()))) { 00193 00194 // cout << "PastryLeafSet: Don't know all siblings..." << endl; 00195 delete result; 00196 return NULL; 00197 } 00198 00199 return result; 00200 }
PastryNewLeafsMessage * PastryLeafSet::getNewLeafsMessage | ( | void | ) |
generates a newLeafs-message if LeafSet changed since last call to this method.
00516 { 00517 std::vector<NodeHandle>::const_iterator it; 00518 PastryNewLeafsMessage* msg; 00519 uint i = 0; 00520 00521 if (! newLeafs) return NULL; 00522 newLeafs = false; 00523 00524 msg = new PastryNewLeafsMessage("PastryNewLeafs"); 00525 00526 msg->setLeafsArraySize(numberOfLeaves); 00527 for (it = leaves.begin(); it != leaves.end(); it++) 00528 msg->setLeafs(i++, *it); 00529 00530 msg->setLength(PASTRYNEWLEAFS_L(msg)); 00531 return msg; 00532 }
void PastryLeafSet::earlyInit | ( | void | ) | [private, virtual] |
const NodeHandle & PastryLeafSet::getBiggestNode | ( | void | ) | const [private] |
return the node with the biggest key in the LeafSet or NodeHandle::UNSPECIFIED_NODE if LeafSet is empty
00369 { 00370 std::vector<NodeHandle>::const_iterator i = leaves.end()-1; 00371 while ((i->isUnspecified()) && (i != bigger)) i--; 00372 return *i; 00373 }
const OverlayKey & PastryLeafSet::getBiggestKey | ( | void | ) | const [private] |
return the biggest key in the LeafSet or OverlayKey::UNSPECIFIED_KEY if LeafSet is empty
00376 { 00377 return getBiggestNode().key; 00378 }
const NodeHandle & PastryLeafSet::getSmallestNode | ( | void | ) | const [private] |
return the node with the smallest key in the LeafSet or NodeHandle::UNSPECIFIED_NODE if LeafSet is empty
00357 { 00358 std::vector<NodeHandle>::const_iterator i = leaves.begin(); 00359 while ((i->isUnspecified()) && (i != smaller)) i++; 00360 return *i; 00361 }
const OverlayKey & PastryLeafSet::getSmallestKey | ( | void | ) | const [private] |
return the smallest key in the LeafSet or OverlayKey::UNSPECIFIED_KEY if LeafSet is empty
00364 { 00365 return getSmallestNode().key; 00366 }
bool PastryLeafSet::isLeft | ( | const OverlayKey & | key | ) | const [private] |
test if a given key should be placed on the left or on the right side of the leaf set
key | key to test |
void PastryLeafSet::insertLeaf | ( | std::vector< NodeHandle >::iterator & | it, | |
const NodeHandle & | node | |||
) | [private] |
insert a leaf at a given position
it | iterator where to insert the new leaf | |
node | NodeHandle of new leaf |
00270 { 00271 bool issmaller = (it <= smaller); 00272 if (issmaller) { 00273 if (!leaves.front().isUnspecified()) { 00274 overlay->callUpdate(leaves.front(), false); 00275 } 00276 overlay->callUpdate(node, true); 00277 00278 leaves.insert(++it, node); 00279 NodeHandle& temp = leaves.front(); 00280 if (!temp.isUnspecified() && leaves.back().isUnspecified()) { 00281 leaves.back() = temp; 00282 } 00283 leaves.erase(leaves.begin()); 00284 00285 00286 } else { 00287 if (!leaves.back().isUnspecified()) { 00288 overlay->callUpdate(leaves.back(), false); 00289 } 00290 overlay->callUpdate(node, true); 00291 00292 leaves.insert(it, node); 00293 NodeHandle& temp = leaves.back(); 00294 if (!temp.isUnspecified() && leaves.front().isUnspecified()) { 00295 leaves.front() = temp; 00296 } 00297 leaves.pop_back(); 00298 } 00299 00300 if (!leaves.front().isUnspecified() && 00301 !leaves.back().isUnspecified()) { 00302 isFull = true; 00303 } else isFull = false; 00304 00305 newLeafs = true; 00306 bigger = leaves.begin() + (numberOfLeaves >> 1); 00307 smaller = bigger - 1; 00308 00309 // ensure balance in leafset 00310 if (!isFull) { 00311 balanceLeafSet(); 00312 } 00313 }
bool PastryLeafSet::balanceLeafSet | ( | ) | [private] |
00316 { 00317 if (isFull || 00318 (!leaves.front().isUnspecified() && 00319 !(leaves.end() - 2)->isUnspecified()) || 00320 (!leaves.back().isUnspecified() && 00321 !(leaves.begin() + 1)->isUnspecified())) 00322 return false; 00323 00324 std::vector<NodeHandle>::iterator it_left, it_right; 00325 00326 for (it_left = smaller, it_right = bigger; 00327 it_right != leaves.end(); --it_left, ++it_right) { 00328 if (it_left->isUnspecified()) { 00329 if (it_right->isUnspecified() || 00330 (it_right + 1) == leaves.end() || 00331 (it_right + 1)->isUnspecified()) return false; 00332 *it_left = *(it_right + 1); 00333 *(it_right + 1) = NodeHandle::UNSPECIFIED_NODE; 00334 return true; 00335 } else if (it_right->isUnspecified()) { 00336 00337 if (it_left == leaves.begin() || 00338 (it_left - 1)->isUnspecified()) return false; 00339 *it_right = *(it_left - 1); 00340 *(it_left - 1) = NodeHandle::UNSPECIFIED_NODE; 00341 return true; 00342 } 00343 } 00344 return false; // should not happen 00345 }
uint PastryLeafSet::numberOfLeaves [private] |
double PastryLeafSet::repairTimeout [private] |
Pastry* PastryLeafSet::overlay [private] |
pointer to the main pastry module
std::vector<NodeHandle> PastryLeafSet::leaves [private] |
std::vector<NodeHandle>::iterator PastryLeafSet::smaller [private] |
std::vector<NodeHandle>::iterator PastryLeafSet::bigger [private] |
std::map<TransportAddress, PLSRepairData> PastryLeafSet::awaitingRepair [private] |
bool PastryLeafSet::newLeafs [private] |
bool PastryLeafSet::isFull [private] |
bool PastryLeafSet::wasFull [private] |