00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00024 #include <NotifierConsts.h>
00025
00026 #include "NTree.h"
00027
00028 #include "GlobalNodeListAccess.h"
00029 #include <GlobalStatistics.h>
00030 #include <BootstrapList.h>
00031
00032 Define_Module(NTree);
00033
00034 using namespace std;
00035
00036
00037
00038
00039
00040
00041
00042
00043 void NTree::initializeOverlay(int stage)
00044 {
00045
00046
00047 if(stage != MIN_STAGE_OVERLAY) return;
00048
00049 maxChildren = par("maxChildren");
00050 if( maxChildren < 5 ){
00051 throw new cRuntimeError("To allow a proper quad-tree, maxChildren has to be 5 or bigger");
00052 }
00053 AOIWidth = par("AOIWidth");
00054
00055 thisNode.setKey(OverlayKey::random());
00056
00057 areaDimension = par("areaDimension");
00058 currentGroup = NULL;
00059
00060 joinTimer = new cMessage("joinTimer");
00061 pingTimer = new cMessage("pingTimer");
00062 pingInterval = par("pingInterval");
00063 scheduleAt( simTime() + pingInterval, pingTimer );
00064
00065
00066 changeState( INIT );
00067
00068
00069 joinsSend = 0;
00070 joinBytes = 0;
00071 joinTimeout = 0;
00072
00073 divideCount = 0;
00074 collapseCount = 0;
00075
00076 treeMaintenanceMessages = 0;
00077 treeMaintenanceBytes = 0;
00078
00079 movesSend = 0;
00080 moveBytes = 0;
00081
00082 WATCH_MAP( ntreeNodes );
00083 WATCH_LIST( groups );
00084 }
00085
00086 bool NTree::handleRpcCall(BaseCallMessage* msg)
00087 {
00088 if( state == SHUTDOWN ){
00089 return false;
00090 }
00091
00092 RPC_SWITCH_START( msg )
00093 RPC_DELEGATE( NTreeJoin, handleJoinCall );
00094 RPC_DELEGATE( NTreePing, handlePingCall );
00095 RPC_DELEGATE( NTreeDivide, handleDivideCall );
00096 RPC_SWITCH_END( )
00097
00098 return RPC_HANDLED;
00099
00100 }
00101
00102 void NTree::handleRpcResponse(BaseResponseMessage *msg,
00103 cPolymorphic* context, int rpcId,
00104 simtime_t rtt)
00105 {
00106 if( state == SHUTDOWN ){
00107 return;
00108 }
00109 RPC_SWITCH_START(msg);
00110 RPC_ON_RESPONSE( NTreeJoin ) {
00111 EV << "[NTree::handleRpcResponse() @ " << thisNode.getIp()
00112 << " (" << thisNode.getKey().toString(16) << ")]\n"
00113 << " Received a NTreeJoin RPC Response: id=" << rpcId << "\n"
00114 << " msg=" << *_NTreeJoinResponse << " rtt=" << rtt
00115 << endl;
00116 handleJoinResponse( _NTreeJoinResponse );
00117 break;
00118 }
00119 RPC_ON_RESPONSE( NTreePing ) {
00120 EV << "[NTree::handleRpcResponse() @ " << thisNode.getIp()
00121 << " (" << thisNode.getKey().toString(16) << ")]\n"
00122 << " Received a NTreePing RPC Response: id=" << rpcId << "\n"
00123 << " msg=" << *_NTreePingResponse << " rtt=" << rtt
00124 << endl;
00125 handlePingResponse( _NTreePingResponse, dynamic_cast<NTreePingContext*>(context) );
00126 break;
00127 }
00128 RPC_ON_RESPONSE( NTreeDivide ) {
00129 EV << "[NTree::handleRpcResponse() @ " << thisNode.getIp()
00130 << " (" << thisNode.getKey().toString(16) << ")]\n"
00131 << " Received a NTreeDivide RPC Response: id=" << rpcId << "\n"
00132 << " msg=" << *_NTreeDivideResponse << " rtt=" << rtt
00133 << endl;
00134 handleDivideResponse( _NTreeDivideResponse, check_and_cast<NTreeGroupDivideContextPtr*>(context)->ptr );
00135 delete context;
00136 break;
00137 }
00138 RPC_SWITCH_END( );
00139 }
00140
00141 void NTree::handleRpcTimeout (BaseCallMessage *msg,
00142 const TransportAddress &dest,
00143 cPolymorphic* context, int rpcId,
00144 const OverlayKey &destKey)
00145 {
00146 if( state == SHUTDOWN ){
00147 return;
00148 }
00149 RPC_SWITCH_START(msg)
00150 RPC_ON_CALL( NTreePing ) {
00151 EV << "[NTree::handleRpcTimeout() @ " << thisNode.getIp()
00152 << " (" << thisNode.getKey().toString(16) << ")]\n"
00153 << " Ping RPC Call timed out: id=" << rpcId << "\n"
00154 << " msg=" << *_NTreePingCall
00155 << " oldNode=" << dest
00156 << endl;
00157 handlePingCallTimeout( _NTreePingCall, dest, dynamic_cast<NTreePingContext*>(context) );
00158 break;
00159 }
00160 RPC_ON_CALL( NTreeJoin ) {
00161 EV << "[NTree::handleRpcTimeout() @ " << thisNode.getIp()
00162 << " (" << thisNode.getKey().toString(16) << ")]\n"
00163 << " Join RPC Call timed out: id=" << rpcId << "\n"
00164 << " msg=" << *_NTreeJoinCall
00165 << " oldNode=" << dest
00166 << endl;
00167 handleJoinCallTimeout( _NTreeJoinCall, dest );
00168 break;
00169 }
00170 RPC_ON_CALL( NTreeDivide ) {
00171 EV << "[NTree::handleRpcTimeout() @ " << thisNode.getIp()
00172 << " (" << thisNode.getKey().toString(16) << ")]\n"
00173 << " Ping RPC Call timed out: id=" << rpcId << "\n"
00174 << " msg=" << *_NTreeDivideCall
00175 << " oldNode=" << dest
00176 << endl;
00177 handleDivideCallTimeout( _NTreeDivideCall, dest, check_and_cast<NTreeGroupDivideContextPtr*>(context)->ptr );
00178 delete context;
00179 break;
00180 }
00181 RPC_SWITCH_END( )
00182
00183 }
00184
00185 void NTree::handleUDPMessage(BaseOverlayMessage* msg)
00186 {
00187 if( state == SHUTDOWN ){
00188 delete msg;
00189 return;
00190 }
00191 if( NTreeMoveMessage* moveMsg = dynamic_cast<NTreeMoveMessage*>(msg) ){
00192 handleMoveMessage( moveMsg );
00193 delete moveMsg;
00194 } else if( NTreeGroupAddMessage* addMsg = dynamic_cast<NTreeGroupAddMessage*>(msg) ){
00195 handleAddMessage( addMsg );
00196 delete addMsg;
00197 } else if( NTreeGroupDeleteMessage* deleteMsg = dynamic_cast<NTreeGroupDeleteMessage*>(msg) ){
00198 handleDeleteMessage( deleteMsg );
00199 delete deleteMsg;
00200 } else if( NTreeLeaveMessage* leaveMsg = dynamic_cast<NTreeLeaveMessage*>(msg) ){
00201 handleLeaveMessage( leaveMsg );
00202 delete leaveMsg;
00203 } else if( NTreeCollapseMessage* collapseMsg = dynamic_cast<NTreeCollapseMessage*>(msg) ){
00204 handleCollapseMessage( collapseMsg );
00205 delete collapseMsg;
00206 } else if( NTreeReplaceNodeMessage* replaceMsg = dynamic_cast<NTreeReplaceNodeMessage*>(msg) ){
00207 handleReplaceMessage( replaceMsg );
00208 delete replaceMsg;
00209 } else if( NTreeTakeOverMessage* takeMsg = dynamic_cast<NTreeTakeOverMessage*>(msg) ){
00210 handleTakeOverMessage( takeMsg );
00211 delete takeMsg;
00212 }
00213 }
00214
00215 void NTree::handleTimerEvent(cMessage* msg)
00216 {
00217 if( state == SHUTDOWN ){
00218 return;
00219 }
00220 if( msg == joinTimer ) {
00221
00222 CompReadyMessage* msg = new CompReadyMessage("fake READY");
00223 msg->setReady(true);
00224 msg->setComp(getThisCompType());
00225 send( msg, "appOut");
00226
00227 GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
00228 gameMsg->setCommand(RESIZE_AOI);
00229 gameMsg->setAOIsize(AOIWidth);
00230 send( gameMsg, "appOut");
00231 } else if( msg == pingTimer ){
00232 pingNodes();
00233 checkParentTimeout();
00234 scheduleAt( simTime() + pingInterval, pingTimer );
00235 }
00236 }
00237
00238 void NTree::handleAppMessage(cMessage* msg)
00239 {
00240 if( GameAPIPositionMessage *posMsg = dynamic_cast<GameAPIPositionMessage*>(msg) ) {
00241 if( state == READY ) {
00242 handleMove( posMsg );
00243 } else if ( state == JOINING ) {
00244
00245 CompReadyMessage* msg = new CompReadyMessage("Overlay not READY!");
00246 msg->setReady(false);
00247 msg->setComp(getThisCompType());
00248 send( msg, "appOut");
00249 } else if ( state == INIT ) {
00250
00251 TransportAddress bootstrapNode = bootstrapList->getBootstrapNode();
00252 if( bootstrapNode.isUnspecified() ){
00253 NTreeGroup grp(Vector2D(areaDimension/2,areaDimension/2), areaDimension);
00254 grp.leader = thisNode;
00255 grp.members.insert(thisNode);
00256 groups.push_front(grp);
00257
00258 NTreeScope initialScope(Vector2D(areaDimension/2,areaDimension/2), areaDimension);
00259 NTreeNode root(initialScope);
00260 root.group = &groups.front();
00261 ntreeNodes.insert(make_pair(initialScope,root));
00262 changeState( READY );
00263 } else {
00264
00265 changeState( JOINING );
00266 position = posMsg->getPosition();
00267 NTreeJoinCall* joinMsg = new NTreeJoinCall("Login");
00268 joinMsg->setPosition( position );
00269 joinMsg->setBitLength( NTREEJOINCALL_L(joinMsg) );
00270 sendUdpRpcCall( bootstrapNode, joinMsg );
00271 }
00272
00273 setBootstrapedIcon();
00274
00275 }
00276 delete msg;
00277 }
00278 }
00279
00280
00281 void NTree::handleJoinCall( NTreeJoinCall* joinCall )
00282 {
00283
00284 std::list<NTreeGroup>::iterator grpIt = findGroup( joinCall->getPosition() );
00285 if( grpIt != groups.end() ) {
00286
00287 if( grpIt->leader == thisNode ) {
00288
00289 NTreeGroupAddMessage* grpAdd = new NTreeGroupAddMessage("New group member");
00290 grpAdd->setPlayer( joinCall->getSrcNode() );
00291 grpAdd->setOrigin( grpIt->scope.origin );
00292 grpAdd->setBitLength( NTREEADD_L(grpAdd) );
00293
00294 RECORD_STATS(
00295 treeMaintenanceMessages += grpIt->members.size();
00296 treeMaintenanceBytes += grpIt->members.size()*grpAdd->getByteLength();
00297 );
00298 sendToGroup( *grpIt, grpAdd );
00299
00300 grpIt->members.insert( joinCall->getSrcNode() );
00301
00302 NTreeJoinResponse* joinResp = new NTreeJoinResponse("Join ACK");
00303 joinResp->setOrigin( grpIt->scope.origin );
00304 joinResp->setSize( grpIt->scope.size );
00305 joinResp->setMembersArraySize( grpIt->members.size() );
00306 unsigned int i = 0;
00307 for( std::set<NodeHandle>::iterator it = grpIt->members.begin(); it != grpIt->members.end(); ++it ) {
00308 joinResp->setMembers( i, *it );
00309 ++i;
00310 }
00311 joinResp->setBitLength( NTREEJOINRESPONSE_L(joinResp) );
00312 sendRpcResponse( joinCall, joinResp );
00313
00314
00315 if( grpIt->members.size() > maxChildren && !grpIt->dividePending && grpIt->scope.size > 2*AOIWidth ){
00316 EV << "[NTree::handleJoinCall() @ " << thisNode.getIp()
00317 << " (" << thisNode.getKey().toString(16) << ")]\n"
00318 << " Group got too big. Trying to divide group\n";
00319 grpIt->dividePending = true;
00320 std::map<NTreeScope,NTreeNode>::iterator nit = ntreeNodes.find( grpIt->scope );
00321 if( nit == ntreeNodes.end() ){
00322 EV << " Host is leader of a group, but not NTreeNode of that group.\n"
00323 << " This should not happen. Dropping group\n";
00324 if( currentGroup == &(*grpIt) ){
00325 currentGroup = NULL;
00326 }
00327 groups.erase( grpIt );
00328 return;
00329 }
00330 EV << " Sending divide calls\n";
00331 NTreeDivideCall* divideCall = new NTreeDivideCall("Divide Group");
00332 divideCall->setOrigin( nit->second.scope.origin );
00333 divideCall->setSize( nit->second.scope.size );
00334 divideCall->setBitLength( NTREEDIVIDECALL_L(divideCall) );
00335
00336 NTreeGroupDivideContext* divideContext = new NTreeGroupDivideContext;
00337 divideContext->nodeScope = nit->second.scope;
00338
00339
00340
00341 unsigned int numMembers = grpIt->members.size();
00342 unsigned int numbers[numMembers];
00343 for( i = 0; i < numMembers; ++i ) numbers[i] = i;
00344 unsigned int upperbound = numMembers;
00345 for (i = 0; i < 4; ++i)
00346 {
00347 upperbound--;
00348 unsigned int index = intuniform(0, upperbound);
00349 std::set<NodeHandle>::iterator newChild = grpIt->members.begin();
00350 std::advance( newChild, numbers[index] );
00351
00352 if( *newChild == thisNode ) {
00353 --i;
00354 } else {
00355 NTreeDivideCall* msg = divideCall->dup();
00356 msg->setQuadrant( i );
00357 EV << " ==> " << (TransportAddress) *newChild << "\n";
00358 NTreeGroupDivideContextPtr* contextPtr = new NTreeGroupDivideContextPtr;
00359 contextPtr->ptr = divideContext;
00360 sendUdpRpcCall( *newChild, msg, contextPtr);
00361 RECORD_STATS(
00362 treeMaintenanceMessages++;
00363 treeMaintenanceBytes += msg->getByteLength();
00364 );
00365 }
00366
00367 swap(numbers[index], numbers[upperbound]);
00368 }
00369 delete divideCall;
00370 }
00371
00372 } else {
00373
00374 sendMessageToUDP( grpIt->leader, joinCall );
00375 }
00376 return;
00377 }
00378
00379 routeViaNTree( joinCall->getPosition(), joinCall, true );
00380 }
00381
00382 void NTree::handleJoinResponse( NTreeJoinResponse* joinResp )
00383 {
00384 EV << "[NTree::handleJoinResponse() @ " << thisNode.getIp()
00385 << " (" << thisNode.getKey().toString(16) << ")]\n"
00386 << " JOIN ACK for group " << joinResp->getOrigin()
00387 << "-" << joinResp->getSize() << "\n";
00388 std::list<NTreeGroup>::iterator git = findGroup( joinResp->getOrigin(), joinResp->getSize() );
00389
00390 NTreeScope groupScope( joinResp->getOrigin(), joinResp->getSize() );
00391 for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
00392 if( it != git && (it->isInScope( groupScope.origin ) || groupScope.contains( it->scope.origin ) )){
00393
00394 EV << " Conflicting group found. Ignoring JOIN ACK\n";
00395
00396
00397
00398 if( state != READY ){
00399 changeState( READY );
00400 }
00401 return;
00402 }
00403 }
00404
00405
00406 if( git != groups.end() ){
00407 if( git->leader != thisNode ) {
00408 EV << " Group already known. Refreshing member list\n";
00409 git->members.clear();
00410 } else {
00411
00412 EV << " Group already known; and I'm leader of that group. Ignoring ACK\n";
00413 return;
00414 }
00415
00416 } else {
00417
00418 NTreeGroup grp(joinResp->getOrigin(), joinResp->getSize());
00419 groups.push_front(grp);
00420 git = groups.begin();
00421 }
00422
00423
00424 git->leader = joinResp->getSrcNode();
00425 for( unsigned int i = 0; i < joinResp->getMembersArraySize(); ++i ){
00426 git->members.insert( joinResp->getMembers(i) );
00427 }
00428
00429
00430 if( state != READY ){
00431 changeState( READY );
00432 }
00433 }
00434
00435
00436 void NTree::handleJoinCallTimeout( NTreeJoinCall* joinCall, const TransportAddress& oldNode)
00437 {
00438 if( state != READY ){
00439 EV << " Overlay not ready. Trying to re-join overlay\n";
00440 changeState( INIT );
00441 }
00442 joinTimeout++;
00443
00444 }
00445
00446 void NTree::handleMove( GameAPIPositionMessage* posMsg )
00447 {
00448 position = posMsg->getPosition();
00449 NTreeMoveMessage* moveMsg = new NTreeMoveMessage("MOVE");
00450 moveMsg->setPlayer( thisNode );
00451 moveMsg->setPosition( position );
00452 moveMsg->setBitLength( NTREEMOVE_L(moveMsg) );
00453
00454
00455 if( currentGroup ){
00456 sendToGroup( *currentGroup, moveMsg, true);
00457 RECORD_STATS(
00458 movesSend += currentGroup->members.size();
00459 moveBytes += moveMsg->getByteLength() * currentGroup->members.size();
00460 globalStatistics->addStdDev( "NTree: Area size", currentGroup->scope.size );
00461 );
00462 }
00463
00464
00465 if( !currentGroup || !currentGroup->isInScope( position ) ){
00466 std::list<NTreeGroup>::iterator it = findGroup( position );
00467 if( it != groups.end() ) {
00468 sendToGroup( *it, moveMsg, true );
00469 currentGroup = &(*it);
00470 RECORD_STATS(
00471 movesSend += currentGroup->members.size();
00472 moveBytes += moveMsg->getByteLength() * currentGroup->members.size();
00473 );
00474 } else {
00475 EV << "[NTree::handleMove() @ " << thisNode.getIp()
00476 << " (" << thisNode.getKey().toString(16) << ")]\n"
00477 << "WARNING: no group for new position. Some updates may get lost!\n";
00478 joinGroup( position );
00479 }
00480 }
00481
00482 delete moveMsg;
00483
00484 if( currentGroup ){
00485
00486 NTreeScope& scope = currentGroup->scope;
00487 NTreeScope area(Vector2D(areaDimension/2.0,areaDimension/2.0),areaDimension);
00488 Vector2D aoiRight(AOIWidth/2.0, 0);
00489 Vector2D aoiTop(0, AOIWidth/2.0);
00490
00491 Vector2D groupRight(scope.size/2.0 +1, 0);
00492 Vector2D groupTop(0, scope.size/2.0 +1);
00493
00494 if(area.contains( position + aoiRight )) joinGroup(position + aoiRight);
00495 if(area.contains( position - aoiRight )) joinGroup(position - aoiRight);
00496 if(area.contains( position + aoiTop )) joinGroup(position + aoiTop);
00497 if(area.contains( position - aoiTop )) joinGroup(position - aoiTop);
00498 if(area.contains( position + (aoiRight + aoiTop)/sqrt(2))) joinGroup(position + (aoiRight + aoiTop)/sqrt(2));
00499 if(area.contains( position + (aoiRight - aoiTop)/sqrt(2))) joinGroup(position + (aoiRight - aoiTop)/sqrt(2));
00500 if(area.contains( position - (aoiRight + aoiTop)/sqrt(2))) joinGroup(position - (aoiRight + aoiTop)/sqrt(2));
00501 if(area.contains( position - (aoiRight - aoiTop)/sqrt(2))) joinGroup(position - (aoiRight - aoiTop)/sqrt(2));
00502
00503 if( scope.contains( position + aoiRight )) leaveGroup( scope.origin + groupRight );
00504 if( scope.contains( position - aoiRight )) leaveGroup( scope.origin - groupRight );
00505 if( scope.contains( position + aoiTop )) leaveGroup( scope.origin + groupTop );
00506 if( scope.contains( position - aoiTop )) leaveGroup( scope.origin - groupTop );
00507 if( scope.contains( position + (aoiRight + aoiTop)/sqrt(2))) leaveGroup( scope.origin + groupRight + groupTop);
00508 if( scope.contains( position + (aoiRight - aoiTop)/sqrt(2))) leaveGroup( scope.origin + groupRight - groupTop);
00509 if( scope.contains( position - (aoiRight + aoiTop)/sqrt(2))) leaveGroup( scope.origin - groupRight + groupTop);
00510 if( scope.contains( position - (aoiRight - aoiTop)/sqrt(2))) leaveGroup( scope.origin - groupRight - groupTop);
00511 }
00512 }
00513
00514 void NTree::handleAddMessage( NTreeGroupAddMessage* addMsg )
00515 {
00516 std::list<NTreeGroup>::iterator it = findGroup( addMsg->getOrigin() );
00517 if( it == groups.end() ){
00518 EV << "[NTree::handleAddMessage() @ " << thisNode.getIp()
00519 << " (" << thisNode.getKey().toString(16) << ")]\n"
00520 << " Received add message for unknown group scope=" << addMsg->getOrigin() << "\n";
00521 return;
00522 }
00523 EV << "[NTree::handleAddMessage() @ " << thisNode.getIp()
00524 << " (" << thisNode.getKey().toString(16) << ")]\n"
00525 << " Received add message for group scope=" << addMsg->getOrigin() << "\n"
00526 << " Player=" << addMsg->getPlayer().getKey().toString(16) << "\n";
00527 it->members.insert( addMsg->getPlayer() );
00528 }
00529
00530 void NTree::handleDeleteMessage( NTreeGroupDeleteMessage* deleteMsg )
00531 {
00532 std::list<NTreeGroup>::iterator it = findGroup( deleteMsg->getOrigin(), deleteMsg->getSize() );
00533
00534 if( it == groups.end() ) return;
00535
00536
00537
00538 ntreeNodes.erase( it->scope );
00539
00540
00541 if( it->isInScope(position) ){
00542 NTreeJoinCall* joinCall = new NTreeJoinCall("JOIN GROUP");
00543 joinCall->setPosition(position);
00544 joinCall->setBitLength( NTREEJOINCALL_L(joinCall) );
00545 RECORD_STATS(
00546 joinsSend++;
00547 joinBytes += joinCall->getByteLength();
00548 );
00549 sendMessage( deleteMsg->getNewChild( it->scope.origin.getQuadrant( position )), joinCall);
00550 }
00551
00552
00553 if( currentGroup == &(*it) ) currentGroup = NULL;
00554 groups.erase( it );
00555 }
00556
00557 void NTree::handleLeaveMessage( NTreeLeaveMessage* leaveMsg )
00558 {
00559 std::list<NTreeGroup>::iterator it = findGroup( leaveMsg->getPosition() );
00560 if( it != groups.end() ){
00561 it->members.erase( leaveMsg->getPlayer() );
00562 }
00563
00564
00565 for( it = groups.begin(); it != groups.end(); ++it ){
00566 if( it->members.find( leaveMsg->getPlayer() ) != it->members.end() ){
00567 return;
00568 }
00569 }
00570
00571
00572 GameAPIListMessage* gameMsg = new GameAPIListMessage("NEIGHBOR_DELETE");
00573 gameMsg->setCommand(NEIGHBOR_UPDATE);
00574 gameMsg->setRemoveNeighborArraySize(1);
00575 gameMsg->setRemoveNeighbor(0, leaveMsg->getPlayer() );
00576 send(gameMsg, "appOut");
00577 }
00578
00579 void NTree::handleCollapseMessage( NTreeCollapseMessage* collapseMsg )
00580 {
00581 EV << "[NTree::handleCollapseMessage() @ " << thisNode.getIp()
00582 << " (" << thisNode.getKey().toString(16) << ")]\n"
00583 << " Got collapse message for group " << collapseMsg->getOrigin() << "\n";
00584
00585 std::map<NTreeScope,NTreeNode>::iterator it = findNTreeNode( collapseMsg->getOrigin(), collapseMsg->getSize() );
00586 if( it != ntreeNodes.end() ){
00587 if( it->second.group ){
00588 EV << " Informing group\n";
00589
00590 NTreeGroupDeleteMessage* delMsg = new NTreeGroupDeleteMessage("Delete Group due to collapse");
00591 delMsg->setOrigin( collapseMsg->getOrigin() );
00592 delMsg->setSize( collapseMsg->getSize() );
00593 for( unsigned int i = 0; i < 4; ++i ){
00594 delMsg->setNewChild( i, collapseMsg->getPlayer() );
00595 }
00596 delMsg->setBitLength( NTREEDELETE_L(delMsg) );
00597 RECORD_STATS(
00598 treeMaintenanceMessages += it->second.group->members.size();
00599 treeMaintenanceBytes += it->second.group->members.size()*delMsg->getByteLength();
00600 );
00601 sendToGroup( *it->second.group, delMsg );
00602
00603 if( currentGroup && *currentGroup == *it->second.group ){
00604 currentGroup = NULL;
00605 }
00606 groups.remove( *it->second.group );
00607
00608 } else {
00609
00610 EV << " Informing children\n";
00611 for( unsigned int i = 0; i < 4; ++i ){
00612 EV << " ==> " << it->second.children[i] << "\n";
00613 collapseMsg->setOrigin( it->second.scope.getSubScope(i).origin );
00614 collapseMsg->setSize( it->second.scope.getSubScope(i).size );
00615 RECORD_STATS(
00616 treeMaintenanceMessages++;
00617 treeMaintenanceBytes += collapseMsg->getByteLength();
00618 );
00619 sendMessage( it->second.children[i], collapseMsg->dup() );
00620 }
00621 }
00622
00623 ntreeNodes.erase( it );
00624 }
00625 }
00626
00627 void NTree::handleMoveMessage( NTreeMoveMessage* moveMsg )
00628 {
00629
00630 GameAPIListMessage* gameMsg = new GameAPIListMessage("NEIGHBOR_UPDATE");
00631 gameMsg->setCommand(NEIGHBOR_UPDATE);
00632
00633 gameMsg->setAddNeighborArraySize(1);
00634 gameMsg->setNeighborPositionArraySize(1);
00635
00636 gameMsg->setAddNeighbor(0, moveMsg->getPlayer() );
00637 gameMsg->setNeighborPosition(0, moveMsg->getPosition() );
00638 send(gameMsg, "appOut");
00639 RECORD_STATS(
00640 globalStatistics->addStdDev(
00641 "NTree: MoveDelay",
00642 SIMTIME_DBL(simTime()) - SIMTIME_DBL(moveMsg->getCreationTime())
00643 );
00644 );
00645 }
00646
00647 void NTree::handlePingCall( NTreePingCall* pingCall )
00648 {
00649 if( NTreeNodePingCall* nodePing = dynamic_cast<NTreeNodePingCall*>(pingCall) ){
00650
00651
00652 NTreeScope origScope( pingCall->getOrigin(), pingCall->getSize() );
00653 NTreeScope myScope;
00654 myScope = origScope.getSubScope( nodePing->getQuadrant() );
00655
00656 std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( myScope );
00657 if( it != ntreeNodes.end() ){
00658
00659
00660 if( nodePing->getParent().isUnspecified() ) it->second.parentIsRoot = true;
00661 for( unsigned int i = 0; i < 4; ++i ){
00662 it->second.siblings[i] = nodePing->getSiblings(i);
00663 }
00664 it->second.lastPing = simTime();
00665
00666
00667 NTreeNodePingResponse* nodeResp = new NTreeNodePingResponse("PONG");
00668 if( it->second.group ){
00669
00670 nodeResp->setAggChildCount( it->second.group->members.size() );
00671 nodeResp->setMembersArraySize( it->second.group->members.size() );
00672 unsigned int i = 0;
00673 for( std::set<NodeHandle>::iterator childIt = it->second.group->members.begin();
00674 childIt != it->second.group->members.end(); ++childIt ){
00675
00676 nodeResp->setMembers( i++, *childIt );
00677 }
00678 } else {
00679
00680 unsigned int aggChildCount = 0;
00681 nodeResp->setMembersArraySize( 4 );
00682 for( unsigned int i = 0; i < 4; ++i ){
00683 aggChildCount += it->second.aggChildCount[i];
00684 nodeResp->setMembers( i, it->second.children[i] );
00685 }
00686 nodeResp->setAggChildCount( aggChildCount );
00687 }
00688 nodeResp->setBitLength( NTREENODEPINGRESPONSE_L(nodeResp) );
00689 sendRpcResponse( nodePing, nodeResp );
00690 } else {
00691 delete pingCall;
00692 }
00693 } else {
00694
00695 std::list<NTreeGroup>::iterator it = findGroup( pingCall->getOrigin(), pingCall->getSize() );
00696 if( it != groups.end() ){
00697
00698
00699 }
00700
00701 NTreePingResponse* pingResp = new NTreePingResponse("PONG");
00702 pingResp->setBitLength( NTREEPINGRESPONSE_L(pingResp) );
00703 sendRpcResponse( pingCall, pingResp );
00704 }
00705
00706 }
00707
00708 void NTree::handlePingResponse( NTreePingResponse* pingResp, NTreePingContext* context )
00709 {
00710 if( NTreeNodePingResponse* nodePing = dynamic_cast<NTreeNodePingResponse*>(pingResp) ){
00711 std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( context->nodeScope );
00712 if( it != ntreeNodes.end() && !it->second.group){
00713
00714 if( it->second.children[context->quadrant] == nodePing->getSrcNode() ){
00715 it->second.aggChildCount[context->quadrant] = nodePing->getAggChildCount();
00716 it->second.childChildren[context->quadrant].clear();
00717 for( unsigned int ii = 0; ii < nodePing->getMembersArraySize(); ++ii ){
00718 it->second.childChildren[context->quadrant].insert( nodePing->getMembers( ii ) );
00719 }
00720
00721
00722 unsigned int aggChildCount = 0;
00723 for( unsigned int i = 0; i < 4; ++i ){
00724 if( !it->second.aggChildCount[i] ) {
00725 aggChildCount = maxChildren;
00726 break;
00727 }
00728
00729 aggChildCount += it->second.aggChildCount[i];
00730 }
00731 if( aggChildCount*2 < maxChildren ){
00732 collapseTree( it );
00733 }
00734 } else {
00735
00736
00737 }
00738 }
00739 }
00740 delete context;
00741 }
00742
00743 void NTree::handlePingCallTimeout( NTreePingCall* pingCall, const TransportAddress& oldNode, NTreePingContext* context )
00744 {
00745 if( context ){
00746 std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( context->nodeScope );
00747 if( it != ntreeNodes.end() && !it->second.group){
00748
00749 if( oldNode == it->second.children[context->quadrant ]){
00750 NTreeReplaceNodeMessage* replaceMsg = new NTreeReplaceNodeMessage("Replace failed node");
00751 replaceMsg->setOrigin( context->nodeScope.getSubScope(context->quadrant).origin );
00752 replaceMsg->setSize( context->nodeScope.getSubScope(context->quadrant).size );
00753 replaceMsg->setParent( thisNode );
00754 replaceMsg->setOldNode( oldNode );
00755 replaceMsg->setIsLeaf( it->second.childChildren[context->quadrant].size() != 4 ||
00756 (it->second.childChildren[context->quadrant].size() == it->second.aggChildCount[context->quadrant]) );
00757 replaceMsg->setChildrenArraySize( it->second.childChildren[context->quadrant].size() );
00758 unsigned int i = 0;
00759 for( std::set<NodeHandle>::iterator cit = it->second.childChildren[context->quadrant].begin();
00760 cit != it->second.childChildren[context->quadrant].end(); ++cit ){
00761 replaceMsg->setChildren( i, *cit );
00762 ++i;
00763 }
00764 replaceMsg->setBitLength( NTREEREPLACE_L(replaceMsg) );
00765
00766
00767 std::set<NodeHandle> invalidNodes;
00768 invalidNodes.insert( thisNode );
00769 if( !it->second.parent.isUnspecified() ){
00770 invalidNodes.insert( it->second.parent );
00771 }
00772 if( !replaceMsg->getIsLeaf() ) {
00773 for( unsigned int i = 0; i < 4; ++i ){
00774 invalidNodes.insert( replaceMsg->getChildren(i) );
00775 }
00776 }
00777 const NodeHandle& dest = getRandomNode( invalidNodes );
00778 RECORD_STATS(
00779 treeMaintenanceMessages++;
00780 treeMaintenanceBytes += replaceMsg->getByteLength();
00781 );
00782 sendMessage(dest, replaceMsg );
00783 }
00784 }
00785 delete context;
00786 } else {
00787
00788 for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
00789
00790 for( std::set<NodeHandle>::iterator mit = it->members.begin(); mit != it->members.end(); ++mit ){
00791 if( oldNode == *mit ){
00792 NTreeLeaveMessage* leaveMsg = new NTreeLeaveMessage("Failed member");
00793 leaveMsg->setPlayer( *mit );
00794 leaveMsg->setPosition( it->scope.origin );
00795 leaveMsg->setBitLength( NTREELEAVE_L(leaveMsg) );
00796 sendToGroup( *it, leaveMsg );
00797
00798 it->members.erase( mit );
00799 break;
00800 }
00801 }
00802 }
00803 }
00804 }
00805
00806 void NTree::handleDivideCall( NTreeDivideCall* divideCall )
00807 {
00808 EV << "[NTree::handleDivide() @ " << thisNode.getIp()
00809 << " (" << thisNode.getKey().toString(16) << ")]\n";
00810 std::list<NTreeGroup>::iterator it = findGroup( divideCall->getOrigin(), divideCall->getSize() );
00811 if( it == groups.end() ){
00812 EV << " Received divide message for unknown group scope=" << divideCall->getOrigin() << "\n";
00813 } else {
00814 EV << " Divide group " << it->scope << "\n";
00815 }
00816
00817
00818 NTreeScope oldScope(divideCall->getOrigin(), divideCall->getSize() );
00819 NTreeScope newScope = oldScope.getSubScope( divideCall->getQuadrant() );
00820
00821
00822
00823
00824 ntreeNodes.erase( oldScope );
00825
00826
00827 NTreeGroup newGroup(newScope);
00828 newGroup.leader = thisNode;
00829 newGroup.members.insert(thisNode);
00830 groups.push_front(newGroup);
00831 if( it != groups.end() ){
00832 if( currentGroup == &(*it) ){
00833 currentGroup = &groups.front();
00834 }
00835 groups.erase( it );
00836 }
00837
00838
00839 NTreeNode newNode(newScope);
00840 newNode.parent = divideCall->getSrcNode();
00841 newNode.group = &groups.front();
00842 ntreeNodes.insert(make_pair(newScope,newNode));
00843
00844
00845 NTreeDivideResponse* divideResp = new NTreeDivideResponse("Divide ACK");
00846 divideResp->setQuadrant( divideCall->getQuadrant() );
00847 divideResp->setBitLength( NTREEDIVIDERESPONSE_L(divideResp) );
00848 RECORD_STATS(
00849 treeMaintenanceMessages++;
00850 treeMaintenanceBytes += divideResp->getByteLength();
00851 );
00852 sendRpcResponse( divideCall, divideResp );
00853 }
00854
00855 void NTree::handleDivideResponse( NTreeDivideResponse* divideResp, NTreeGroupDivideContext* context )
00856 {
00857 context->newChild[ divideResp->getQuadrant() ] = divideResp->getSrcNode();
00858 for( unsigned int i = 0; i < 4; ++i ){
00859 if( context->newChild[i].isUnspecified() ){
00860
00861 return;
00862 }
00863 }
00864 divideNode( context );
00865 delete context;
00866 }
00867
00868 void NTree::handleDivideCallTimeout( NTreeDivideCall* divideCall, const TransportAddress& oldNode, NTreeGroupDivideContext* context )
00869 {
00870 std::set<NodeHandle> invalidNodes;
00871 invalidNodes.insert( thisNode );
00872 NodeHandle dest = getRandomNode( invalidNodes );
00873 RECORD_STATS(
00874 treeMaintenanceMessages++;
00875 treeMaintenanceBytes += divideCall->getByteLength();
00876 );
00877 NTreeGroupDivideContextPtr* contextPtr = new NTreeGroupDivideContextPtr;
00878 contextPtr->ptr = context;
00879 sendUdpRpcCall( dest, divideCall->dup(), contextPtr );
00880 }
00881
00882 void NTree::handleReplaceMessage( NTreeReplaceNodeMessage* replaceMsg )
00883 {
00884 EV << "[NTree::handleReplaceMessage() @ " << thisNode.getIp()
00885 << " (" << thisNode.getKey().toString(16) << ")]\n"
00886 << " Was asked to replace " << replaceMsg->getOldNode() << " for group " << replaceMsg->getOrigin() << "\n";
00887
00888 NTreeScope newScope( replaceMsg->getOrigin(), replaceMsg->getSize() );
00889 NTreeNode newNode(newScope);
00890 newNode.parent = replaceMsg->getParent();
00891
00892 if( replaceMsg->getIsLeaf() ){
00893 std::list<NTreeGroup>::iterator it = findGroup( replaceMsg->getOrigin(), replaceMsg->getSize() );
00894 if( it == groups.end() ){
00895 NTreeGroup newGrp( newScope );
00896
00897 groups.push_front( newGrp );
00898 it = groups.begin();
00899 }
00900 it->leader = thisNode;
00901 it->members.insert( thisNode );
00902 for( unsigned int i = 0; i < replaceMsg->getChildrenArraySize(); ++i ){
00903 it->members.insert( replaceMsg->getChildren(i) );
00904 }
00905 newNode.group = &(*it);
00906 } else {
00907 for( unsigned int i = 0; i < 4; ++i ){
00908 newNode.children[i] = replaceMsg->getChildren(i);
00909 }
00910 }
00911
00912 ntreeNodes.insert(make_pair(newScope,newNode));
00913
00914
00915 NTreeTakeOverMessage* takeMsg = new NTreeTakeOverMessage("I took over");
00916 takeMsg->setPlayer( thisNode );
00917 takeMsg->setOrigin( newScope.origin );
00918 takeMsg->setSize( newScope.size );
00919 takeMsg->setBitLength( NTREETAKEOVER_L(takeMsg) );
00920
00921 sendMessage( newNode.parent, takeMsg->dup() );
00922 sendMessage( replaceMsg->getOldNode(), takeMsg->dup() );
00923 RECORD_STATS(
00924 treeMaintenanceMessages+=2;
00925 treeMaintenanceBytes += 2*takeMsg->getByteLength();
00926 );
00927 if( newNode.group ){
00928 RECORD_STATS(
00929 treeMaintenanceMessages += newNode.group->members.size();
00930 treeMaintenanceBytes += newNode.group->members.size()*takeMsg->getByteLength();
00931 );
00932 sendToGroup( *newNode.group, takeMsg );
00933 } else {
00934 for( unsigned int i = 0; i < 4; ++i ){
00935 RECORD_STATS(
00936 treeMaintenanceMessages++;
00937 treeMaintenanceBytes += takeMsg->getByteLength();
00938 );
00939 sendMessage( newNode.children[i], takeMsg->dup() );
00940 }
00941 delete takeMsg;
00942 }
00943
00944 }
00945
00946 void NTree::handleTakeOverMessage( NTreeTakeOverMessage* takeMsg )
00947 {
00948
00949 std::list<NTreeGroup>::iterator git = findGroup( takeMsg->getOrigin(), takeMsg->getSize() );
00950 if( git != groups.end() ){
00951 git->leader = takeMsg->getPlayer();
00952 }
00953
00954
00955 NTreeScope takeScope( takeMsg->getOrigin(), takeMsg->getSize() );
00956 for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
00957
00958 if( takeMsg->getSize() == it->second.scope.size*2.0 ){
00959 for( unsigned int i = 0; i < 4; ++i ){
00960 if( takeScope.getSubScope(i) == it->first ){
00961 it->second.parent = takeMsg->getPlayer();
00962 }
00963 }
00964
00965 } else if( takeMsg->getSize()*2.0 == it->second.scope.size && !it->second.group ){
00966 for( unsigned int i = 0; i < 4; ++i ){
00967 if( it->first.getSubScope(i) == takeScope ){
00968 it->second.children[i] = takeMsg->getPlayer();
00969 }
00970 }
00971 } else if( it->second.scope == takeScope && takeMsg->getPlayer() != thisNode ){
00972
00973 ntreeNodes.erase( it );
00974 return;
00975 }
00976 }
00977
00978 }
00979
00980 void NTree::handleNodeGracefulLeaveNotification()
00981 {
00982 for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
00983
00984 NTreeReplaceNodeMessage* replaceMsg = new NTreeReplaceNodeMessage("Replace me");
00985 replaceMsg->setOrigin( it->second.scope.origin );
00986 replaceMsg->setSize( it->second.scope.size );
00987 replaceMsg->setParent( it->second.parent );
00988 if( it->second.group ){
00989 replaceMsg->setIsLeaf( true );
00990 replaceMsg->setChildrenArraySize( it->second.group->members.size() );
00991 unsigned int i = 0;
00992 for( std::set<NodeHandle>::iterator mit = it->second.group->members.begin(); mit != it->second.group->members.end(); ++mit ){
00993 replaceMsg->setChildren(i, *mit );
00994 ++i;
00995 }
00996 } else {
00997 replaceMsg->setIsLeaf( false );
00998 replaceMsg->setChildrenArraySize( 4 );
00999 for( unsigned int i = 0; i < 4; ++i ){
01000 replaceMsg->setChildren(i, it->second.children[i] );
01001 }
01002 }
01003 replaceMsg->setBitLength( NTREEREPLACE_L(replaceMsg) );
01004
01005
01006 std::set<NodeHandle> invalidNodes;
01007 invalidNodes.insert( thisNode );
01008 if( !it->second.parent.isUnspecified() ){
01009 invalidNodes.insert( it->second.parent );
01010 }
01011 if( !it->second.group ) {
01012 for( unsigned int i = 0; i < 4; ++i ){
01013 invalidNodes.insert( it->second.children[i] );
01014 }
01015 }
01016 const NodeHandle& dest = getRandomNode( invalidNodes );
01017
01018
01019 RECORD_STATS(
01020 treeMaintenanceMessages++;
01021 treeMaintenanceBytes += replaceMsg->getByteLength();
01022 );
01023 sendMessage( dest, replaceMsg );
01024 }
01025 while( groups.size() ){
01026
01027 leaveGroup( groups.begin()->scope.origin, true );
01028 }
01029
01030 ntreeNodes.clear();
01031
01032 currentGroup = NULL;
01033 changeState( SHUTDOWN );
01034 }
01035
01036 void NTree::pingNodes()
01037 {
01038 for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
01039
01040 unsigned int i = 0;
01041 if( it->second.group ){
01042
01043 NTreePingCall* pingCall = new NTreePingCall("PING");
01044 pingCall->setOrigin( it->second.scope.origin );
01045 pingCall->setSize( it->second.scope.size );
01046 pingCall->setParent( it->second.parent );
01047 pingCall->setBitLength( NTREEPINGCALL_L(pingCall) );
01048 sendToGroup( *it->second.group, pingCall );
01049 } else {
01050 NTreeNodePingCall* pingCall = new NTreeNodePingCall("PING");
01051 pingCall->setOrigin( it->second.scope.origin );
01052 pingCall->setSize( it->second.scope.size );
01053 pingCall->setParent( it->second.parent );
01054
01055 for( i = 0; i < 4; ++i ){
01056 pingCall->setSiblings(i, it->second.children[i] );
01057 }
01058 pingCall->setBitLength( NTREENODEPINGCALL_L(pingCall) );
01059
01060 for( i = 0; i < 4; ++i ){
01061 pingCall->setQuadrant( i );
01062 sendUdpRpcCall( it->second.children[i], pingCall->dup(), new NTreePingContext(it->second.scope, i) );
01063 }
01064 delete pingCall;
01065 }
01066
01067 }
01068 }
01069
01070 void NTree::checkParentTimeout()
01071 {
01072
01073 for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ){
01074 if( it->second.parent.isUnspecified() || (it->second.lastPing == 0) ) {
01075 ++it;
01076 continue;
01077 }
01078 if( it->second.lastPing + pingInterval + pingInterval < simTime() ){
01079
01080 EV << "[NTree::checkParentTimeout() @ " << thisNode.getIp()
01081 << " (" << thisNode.getKey().toString(16) << ")]\n"
01082 << " Parent for node" << it->second << " timed out\n";
01083
01084
01085 if( it->second.parentIsRoot ) {
01086 if( it->second.siblings[0] == thisNode ){
01087 EV << " Parent was root. Replacing him\n";
01088 NTreeReplaceNodeMessage* replaceMsg = new NTreeReplaceNodeMessage("Replace failed ROOT.");
01089 replaceMsg->setOrigin( Vector2D(areaDimension/2.0, areaDimension/2.0) );
01090 replaceMsg->setSize( areaDimension );
01091 replaceMsg->setIsLeaf( false );
01092 replaceMsg->setChildrenArraySize( 4 );
01093 replaceMsg->setOldNode( it->second.parent );
01094
01095 std::set<NodeHandle> invalidNodes;
01096 for( unsigned int i = 0; i < 4; ++i ){
01097 replaceMsg->setChildren( i, it->second.siblings[i] );
01098 invalidNodes.insert( replaceMsg->getChildren(i) );
01099 }
01100 replaceMsg->setBitLength( NTREEREPLACE_L(replaceMsg) );
01101
01102 const NodeHandle& dest = getRandomNode( invalidNodes );
01103 RECORD_STATS(
01104 treeMaintenanceMessages++;
01105 treeMaintenanceBytes += replaceMsg->getByteLength();
01106 );
01107 sendMessage(dest, replaceMsg );
01108 }
01109 ++it;
01110 } else {
01111
01112 if( it->second.group ){
01113 if( currentGroup && *currentGroup == *it->second.group ){
01114 currentGroup = NULL;
01115 }
01116 groups.remove( *it->second.group );
01117 }
01118 ntreeNodes.erase( it++ );
01119 }
01120 } else {
01121 ++it;
01122 }
01123 }
01124 }
01125
01126 void NTree::divideNode( NTreeGroupDivideContext* context )
01127 {
01128 EV << "[NTree::divideNode() @ " << thisNode.getIp()
01129 << " (" << thisNode.getKey().toString(16) << ")]\n"
01130 << " Trying to divide node " << context->nodeScope << "\n";
01131 std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.find( context->nodeScope );
01132 if( it == ntreeNodes.end() ){
01133 EV << " However, node is not in the list of known nodes\n";
01134 return;
01135 }
01136 if( !it->second.group ){
01137 EV << " However, node has no known group attached\n";
01138 return;
01139 }
01140
01141 NTreeGroupDeleteMessage* delMsg = new NTreeGroupDeleteMessage("Delete Group due to divide");
01142 delMsg->setOrigin( context->nodeScope.origin );
01143 delMsg->setSize( context->nodeScope.size );
01144 delMsg->setBitLength( NTREEDELETE_L(delMsg) );
01145 for( unsigned int i = 0; i < 4; ++i ){
01146 delMsg->setNewChild(i, context->newChild[i] );
01147 }
01148 RECORD_STATS(
01149 divideCount ++;
01150 treeMaintenanceMessages+= it->second.group->members.size();
01151 treeMaintenanceBytes += it->second.group->members.size()*delMsg->getByteLength();
01152 );
01153 sendToGroup( *it->second.group, delMsg );
01154
01155
01156 if( currentGroup && *currentGroup == *it->second.group ){
01157 currentGroup = NULL;
01158 }
01159 groups.remove( *it->second.group );
01160 it->second.group= NULL;
01161
01162
01163 for( unsigned int i = 0; i < 4; ++i ){
01164 it->second.children[i] = context->newChild[i];
01165 }
01166 }
01167
01168 void NTree::collapseTree( std::map<NTreeScope,NTreeNode>::iterator node )
01169 {
01170 EV << "[NTree::CollapseTree() @ " << thisNode.getIp()
01171 << " (" << thisNode.getKey().toString(16) << ")]\n"
01172 << " Collapsing tree" << node->second << "\n";
01173
01174 NTreeCollapseMessage* collapseMsg = new NTreeCollapseMessage("Collapse Tree");
01175 collapseMsg->setPlayer( thisNode );
01176 collapseMsg->setBitLength( NTREECOLLAPSE_L(collapseMsg) );
01177
01178 for( unsigned int i = 0; i < 4; ++i ){
01179 collapseMsg->setOrigin( node->second.scope.getSubScope(i).origin );
01180 collapseMsg->setSize( node->second.scope.getSubScope(i).size );
01181 RECORD_STATS(
01182 treeMaintenanceMessages++;
01183 treeMaintenanceBytes += collapseMsg->getByteLength();
01184 collapseCount ++;
01185 );
01186 sendMessage( node->second.children[i], collapseMsg->dup() );
01187
01188 node->second.children[i] = NodeHandle::UNSPECIFIED_NODE;
01189 node->second.childChildren[i].clear();
01190 node->second.aggChildCount[i] = 0;
01191 }
01192 delete collapseMsg;
01193
01194
01195 NTreeGroup newGroup( node->second.scope );
01196 newGroup.leader = thisNode;
01197 newGroup.members.insert( thisNode );
01198 groups.push_front( newGroup );
01199
01200 node->second.group = &(groups.front());
01201 }
01202
01203 void NTree::joinGroup( Vector2D position )
01204 {
01205 std::list<NTreeGroup>::iterator grpIt = findGroup( position );
01206 if( grpIt == groups.end() ) {
01207 NTreeJoinCall* joinCall = new NTreeJoinCall("JOIN GROUP");
01208 joinCall->setPosition( position );
01209 joinCall->setBitLength( NTREEJOINCALL_L(joinCall) );
01210 RECORD_STATS(
01211 joinsSend++;
01212 joinBytes += joinCall->getByteLength();
01213 );
01214 routeViaNTree( position, joinCall );
01215 }
01216 }
01217
01218 void NTree::leaveGroup( Vector2D position, bool force )
01219 {
01220 std::list<NTreeGroup>::iterator grpIt = findGroup( position );
01221
01222 if( grpIt != groups.end() && (grpIt->leader != thisNode || force) ) {
01223 NTreeLeaveMessage* leaveMsg = new NTreeLeaveMessage("Leave Group");
01224 leaveMsg->setPlayer( thisNode );
01225 leaveMsg->setPosition( position );
01226 leaveMsg->setBitLength( NTREELEAVE_L(leaveMsg) );
01227 sendToGroup( *grpIt, leaveMsg );
01228
01229 if( currentGroup == &(*grpIt) ){
01230 EV << "[NTree::leaveGroup() @ " << thisNode.getIp()
01231 << " (" << thisNode.getKey().toString(16) << ")]\n"
01232 << " WARNING: Leaving group " << position << "\n"
01233 << " This group is marked as current group!\n";
01234 currentGroup = NULL;
01235 }
01236 groups.erase( grpIt );
01237 }
01238 }
01239
01240 void NTree::routeViaNTree( const Vector2D& pos, cPacket* msg, bool forward )
01241 {
01242 NodeHandle dest;
01243 if( ntreeNodes.size() ) {
01244
01245 std::map<NTreeScope,NTreeNode>::iterator it = findNTreeNode( pos );
01246 if( it != ntreeNodes.end() ){
01247
01248 dest = it->second.getChildForPos( pos );
01249 } else {
01250
01251 dest = ntreeNodes.begin()->second.parent;
01252 }
01253 } else {
01254
01255 if( currentGroup ){
01256 dest = currentGroup->leader;
01257 } else if( groups.size() ){
01258 dest = groups.begin()->leader;
01259 } else {
01260 EV << "[NTree::routeViaNTree() @ " << thisNode.getIp()
01261 << " (" << thisNode.getKey().toString(16) << ")]\n"
01262 << " No ntree node and no group known. Dropping message & re-join!\n";
01263 changeState( INIT );
01264 delete msg;
01265 return;
01266 }
01267 }
01268 if( forward && dest == thisNode ) {
01269 EV << "[NTree::routeViaNTree() @ " << thisNode.getIp()
01270 << " (" << thisNode.getKey().toString(16) << ")]\n"
01271 << " Trying to route message " << msg << " to myself\n"
01272 << " This will result in a loop. Dropping message\n";
01273 delete msg;
01274 } else {
01275 sendMessage( dest, msg, forward );
01276 }
01277
01278 }
01279
01280 void NTree::sendToGroup( const NTreeGroup& grp, cPacket* msg, bool keepMsg )
01281 {
01282 EV << "[NTree::sendToGroup() @ " << thisNode.getIp()
01283 << " (" << thisNode.getKey().toString(16) << ")]\n"
01284 << " Send message " << msg << "\n"
01285 << " to group scope=" << grp.scope.origin << "\n";
01286 NTree::sendToGroup( grp.members, msg, keepMsg );
01287 }
01288
01289 void NTree::sendToGroup( const std::set<NodeHandle>& grp, cPacket* msg, bool keepMsg )
01290 {
01291 for( std::set<NodeHandle>::iterator it = grp.begin(); it != grp.end(); ++it ){
01292 sendMessage( *it, msg->dup(), false );
01293 }
01294 if (!keepMsg) delete msg;
01295 }
01296
01297
01298 void NTree::sendMessage(const TransportAddress& dest, cPacket* msg, bool forward)
01299 {
01300 if( dest.isUnspecified() ) {
01301 EV << "[NTree::sendMessage() @ " << thisNode.getIp()
01302 << " (" << thisNode.getKey().toString(16) << ")]\n"
01303 << " WARNING: Trying to send message " << msg
01304 << " to unspecified destination. Dropping packet!\n";
01305 delete msg;
01306 return;
01307 }
01308
01309
01310 BaseCallMessage* rpc = dynamic_cast<BaseCallMessage*>(msg);
01311 if( rpc && !forward ){
01312
01313
01314
01315
01316
01317 sendUdpRpcCall( TransportAddress(dest), rpc );
01318 } else {
01319 sendMessageToUDP( dest, msg );
01320 }
01321 }
01322
01323 void NTree::changeState( int newState ) {
01324 switch( newState ){
01325 case INIT:
01326 state = INIT;
01327 if( !joinTimer->isScheduled() ) {
01328 scheduleAt( ceil(simTime() + (simtime_t) par("joinDelay")), joinTimer );
01329 }
01330 break;
01331
01332 case READY:
01333 state = READY;
01334 setBootstrapedIcon();
01335 if( !currentGroup && groups.size() ) currentGroup = &groups.front();
01336 setOverlayReady( true );
01337 break;
01338
01339 case JOINING:
01340 state = JOINING;
01341 setOverlayReady( false );
01342 break;
01343
01344 case SHUTDOWN:
01345 state = SHUTDOWN;
01346 cancelAndDelete( pingTimer );
01347 pingTimer = NULL;
01348 setOverlayReady( false );
01349 break;
01350 }
01351 setBootstrapedIcon();
01352 }
01353
01354 void NTree::setBootstrapedIcon()
01355 {
01356 if(ev.isGUI()) {
01357 if(state == READY) {
01358 getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "green");
01359 getDisplayString().setTagArg("i", 1, "green");
01360 }
01361 else if(state == JOINING) {
01362 getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "yellow");
01363 getDisplayString().setTagArg("i", 1, "yellow");
01364 }
01365 else {
01366 getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "red");
01367 getDisplayString().setTagArg("i", 1, "red");
01368 }
01369 }
01370 }
01371
01372 std::list<NTreeGroup>::iterator NTree::findGroup(const Vector2D& pos)
01373 {
01374 for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
01375 if( it->isInScope( pos ) ) return it;
01376 }
01377 return groups.end();
01378 }
01379
01380 std::list<NTreeGroup>::iterator NTree::findGroup(const Vector2D& pos, double size)
01381 {
01382 for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
01383 if( it->scope.origin == pos && it->scope.size == size ) return it;
01384 }
01385 return groups.end();
01386 }
01387
01388 std::map<NTreeScope,NTreeNode>::iterator NTree::findNTreeNode(const Vector2D& pos)
01389 {
01390 double size = areaDimension + 1;
01391 std::map<NTreeScope,NTreeNode>::iterator bestNode = ntreeNodes.end();
01392 for( std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
01393 if( it->second.isInScope( pos ) && it->second.scope.size < size ){
01394 bestNode = it;
01395 size = bestNode->second.scope.size;
01396 }
01397 }
01398 return bestNode;
01399 }
01400
01401 std::map<NTreeScope,NTreeNode>::iterator NTree::findNTreeNode(const Vector2D& pos, double size)
01402 {
01403 return ntreeNodes.find( NTreeScope( pos, size ) );
01404 }
01405
01406 NodeHandle NTree::getRandomNode( std::set<NodeHandle> invalidNodes )
01407 {
01408
01409 bool found = false;
01410 NodeHandle dest;
01411 while( !found ){
01412 dest = globalNodeList->getRandomNode();
01413 found = true;
01414 for( std::set<NodeHandle>::iterator it = invalidNodes.begin(); it != invalidNodes.end(); ++it ){
01415 if( dest == *it ){
01416 found = false;
01417 break;
01418 }
01419 }
01420 }
01421 return dest;
01422 }
01423
01424 void NTree::finishOverlay()
01425 {
01426 simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
01427 if (time < GlobalStatistics::MIN_MEASURED) return;
01428 globalStatistics->addStdDev("NTree: Joins send per second", joinsSend / time );
01429 globalStatistics->addStdDev("NTree: Join bytes send per second", joinBytes / time );
01430 globalStatistics->addStdDev("NTree: Join timeouts per second", joinTimeout / time );
01431 globalStatistics->addStdDev("NTree: Tree maintenance messages send per second", treeMaintenanceMessages / time );
01432 globalStatistics->addStdDev("NTree: Tree maintenance bytes send per second", treeMaintenanceBytes / time );
01433 globalStatistics->addStdDev("NTree: Move messages send per second", movesSend / time );
01434 globalStatistics->addStdDev("NTree: Move bytes send per second", moveBytes / time );
01435 globalStatistics->addStdDev("NTree: Tree collapsed per second", collapseCount / time );
01436 globalStatistics->addStdDev("NTree: Tree divides per second", divideCount / time );
01437 }
01438
01439 NTree::~NTree()
01440 {
01441 cancelAndDelete(joinTimer);
01442 cancelAndDelete(pingTimer);
01443 }
01444