DHT Class Reference

A Distributed Hash Table (DHT) for KBR protocols. More...

#include <DHT.h>

Inheritance diagram for DHT:
BaseApp BaseRpc RpcListener

List of all members.

Classes

class  PendingRpcsEntry

Public Member Functions

 DHT ()
virtual ~DHT ()

Private Types

enum  PendingRpcsStates {
  INIT = 0, LOOKUP_STARTED = 1, GET_HASH_SENT = 2, GET_VALUE_SENT = 3,
  PUT_SENT = 4
}
typedef std::map< uint32_t,
PendingRpcsEntry
PendingRpcs

Private Member Functions

void initializeApp (int stage)
 initializes derived class-attributes
void finishApp ()
 collects statistical data of derived app
void handleTimerEvent (cMessage *msg)
bool handleRpcCall (BaseCallMessage *msg)
 Processes Remote-Procedure-Call invocation messages.
void handleRpcResponse (BaseResponseMessage *msg, cPolymorphic *context, int rpcId, simtime_t rtt)
 This method is called if an RPC response has been received.
void handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, cPolymorphic *context, int rpcId, const OverlayKey &destKey)
 This method is called if an RPC timeout has been reached.
void handlePutRequest (DHTPutCall *dhtMsg)
void handleGetRequest (DHTGetCall *dhtMsg)
void handlePutResponse (DHTPutResponse *dhtMsg, int rpcId)
void handleGetResponse (DHTGetResponse *dhtMsg, int rpcId)
void handlePutCAPIRequest (DHTputCAPICall *capiPutMsg)
void handleGetCAPIRequest (DHTgetCAPICall *capiPutMsg)
void handleDumpDhtRequest (DHTdumpCall *call)
void update (const NodeHandle &node, bool joined)
 Common API function: informs application about neighbors and own nodeID.
void handleLookupResponse (LookupResponse *lookupMsg, int rpcId)
void sendMaintenancePutCall (const TransportAddress &dest, const OverlayKey &key, const DhtDataEntry &entry)
int resultValuesBitLength (DHTGetResponse *msg)

Private Attributes

uint numReplica
int numGetRequests
double ratioIdentical
double maintenanceMessages
double normalMessages
double numBytesMaintenance
double numBytesNormal
bool secureMaintenance
 use a secure maintenance algorithm based on majority decisions
bool invalidDataAttack
 if node is malicious, it tries a invalidData attack
bool maintenanceAttack
 if node is malicious, it tries a maintenanceData attack
PendingRpcs pendingRpcs
 a map of all pending RPC operations
DHTDataStoragedataStorage
 pointer to the dht data storage

Friends

std::ostream & operator<< (std::ostream &Stream, const PendingRpcsEntry &entry)

Detailed Description

A Distributed Hash Table (DHT) for KBR protocols.

A Distributed Hash Table (DHT) for KBR protocols

Definition at line 44 of file DHT.h.


Member Typedef Documentation

typedef std::map<uint32_t, PendingRpcsEntry> DHT::PendingRpcs [private]

Definition at line 125 of file DHT.h.


Member Enumeration Documentation

enum DHT::PendingRpcsStates [private]
Enumerator:
INIT 
LOOKUP_STARTED 
GET_HASH_SENT 
GET_VALUE_SENT 
PUT_SENT 

Definition at line 51 of file DHT.h.

00051                            {
00052         INIT = 0,
00053         LOOKUP_STARTED = 1,
00054         GET_HASH_SENT = 2,
00055         GET_VALUE_SENT = 3,
00056         PUT_SENT = 4
00057     };


Constructor & Destructor Documentation

DHT::DHT (  ) 

Definition at line 36 of file DHT.cc.

00037 {
00038     dataStorage = NULL;
00039 }

DHT::~DHT (  )  [virtual]

Definition at line 41 of file DHT.cc.

00042 {
00043     PendingRpcs::iterator it;
00044 
00045     for (it = pendingRpcs.begin(); it != pendingRpcs.end(); it++) {
00046         delete(it->second.putCallMsg);
00047         delete(it->second.getCallMsg);
00048     }
00049 
00050     pendingRpcs.clear();
00051 
00052     if (dataStorage != NULL) {
00053         dataStorage->clear();
00054     }
00055 }


Member Function Documentation

void DHT::finishApp (  )  [private, virtual]

collects statistical data of derived app

Reimplemented from BaseApp.

Definition at line 932 of file DHT.cc.

00933 {
00934     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
00935 
00936     if (time >= GlobalStatistics::MIN_MEASURED) {
00937         globalStatistics->addStdDev("DHT: Sent Maintenance Messages/s",
00938                                     maintenanceMessages / time);
00939         globalStatistics->addStdDev("DHT: Sent Normal Messages/s",
00940                                     normalMessages / time);
00941         globalStatistics->addStdDev("DHT: Sent Maintenance Bytes/s",
00942                                     numBytesMaintenance / time);
00943         globalStatistics->addStdDev("DHT: Sent Normal Bytes/s",
00944                                     numBytesNormal / time);
00945     }
00946 }

void DHT::handleDumpDhtRequest ( DHTdumpCall *  call  )  [private]

Definition at line 515 of file DHT.cc.

Referenced by handleRpcCall().

00516 {
00517     DHTdumpResponse* response = new DHTdumpResponse();
00518     DhtDumpVector* dumpVector = dataStorage->dumpDht();
00519 
00520     response->setRecordArraySize(dumpVector->size());
00521 
00522     for (uint32_t i = 0; i < dumpVector->size(); i++) {
00523         response->setRecord(i, (*dumpVector)[i]);
00524     }
00525 
00526     delete dumpVector;
00527 
00528     sendRpcResponse(call, response);
00529 }

void DHT::handleGetCAPIRequest ( DHTgetCAPICall *  capiPutMsg  )  [private]

Definition at line 501 of file DHT.cc.

Referenced by handleRpcCall().

