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