00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00024 #include "PubSubLobby.h"
00025
00026 #include <GlobalStatistics.h>
00027 #include <GlobalNodeListAccess.h>
00028
00029 using namespace std;
00030
00031 std::ostream& operator<< (std::ostream& o, const PubSubLobby::ChildEntry& entry)
00032 {
00033 o << "Node: " << entry.handle << " ressources: " << entry.ressources;
00034 return o;
00035 }
00036
00037 Define_Module(PubSubLobby);
00038
00039 void PubSubLobby::initializeOverlay(int stage)
00040 {
00041
00042
00043 if(stage != MIN_STAGE_OVERLAY) return;
00044
00045 numSubspaces = par("numSubspaces");
00046 subspaceSize = (int) ( (unsigned int) par("areaDimension") / numSubspaces);
00047
00048
00049 subspaces.resize( numSubspaces );
00050 for ( int i = 0; i < numSubspaces; ++i ) {
00051 for( int ii = 0; ii < numSubspaces; ++ii ) {
00052 PubSubSubspaceId region( i, ii, numSubspaces );
00053 subspaces[i].push_back( PubSubSubspaceLobby( region ) );
00054 }
00055 WATCH_VECTOR( subspaces[i] );
00056 }
00057 thisNode.setKey( OverlayKey::random() );
00058 GlobalNodeListAccess().get()->registerPeer( thisNode );
00059
00060 numPubSubSignalingMessages = 0;
00061 pubSubSignalingMessagesSize = 0;
00062 WATCH( numPubSubSignalingMessages );
00063 WATCH( pubSubSignalingMessagesSize );
00064 WATCH_MAP( playerMap );
00065 }
00066
00067 void PubSubLobby::handleTimerEvent(cMessage* msg)
00068 {
00069 if( PubSubTimer* timer = dynamic_cast<PubSubTimer*>(msg) ) {
00070 if( timer->getType() == PUBSUB_TAKEOVER_GRACE_TIME ){
00071
00072
00073
00074 PubSubSubspaceId subspaceId(timer->getSubspaceId(), numSubspaces );
00075 subspaces[subspaceId.getX()][subspaceId.getY()].waitingForRespNode = false;
00076 delete timer;
00077 }
00078 }
00079 }
00080
00081 void PubSubLobby::handleUDPMessage(BaseOverlayMessage* msg)
00082 {
00083 if( PubSubFailedNodeMessage* failMsg = dynamic_cast<PubSubFailedNodeMessage*>(msg) ){
00084 failedNode( failMsg->getFailedNode() );
00085 delete msg;
00086
00087 } else if( PubSubReplacementMessage* repMsg = dynamic_cast<PubSubReplacementMessage*>(msg) ){
00088 replaceResponsibleNode( repMsg->getSubspaceId(), repMsg->getNewResponsibleNode() );
00089 delete msg;
00090 } else if( PubSubHelpReleaseMessage* helpRMsg = dynamic_cast<PubSubHelpReleaseMessage*>(msg) ){
00091 handleHelpReleaseMessage( helpRMsg );
00092 delete msg;
00093 }
00094 }
00095
00096 bool PubSubLobby::handleRpcCall(BaseCallMessage* msg)
00097 {
00098
00099 RPC_SWITCH_START( msg )
00100 RPC_DELEGATE( PubSubJoin, handleJoin );
00101 RPC_DELEGATE( PubSubHelp, handleHelpCall );
00102 RPC_DELEGATE( PubSubResponsibleNode, handleRespCall );
00103 RPC_SWITCH_END( )
00104
00105 return RPC_HANDLED;
00106 }
00107
00108 void PubSubLobby::handleRpcResponse(BaseResponseMessage *msg,
00109 cPolymorphic* context,
00110 int rpcId, simtime_t rtt)
00111 {
00112 RPC_SWITCH_START(msg);
00113 RPC_ON_RESPONSE( PubSubTakeOverSubspace ) {
00114 handleTakeOverResponse( _PubSubTakeOverSubspaceResponse );
00115 break;
00116 }
00117 RPC_SWITCH_END( );
00118 }
00119
00120 void PubSubLobby::handleRpcTimeout (BaseCallMessage *msg,
00121 const TransportAddress &dest,
00122 cPolymorphic* context, int rpcId,
00123 const OverlayKey &destKey)
00124 {
00125 RPC_SWITCH_START(msg)
00126 RPC_ON_CALL( PubSubTakeOverSubspace ) {
00127 handleTakeOverTimeout( _PubSubTakeOverSubspaceCall, dest );
00128 EV << "[PubSubMMOG::handleRpcTimeout() @ " << thisNode.getAddress()
00129 << " (" << thisNode.getKey().toString(16) << ")]\n"
00130 << " TakeOverSubspace RPC Call timed out: id=" << rpcId << "\n"
00131 << " msg=" << *_PubSubTakeOverSubspaceCall
00132 << endl;
00133 break;
00134 }
00135 RPC_SWITCH_END( )
00136 }
00137
00138 void PubSubLobby::handleJoin( PubSubJoinCall* joinMsg )
00139 {
00140
00141 ChildEntry e;
00142 e.handle = joinMsg->getSrcNode();
00143 e.ressources = joinMsg->getRessources();
00144
00145 pair<PlayerMap::iterator, bool> inserter;
00146 inserter = playerMap.insert( make_pair( e.handle, e ));
00147 ChildEntry* childEntry = &(inserter.first->second);
00148
00149
00150 PlayerRessourceMap::iterator rInserter;
00151 rInserter = playerRessourceMap.insert( make_pair( e.ressources, childEntry ));
00152 bool insertedAtBegin = rInserter == playerRessourceMap.begin();
00153
00154
00155 PubSubJoinResponse* joinResp = new PubSubJoinResponse( "Join Response");
00156 unsigned int x = (unsigned int) (joinMsg->getPosition().x / subspaceSize);
00157 unsigned int y = (unsigned int) (joinMsg->getPosition().y / subspaceSize);
00158 PubSubSubspaceLobby& subspace = subspaces[x][y];
00159 NodeHandle respNode = subspace.getResponsibleNode();
00160 joinResp->setResponsibleNode( respNode );
00161 joinResp->setBitLength( PUBSUB_JOINRESPONSE_L( joinResp ));
00162 RECORD_STATS(
00163 ++numPubSubSignalingMessages;
00164 pubSubSignalingMessagesSize += joinResp->getByteLength()
00165 );
00166 sendRpcResponse( joinMsg, joinResp );
00167
00168 if( respNode.isUnspecified() && !subspace.waitingForRespNode) {
00169
00170
00171 PubSubTakeOverSubspaceCall* toCall = new PubSubTakeOverSubspaceCall( "Take over subspace");
00172 toCall->setSubspacePos( Vector2D(x, y) );
00173
00174 ChildEntry* child = playerRessourceMap.begin()->second;
00175 toCall->setBitLength( PUBSUB_TAKEOVERSUBSPACECALL_L( toCall ));
00176 RECORD_STATS(
00177 ++numPubSubSignalingMessages;
00178 pubSubSignalingMessagesSize += toCall->getByteLength()
00179 );
00180 sendUdpRpcCall( child->handle, toCall );
00181
00182 playerRessourceMap.erase( playerRessourceMap.begin() );
00183 child->dutySet.insert( subspace.getId().getId() );
00184 child->ressources-=2;
00185 if( insertedAtBegin ){
00186 rInserter = playerRessourceMap.insert( make_pair(child->ressources, child) );
00187 } else {
00188 playerRessourceMap.insert( make_pair(child->ressources, child) );
00189 }
00190
00191 subspace.waitingForRespNode = true;
00192 }
00193
00194
00195 if( waitingForHelp.size() > 0 ) {
00196 std::list<PubSubHelpCall*>::iterator it = waitingForHelp.begin();
00197 while( it != waitingForHelp.end() ) {
00198
00199 if( childEntry->dutySet.insert( (*it)->getSubspaceId() ).second ){
00200
00201
00202 childEntry->ressources -= ( (*it)->getHelpType() == PUBSUB_BACKUP ) ? 2 : 1;
00203 }
00204
00205 PubSubHelpResponse* helpResp = new PubSubHelpResponse("Ask him to help you");
00206 helpResp->setSubspaceId( (*it)->getSubspaceId() );
00207 helpResp->setType( (*it)->getType() );
00208 helpResp->setNode( e.handle );
00209 helpResp->setBitLength( PUBSUB_HELPRESPONSE_L( helpResp ));
00210 RECORD_STATS(
00211 ++numPubSubSignalingMessages;
00212 pubSubSignalingMessagesSize += helpResp->getByteLength()
00213 );
00214 sendRpcResponse( *it, helpResp );
00215
00216 waitingForHelp.erase( it++ );
00217
00218 if( childEntry->ressources <= 0 ) break;
00219 }
00220
00221 playerRessourceMap.erase( rInserter );
00222 playerRessourceMap.insert( make_pair(childEntry->ressources, childEntry) );
00223 }
00224 }
00225
00226 void PubSubLobby::handleHelpCall( PubSubHelpCall* helpMsg )
00227 {
00228
00229 const NodeHandle& src = helpMsg->getSrcNode();
00230 int subspaceId = helpMsg->getSubspaceId();
00231 PlayerRessourceMap::iterator it;
00232 for( it = playerRessourceMap.begin(); it != playerRessourceMap.end(); ++it ){
00233 if( it->second->handle != src &&
00234 it->second->dutySet.find( subspaceId ) == it->second->dutySet.end() &&
00235 it->second->ressources > 1 ){
00236 break;
00237 }
00238 }
00239
00240
00241 if( it == playerRessourceMap.end() ){
00242 waitingForHelp.push_back( helpMsg );
00243 return;
00244 }
00245
00246
00247 ChildEntry* child = it->second;
00248 child->ressources -= ( helpMsg->getHelpType() == PUBSUB_BACKUP ) ? 2 : 1;
00249 child->dutySet.insert( subspaceId );
00250 playerRessourceMap.erase( it );
00251 playerRessourceMap.insert( make_pair(child->ressources, child) );
00252
00253
00254 PubSubHelpResponse* helpResp = new PubSubHelpResponse("Ask him to help you");
00255 helpResp->setSubspaceId( subspaceId );
00256 helpResp->setHelpType( helpMsg->getHelpType() );
00257 helpResp->setNode( child->handle );
00258 helpResp->setBitLength( PUBSUB_HELPRESPONSE_L( helpResp ));
00259 RECORD_STATS(
00260 ++numPubSubSignalingMessages;
00261 pubSubSignalingMessagesSize += helpResp->getByteLength()
00262 );
00263 sendRpcResponse( helpMsg, helpResp );
00264 }
00265
00266 void PubSubLobby::handleRespCall( PubSubResponsibleNodeCall* respCall )
00267 {
00268 unsigned int x = (unsigned int) respCall->getSubspacePos().x;
00269 unsigned int y = (unsigned int) respCall->getSubspacePos().y;
00270 NodeHandle respNode = subspaces[x][y].getResponsibleNode();
00271 if( !respNode.isUnspecified() ) {
00272 PubSubSubspaceId region( x, y, numSubspaces);
00273
00274 PubSubResponsibleNodeResponse* msg = new PubSubResponsibleNodeResponse( "ResponsibleNode Response");
00275 msg->setResponsibleNode( respNode );
00276 msg->setSubspaceId( region.getId() );
00277 msg->setBitLength( PUBSUB_RESPONSIBLENODERESPONSE_L( msg ));
00278 RECORD_STATS(
00279 ++numPubSubSignalingMessages;
00280 pubSubSignalingMessagesSize += msg->getByteLength()
00281 );
00282 sendRpcResponse( respCall, msg );
00283 } else {
00284
00285
00286 PubSubSubspaceLobby& subspace = subspaces[x][y];
00287 subspace.waitingNodes.push_back( respCall );
00288
00289 if (!subspace.waitingForRespNode) {
00290
00291 PubSubTakeOverSubspaceCall* msg = new PubSubTakeOverSubspaceCall( "Take over subspace");
00292 msg->setSubspacePos( Vector2D( x, y) );
00293
00294 ChildEntry* child = playerRessourceMap.begin()->second;
00295 msg->setBitLength( PUBSUB_TAKEOVERSUBSPACECALL_L( msg ));
00296 RECORD_STATS(
00297 ++numPubSubSignalingMessages;
00298 pubSubSignalingMessagesSize += msg->getByteLength()
00299 );
00300 sendUdpRpcCall( child->handle, msg );
00301
00302 playerRessourceMap.erase( playerRessourceMap.begin() );
00303 child->dutySet.insert( subspace.getId().getId() );
00304
00305
00306 child->ressources-=1;
00307 playerRessourceMap.insert( make_pair(child->ressources, child) );
00308
00309 subspace.waitingForRespNode = true;
00310 }
00311 }
00312 }
00313
00314 void PubSubLobby::handleTakeOverResponse( PubSubTakeOverSubspaceResponse* takeOverResp )
00315 {
00316 NodeHandle respNode = takeOverResp->getSrcNode();
00317 unsigned int x = (unsigned int) takeOverResp->getSubspacePos().x;
00318 unsigned int y = (unsigned int) takeOverResp->getSubspacePos().y;
00319 PubSubSubspaceId region( x, y, numSubspaces);
00320
00321 replaceResponsibleNode( region, takeOverResp->getSrcNode() );
00322 }
00323
00324 void PubSubLobby::handleTakeOverTimeout( PubSubTakeOverSubspaceCall* takeOverCall, const TransportAddress& oldNode )
00325 {
00326 Vector2D pos = takeOverCall->getSubspacePos();
00327 subspaces[(int) pos.x][(int) pos.y].waitingForRespNode = false;
00328 failedNode( oldNode );
00329 }
00330
00331 void PubSubLobby::handleHelpReleaseMessage( PubSubHelpReleaseMessage* helpRMsg )
00332 {
00333 PlayerMap::iterator playerIt = playerMap.find( helpRMsg->getNode() );
00334 if( playerIt == playerMap.end() ){
00335
00336 return;
00337 }
00338 ChildEntry* nodeEntry = &(playerIt->second);
00339
00340
00341 nodeEntry->dutySet.erase( helpRMsg->getSubspaceId() );
00342
00343
00344 pair<PlayerRessourceMap::iterator, PlayerRessourceMap::iterator> resRange;
00345 PlayerRessourceMap::iterator resIt;
00346 resRange = playerRessourceMap.equal_range( nodeEntry->ressources );
00347 for( resIt = resRange.first; resIt != resRange.second; ++resIt ){
00348 if( resIt->second == nodeEntry ){
00349 playerRessourceMap.erase( resIt );
00350 break;
00351 }
00352 }
00353 nodeEntry->ressources += 1;
00354 playerRessourceMap.insert( make_pair(nodeEntry->ressources, nodeEntry) );
00355 }
00356
00357 void PubSubLobby::replaceResponsibleNode( int subspaceId, NodeHandle respNode )
00358 {
00359 replaceResponsibleNode( PubSubSubspaceId( subspaceId, numSubspaces), respNode );
00360 }
00361
00362 void PubSubLobby::replaceResponsibleNode( PubSubSubspaceId subspaceId, NodeHandle respNode )
00363 {
00364
00365 PubSubSubspaceLobby& subspace = subspaces[subspaceId.getX()][subspaceId.getY()];
00366
00367
00368
00369 subspace.setResponsibleNode( respNode );
00370 subspace.waitingForRespNode = false;
00371
00372
00373 pair<PlayerRessourceMap::iterator, PlayerRessourceMap::iterator> resRange;
00374 PlayerRessourceMap::iterator resIt;
00375 PlayerMap::iterator plIt = playerMap.find( respNode );
00376
00377 if( plIt == playerMap.end() ){
00378
00379
00380
00381 opp_error("PlayerMap inconsistent: Allegedly failed node wants to become Responsible node");
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 std::list<PubSubResponsibleNodeCall*>::iterator it;
00399 for( it = subspace.waitingNodes.begin(); it != subspace.waitingNodes.end(); ++it ) {
00400 PubSubResponsibleNodeResponse* msg = new PubSubResponsibleNodeResponse( "ResponsibleNode Response");
00401 msg->setResponsibleNode( respNode );
00402 msg->setSubspaceId( subspaceId.getId() );
00403 msg->setBitLength( PUBSUB_RESPONSIBLENODERESPONSE_L( msg ));
00404 RECORD_STATS(
00405 ++numPubSubSignalingMessages;
00406 pubSubSignalingMessagesSize += msg->getByteLength()
00407 );
00408 sendRpcResponse( *it, msg );
00409 }
00410 subspace.waitingNodes.clear();
00411 }
00412
00413
00414 void PubSubLobby::failedNode(const TransportAddress& node)
00415 {
00416 if( node.isUnspecified() ) return;
00417
00418
00419 PlayerMap::iterator playerIt = playerMap.find( node );
00420 if( playerIt == playerMap.end() ){
00421
00422 return;
00423 }
00424 ChildEntry* respNodeEntry = &(playerIt->second);
00425
00426
00427 if( GlobalNodeListAccess().get()->getPeerInfo( node ) ){
00428 opp_error("Trying to delete node that's still there...");
00429 }
00430
00431
00432 set<int>::iterator dutyIt;
00433 for( dutyIt = respNodeEntry->dutySet.begin(); dutyIt != respNodeEntry->dutySet.end(); ++dutyIt ){
00434 PubSubSubspaceId subspaceId( *dutyIt, numSubspaces );
00435 PubSubSubspaceLobby& subspace = subspaces[subspaceId.getX()][subspaceId.getY()];
00436 if( !subspace.getResponsibleNode().isUnspecified() && node == subspace.getResponsibleNode() ){
00437
00438 subspace.setResponsibleNode(NodeHandle());
00439
00440
00441 subspace.waitingForRespNode = true;
00442 PubSubTimer* graceTimer = new PubSubTimer("Grace timer for claiming subspace");
00443 graceTimer->setType( PUBSUB_TAKEOVER_GRACE_TIME );
00444 graceTimer->setSubspaceId( subspace.getId().getId() );
00445 scheduleAt( simTime() + 5, graceTimer );
00446 }
00447 }
00448
00449
00450 pair<PlayerRessourceMap::iterator, PlayerRessourceMap::iterator> resRange;
00451 PlayerRessourceMap::iterator resIt;
00452
00453 resRange = playerRessourceMap.equal_range( respNodeEntry->ressources );
00454 for( resIt = resRange.first; resIt != resRange.second; ++resIt ){
00455 if( resIt->second == respNodeEntry ){
00456 playerRessourceMap.erase( resIt );
00457 break;
00458 }
00459 }
00460 playerMap.erase( playerIt );
00461 }
00462
00463 void PubSubLobby::finishOverlay()
00464 {
00465 simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
00466 if (time < GlobalStatistics::MIN_MEASURED) return;
00467
00468 globalStatistics->addStdDev("PubSubLobby: Sent Signaling Messages/s",
00469 numPubSubSignalingMessages / time);
00470 globalStatistics->addStdDev("PubSubLobby: Sent Signaling bytes/s",
00471 pubSubSignalingMessagesSize / time);
00472 }
00473
00474 PubSubLobby::~PubSubLobby()
00475 {
00476 }