00502 {
00503     LookupCall* lookupCall = new LookupCall();
00504     lookupCall->setKey(capiGetMsg->getKey());
00505     lookupCall->setNumSiblings(numReplica);
00506     sendInternalRpcCall(OVERLAY_COMP, lookupCall, NULL, -1, 0,
00507                         capiGetMsg->getNonce());
00508 
00509     PendingRpcsEntry entry;
00510     entry.getCallMsg = capiGetMsg;
00511     entry.state = LOOKUP_STARTED;
00512     pendingRpcs.insert(make_pair(capiGetMsg->getNonce(), entry));
00513 }

void DHT::handleGetRequest ( DHTGetCall *  dhtMsg  )  [private]

Definition at line 417 of file DHT.cc.

Referenced by handleRpcCall().

00418 {
00419     std::string tempString = "GET_REQUEST received: "
00420             + std::string(dhtMsg->getKey().toString(16));
00421 
00422     getParentModule()->getParentModule()->bubble(tempString.c_str());
00423 
00424     if (dhtMsg->getKey().isUnspecified()) {
00425         throw cRuntimeError("DHT::handleGetRequest: Unspecified key!");
00426     }
00427 
00428     DhtDumpVector* dataVect = dataStorage->dumpDht(dhtMsg->getKey(),
00429                                                    dhtMsg->getKind(),
00430                                                    dhtMsg->getId());
00431 
00432     if (overlay->isMalicious() && invalidDataAttack) {
00433         dataVect->resize(1);
00434         dataVect->at(0).setKey(dhtMsg->getKey());
00435         dataVect->at(0).setKind(dhtMsg->getKind());
00436         dataVect->at(0).setId(dhtMsg->getId());
00437         dataVect->at(0).setValue("Modified Data");
00438         dataVect->at(0).setTtl(3600*24*365);
00439         dataVect->at(0).setOwnerNode(overlay->getThisNode());
00440         dataVect->at(0).setIs_modifiable(false);
00441         dataVect->at(0).setResponsible(true);
00442     }
00443 
00444     // send back
00445     DHTGetResponse* responseMsg = new DHTGetResponse();
00446     responseMsg->setKey(dhtMsg->getKey());
00447     responseMsg->setIsHash(dhtMsg->getIsHash());
00448 
00449     if (dataVect->size() == 0) {
00450         responseMsg->setHashValue(BinaryValue::UNSPECIFIED_VALUE);
00451         responseMsg->setResultArraySize(0);
00452     } else {
00453         if (dhtMsg->getIsHash()) {
00454             // TODO: verify this
00455             BinaryValue resultValues;
00456             for (uint32_t i = 0; i < dataVect->size(); i++) {
00457                 resultValues += (*dataVect)[i].getValue();
00458             }
00459 
00460             CSHA1 sha1;
00461             BinaryValue hashValue(20);
00462             sha1.Reset();
00463             sha1.Update((uint8_t*) (&(*resultValues.begin())),
00464                         resultValues.size());
00465             sha1.Final();
00466             sha1.GetHash((unsigned char*)&hashValue[0]);
00467 
00468             responseMsg->setHashValue(hashValue);
00469         } else {
00470             responseMsg->setResultArraySize(dataVect->size());
00471 
00472             for (uint32_t i = 0; i < dataVect->size(); i++) {
00473                 responseMsg->setResult(i, (*dataVect)[i]);
00474             }
00475 
00476         }
00477     }
00478     delete dataVect;
00479 
00480     responseMsg->setBitLength(GETRESPONSE_L(responseMsg));
00481     RECORD_STATS(normalMessages++;
00482                  numBytesNormal += responseMsg->getByteLength());
00483     sendRpcResponse(dhtMsg, responseMsg);
00484 }

void DHT::handleGetResponse ( DHTGetResponse *  dhtMsg,
int  rpcId 
) [private]

Definition at line 555 of file DHT.cc.

Referenced by handleRpcResponse().

