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 (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


Member Typedef Documentation

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

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


Constructor & Destructor Documentation

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 }


Member Function Documentation

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

initializes derived class-attributes

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

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

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

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

Returns:
true, if rpc has been handled

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.

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

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

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

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

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

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


Member Data Documentation

int Scribe::childTimeout [private]

Referenced by initializeApp(), and startTimer().

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]


The documentation for this class was generated from the following files:

Generated on Fri Sep 19 13:05:08 2008 for ITM OverSim by  doxygen 1.5.5