Scribe Class Reference

#include <Scribe.h>

Inheritance diagram for Scribe:

BaseApp BaseRpc RpcListener

List of all members.

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


Member Typedef Documentation

typedef map<OverlayKey, ScribeGroup> Scribe::GroupList [private]

typedef multimap<NodeHandle, ScribeTimer*> Scribe::ChildTimeoutList [private]


Constructor & Destructor Documentation

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 }


Member Function Documentation

void Scribe::initializeApp ( int  stage  )  [virtual]

initializes derived class-attributes

Parameters:
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)

Parameters:
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

Parameters:
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

Parameters:
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.

Returns:
true, if rpc has been handled

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.

Parameters:
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

Parameters:
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

Parameters:
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.

Parameters:
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.

Parameters:
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.

Parameters:
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 }


Member Data Documentation

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]

number of received packets

Reimplemented from BaseApp.

int Scribe::receivedBytes [private]

int Scribe::numHeartbeat [private]

int Scribe::heartbeatBytes [private]

int Scribe::numSubscriptionRefresh [private]

int Scribe::subscriptionRefreshBytes [private]


The documentation for this class was generated from the following files:
Generated on Thu Apr 17 13:19:30 2008 for ITM OverSim by  doxygen 1.5.3