00556 {
00557     NodeVector* hashVector = NULL;
00558     PendingRpcs::iterator it = pendingRpcs.find(rpcId);
00559 
00560     if (it == pendingRpcs.end()) // unknown request
00561         return;
00562 
00563     if (it->second.state == GET_VALUE_SENT) {
00564         // we have sent a 'real' get request
00565         if (!dhtMsg->getIsHash()) {
00566             // TODO verify hash
00567             DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse();
00568             capiGetRespMsg->setResultArraySize(dhtMsg->getResultArraySize());
00569             for (uint i = 0; i < dhtMsg->getResultArraySize(); i++) {
00570                 capiGetRespMsg->setResult(i, dhtMsg->getResult(i));
00571             }
00572             capiGetRespMsg->setIsSuccess(true);
00573             sendRpcResponse(it->second.getCallMsg, capiGetRespMsg);
00574             pendingRpcs.erase(rpcId);
00575             return;
00576         }
00577     }
00578 
00579     if (dhtMsg->getIsHash()) {
00580         std::map<BinaryValue, NodeVector>::iterator itHashes =
00581             it->second.hashes.find(dhtMsg->getHashValue());
00582 
00583         if (itHashes == it->second.hashes.end()) {
00584             // new hash
00585             NodeVector vect;
00586             vect.push_back(dhtMsg->getSrcNode());
00587             it->second.hashes.insert(make_pair(dhtMsg->getHashValue(),
00588                                                vect));
00589         } else {
00590             itHashes->second.push_back(dhtMsg->getSrcNode());
00591         }
00592 
00593         it->second.numResponses++;
00594 
00595         if (it->second.state == GET_VALUE_SENT) {
00596             // we have already sent a real get request
00597             return;
00598         }
00599 
00600         // count the maximum number of equal hash values received so far
00601         unsigned int maxCount = 0;
00602 
00603 
00604         for (itHashes = it->second.hashes.begin();
00605         itHashes != it->second.hashes.end(); itHashes++) {
00606 
00607             if (itHashes->second.size() > maxCount) {
00608                 maxCount = itHashes->second.size();
00609                 hashVector = &(itHashes->second);
00610             }
00611         }
00612 
00613         if ((double) maxCount / (double) it->second.numAvailableReplica
00614                 >= ratioIdentical) {
00615             it->second.hashVector = hashVector;
00616         } else if (it->second.numResponses >= numGetRequests) {
00617             // we'll try to ask some other nodes
00618             if (it->second.replica.size() > 0) {
00619                 DHTGetCall* getCall = new DHTGetCall();
00620                 getCall->setKey(dhtMsg->getKey());
00621                 getCall->setKind(dhtMsg->getKind());
00622                 getCall->setId(dhtMsg->getId());
00623                 getCall->setIsHash(true);
00624                 getCall->setBitLength(GETCALL_L(getCall));
00625                 RECORD_STATS(normalMessages++;
00626                 numBytesNormal += getCall->getByteLength());
00627                 sendRouteRpcCall(TIER1_COMP,
00628                                  it->second.replica.back(), getCall,
00629                                  NULL, DEFAULT_ROUTING, -1, 0, rpcId);
00630                 it->second.replica.pop_back();
00631                 it->second.state = GET_HASH_SENT;
00632             } else if (hashVector == NULL) {
00633                 // we don't have anyone else to ask and no hash
00634                 DHTgetCAPIResponse* capiGetRespMsg =
00635                     new DHTgetCAPIResponse();
00636                 DhtDumpEntry result;
00637                 result.setKey(dhtMsg->getKey());
00638                 result.setValue(BinaryValue::UNSPECIFIED_VALUE);
00639                 capiGetRespMsg->setResultArraySize(1);
00640                 capiGetRespMsg->setResult(0, result);
00641                 capiGetRespMsg->setIsSuccess(false);
00642                 sendRpcResponse(it->second.getCallMsg, capiGetRespMsg);
00643 #if 0
00644                 cout << "DHT: GET failed: hash (no one else)" << endl;
00645                 cout << "numResponses: " << it->second.numResponses
00646                      << " numAvailableReplica: " << it->second.numAvailableReplica << endl;
00647 
00648                 for (itHashes = it->second.hashes.begin();
00649                      itHashes != it->second.hashes.end(); itHashes++) {
00650                     cout << "   - " << itHashes->first << " ("
00651                          << itHashes->second.size() << ")" << endl;
00652                 }
00653 #endif
00654 
00655                 pendingRpcs.erase(rpcId);
00656                 return;
00657             } else {
00658                 // we don't have anyone else to ask => take what we've got
00659                 it->second.hashVector = hashVector;
00660             }
00661         }
00662     }
00663 
00664     if ((it->second.state != GET_VALUE_SENT) &&
00665             (it->second.hashVector != NULL)) {
00666         // we have already received all the response and chosen a hash
00667         if (it->second.hashVector->size() > 0) {
00668             DHTGetCall* getCall = new DHTGetCall();
00669             getCall->setKey(it->second.getCallMsg->getKey());
00670             getCall->setKind(it->second.getCallMsg->getKind());
00671             getCall->setId(it->second.getCallMsg->getId());
00672             getCall->setIsHash(false);
00673             getCall->setBitLength(GETCALL_L(getCall));
00674             RECORD_STATS(normalMessages++;
00675                          numBytesNormal += getCall->getByteLength());
00676             sendRouteRpcCall(TIER1_COMP, it->second.hashVector->back(),
00677                              getCall, NULL, DEFAULT_ROUTING, -1, 0, rpcId);
00678             it->second.hashVector->pop_back();
00679             it->second.state = GET_VALUE_SENT;
00680         } else { // we don't have anyone else to ask
00681             DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse();
00682             DhtDumpEntry result;
00683             result.setKey(dhtMsg->getKey());
00684             result.setValue(BinaryValue::UNSPECIFIED_VALUE);
00685             capiGetRespMsg->setResultArraySize(1);
00686             capiGetRespMsg->setResult(0, result);
00687             capiGetRespMsg->setIsSuccess(false);
00688             sendRpcResponse(it->second.getCallMsg, capiGetRespMsg);
00689             //cout << "DHT: GET failed: hash2 (no one else)" << endl;
00690             pendingRpcs.erase(rpcId);
00691         }
00692     }
00693 }

void DHT::handleLookupResponse ( LookupResponse *  lookupMsg,
int  rpcId 
) [private]

Definition at line 810 of file DHT.cc.

Referenced by handleRpcResponse().

