#include <Scribe.h>
Public Member Functions | |
Scribe () | |
~Scribe () | |
virtual void | initializeApp (int stage) |
initializes derived class-attributes | |
virtual void | handleUpperMessage (cMessage *msg) |
handleUpperMessage gets called of handleMessage(cMessage* msg) if msg arrivedOn from_upperTier (currently msg gets deleted in this function) | |
virtual void | handleReadyMessage (TierReadyMessage *msg) |
method to handle ready messages from the overlay | |
virtual void | handleTimerEvent (cMessage *msg) |
processes self-messages | |
virtual bool | handleRpc (BaseCallMessage *msg) |
Processes Remote-Procedure-Call invokation messages. | |
virtual void | handleRpcResponse (BaseResponseMessage *msg, int rpcId, simtime_t rtt) |
This method is called if an RPC response has been received. | |
virtual void | forward (OverlayKey *key, cMessage **msg, NodeHandle *nextHopNode) |
Common API function: handles messages from overlay to be forwarded. | |
virtual void | deliver (OverlayKey &key, cMessage *msg) |
Common API function: handles delivered messages from overlay. | |
virtual void | update (const NodeHandle &node, bool joined) |
Common API function: informs application about neighbors and own nodeID. | |
virtual void | finishApp () |
collects statistical data of derived app | |
Protected Member Functions | |
void | handleJoinResponse (ScribeJoinResponse *joinResponse) |
Handles a response to a join call send by this node. | |
void | handleJoinCall (ScribeJoinCall *joinMsg) |
Handles a join request from another node. | |
void | handlePublishCall (ScribePublishCall *publishCall) |
Handles a publish call from another node. | |
void | handlePublishResponse (ScribePublishResponse *publishResponse) |
Handles a response to a publish call send b this node. | |
void | handleJoinMessage (ScribeJoinCall *joinMsg, bool amIRoot) |
Handles join requests from other nodes. | |
void | handleLeaveMessage (ScribeLeaveMessage *leaveMsg) |
Handles leave requests from other nodes. | |
void | subscribeToGroup (const OverlayKey &groupId) |
Gets called if the local node wants to subscribe to a multicast group. | |
void | leaveGroup (const OverlayKey &group) |
Gets called if the local node wants to leave a multicast group. | |
void | startTimer (ScribeTimer *timer) |
Starts a local timer. | |
void | addChildToGroup (const NodeHandle &child, ScribeGroup &group) |
Adds a child to a multicast group. | |
void | removeChildFromGroup (const NodeHandle &child, ScribeGroup &group) |
Removes a child from a multicast group. | |
void | removeChildFromGroup (ScribeTimer *timer) |
Removes a child from a multicast group. | |
void | checkGroupEmpty (ScribeGroup &group) |
Chechs wheter there are any subscibers left to a given root. | |
void | refreshChildTimer (NodeHandle &child, OverlayKey &groupId) |
Refreshes a child timer. | |
void | deliverALMDataToGroup (ScribeDataMessage *dataMsg) |
Delivers a multicast message to all children in the multicast group. | |
void | deliverALMDataToRoot (ALMMulticastMessage *mcastMsg) |
Delivers a multicast message to the tree's root. | |
Private Types | |
typedef map < OverlayKey, ScribeGroup > | GroupList |
typedef multimap < NodeHandle, ScribeTimer * > | ChildTimeoutList |
Private Attributes | |
GroupList | groupList |
ChildTimeoutList | childTimeoutList |
int | childTimeout |
int | parentTimeout |
ScribeTimer * | subscriptionTimer |
int | numJoins |
int | numChildTimeout |
int | numParentTimeout |
int | numForward |
int | forwardBytes |
int | numReceived |
number of received packets | |
int | receivedBytes |
int | numHeartbeat |
int | heartbeatBytes |
int | numSubscriptionRefresh |
int | subscriptionRefreshBytes |
typedef map<OverlayKey, ScribeGroup> Scribe::GroupList [private] |
typedef multimap<NodeHandle, ScribeTimer*> Scribe::ChildTimeoutList [private] |
Scribe::Scribe | ( | ) |
00031 { 00032 subscriptionTimer = new ScribeTimer("Subscription timer"); 00033 subscriptionTimer->setTimerType( SCRIBE_SUBSCRIPTION_REFRESH ); 00034 numJoins = 0; 00035 numChildTimeout = 0; 00036 numParentTimeout = 0; 00037 numForward = 0; 00038 forwardBytes = 0; 00039 numReceived = 0; 00040 receivedBytes = 0; 00041 numHeartbeat = 0; 00042 heartbeatBytes = 0; 00043 numSubscriptionRefresh = 0; 00044 subscriptionRefreshBytes = 0; 00045 }
Scribe::~Scribe | ( | ) |
00048 { 00049 groupList.clear(); 00050 cancelAndDelete(subscriptionTimer); 00051 // TODO: clear childTimeoutList 00052 }
void Scribe::initializeApp | ( | int | stage | ) | [virtual] |
initializes derived class-attributes
stage | the init stage |
Reimplemented from BaseApp.
00055 { 00056 if( stage != (numInitStages()-1)) 00057 { 00058 return; 00059 } 00060 WATCH(groupList); 00061 WATCH(numJoins); 00062 WATCH(numForward); 00063 WATCH(forwardBytes); 00064 WATCH(numReceived); 00065 WATCH(receivedBytes); 00066 WATCH(numHeartbeat); 00067 WATCH(heartbeatBytes); 00068 WATCH(numSubscriptionRefresh); 00069 WATCH(subscriptionRefreshBytes); 00070 WATCH(numChildTimeout); 00071 WATCH(numParentTimeout); 00072 00073 childTimeout = par("childTimeout"); 00074 parentTimeout = par("parentTimeout"); 00075 00076 }
void Scribe::handleUpperMessage | ( | cMessage * | msg | ) | [virtual] |
handleUpperMessage gets called of handleMessage(cMessage* msg) if msg arrivedOn from_upperTier (currently msg gets deleted in this function)
msg | the message to handle |
Reimplemented from BaseApp.
00182 { 00183 if( ALMSubscribeMessage* subscribeMsg = dynamic_cast<ALMSubscribeMessage*>(msg)){ 00184 subscribeToGroup( subscribeMsg->getGroupId() ); 00185 delete msg; 00186 } else if( ALMLeaveMessage* leaveMsg = dynamic_cast<ALMLeaveMessage*>(msg)){ 00187 leaveGroup( leaveMsg->getGroupId() ); 00188 delete msg; 00189 } else if( ALMMulticastMessage* mcastMsg = dynamic_cast<ALMMulticastMessage*>(msg) ){ 00190 deliverALMDataToRoot( mcastMsg ); 00191 } else if( ALMAnycastMessage* acastMsg = dynamic_cast<ALMAnycastMessage*>(msg) ){ 00192 // FIXME: anycast not implemented yet 00193 EV << "[Scribe::handleUpperMessage() @ " << thisNode.ip 00194 << " (" << thisNode.key.toString(16) << ")]\n" 00195 << " Anycast message for group " << acastMsg->getGroupId() << "\n" 00196 << " ignored: Not implemented yet!" 00197 << endl; 00198 delete msg; 00199 } else if( ALMCreateMessage* createMsg = dynamic_cast<ALMCreateMessage*>(msg) ){ 00200 EV << "[Scribe::handleUpperMessage() @ " << thisNode.ip 00201 << " (" << thisNode.key.toString(16) << ")]\n" 00202 << " Create message for group " << createMsg->getGroupId() << "\n" 00203 << " ignored: Scribe has implicit create on SUBSCRIBE" 00204 << endl; 00205 delete msg; 00206 } else if( ALMDeleteMessage* deleteMsg = dynamic_cast<ALMDeleteMessage*>(msg) ){ 00207 EV << "[Scribe::handleUpperMessage() @ " << thisNode.ip 00208 << " (" << thisNode.key.toString(16) << ")]\n" 00209 << " Delete message for group " << deleteMsg->getGroupId() << "\n" 00210 << " ignored: Scribe has implicit delete on LEAVE" 00211 << endl; 00212 delete msg; 00213 } 00214 }
void Scribe::handleReadyMessage | ( | TierReadyMessage * | msg | ) | [virtual] |
method to handle ready messages from the overlay
msg | message to handle |
Reimplemented from BaseApp.
00217 { 00218 if( !msg->getReady() ) { 00219 delete msg; 00220 return; 00221 } 00222 // FIXME/TODO: thisNode should already be in msg 00223 msg->setThisNode( thisNode ); 00224 send( msg, "to_upperTier" ); 00225 startTimer( subscriptionTimer ); 00226 }
void Scribe::handleTimerEvent | ( | cMessage * | msg | ) | [virtual] |
processes self-messages
method to handle self-messages should be overwritten in derived application if needed
msg | self-message |
Reimplemented from BaseApp.
00229 { 00230 ScribeTimer* timer = dynamic_cast<ScribeTimer*>(msg); 00231 assert( timer ); 00232 switch( timer->getTimerType() ) { 00233 case SCRIBE_SUBSCRIPTION_REFRESH: 00234 // renew subscriptions for all groups 00235 for( GroupList::iterator it = groupList.begin(); it != groupList.end(); ++it ) { 00236 NodeHandle parent = it->second.getParent(); 00237 if( !parent.isUnspecified() ){ 00238 ScribeSubscriptionRefreshMessage* refreshMsg = new ScribeSubscriptionRefreshMessage; 00239 refreshMsg->setGroupId( it->second.getGroupId() ); 00240 refreshMsg->setSrc( thisNode ); 00241 00242 refreshMsg->setLength(SCRIBE_SUBSCRIPTIONREFRESH_L(refreshMsg)); 00243 RECORD_STATS(++numSubscriptionRefresh; 00244 subscriptionRefreshBytes += refreshMsg->byteLength() 00245 ); 00246 callRoute( OverlayKey::UNSPECIFIED_KEY, refreshMsg, parent ); 00247 } 00248 } 00249 startTimer( subscriptionTimer ); 00250 break; 00251 00252 case SCRIBE_HEARTBEAT: 00253 { 00254 // Send heartbeat messages to all children in the group 00255 GroupList::iterator groupIt = groupList.find( timer->getGroup() ); 00256 if( groupIt == groupList.end() ) { 00257 // FIXME: should not happen 00258 delete timer; 00259 return; 00260 } 00261 for( set<NodeHandle>::iterator it = groupIt->second.getChildrenBegin(); 00262 it != groupIt->second.getChildrenEnd(); ++it ) { 00263 ScribeDataMessage* heartbeatMsg = new ScribeDataMessage("Heartbeat"); 00264 heartbeatMsg->setEmpty( true ); 00265 heartbeatMsg->setGroupId( timer->getGroup() ); 00266 00267 heartbeatMsg->setLength(SCRIBE_DATA_L(heartbeatMsg)); 00268 RECORD_STATS(++numHeartbeat; heartbeatBytes += heartbeatMsg->byteLength()); 00269 callRoute( OverlayKey::UNSPECIFIED_KEY, heartbeatMsg, *it ); 00270 } 00271 startTimer( timer ); 00272 break; 00273 } 00274 case SCRIBE_CHILD_TIMEOUT: 00275 // Child failed, remove it from group 00276 RECORD_STATS(++numChildTimeout); 00277 removeChildFromGroup( timer ); 00278 break; 00279 00280 case SCRIBE_PARENT_TIMEOUT: 00281 // Parent failed, send new join to rejoin group 00282 RECORD_STATS(++numParentTimeout); 00283 OverlayKey key = timer->getGroup(); 00284 EV << "[Scribe::handleTimerEvent() @ " << thisNode.ip 00285 << " (" << thisNode.key.toString(16) << ")]\n" 00286 << " Parent of group " << key << "\n" 00287 << " failed to send heartbeat, trying to rejoin" 00288 << endl; 00289 00290 ScribeJoinCall* newJoin = new ScribeJoinCall; 00291 newJoin->setGroupId( key ); 00292 newJoin->setLength( SCRIBE_JOINCALL_L(newJoin) ); 00293 sendRouteRpcCall(TIER1_COMP, key, newJoin); 00294 00295 GroupList::iterator groupIt = groupList.find( timer->getGroup() ); 00296 if( groupIt == groupList.end() ) { 00297 // FIXME: should not happen 00298 delete timer; 00299 return; 00300 } 00301 groupIt->second.setParentTimer( NULL ); 00302 cancelAndDelete( timer ); 00303 break; 00304 } 00305 00306 }
bool Scribe::handleRpc | ( | BaseCallMessage * | msg | ) | [virtual] |
Processes Remote-Procedure-Call invokation messages.
This method should be overloaded when the overlay provides RPC functionality.
Reimplemented from BaseRpc.
00141 { 00142 RPC_SWITCH_START(msg); 00143 RPC_DELEGATE(ScribeJoin, handleJoinCall); 00144 RPC_DELEGATE(ScribePublish, handlePublishCall); 00145 RPC_SWITCH_END( ); 00146 return RPC_HANDLED; 00147 }
void Scribe::handleRpcResponse | ( | BaseResponseMessage * | msg, | |
int | rpcId, | |||
simtime_t | rtt | |||
) | [virtual] |
This method is called if an RPC response has been received.
msg | The response message. | |
rpcId | The RPC id. | |
rtt | The Round-Trip-Time of this RPC |
Reimplemented from RpcListener.
00150 { 00151 RPC_SWITCH_START(msg); 00152 RPC_ON_RESPONSE( ScribeJoin ) { 00153 handleJoinResponse( _ScribeJoinResponse ); 00154 EV << "[Scribe::handleRpcResponse() @ " << thisNode.ip 00155 << " (" << thisNode.key.toString(16) << ")]\n" 00156 << " Received a ScribeJoin RPC Response: id=" << rpcId << "\n" 00157 << " msg=" << *_ScribeJoinResponse << " rtt=" << rtt 00158 << endl; 00159 break; 00160 } 00161 RPC_ON_RESPONSE( ScribePublish ) { 00162 handlePublishResponse( _ScribePublishResponse ); 00163 } 00164 RPC_SWITCH_END( ); 00165 }
void Scribe::forward | ( | OverlayKey * | key, | |
cMessage ** | msg, | |||
NodeHandle * | nextHopNode | |||
) | [virtual] |
Common API function: handles messages from overlay to be forwarded.
method to handle decapsulated KBRdeliver messages from overlay module, should be overwritten in derived application if needed
key | destination key | |
msg | message to forward | |
nextHopNode | next hop |
Reimplemented from BaseApp.
00107 { 00108 ScribeJoinCall* joinMsg = dynamic_cast<ScribeJoinCall*> (*msg); 00109 if( joinMsg == NULL ) { 00110 // nothing to be done 00111 return; 00112 } 00113 00114 if( joinMsg->getSrcNode() == thisNode ) return; 00115 00116 handleJoinMessage( joinMsg, false ); 00117 00118 *msg = NULL; 00119 }
void Scribe::deliver | ( | OverlayKey & | key, | |
cMessage * | msg | |||
) | [virtual] |
Common API function: handles delivered messages from overlay.
method to handle decapsulated KBRdeliver messages from overlay module, should be overwritten in derived application
key | destination key | |
msg | delivered message |
Reimplemented from BaseApp.
00168 { 00169 if( ScribeSubscriptionRefreshMessage* refreshMsg = 00170 dynamic_cast<ScribeSubscriptionRefreshMessage*>(msg) ){ 00171 // reset child timeout 00172 refreshChildTimer( refreshMsg->getSrc(), refreshMsg->getGroupId() ); 00173 delete refreshMsg; 00174 } else if( ScribeDataMessage* data = dynamic_cast<ScribeDataMessage*>(msg) ){ 00175 deliverALMDataToGroup( data ); 00176 } else if( ScribeLeaveMessage* leaveMsg = dynamic_cast<ScribeLeaveMessage*>(msg) ){ 00177 handleLeaveMessage( leaveMsg ); 00178 } 00179 }
void Scribe::update | ( | const NodeHandle & | node, | |
bool | joined | |||
) | [virtual] |
Common API function: informs application about neighbors and own nodeID.
node | new or lost neighbor | |
joined | new or lost? |
Reimplemented from BaseApp.
00122 { 00123 // if node is closer to any group i'm root of, subscribe 00124 for( GroupList::iterator it = groupList.begin(); it != groupList.end(); ++it ){ 00125 // if I'm root ... 00126 if( !it->second.getParent().isUnspecified() && it->second.getParent() == thisNode ) { 00127 KeyDistanceComparator<KeyRingMetric> comp( it->second.getGroupId() ); 00128 // ... and new node is closer to groupId 00129 if( comp.compare(node.key, thisNode.key) < 0){ 00130 // then the new node is new group root, so send him a subscribe 00131 ScribeJoinCall* m = new ScribeJoinCall; 00132 m->setGroupId( it->second.getGroupId() ); 00133 m->setLength( SCRIBE_JOINCALL_L(m) ); 00134 sendRouteRpcCall(TIER1_COMP, node, m); 00135 } 00136 } 00137 } 00138 }
void Scribe::finishApp | ( | ) | [virtual] |
collects statistical data of derived app
Reimplemented from BaseApp.
00079 { 00080 simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime); 00081 globalStatistics->addStdDev("Scribe: Received JOIN Messages/s", 00082 numJoins / time); 00083 globalStatistics->addStdDev("Scribe: Forwarded Multicast Messages/s", 00084 numForward / time); 00085 globalStatistics->addStdDev("Scribe: Forwarded Multicast Bytes/s", 00086 forwardBytes / time); 00087 globalStatistics->addStdDev("Scribe: Received Multicast Messages/s (subscribed groups only)", 00088 numReceived / time); 00089 globalStatistics->addStdDev("Scribe: Received Multicast Bytes/s (subscribed groups only)", 00090 receivedBytes / time); 00091 globalStatistics->addStdDev("Scribe: Send Heartbeat Messages/s", 00092 numHeartbeat / time); 00093 globalStatistics->addStdDev("Scribe: Send Heartbeat Bytes/s", 00094 heartbeatBytes / time); 00095 globalStatistics->addStdDev("Scribe: Send Subscription Refresh Messages/s", 00096 numSubscriptionRefresh / time); 00097 globalStatistics->addStdDev("Scribe: Send Subscription Refresh Bytes/s", 00098 subscriptionRefreshBytes / time); 00099 globalStatistics->addStdDev("Scribe: Number of Child Timeouts/s", 00100 numChildTimeout / time); 00101 globalStatistics->addStdDev("Scribe: Number of Parent Timeouts/s", 00102 numParentTimeout / time); 00103 }
void Scribe::handleJoinResponse | ( | ScribeJoinResponse * | joinResponse | ) | [protected] |
Handles a response to a join call send by this node.
00395 { 00396 GroupList::iterator it = groupList.find( joinResponse->getGroupId() ); 00397 if( it == groupList.end() ) { 00398 EV << "[Scribe::handleJoinResponse() @ " << thisNode.ip 00399 << " (" << thisNode.key.toString(16) << ")]\n" 00400 << "Getting join response for an unknown group!\n"; 00401 return; 00402 } 00403 it->second.setParent( joinResponse->getSrcNode() ); 00404 00405 // Create new heartbeat timer 00406 ScribeTimer* parentTimeout = new ScribeTimer("ParentTimeoutTimer"); 00407 parentTimeout->setTimerType( SCRIBE_PARENT_TIMEOUT ); 00408 parentTimeout->setGroup( it->second.getGroupId() ); 00409 startTimer( parentTimeout ); 00410 if( ScribeTimer* t = it->second.getParentTimer() ){ 00411 // delete old timer, if any 00412 if( t ) cancelAndDelete( t ); 00413 } 00414 it->second.setParentTimer( parentTimeout ); 00415 }
void Scribe::handleJoinCall | ( | ScribeJoinCall * | joinMsg | ) | [protected] |
Handles a join request from another node.
This method only gets called if the local node is the root of the multicast group. It only calls handlePublishCall with amIRoot parameter set to "true"
00309 { 00310 handleJoinMessage( joinMsg, true ); 00311 }
void Scribe::handlePublishCall | ( | ScribePublishCall * | publishCall | ) | [protected] |
Handles a publish call from another node.
Publish calls are used to send multicast messages to the root of the multicast tree.
00360 { 00361 // find group 00362 GroupList::iterator it = groupList.find( publishCall->getGroupId() ); 00363 if( it == groupList.end() || 00364 it->second.getParent().isUnspecified() || 00365 it->second.getParent() != thisNode ){ 00366 // if I don't know the group or I am not root, inform sender 00367 // TODO: forward message when I'm not root but know the rendevous point? 00368 ScribePublishResponse* msg = new ScribePublishResponse("Wrong Root"); 00369 msg->setGroupId( publishCall->getGroupId() ); 00370 msg->setWrongRoot( true ); 00371 msg->setLength( SCRIBE_PUBLISHRESPONSE_L(msg) ); 00372 sendRpcResponse( publishCall, msg ); 00373 } else { 00374 ScribeDataMessage* data = dynamic_cast<ScribeDataMessage*>(publishCall->decapsulate()); 00375 00376 ScribePublishResponse* msg = new ScribePublishResponse("Publish Successful"); 00377 msg->setGroupId( publishCall->getGroupId() ); 00378 msg->setLength( SCRIBE_PUBLISHRESPONSE_L(msg) ); 00379 sendRpcResponse( publishCall, msg ); 00380 00381 if( !data ) { 00382 // TODO: throw exception? this should never happen 00383 EV << "[Scribe::handlePublishCall() @ " << thisNode.ip 00384 << " (" << thisNode.key.toString(16) << ")]\n" 00385 << " PublishCall for group " << msg->getGroupId() 00386 << " does not contain a calid ALM data message!\n" 00387 << endl; 00388 return; 00389 } 00390 deliverALMDataToGroup( data ); 00391 } 00392 }
void Scribe::handlePublishResponse | ( | ScribePublishResponse * | publishResponse | ) | [protected] |
Handles a response to a publish call send b this node.
Publish calls are used to send multicast messages to the root of the multicast tree.
00418 { 00419 GroupList::iterator it = groupList.find( publishResponse->getGroupId() ); 00420 if( it == groupList.end() ) { 00421 EV << "[Scribe::handlePublishResponse() @ " << thisNode.ip 00422 << " (" << thisNode.key.toString(16) << ")]\n" 00423 << "Getting publish response for an unknown group!\n"; 00424 return; 00425 } 00426 00427 if( publishResponse->getWrongRoot() ) { 00428 it->second.setRendezvousPoint( NodeHandle::UNSPECIFIED_NODE ); 00429 } else { 00430 it->second.setRendezvousPoint( publishResponse->getSrcNode() ); 00431 } 00432 }
void Scribe::handleJoinMessage | ( | ScribeJoinCall * | joinMsg, | |
bool | amIRoot | |||
) | [protected] |
Handles join requests from other nodes.
00314 { 00315 RECORD_STATS(++numJoins); 00316 OverlayKey key = joinMsg->getGroupId(); 00317 00318 EV << "[Scribe::handleJoinMessage() @ " << thisNode.ip 00319 << " (" << thisNode.key.toString(16) << ")]\n" 00320 << " Received a ScribeJoin for group " << key << "\n" 00321 << " msg=" << joinMsg 00322 << endl; 00323 00324 // Insert group into grouplist, if not already there 00325 pair<GroupList::iterator, bool> groupInserter; 00326 groupInserter = groupList.insert( make_pair(key, ScribeGroup(key)) ); 00327 00328 // If group is new or no parent is known, send join to parent (unless I am root, so there is no parent) 00329 if ( !amIRoot && ( groupInserter.second || groupInserter.first->second.getParent().isUnspecified()) ) { 00330 ScribeJoinCall* newJoin = new ScribeJoinCall; 00331 newJoin->setGroupId( key ); 00332 newJoin->setLength( SCRIBE_JOINCALL_L(newJoin) ); 00333 sendRouteRpcCall(TIER1_COMP, key, newJoin); 00334 } 00335 00336 // If group had no children, start heartbeat timer for group 00337 if( groupInserter.first->second.numChildren() == 0 ) { 00338 ScribeTimer* heartbeat = new ScribeTimer("HeartbeatTimer"); 00339 heartbeat->setTimerType( SCRIBE_HEARTBEAT ); 00340 heartbeat->setGroup( groupInserter.first->second.getGroupId() ); 00341 startTimer( heartbeat ); 00342 if( ScribeTimer* t = groupInserter.first->second.getHeartbeatTimer() ){ 00343 // delete old timer, if any 00344 if( t ) cancelAndDelete( t ); 00345 } 00346 groupInserter.first->second.setHeartbeatTimer( heartbeat ); 00347 } 00348 00349 // Add child to group 00350 addChildToGroup( joinMsg->getSrcNode(), groupInserter.first->second ); 00351 00352 // Send joinResponse 00353 ScribeJoinResponse* joinResponse = new ScribeJoinResponse; 00354 joinResponse->setGroupId( key ); 00355 joinResponse->setLength( SCRIBE_JOINRESPONSE_L(joinResponse) ); 00356 sendRpcResponse( joinMsg, joinResponse ); 00357 }
void Scribe::handleLeaveMessage | ( | ScribeLeaveMessage * | leaveMsg | ) | [protected] |
Handles leave requests from other nodes.
00435 { 00436 GroupList::iterator it = groupList.find( leaveMsg->getGroupId() ); 00437 if( it != groupList.end() ){ 00438 removeChildFromGroup( leaveMsg->getSrc(), it->second ); 00439 } 00440 delete leaveMsg; 00441 }
void Scribe::subscribeToGroup | ( | const OverlayKey & | groupId | ) | [protected] |
Gets called if the local node wants to subscribe to a multicast group.
groupId | the ID of the group to join |
00444 { 00445 EV << "[Scribe::subscribeToGroup() @ " << thisNode.ip 00446 << " (" << thisNode.key.toString(16) << ")]\n" 00447 << " Trying to join group " << groupId << "\n"; 00448 00449 // Insert group into grouplist, if not known yet 00450 pair<GroupList::iterator, bool> groupInserter; 00451 groupInserter = groupList.insert( make_pair(groupId, ScribeGroup(groupId)) ); 00452 00453 // Set subscription status 00454 groupInserter.first->second.setSubscription(true); 00455 00456 // Send join call if I'm not already a forwarder of this group 00457 if( groupInserter.second || groupInserter.first->second.getParent().isUnspecified()) { 00458 ScribeJoinCall* m = new ScribeJoinCall; 00459 m->setGroupId( groupId ); 00460 m->setLength( SCRIBE_JOINCALL_L(m) ); 00461 sendRouteRpcCall(TIER1_COMP, m->getGroupId(), m); 00462 } 00463 }
void Scribe::leaveGroup | ( | const OverlayKey & | group | ) | [protected] |
Gets called if the local node wants to leave a multicast group.
group | the ID of the group to leave |
00466 { 00467 GroupList::iterator it = groupList.find( group ); 00468 if( it != groupList.end() ){ 00469 it->second.setSubscription( false ); 00470 checkGroupEmpty( it->second ); 00471 } 00472 }
void Scribe::startTimer | ( | ScribeTimer * | timer | ) | [protected] |
Starts a local timer.
This method automaticly determines the type of the timer and schedules it accordingly. If the timer is already scheduled, it gets canceled before getting rescheduled.
00585 { 00586 if( timer->isScheduled() ) { 00587 cancelEvent( timer ); 00588 } 00589 00590 int duration = 0; 00591 switch( timer->getTimerType() ) { 00592 case SCRIBE_HEARTBEAT: 00593 duration = parentTimeout/2; 00594 break; 00595 case SCRIBE_SUBSCRIPTION_REFRESH: 00596 duration = childTimeout/2; 00597 break; 00598 case SCRIBE_PARENT_TIMEOUT: 00599 duration = parentTimeout; 00600 break; 00601 case SCRIBE_CHILD_TIMEOUT: 00602 duration = childTimeout; 00603 break; 00604 } 00605 scheduleAt(simulation.simTime() + duration, timer ); 00606 }
void Scribe::addChildToGroup | ( | const NodeHandle & | child, | |
ScribeGroup & | group | |||
) | [protected] |
Adds a child to a multicast group.
00475 { 00476 if( child == thisNode ) { 00477 // Join from ourself, ignore 00478 return; 00479 } 00480 00481 // add child to group's children list 00482 pair<set<NodeHandle>::iterator, bool> inserter = 00483 group.addChild( child ); 00484 00485 if( inserter.second ) { 00486 // if child has not been in the list, create new timeout msg 00487 ScribeTimer* timeoutMsg = new ScribeTimer; 00488 timeoutMsg->setTimerType( SCRIBE_CHILD_TIMEOUT ); 00489 00490 // Remember child and group 00491 timeoutMsg->setChild( *inserter.first ); 00492 timeoutMsg->setGroup( group.getGroupId() ); 00493 00494 startTimer( timeoutMsg ); 00495 childTimeoutList.insert( make_pair(child, timeoutMsg) ); 00496 } 00497 }
void Scribe::removeChildFromGroup | ( | const NodeHandle & | child, | |
ScribeGroup & | group | |||
) | [protected] |
Removes a child from a multicast group.
00500 { 00501 // find timer 00502 ScribeTimer* timer = NULL; 00503 pair<ChildTimeoutList::iterator, ChildTimeoutList::iterator> ret = 00504 childTimeoutList.equal_range( child ); 00505 if( ret.first != childTimeoutList.end() ){ 00506 for( ChildTimeoutList::iterator it = ret.first; it!=ret.second; ++it) { 00507 if( group == it->second->getGroup() ) { 00508 timer = it->second; 00509 childTimeoutList.erase( it ); 00510 cancelAndDelete( timer ); 00511 break; 00512 } 00513 } 00514 } 00515 00516 // remove child from group's childrenlist 00517 group.removeChild( child ); 00518 00519 checkGroupEmpty( group ); 00520 }
void Scribe::removeChildFromGroup | ( | ScribeTimer * | timer | ) | [protected] |
Removes a child from a multicast group.
Both the child and the group are determined from the timer message This method gets calld if a subscription timer of a child expires.
00523 { 00524 NodeHandle& child = timer->getChild(); 00525 00526 GroupList::iterator groupIt = groupList.find( timer->getGroup() ); 00527 if( groupIt != groupList.end() ) { 00528 ScribeGroup& group = groupIt->second; 00529 // remove child from group's childrenlist 00530 group.removeChild( child ); 00531 00532 checkGroupEmpty( group ); 00533 } 00534 00535 // remove timer from timeoutlist 00536 pair<ChildTimeoutList::iterator, ChildTimeoutList::iterator> ret = 00537 childTimeoutList.equal_range( child ); 00538 if( ret.first != childTimeoutList.end() ) { 00539 for( ChildTimeoutList::iterator it = ret.first; it!=ret.second; ++it) { 00540 if( it->second == timer ) { 00541 childTimeoutList.erase( it ); 00542 cancelAndDelete( timer ); 00543 break; 00544 } 00545 } 00546 } 00547 }
void Scribe::checkGroupEmpty | ( | ScribeGroup & | group | ) | [protected] |
Chechs wheter there are any subscibers left to a given root.
00550 { 00551 if( !group.isForwarder() && !group.getSubscription() && !group.getAmISource()){ 00552 00553 if( !group.getParent().isUnspecified() && group.getParent() != thisNode ) { 00554 00555 ScribeLeaveMessage* msg = new ScribeLeaveMessage("Leave"); 00556 msg->setGroupId( group.getGroupId() ); 00557 msg->setSrc( thisNode ); 00558 msg->setLength( SCRIBE_LEAVE_L(msg) ); 00559 callRoute( OverlayKey::UNSPECIFIED_KEY, msg, group.getParent() ); 00560 } 00561 00562 if( group.getParentTimer() ) cancelAndDelete( group.getParentTimer() ); 00563 if( group.getHeartbeatTimer() ) cancelAndDelete( group.getHeartbeatTimer() ); 00564 groupList.erase( group.getGroupId() ); 00565 } 00566 }
void Scribe::refreshChildTimer | ( | NodeHandle & | child, | |
OverlayKey & | groupId | |||
) | [protected] |
Refreshes a child timer.
If a child sends a subscribtion refresh, this method gets called. It finds the subscriptionTimeout timer for the group and reschedules it.
00569 { 00570 // find timer 00571 pair<ChildTimeoutList::iterator, ChildTimeoutList::iterator> ret = 00572 childTimeoutList.equal_range( child ); 00573 // no timer yet? 00574 if( ret.first == childTimeoutList.end() ) return; 00575 00576 // restart timer 00577 for( ChildTimeoutList::iterator it = ret.first; it!=ret.second; ++it) { 00578 if( it->first == child && it->second->getGroup() == groupId ) { 00579 startTimer( it->second ); 00580 } 00581 } 00582 }
void Scribe::deliverALMDataToGroup | ( | ScribeDataMessage * | dataMsg | ) | [protected] |
Delivers a multicast message to all children in the multicast group.
00648 { 00649 // find group 00650 GroupList::iterator it = groupList.find( dataMsg->getGroupId() ); 00651 if( it == groupList.end() ) { 00652 EV << "[Scribe::deliverALMDataToGroup() @ " << thisNode.ip 00653 << "Getting ALM data message response for an unknown group!\n"; 00654 delete dataMsg; 00655 return; 00656 } 00657 // FIXME: ignore message if not from designated parent to avoid duplicates 00658 00659 // reset parent heartbeat Timer 00660 ScribeTimer *timer = it->second.getParentTimer(); 00661 if( timer ) startTimer( timer ); 00662 00663 // Only empty heartbeat? 00664 if( dataMsg->getEmpty() ) { 00665 delete dataMsg; 00666 return; 00667 } 00668 00669 // deliver data to children 00670 for( set<NodeHandle>::iterator cit = it->second.getChildrenBegin(); 00671 cit != it->second.getChildrenEnd(); ++cit ) { 00672 ScribeDataMessage* newMsg = new ScribeDataMessage( *dataMsg ); 00673 newMsg->setLength( SCRIBE_DATA_L(newMsg) ); 00674 RECORD_STATS(++numForward; forwardBytes += newMsg->byteLength()); 00675 callRoute( OverlayKey::UNSPECIFIED_KEY, newMsg, *cit ); 00676 } 00677 00678 // deliver to myself if I'm subscribed to that group 00679 if( it->second.getSubscription() ) { 00680 ALMMulticastMessage* mcastMsg = new ALMMulticastMessage( dataMsg->name() ); 00681 mcastMsg->setGroupId( dataMsg->getGroupId() ); 00682 mcastMsg->encapsulate( dataMsg->decapsulate() ); 00683 RECORD_STATS(++numReceived; receivedBytes += dataMsg->byteLength()); 00684 send( mcastMsg, "to_upperTier" ); 00685 } 00686 00687 delete dataMsg; 00688 }
void Scribe::deliverALMDataToRoot | ( | ALMMulticastMessage * | mcastMsg | ) | [protected] |
Delivers a multicast message to the tree's root.
This method gets called when the local app wants to publish some data to the multiacst group.
00609 { 00610 // find group 00611 pair<GroupList::iterator, bool> groupInserter; 00612 groupInserter = groupList.insert( make_pair(mcastMsg->getGroupId(), ScribeGroup(mcastMsg->getGroupId())) ); 00613 00614 // Group is not known yet 00615 if( groupInserter.second ) { 00616 groupInserter.first->second.setAmISource( true ); 00617 // TODO: Start/Restart timer to clean up cached groups 00618 // If the timer expires, the flag should be cleared and checkGroupEmpty should be called 00619 // 00620 // FIXME: amISource should be set allways if app publishes messages to the group 00621 // As the timer is not implemented yet, we only set the flag in "sender, but not receiver" mode 00622 // to reduce the amount of unneccessary cached groups 00623 } 00624 00625 ScribeDataMessage* dataMsg = new ScribeDataMessage( mcastMsg->name() ); 00626 dataMsg->setGroupId( mcastMsg->getGroupId() ); 00627 dataMsg->encapsulate( mcastMsg->decapsulate() ); 00628 00629 // Send publish ... 00630 ScribePublishCall* msg = new ScribePublishCall( "ScribePublish" ); 00631 msg->setGroupId( dataMsg->getGroupId() ); 00632 msg->encapsulate( dataMsg ); 00633 msg->setLength( SCRIBE_PUBLISHCALL_L(msg) ); 00634 00635 if( !groupInserter.first->second.getRendezvousPoint().isUnspecified() ) { 00636 // ... directly to the rendevouz point, if known ... 00637 sendRouteRpcCall(TIER1_COMP, groupInserter.first->second.getRendezvousPoint(), msg); 00638 } else { 00639 // ... else route it via KBR 00640 sendRouteRpcCall(TIER1_COMP, msg->getGroupId(), msg); 00641 } 00642 00643 delete mcastMsg; 00644 }
GroupList Scribe::groupList [private] |
ChildTimeoutList Scribe::childTimeoutList [private] |
int Scribe::childTimeout [private] |
int Scribe::parentTimeout [private] |
ScribeTimer* Scribe::subscriptionTimer [private] |
int Scribe::numJoins [private] |
int Scribe::numChildTimeout [private] |
int Scribe::numParentTimeout [private] |
int Scribe::numForward [private] |
int Scribe::forwardBytes [private] |
int Scribe::numReceived [private] |
int Scribe::receivedBytes [private] |
int Scribe::numHeartbeat [private] |
int Scribe::heartbeatBytes [private] |
int Scribe::numSubscriptionRefresh [private] |
int Scribe::subscriptionRefreshBytes [private] |