NTree.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 // TODO: Use standard join() for login
00037 
00038 // TODO: On move receive, check if sender is in member list, add
00039 // TODO: On group leave, check for now-lost members, tell app to remove them
00040 // TODO: On divide/collapse/etc (i.e. when deleting groups), check for lost members, tell app to remove them(?)
00041 // TODO: Timeout players when no move received for longer period?
00042 
00043 void NTree::initializeOverlay(int stage)
00044 {
00045     // because of IPAddressResolver, we need to wait until interfaces are registered,
00046     // address auto-assignment takes place etc.
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     // FIXME: Use standard baseOverlay::join()
00066     changeState( INIT );
00067 
00068     // statistics
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     // delegate messages
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         // send a fake ready message to app to get initial position
00222         CompReadyMessage* msg = new CompReadyMessage("fake READY");
00223         msg->setReady(true);
00224         msg->setComp(getThisCompType());
00225         send( msg, "appOut");
00226         // send initial AOI size to the application
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             // We are not connected to the overlay, inform app
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             // This is only called for the first MOVE message
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                 // Trigger login
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     // Check if we know the group
00284     std::list<NTreeGroup>::iterator grpIt = findGroup( joinCall->getPosition() );
00285     if( grpIt != groups.end() ) {
00286         // If we are leader, acknowlede Join
00287         if( grpIt->leader == thisNode ) {
00288             // Inform group about new member
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             // Acknowledge Join, send information about group
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             // If group is to big, divide group
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                 // select 4 random members of the group to become leader of subgroup
00340                 // "lotto" algoritm so nobody gets elected twice
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 ) { // don't select myself
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             // forward join to leader
00374             sendMessageToUDP( grpIt->leader, joinCall );
00375         }
00376         return;
00377     }
00378     // We don't know the group, forward join via the NTree
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     // Check for conflicting groups
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             // Oops, conflicting group found. joinResp is probably outdated
00394             EV << "    Conflicting group found. Ignoring JOIN ACK\n";
00395 
00396             // if our login resulted in a divide, and we got the divide earlier that the ack,
00397             // we missed to update our state. fixing.
00398             if( state != READY ){
00399                 changeState( READY );
00400             }
00401             return;
00402         }
00403     }
00404 
00405     // if group already known, clear member list (new member list will be taken from message)
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             // We are leader of the already known group. Something's fishy, ignore join
00412             EV << "    Group already known; and I'm leader of that group. Ignoring ACK\n";
00413             return;
00414         }
00415 
00416     } else {
00417         // Else create new group
00418         NTreeGroup grp(joinResp->getOrigin(), joinResp->getSize());
00419         groups.push_front(grp);
00420         git = groups.begin();
00421     }
00422 
00423     // Fill in member list and leader of the group from message
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     // If we were still joining the overlay, we are now ready to go
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     // TODO: Other cases when re-try is useful?
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     // Send to old group
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     // Find group for new position
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         // Join new groups in our AoI and leave groups outside the AoI
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     // Group already deleted
00534     if( it == groups.end() ) return;
00535 
00536     // Check if I believe to own the group
00537     // In that case, delete the corresponding node
00538     ntreeNodes.erase( it->scope );
00539 
00540     // Join new sub-group
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     // delete group
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     // If player not otherwise known
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     // Inform app
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             // leaf, inform group
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             // delete group
00603             if( currentGroup && *currentGroup == *it->second.group ){
00604                 currentGroup = NULL;
00605             }
00606             groups.remove( *it->second.group );
00607 
00608         } else {
00609             // node, inform children
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         // delete node
00623         ntreeNodes.erase( it );
00624     }
00625 }
00626 
00627 void NTree::handleMoveMessage( NTreeMoveMessage* moveMsg )
00628 {
00629     // Inform app
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         // node Ping
00651         // compute my scope
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             // TODO: save parentParent?
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             // Answer ping
00667             NTreeNodePingResponse* nodeResp = new NTreeNodePingResponse("PONG");
00668             if( it->second.group ){
00669                 // leaf
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                 // ordinary node
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         // Group ping
00695         std::list<NTreeGroup>::iterator it = findGroup( pingCall->getOrigin(), pingCall->getSize() );
00696         if( it != groups.end() ){
00697             // TODO: save parentParent
00698 
00699         }
00700         // Answer ping
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             // If child found, update children info in node
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                 // Collapse tree if aggChildCount is too low
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                 // child not found
00736                 // TODO: what to do now?
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             // If child found, replace it
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                 // Find node to replace failed node
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         // Group ping. Simple delete node from all groups
00788         for( std::list<NTreeGroup>::iterator it = groups.begin(); it != groups.end(); ++it ){
00789             // we have to search the group members manually, as we only have a TransportAddress to compare
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     // Calculate new scope
00818     NTreeScope oldScope(divideCall->getOrigin(), divideCall->getSize() );
00819     NTreeScope newScope = oldScope.getSubScope( divideCall->getQuadrant() );
00820     
00821     // If we own the node that is beeing divided, something went wrong
00822     // However, ther is nothing we can do about it except removing the offending node
00823     // Sombody obviously took over without us noticing
00824     ntreeNodes.erase( oldScope );
00825 
00826     // Create new group, delete old group
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     // Create new ntreeNode
00839     NTreeNode newNode(newScope);
00840     newNode.parent = divideCall->getSrcNode();
00841     newNode.group = &groups.front();
00842     ntreeNodes.insert(make_pair(newScope,newNode));
00843 
00844     // Acknowledge Divide
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             // Some responses still missing
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     // Create new ntreeNode
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             // TODO: check for conflicting groups?
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     // Inform parent+children
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() ); // also inform old node if is is (against expectations) still alive
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     // CHeck if group leader gets replaced
00949     std::list<NTreeGroup>::iterator git = findGroup( takeMsg->getOrigin(), takeMsg->getSize() );
00950     if( git != groups.end() ){
00951         git->leader = takeMsg->getPlayer();
00952     }
00953 
00954     // Check if a node gets replaced
00955     NTreeScope takeScope( takeMsg->getOrigin(), takeMsg->getSize() );
00956     for(std::map<NTreeScope,NTreeNode>::iterator it = ntreeNodes.begin(); it != ntreeNodes.end(); ++it ){
00957         // Check if parent is replaced
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             // Else check if child is replaced
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             // Uh-oh. Somebody replaced me. Yield ownership
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         // Replace me on all nodes
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         // Search random node to replace me
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         // Inform node of his new responsabilities
01019         RECORD_STATS(
01020                 treeMaintenanceMessages++;
01021                 treeMaintenanceBytes += replaceMsg->getByteLength();
01022         );
01023         sendMessage( dest, replaceMsg );
01024     }
01025     while( groups.size() ){
01026         // Leave all groups
01027         leaveGroup( groups.begin()->scope.origin, true );
01028     }
01029     // clear ntree
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             // Leaf
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     // Go throup all nodes. iterator is incremented in-loop to allow deletion
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             // Parent timed out
01080             EV << "[NTree::checkParentTimeout() @ " << thisNode.getIp()
01081                 << " (" << thisNode.getKey().toString(16) << ")]\n"
01082                 << "    Parent for node" << it->second << " timed out\n";
01083             // Replace parent if parent is root. Other parents will be replaced by their parents
01084             // Also, only sibling[0] does the replacing to avoid conflicts.
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                 // else drop node
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     // Inform group members
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     // delete group
01156     if( currentGroup && *currentGroup == *it->second.group ){
01157         currentGroup = NULL;
01158     }
01159     groups.remove( *it->second.group );
01160     it->second.group= NULL;
01161 
01162     // add children to ntreeNode
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     // Inform children
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         // and update node
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     // create group for node
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     // Don't leave group if I'm leader of that group (except if forced)
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         // Check if pos is in scope of one ntree node
01245         std::map<NTreeScope,NTreeNode>::iterator it = findNTreeNode( pos );
01246         if( it != ntreeNodes.end() ){
01247             // Forward message to appropriate child
01248             dest = it->second.getChildForPos( pos );
01249         } else {
01250             // else send to parent of highest ntreeNode
01251             dest = ntreeNodes.begin()->second.parent;
01252         }
01253     } else {
01254         // No Ntree known. Send to group leader
01255         if( currentGroup ){
01256             dest = currentGroup->leader;
01257         } else if( groups.size() ){
01258             dest = groups.begin()->leader;
01259         } else { // No group known. We have to re-join. (Even though a JOIN might still be in progress)
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     // TODO: statistics?
01310     BaseCallMessage* rpc = dynamic_cast<BaseCallMessage*>(msg);
01311     if( rpc && !forward ){
01312         // Slightly evil: If an OverlayKey is set, the RPC response
01313         // may get dropped if it was forwarded (because OverSim expects
01314         // frowarding to be done with BaseRoutMessages. Which we can't do,
01315         // because we are not routing to overlay keys but to positions.
01316         // Thus, we cast the OverlayKey away.
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     // FIXME: This is cheating...
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