00811 {
00812     PendingRpcs::iterator it = pendingRpcs.find(rpcId);
00813 
00814     if (it == pendingRpcs.end()) {
00815         return;
00816     }
00817 
00818     if (it->second.putCallMsg != NULL) {
00819 
00820 #if 0
00821         cout << "DHT::handleLookupResponse(): PUT "
00822              << lookupMsg->getKey() << " ("
00823              << overlay->getThisNode().getKey() << ")" << endl;
00824 
00825         for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) {
00826             cout << i << ": " << lookupMsg->getSiblings(i) << endl;
00827         }
00828 #endif
00829 
00830         if ((lookupMsg->getIsValid() == false)
00831                 || (lookupMsg->getSiblingsArraySize() == 0)) {
00832 
00833             EV << "[DHT::handleLookupResponse()]\n"
00834                << "    Unable to get replica list : invalid lookup"
00835                << endl;
00836             DHTputCAPIResponse* capiPutRespMsg = new DHTputCAPIResponse();
00837             capiPutRespMsg->setIsSuccess(false);
00838             //cout << "DHT::lookup failed" << endl;
00839             sendRpcResponse(it->second.putCallMsg, capiPutRespMsg);
00840             pendingRpcs.erase(rpcId);
00841             return;
00842         }
00843 
00844         if ((it->second.putCallMsg->getId() == 0) &&
00845                 (it->second.putCallMsg->getValue().size() > 0)) {
00846             // pick a random id before replication of the data item
00847             // id 0 is kept for delete requests (i.e. a put with empty value)
00848             it->second.putCallMsg->setId(intuniform(1, 2147483647));
00849         }
00850 
00851         for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) {
00852             DHTPutCall* dhtMsg = new DHTPutCall();
00853             dhtMsg->setKey(it->second.putCallMsg->getKey());
00854             dhtMsg->setKind(it->second.putCallMsg->getKind());
00855             dhtMsg->setId(it->second.putCallMsg->getId());
00856             dhtMsg->setValue(it->second.putCallMsg->getValue());
00857             dhtMsg->setTtl(it->second.putCallMsg->getTtl());
00858             dhtMsg->setIsModifiable(it->second.putCallMsg->getIsModifiable());
00859             dhtMsg->setMaintenance(false);
00860             dhtMsg->setBitLength(PUTCALL_L(dhtMsg));
00861             RECORD_STATS(normalMessages++;
00862                          numBytesNormal += dhtMsg->getByteLength());
00863             sendRouteRpcCall(TIER1_COMP, lookupMsg->getSiblings(i),
00864                              dhtMsg, NULL, DEFAULT_ROUTING, -1,
00865                              0, rpcId);
00866         }
00867 
00868         it->second.state = PUT_SENT;
00869         it->second.numResponses = 0;
00870         it->second.numFailed = 0;
00871         it->second.numSent = lookupMsg->getSiblingsArraySize();
00872     }
00873     else if (it->second.getCallMsg != NULL) {
00874 
00875 #if 0
00876         cout << "DHT::handleLookupResponse(): GET "
00877              << lookupMsg->getKey() << " ("
00878              << overlay->getThisNode().getKey() << ")" << endl;
00879 
00880         for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) {
00881             cout << i << ": " << lookupMsg->getSiblings(i) << endl;
00882         }
00883 #endif
00884 
00885         if ((lookupMsg->getIsValid() == false)
00886                 || (lookupMsg->getSiblingsArraySize() == 0)) {
00887 
00888             EV << "[DHT::handleLookupResponse()]\n"
00889                << "    Unable to get replica list : invalid lookup"
00890                << endl;
00891             DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse();
00892             DhtDumpEntry result;
00893             result.setKey(lookupMsg->getKey());
00894             result.setValue(BinaryValue::UNSPECIFIED_VALUE);
00895             capiGetRespMsg->setResultArraySize(1);
00896             capiGetRespMsg->setResult(0, result);
00897             capiGetRespMsg->setIsSuccess(false);
00898             //cout << "DHT: lookup failed 2" << endl;
00899             sendRpcResponse(it->second.getCallMsg, capiGetRespMsg);
00900             pendingRpcs.erase(rpcId);
00901             return;
00902         }
00903 
00904         it->second.numSent = 0;
00905 
00906         for (unsigned int i = 0; i < lookupMsg->getSiblingsArraySize(); i++) {
00907             if (i < (unsigned int)numGetRequests) {
00908                 DHTGetCall* dhtMsg = new DHTGetCall();
00909                 dhtMsg->setKey(it->second.getCallMsg->getKey());
00910                 dhtMsg->setKind(it->second.getCallMsg->getKind());
00911                 dhtMsg->setId(it->second.getCallMsg->getId());
00912                 dhtMsg->setIsHash(true);
00913                 dhtMsg->setBitLength(GETCALL_L(dhtMsg));
00914                 RECORD_STATS(normalMessages++;
00915                              numBytesNormal += dhtMsg->getByteLength());
00916                 sendRouteRpcCall(TIER1_COMP, lookupMsg->getSiblings(i), dhtMsg,
00917                                  NULL, DEFAULT_ROUTING, -1, 0, rpcId);
00918                 it->second.numSent++;
00919             } else {
00920                 // we don't send, we just store the remaining keys
00921                 it->second.replica.push_back(lookupMsg->getSiblings(i));
00922             }
00923         }
00924 
00925         it->second.numAvailableReplica = lookupMsg->getSiblingsArraySize();
00926         it->second.numResponses = 0;
00927         it->second.hashVector = NULL;
00928         it->second.state = GET_HASH_SENT;
00929     }
00930 }

void DHT::handlePutCAPIRequest ( DHTputCAPICall *  capiPutMsg  )  [private]

Definition at line 486 of file DHT.cc.

Referenced by handleRpcCall().

00487 {
00488     // asks the replica list
00489     LookupCall* lookupCall = new LookupCall();
00490     lookupCall->setKey(capiPutMsg->getKey());
00491     lookupCall->setNumSiblings(numReplica);
00492     sendInternalRpcCall(OVERLAY_COMP, lookupCall, NULL, -1, 0,
00493                         capiPutMsg->getNonce());
00494 
00495     PendingRpcsEntry entry;
00496     entry.putCallMsg = capiPutMsg;
00497     entry.state = LOOKUP_STARTED;
00498     pendingRpcs.insert(make_pair(capiPutMsg->getNonce(), entry));
00499 }

void DHT::handlePutRequest ( DHTPutCall *  dhtMsg  )  [private]

Definition at line 292 of file DHT.cc.

Referenced by handleRpcCall().

