RetroShare/libbitdht/src/bitdht/bdhash.cc
drbob 74961774cc * Added new interface functions for start / stop DHT and to get stats.
* Implemented start/stop interface in udpbitdht and bemanager
 * added Restart of DHT if it fails to get going.
 * added start / stop functionality to bdnode and bdstore
 * added cleanup code to rest of bitdht classes.
 * reworked NetworkSize calc functions.
 * added thread debugging (prints at start / stop / join).
 * TESTS: added utest.h header file for automated unit testing (from libretroshare)
 * TESTS: bdmetric_test started conversion to automated tests
 * TESTS: udpbitdht_nettest. Added dht start / stop and network reset (thread join) functionality.
 * TESTS: fresh bdboot.txt



git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3678 b45a01b8-16f6-495d-af2f-9b41ad6348cc
2010-10-17 20:55:32 +00:00

288 lines
6.6 KiB
C++

/*
* bitdht/bdhash.cc
*
* BitDHT: An Flexible DHT library.
*
* Copyright 2010 by Robert Fernie
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 3 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "bitdht@lunamutt.com".
*
*/
#include "bitdht/bdhash.h"
#include "bitdht/bdstddht.h"
#include <iostream>
bdHashEntry::bdHashEntry(std::string value, std::string secret, time_t lifetime, time_t store)
:mValue(value), mStoreTS(store), mSecret(secret), mLifetime(lifetime)
{
return;
}
/**************************** class bdHashSet ********************************/
bdHashSet::bdHashSet(bdNodeId *id)
:mId(*id)
{
return;
}
int bdHashSet::search(std::string key, uint32_t maxAge, std::list<bdHashEntry> &entries)
{
std::multimap<std::string, bdHashEntry>::iterator sit, eit, it;
sit = mEntries.lower_bound(key);
eit = mEntries.upper_bound(key);
time_t now = time(NULL);
for(it = sit; it != eit; it++)
{
time_t age = now - it->second.mStoreTS;
if (age < (int32_t) maxAge)
{
entries.push_back(it->second);
}
}
return (0 < entries.size());
}
/***
* With modification.
* If there is no secret -> it cannot be deleted (must timeout), but can be extended.
* If there is a secret -> must include it to modify.
*
* Therefore if identical entry without secret comes along - what do I do?
* -> create duplicate?
*/
int bdHashSet::modify(std::string key, bdHashEntry *entry, uint32_t modFlags)
{
std::multimap<std::string, bdHashEntry>::iterator sit, eit, it;
sit = mEntries.lower_bound(key);
eit = mEntries.upper_bound(key);
time_t now = time(NULL);
bool updated = false;
for(it = sit; it != eit; it++)
{
/* check it all */
if (it->second.mValue == entry->mValue)
{
bool noSecret = (it->second.mSecret == "");
bool sameSecret = (it->second.mSecret == entry->mSecret);
bool update = false;
if (noSecret && sameSecret)
{
/* only allowed to increase lifetime */
if (modFlags == BITDHT_HASH_ENTRY_ADD)
{
time_t existKillTime = it->second.mLifetime + it->second.mStoreTS;
time_t newKillTime = entry->mLifetime + now;
if (newKillTime > existKillTime)
{
update = true;
}
}
}
else if (sameSecret)
{
if (modFlags == BITDHT_HASH_ENTRY_ADD)
{
update = true;
}
else if (modFlags == BITDHT_HASH_ENTRY_DELETE)
{
/* do it here */
mEntries.erase(it);
return 1;
}
}
if (update)
{
it->second.mStoreTS = now;
it->second.mLifetime = entry->mLifetime;
updated = true;
}
}
}
if ((!updated) && (modFlags == BITDHT_HASH_ENTRY_ADD))
{
/* create a new entry */
bdHashEntry newEntry(entry->mValue, entry->mSecret, entry->mLifetime, now);
mEntries.insert(std::pair<std::string, bdHashEntry>(key, newEntry));
updated = true;
}
return updated;
}
int bdHashSet::printHashSet(std::ostream &out)
{
time_t now = time(NULL);
std::multimap<std::string, bdHashEntry>::iterator it;
out << "Hash: ";
bdStdPrintNodeId(out, &mId); // Allowing "Std" as we dont need dht functions everywhere.
out << std::endl;
for(it = mEntries.begin(); it != mEntries.end();it++)
{
time_t age = now - it->second.mStoreTS;
out << "\tK:" << bdStdConvertToPrintable(it->first);
out << " V:" << bdStdConvertToPrintable(it->second.mValue);
out << " A:" << age << " L:" << it->second.mLifetime;
out << " S:" << bdStdConvertToPrintable(it->second.mSecret);
out << std::endl;
}
return 1;
}
int bdHashSet::cleanupHashSet(uint32_t maxAge)
{
time_t now = time(NULL);
/* this is nasty... but don't know how to effectively remove from multimaps
* * Must do full repeat for each removal.
*/
std::multimap<std::string, bdHashEntry>::iterator it;
for(it = mEntries.begin(); it != mEntries.end();)
{
time_t age = now - it->second.mStoreTS;
if ((age > (int32_t) maxAge) || (age > it->second.mLifetime))
{
mEntries.erase(it);
it = mEntries.begin();
}
else
{
it++;
}
}
return 1;
}
/******************************* class bdHashSpace ***************************/
bdHashSpace::bdHashSpace()
{
return;
}
/* accessors */
int bdHashSpace::search(bdNodeId *id, std::string key, uint32_t maxAge, std::list<bdHashEntry> &entries)
{
std::map<bdNodeId, bdHashSet>::iterator it;
it = mHashTable.find(*id);
if (it == mHashTable.end())
{
/* no entry */
return 1;
}
return it->second.search(key, maxAge, entries);
}
int bdHashSpace::modify(bdNodeId *id, std::string key, bdHashEntry *entry, uint32_t modFlags)
{
std::map<bdNodeId, bdHashSet>::iterator it;
it = mHashTable.find(*id);
if (it == mHashTable.end())
{
if (modFlags == BITDHT_HASH_ENTRY_DELETE)
{
/* done already */
return 1;
}
//mHashTable[*id] = bdHashSet(id);
mHashTable.insert(std::pair<bdNodeId, bdHashSet>(*id, bdHashSet(id)));
it = mHashTable.find(*id);
}
return it->second.modify(key, entry, modFlags);
}
int bdHashSpace::printHashSpace(std::ostream &out)
{
std::map<bdNodeId, bdHashSet>::iterator it;
out << "bdHashSpace::printHashSpace()" << std::endl;
out << "--------------------------------------------" << std::endl;
for(it = mHashTable.begin(); it != mHashTable.end(); it++)
{
it->second.printHashSet(out);
}
out << "--------------------------------------------" << std::endl;
return 1;
}
int bdHashSpace::cleanHashSpace(bdNodeId *min, bdNodeId *max, time_t maxAge)
{
std::map<bdNodeId, bdHashSet>::iterator it;
std::list<bdNodeId> eraseList;
std::list<bdNodeId>::iterator eit;
for(it = mHashTable.begin(); it != mHashTable.end(); it++)
{
if ((it->first < *min) ||
(*max < it->first))
{
/* schedule for erasure */
eraseList.push_back(it->first);
}
else
{
/* clean up Hash Set */
it->second.cleanupHashSet(maxAge);
}
}
/* cleanup */
while(eraseList.size() > 0)
{
bdNodeId &eId = eraseList.front();
it = mHashTable.find(eId);
if (it != mHashTable.end())
{
mHashTable.erase(it);
}
}
return 1;
}
int bdHashSpace::clear()
{
mHashTable.clear();
return 1;
}