00293 {
00294     std::string tempString = "PUT_REQUEST received: "
00295             + std::string(dhtMsg->getKey().toString(16));
00296     getParentModule()->getParentModule()->bubble(tempString.c_str());
00297 
00298     bool err;
00299     bool isSibling = overlay->isSiblingFor(overlay->getThisNode(),
00300                   dhtMsg->getKey(), secureMaintenance ? numReplica : 1, &err);
00301     if (err) {
00302         isSibling = true;
00303     }
00304 
00305     if (secureMaintenance && dhtMsg->getMaintenance()) {
00306         DhtDataEntry* entry = dataStorage->getDataEntry(dhtMsg->getKey(),
00307                                                         dhtMsg->getKind(),
00308                                                         dhtMsg->getId());
00309         if (entry == NULL) {
00310             // add ttl timer
00311             DHTTtlTimer *timerMsg = new DHTTtlTimer("ttl_timer");
00312             timerMsg->setKey(dhtMsg->getKey());
00313             timerMsg->setKind(dhtMsg->getKind());
00314             timerMsg->setId(dhtMsg->getId());
00315             scheduleAt(simTime() + dhtMsg->getTtl(), timerMsg);
00316 
00317             entry = dataStorage->addData(dhtMsg->getKey(), dhtMsg->getKind(),
00318                                  dhtMsg->getId(), dhtMsg->getValue(), timerMsg,
00319                                  dhtMsg->getIsModifiable(), dhtMsg->getSrcNode(),
00320                                  isSibling);
00321         } else if ((entry->siblingVote.size() == 0) && isSibling) {
00322             // we already have a verified entry with this key and are
00323             // still responsible => ignore maintenance calls
00324             delete dhtMsg;
00325             return;
00326         }
00327 
00328         SiblingVoteMap::iterator it = entry->siblingVote.find(dhtMsg->getValue());
00329         if (it == entry->siblingVote.end()) {
00330             // new hash
00331             NodeVector vect;
00332             vect.add(dhtMsg->getSrcNode());
00333             entry->siblingVote.insert(make_pair(dhtMsg->getValue(),
00334                                                 vect));
00335         } else {
00336             it->second.add(dhtMsg->getSrcNode());
00337         }
00338 
00339         size_t maxCount = 0;
00340         SiblingVoteMap::iterator majorityIt;
00341 
00342         for (it = entry->siblingVote.begin(); it != entry->siblingVote.end(); it++) {
00343             if (it->second.size() > maxCount) {
00344                 maxCount = it->second.size();
00345                 majorityIt = it;
00346             }
00347         }
00348 
00349         entry->value = majorityIt->first;
00350         entry->responsible = true;
00351 
00352         if (maxCount > numReplica) {
00353             entry->siblingVote.clear();
00354         }
00355 
00356         // send back
00357         DHTPutResponse* responseMsg = new DHTPutResponse();
00358         responseMsg->setSuccess(true);
00359         responseMsg->setBitLength(PUTRESPONSE_L(responseMsg));
00360         RECORD_STATS(normalMessages++; numBytesNormal += responseMsg->getByteLength());
00361 
00362         sendRpcResponse(dhtMsg, responseMsg);
00363 
00364         return;
00365     }
00366 
00367 #if 0
00368     if (!(dataStorage->isModifiable(dhtMsg->getKey(), dhtMsg->getKind(),
00369                                     dhtMsg->getId()))) {
00370         // check if the put request came from the right node
00371         NodeHandle sourceNode = dataStorage->getSourceNode(dhtMsg->getKey(),
00372                                     dhtMsg->getKind(), dhtMsg->getId());
00373         if (((!sourceNode.isUnspecified())
00374                 && (!dhtMsg->getSrcNode().isUnspecified()) && (sourceNode
00375                 != dhtMsg->getSrcNode())) || ((dhtMsg->getMaintenance())
00376                 && (dhtMsg->getOwnerNode() == sourceNode))) {
00377             // TODO: set owner
00378             DHTPutResponse* responseMsg = new DHTPutResponse();
00379             responseMsg->setSuccess(false);
00380             responseMsg->setBitLength(PUTRESPONSE_L(responseMsg));
00381             RECORD_STATS(normalMessages++;
00382                          numBytesNormal += responseMsg->getByteLength());
00383             sendRpcResponse(dhtMsg, responseMsg);
00384             return;
00385         }
00386 
00387     }
00388 #endif
00389 
00390     // remove data item from local data storage
00391     dataStorage->removeData(dhtMsg->getKey(), dhtMsg->getKind(),
00392                             dhtMsg->getId());
00393 
00394     if (dhtMsg->getValue().size() > 0) {
00395         // add ttl timer
00396         DHTTtlTimer *timerMsg = new DHTTtlTimer("ttl_timer");
00397         timerMsg->setKey(dhtMsg->getKey());
00398         timerMsg->setKind(dhtMsg->getKind());
00399         timerMsg->setId(dhtMsg->getId());
00400         scheduleAt(simTime() + dhtMsg->getTtl(), timerMsg);
00401         // storage data item in local data storage
00402         dataStorage->addData(dhtMsg->getKey(), dhtMsg->getKind(),
00403                                      dhtMsg->getId(), dhtMsg->getValue(), timerMsg,
00404                              dhtMsg->getIsModifiable(), dhtMsg->getSrcNode(),
00405                              isSibling);
00406     }
00407 
00408     // send back
00409     DHTPutResponse* responseMsg = new DHTPutResponse();
00410     responseMsg->setSuccess(true);
00411     responseMsg->setBitLength(PUTRESPONSE_L(responseMsg));
00412     RECORD_STATS(normalMessages++; numBytesNormal += responseMsg->getByteLength());
00413 
00414     sendRpcResponse(dhtMsg, responseMsg);
00415 }

void DHT::handlePutResponse ( DHTPutResponse *  dhtMsg,
int  rpcId 
) [private]

Definition at line 531 of file DHT.cc.

Referenced by handleRpcResponse().

00532 {
00533     PendingRpcs::iterator it = pendingRpcs.find(rpcId);
00534 
00535     if (it == pendingRpcs.end()) // unknown request
00536         return;
00537 
00538     if (dhtMsg->getSuccess()) {
00539         it->second.numResponses++;
00540     } else {
00541         it->second.numFailed++;
00542     }
00543 
00544 
00545 //    if ((it->second.numFailed + it->second.numResponses) == it->second.numSent) {
00546     if (it->second.numResponses / (double)it->second.numSent > 0.5) {
00547 
00548         DHTputCAPIResponse* capiPutRespMsg = new DHTputCAPIResponse();
00549         capiPutRespMsg->setIsSuccess(true);
00550         sendRpcResponse(it->second.putCallMsg, capiPutRespMsg);
00551         pendingRpcs.erase(rpcId);
00552     }
00553 }

bool DHT::handleRpcCall ( BaseCallMessage *  msg  )  [private, virtual]

Processes Remote-Procedure-Call invocation messages.


This method should be overloaded when the overlay provides RPC functionality.

Returns:
true, if rpc has been handled

Reimplemented from BaseRpc.

Definition at line 105 of file DHT.cc.

00106 {
00107     RPC_SWITCH_START(msg)
00108         // RPCs between nodes
00109         RPC_DELEGATE(DHTPut, handlePutRequest);
00110         RPC_DELEGATE(DHTGet, handleGetRequest);
00111         // internal RPCs
00112         RPC_DELEGATE(DHTputCAPI, handlePutCAPIRequest);
00113         RPC_DELEGATE(DHTgetCAPI, handleGetCAPIRequest);
00114         RPC_DELEGATE(DHTdump, handleDumpDhtRequest);
00115     RPC_SWITCH_END( )
00116 
00117     return RPC_HANDLED;
00118 }

void DHT::handleRpcResponse ( BaseResponseMessage *  msg,
cPolymorphic *  context,
int  rpcId,
simtime_t  rtt 
) [private, 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.

Definition at line 120 of file DHT.cc.

00122 {
00123     RPC_SWITCH_START(msg)
00124         RPC_ON_RESPONSE(DHTPut){
00125         handlePutResponse(_DHTPutResponse, rpcId);
00126         EV << "[DHT::handleRpcResponse()]\n"
00127            << "    DHT Put RPC Response received: id=" << rpcId
00128            << " msg=" << *_DHTPutResponse << " rtt=" << rtt
00129            << endl;
00130         break;
00131     }
00132     RPC_ON_RESPONSE(DHTGet) {
00133         handleGetResponse(_DHTGetResponse, rpcId);
00134         EV << "[DHT::handleRpcResponse()]\n"
00135            << "    DHT Get RPC Response received: id=" << rpcId
00136            << " msg=" << *_DHTGetResponse << " rtt=" << rtt
00137            << endl;
00138         break;
00139     }
00140     RPC_ON_RESPONSE(Lookup) {
00141         handleLookupResponse(_LookupResponse, rpcId);
00142         EV << "[DHT::handleRpcResponse()]\n"
00143            << "    Lookup RPC Response received: id=" << rpcId
00144            << " msg=" << *_LookupResponse << " rtt=" << rtt
00145            << endl;
00146         break;
00147     }
00148     RPC_SWITCH_END()
00149 }

void DHT::handleRpcTimeout ( BaseCallMessage *  msg,
const TransportAddress dest,
cPolymorphic *  context,
int  rpcId,
const OverlayKey destKey 
) [private, virtual]

This method is called if an RPC timeout has been reached.

Parameters:
msg The original RPC message.
dest The destination node
context Pointer to an optional state object. The object has to be handled/deleted by the handleRpcResponse() code
rpcId The RPC id.
destKey the destination OverlayKey

Reimplemented from RpcListener.

Definition at line 151 of file DHT.cc.

00154 {
00155     RPC_SWITCH_START(msg)
00156     RPC_ON_CALL(DHTPut){
00157         EV << "[DHT::handleRpcResponse()]\n"
00158            << "    DHTPut Timeout"
00159            << endl;
00160 
00161         PendingRpcs::iterator it = pendingRpcs.find(rpcId);
00162 
00163         if (it == pendingRpcs.end()) // unknown request
00164             return;
00165 
00166         it->second.numFailed++;
00167 
00168         if (it->second.numFailed / (double)it->second.numSent >= 0.5) {
00169             DHTputCAPIResponse* capiPutRespMsg = new DHTputCAPIResponse();
00170             capiPutRespMsg->setIsSuccess(false);
00171             sendRpcResponse(it->second.putCallMsg, capiPutRespMsg);
00172             //cout << "timeout 1" << endl;
00173             pendingRpcs.erase(rpcId);
00174         }
00175 
00176         break;
00177     }
00178     RPC_ON_CALL(DHTGet) {
00179         EV << "[DHT::handleRpcResponse()]\n"
00180            << "    DHTGet Timeout"
00181            << endl;
00182 
00183         PendingRpcs::iterator it = pendingRpcs.find(rpcId);
00184 
00185         if (it == pendingRpcs.end()) { // unknown request
00186             return;
00187         }
00188 
00189         if (it->second.state == GET_VALUE_SENT) {
00190             // we have sent a 'real' get request
00191             // ask anyone else, if possible
00192             if ((it->second.hashVector != NULL)
00193                 && (it->second.hashVector->size() > 0)) {
00194 
00195                 DHTGetCall* getCall = new DHTGetCall();
00196                 getCall->setKey(_DHTGetCall->getKey());
00197                 getCall->setKind(_DHTGetCall->getKind());
00198                 getCall->setId(_DHTGetCall->getId());
00199                 getCall->setIsHash(false);
00200                 getCall->setBitLength(GETCALL_L(getCall));
00201                 RECORD_STATS(normalMessages++;
00202                              numBytesNormal += getCall->getByteLength());
00203 
00204                 sendRouteRpcCall(TIER1_COMP, it->second.hashVector->back(),
00205                                  getCall, NULL, DEFAULT_ROUTING, -1, 0, rpcId);
00206                 it->second.hashVector->pop_back();
00207             } else {
00208                 // no one else
00209                 DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse();
00210                 capiGetRespMsg->setIsSuccess(false);
00211                 sendRpcResponse(it->second.getCallMsg,
00212                                 capiGetRespMsg);
00213                 //cout << "DHT: GET failed: timeout (no one else)" << endl;
00214                 pendingRpcs.erase(rpcId);
00215                 return;
00216             }
00217         } else {
00218             // timeout while waiting for hashes
00219             // try to ask another one of the replica list for the hash
00220             if (it->second.replica.size() > 0) {
00221                 DHTGetCall* getCall = new DHTGetCall();
00222                 getCall->setKey(_DHTGetCall->getKey());
00223                 getCall->setKind(_DHTGetCall->getKind());
00224                 getCall->setId(_DHTGetCall->getId());
00225                 getCall->setIsHash(true);
00226                 getCall->setBitLength(GETCALL_L(getCall));
00227 
00228                 RECORD_STATS(normalMessages++;
00229                              numBytesNormal += getCall->getByteLength());
00230 
00231                 sendRouteRpcCall(TIER1_COMP, it->second.replica.back(),
00232                                  getCall, NULL, DEFAULT_ROUTING, -1, 0,
00233                                  rpcId);
00234                 it->second.replica.pop_back();
00235             } else {
00236                 // no one else to ask, see what we can do with what we have
00237                 if (it->second.numResponses > 0) {
00238                     unsigned int maxCount = 0;
00239                     NodeVector* hashVector = NULL;
00240                     std::map<BinaryValue, NodeVector>::iterator itHashes;
00241                     for (itHashes = it->second.hashes.begin();
00242                          itHashes != it->second.hashes.end(); itHashes++) {
00243 
00244                         if (itHashes->second.size() > maxCount) {
00245                             maxCount = itHashes->second.size();
00246                             hashVector = &(itHashes->second);
00247                         }
00248                     }
00249 
00250                     // since it makes no difference for us, if we
00251                     // return a invalid result or return nothing,
00252                     // we simply return the value with the highest probability
00253                     it->second.hashVector = hashVector;
00254 #if 0
00255                     if ((double)maxCount/(double)it->second.numResponses >=
00256                                                              ratioIdentical) {
00257                         it->second.hashVector = hashVector;
00258                     }
00259 #endif
00260                 }
00261 
00262                 if ((it->second.hashVector != NULL)
00263                      && (it->second.hashVector->size() > 0)) {
00264 
00265                     DHTGetCall* getCall = new DHTGetCall();
00266                     getCall->setKey(_DHTGetCall->getKey());
00267                     getCall->setKind(_DHTGetCall->getKind());
00268                     getCall->setId(_DHTGetCall->getId());
00269                     getCall->setIsHash(false);
00270                     getCall->setBitLength(GETCALL_L(getCall));
00271                     RECORD_STATS(normalMessages++;
00272                                  numBytesNormal += getCall->getByteLength());
00273                     sendRouteRpcCall(TIER1_COMP, it->second.hashVector->back(),
00274                                      getCall, NULL, DEFAULT_ROUTING, -1,
00275                                      0, rpcId);
00276                     it->second.hashVector->pop_back();
00277                 } else {
00278                     // no more nodes to ask -> get failed
00279                     DHTgetCAPIResponse* capiGetRespMsg = new DHTgetCAPIResponse();
00280                     capiGetRespMsg->setIsSuccess(false);
00281                     sendRpcResponse(it->second.getCallMsg, capiGetRespMsg);
00282                     //cout << "DHT: GET failed: timeout2 (no one else)" << endl;
00283                     pendingRpcs.erase(rpcId);
00284                 }
00285             }
00286         }
00287         break;
00288     }
00289     RPC_SWITCH_END( )
00290 }

void DHT::handleTimerEvent ( cMessage *  msg  )  [private, virtual]

Reimplemented from BaseRpc.

Definition at line 88 of file DHT.cc.

00089 {
00090     DHTTtlTimer* msg_timer = dynamic_cast<DHTTtlTimer*> (msg);
00091 
00092     if (msg_timer) {
00093         EV << "[DHT::handleTimerEvent()]\n"
00094            << "    received timer ttl, key: "
00095            << msg_timer->getKey().toString(16)
00096            << "\n (overlay->getThisNode().getKey() = "
00097            << overlay->getThisNode().getKey().toString(16) << ")"
00098            << endl;
00099 
00100         dataStorage->removeData(msg_timer->getKey(), msg_timer->getKind(),
00101                                 msg_timer->getId());
00102     }
00103 }

void DHT::initializeApp ( int  stage  )  [private, virtual]

initializes derived class-attributes

Parameters:
stage the init stage

Reimplemented from BaseApp.

Definition at line 57 of file DHT.cc.

00058 {
00059     if (stage != MIN_STAGE_APP)
00060         return;
00061 
00062     dataStorage = check_and_cast<DHTDataStorage*>
00063                       (getParentModule()->getSubmodule("dhtDataStorage"));
00064 
00065     numReplica = par("numReplica");
00066     numGetRequests = par("numGetRequests");
00067     ratioIdentical = par("ratioIdentical");
00068     secureMaintenance = par("secureMaintenance");
00069     invalidDataAttack = par("invalidDataAttack");
00070     maintenanceAttack = par("maintenanceAttack");
00071 
00072     if ((int)numReplica > overlay->getMaxNumSiblings()) {
00073         opp_error("DHT::initialize(): numReplica bigger than what this "
00074                   "overlay can handle (%d)", overlay->getMaxNumSiblings());
00075     }
00076 
00077     maintenanceMessages = 0;
00078     normalMessages = 0;
00079     numBytesMaintenance = 0;
00080     numBytesNormal = 0;
00081     WATCH(maintenanceMessages);
00082     WATCH(normalMessages);
00083     WATCH(numBytesNormal);
00084     WATCH(numBytesMaintenance);
00085     WATCH_MAP(pendingRpcs);
00086 }

int DHT::resultValuesBitLength ( DHTGetResponse *  msg  )  [private]

Definition at line 948 of file DHT.cc.

00948                                                   {
00949     int bitSize = 0;
00950     for (uint i = 0; i < msg->getResultArraySize(); i++) {
00951         bitSize += msg->getResult(i).getValue().size();
00952 
00953     }
00954     return bitSize;
00955 }

void DHT::sendMaintenancePutCall ( const TransportAddress dest,
const OverlayKey key,
const DhtDataEntry entry 
) [private]

Definition at line 783 of file DHT.cc.

Referenced by update().

00785                                                             {
00786 
00787     DHTPutCall* dhtMsg = new DHTPutCall();
00788 
00789     dhtMsg->setKey(key);
00790     dhtMsg->setKind(entry.kind);
00791     dhtMsg->setId(entry.id);
00792 
00793     if (overlay->isMalicious() && maintenanceAttack) {
00794         dhtMsg->setValue("Modified Data");
00795     } else {
00796         dhtMsg->setValue(entry.value);
00797     }
00798 
00799     dhtMsg->setTtl((int)SIMTIME_DBL(entry.ttlMessage->getArrivalTime()
00800                                     - simTime()));
00801     dhtMsg->setIsModifiable(entry.is_modifiable);
00802     dhtMsg->setMaintenance(true);
00803     dhtMsg->setBitLength(PUTCALL_L(dhtMsg));
00804     RECORD_STATS(maintenanceMessages++;
00805                  numBytesMaintenance += dhtMsg->getByteLength());
00806 
00807     sendRouteRpcCall(TIER1_COMP, node, dhtMsg);
00808 }

void DHT::update ( const NodeHandle node,
bool  joined 
) [private, virtual]

Common API function: informs application about neighbors and own nodeID.

Parameters:
node new or lost neighbor
joined new or lost?

Reimplemented from BaseApp.

Definition at line 695 of file DHT.cc.

00696 {
00697     OverlayKey key;
00698     bool err = false;
00699     DhtDataEntry entry;
00700     std::map<OverlayKey, DhtDataEntry>::iterator it;
00701 
00702     EV << "[DHT::update() @ " << overlay->getThisNode().getAddress()
00703        << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00704        << "    Update called()"
00705        << endl;
00706 
00707     if (secureMaintenance) {
00708         for (it = dataStorage->begin(); it != dataStorage->end(); it++) {
00709             if (it->second.responsible) {
00710                 NodeVector* siblings = overlay->local_lookup(it->first,
00711                                                              numReplica,
00712                                                              false);
00713                 if (siblings->size() == 0) {
00714                     delete siblings;
00715                     continue;
00716                 }
00717 
00718                 if (joined) {
00719                     EV << "[DHT::update() @ " << overlay->getThisNode().getAddress()
00720                        << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00721                        << "    Potential new sibling for record " << it->first
00722                        << endl;
00723 
00724                     if (overlay->distance(node.getKey(), it->first) <=
00725                         overlay->distance(siblings->back().getKey(), it->first)) {
00726 
00727                         sendMaintenancePutCall(node, it->first, it->second);
00728                     }
00729 
00730                     if (overlay->distance(overlay->getThisNode().getKey(), it->first) >
00731                         overlay->distance(siblings->back().getKey(), it->first)) {
00732 
00733                         it->second.responsible = false;
00734                     }
00735                 } else {
00736                     if (overlay->distance(node.getKey(), it->first) <
00737                         overlay->distance(siblings->back().getKey(), it->first)) {
00738 
00739                         sendMaintenancePutCall(siblings->back(), it->first,
00740                                                it->second);
00741                     }
00742                 }
00743 
00744                 delete siblings;
00745             }
00746         }
00747 
00748         return;
00749     }
00750 
00751     for (it = dataStorage->begin(); it != dataStorage->end(); it++) {
00752         key = it->first;
00753         entry = it->second;
00754         if (joined) {
00755             if (entry.responsible && (overlay->isSiblingFor(node, key,
00756                                                             numReplica, &err)
00757                     || err)) { // hack for Chord, if we've got a new predecessor
00758 
00759                 if (err) {
00760                     EV << "[DHT::update()]\n"
00761                        << "    Unable to know if key: " << key
00762                        << " is in range of node: " << node
00763                        << endl;
00764                     // For Chord: we've got a new predecessor
00765                     // TODO: only send record, if we are not responsible any more
00766                     // TODO: check all protocols to change routing table first,
00767                     //       and than call update.
00768 
00769                     //if (overlay->isSiblingFor(overlay->getThisNode(), key, 1, &err)) {
00770                     //    continue;
00771                     //}
00772                 }
00773 
00774                 sendMaintenancePutCall(node, key, entry);
00775             }
00776         }
00777         //TODO: move this to the inner block above?
00778         entry.responsible = overlay->isSiblingFor(overlay->getThisNode(),
00779                                                   key, 1, &err);
00780     }
00781 }


Friends And Related Function Documentation

std::ostream& operator<< ( std::ostream &  Stream,
const PendingRpcsEntry entry 
) [friend]

Definition at line 957 of file DHT.cc.

00958 {
00959     if (entry.getCallMsg) {
00960         os << "GET";
00961     } else if (entry.putCallMsg) {
00962         os << "PUT";
00963     }
00964 
00965     os << " state: " << entry.state
00966        << " numSent: " << entry.numSent
00967        << " numResponses: " << entry.numResponses
00968        << " numFailed: " << entry.numFailed
00969        << " numAvailableReplica: " << entry.numAvailableReplica;
00970 
00971     if (entry.replica.size() > 0) {
00972         os << " replicaSize: " << entry.replica.size();
00973     }
00974 
00975     if (entry.hashVector != NULL) {
00976         os << " hashVectorSize: " << entry.hashVector->size();
00977     }
00978 
00979     if (entry.hashes.size() > 0) {
00980         os << " hashes:";
00981         std::map<BinaryValue, NodeVector>::const_iterator it;
00982 
00983         int i = 0;
00984         for (it = entry.hashes.begin(); it != entry.hashes.end(); it++, i++) {
00985             os << " hash" << i << ":" << it->second.size();
00986         }
00987     }
00988 
00989     return os;
00990 }


Member Data Documentation

pointer to the dht data storage

Definition at line 129 of file DHT.h.

Referenced by DHT(), handleDumpDhtRequest(), handleGetRequest(), handlePutRequest(), handleTimerEvent(), initializeApp(), update(), and ~DHT().

bool DHT::invalidDataAttack [private]

if node is malicious, it tries a invalidData attack

Definition at line 122 of file DHT.h.

Referenced by handleGetRequest(), and initializeApp().

bool DHT::maintenanceAttack [private]

if node is malicious, it tries a maintenanceData attack

Definition at line 123 of file DHT.h.

Referenced by initializeApp(), and sendMaintenancePutCall().

double DHT::maintenanceMessages [private]

Definition at line 116 of file DHT.h.

Referenced by finishApp(), initializeApp(), and sendMaintenancePutCall().

double DHT::normalMessages [private]
double DHT::numBytesMaintenance [private]

Definition at line 118 of file DHT.h.

Referenced by finishApp(), initializeApp(), and sendMaintenancePutCall().

double DHT::numBytesNormal [private]
int DHT::numGetRequests [private]

Definition at line 114 of file DHT.h.

Referenced by handleGetResponse(), handleLookupResponse(), and initializeApp().

uint DHT::numReplica [private]

a map of all pending RPC operations

Definition at line 126 of file DHT.h.

Referenced by handleGetCAPIRequest(), handleGetResponse(), handleLookupResponse(), handlePutCAPIRequest(), handlePutResponse(), handleRpcTimeout(), initializeApp(), and ~DHT().

double DHT::ratioIdentical [private]

Definition at line 115 of file DHT.h.

Referenced by handleGetResponse(), handleRpcTimeout(), and initializeApp().

bool DHT::secureMaintenance [private]

use a secure maintenance algorithm based on majority decisions

Definition at line 121 of file DHT.h.

Referenced by handlePutRequest(), initializeApp(), and update().


The documentation for this class was generated from the following files:
Generated on Wed May 26 16:21:17 2010 for OverSim by  doxygen 1.6.3