content server caches ObjectDbPtr
use Hash instead of Hash string
use constant instead of raw number
Change-Id: Ib3f5f2d4cd755bfb73b38c2621ad2383522b2621
diff --git a/src/content-server.cc b/src/content-server.cc
index 66bf26b..2aa19ca 100644
--- a/src/content-server.cc
+++ b/src/content-server.cc
@@ -21,6 +21,11 @@
#include "content-server.h"
#include "logging.h"
+#include <boost/make_shared.hpp>
+#include <utility>
+#include "task.h"
+#include "periodic-task.h"
+#include "simple-interval-generator.h"
#include <boost/lexical_cast.hpp>
INIT_LOGGER ("ContentServer");
@@ -29,6 +34,8 @@
using namespace std;
using namespace boost;
+static const int DB_CACHE_LIFETIME = 60;
+
ContentServer::ContentServer(CcnxWrapperPtr ccnx, ActionLogPtr actionLog,
const boost::filesystem::path &rootDir,
const Ccnx::Name &deviceName, const std::string &sharedFolderName,
@@ -38,17 +45,19 @@
, m_actionLog(actionLog)
, m_dbFolder(rootDir / ".chronoshare")
, m_freshness(freshness)
- , m_executor (1)
+ , m_scheduler (new Scheduler())
, m_deviceName (deviceName)
, m_sharedFolderName (sharedFolderName)
, m_appName (appName)
{
- m_executor.start ();
+ m_scheduler->start ();
+ TaskPtr flushStaleDbCacheTask = boost::make_shared<PeriodicTask>(boost::bind(&ContentServer::flushStaleDbCache, this), "flush-state-db-cache", m_scheduler, boost::make_shared<SimpleIntervalGenerator>(DB_CACHE_LIFETIME));
+ m_scheduler->addTask(flushStaleDbCacheTask);
}
ContentServer::~ContentServer()
{
- m_executor.shutdown ();
+ m_scheduler->shutdown ();
ScopedLock lock (m_mutex);
for (PrefixIt it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
@@ -123,7 +132,7 @@
ContentServer::serve_Action (Name forwardingHint, Name locatorPrefix, Name interest)
{
_LOG_DEBUG (">> content server serving ACTION, hint: " << forwardingHint << ", locatorPrefix: " << locatorPrefix << ", interest: " << interest);
- m_executor.execute (bind (&ContentServer::serve_Action_Execute, this, forwardingHint, locatorPrefix, interest));
+ m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_Action_Execute, this, forwardingHint, locatorPrefix, interest), boost::lexical_cast<string>(interest));
// need to unlock ccnx mutex... or at least don't lock it
}
@@ -132,7 +141,7 @@
{
_LOG_DEBUG (">> content server serving FILE, hint: " << forwardingHint << ", locatorPrefix: " << locatorPrefix << ", interest: " << interest);
- m_executor.execute (bind (&ContentServer::serve_File_Execute, this, forwardingHint, locatorPrefix, interest));
+ m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_File_Execute, this, forwardingHint, locatorPrefix, interest), boost::lexical_cast<string>(interest));
// need to unlock ccnx mutex... or at least don't lock it
}
@@ -153,42 +162,59 @@
_LOG_DEBUG (" server FILE for device: " << deviceName << ", file_hash: " << hash.shortHash () << " segment: " << segment);
string hashStr = lexical_cast<string> (hash);
- if (ObjectDb::DoesExist (m_dbFolder, deviceName, hashStr)) // this is kind of overkill, as it counts available segments
+
+ ObjectDbPtr db;
+
+ ScopedLock(m_dbCacheMutex);
+ {
+ DbCache::iterator it = m_dbCache.find(hash);
+ if (it != m_dbCache.end())
{
- ObjectDb db (m_dbFolder, hashStr);
- // may do prefetching
-
- BytesPtr co = db.fetchSegment (deviceName, segment);
- if (co)
+ db = it->second;
+ }
+ else
+ {
+ if (ObjectDb::DoesExist (m_dbFolder, deviceName, hashStr)) // this is kind of overkill, as it counts available segments
{
- if (forwardingHint.size () == 0)
- {
- _LOG_DEBUG (ParsedContentObject (*co).name ());
- m_ccnx->putToCcnd (*co);
- }
- else
- {
- if (m_freshness > 0)
- {
- m_ccnx->publishData(interest, *co, m_freshness);
- }
- else
- {
- m_ccnx->publishData(interest, *co);
- }
- }
-
+ db = boost::make_shared<ObjectDb>(m_dbFolder, hashStr);
+ m_dbCache.insert(make_pair(hash, db));
}
else
{
- _LOG_ERROR ("ObjectDd exists, but no segment " << segment << " for device: " << deviceName << ", file_hash: " << hash.shortHash ());
+ _LOG_ERROR ("ObjectDd doesn't exist for device: " << deviceName << ", file_hash: " << hash.shortHash ());
}
}
- else
- {
- _LOG_ERROR ("ObjectDd doesn't exist for device: " << deviceName << ", file_hash: " << hash.shortHash ());
- }
+ }
+ if (db)
+ {
+ BytesPtr co = db->fetchSegment (deviceName, segment);
+ if (co)
+ {
+ if (forwardingHint.size () == 0)
+ {
+ _LOG_DEBUG (ParsedContentObject (*co).name ());
+ m_ccnx->putToCcnd (*co);
+ }
+ else
+ {
+ if (m_freshness > 0)
+ {
+ m_ccnx->publishData(interest, *co, m_freshness);
+ }
+ else
+ {
+ m_ccnx->publishData(interest, *co);
+ }
+ }
+
+ }
+ else
+ {
+ _LOG_ERROR ("ObjectDd exists, but no segment " << segment << " for device: " << deviceName << ", file_hash: " << hash.shortHash ());
+ }
+
+ }
}
void
@@ -231,3 +257,22 @@
_LOG_ERROR ("ACTION not found for device: " << deviceName << " and seqno: " << seqno);
}
}
+
+void
+ContentServer::flushStaleDbCache()
+{
+ ScopedLock(m_dbCacheMutex);
+ DbCache::iterator it = m_dbCache.begin();
+ while (it != m_dbCache.end())
+ {
+ ObjectDbPtr db = it->second;
+ if (db->secondsSinceLastUse() >= DB_CACHE_LIFETIME)
+ {
+ m_dbCache.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
diff --git a/src/content-server.h b/src/content-server.h
index c4b70c6..7d9b3ed 100644
--- a/src/content-server.h
+++ b/src/content-server.h
@@ -26,9 +26,10 @@
#include "object-db.h"
#include "action-log.h"
#include <set>
+#include <map>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
-#include "executor.h"
+#include "scheduler.h"
class ContentServer
{
@@ -61,6 +62,9 @@
void
serve_File_Execute(Ccnx::Name forwardingHint, Ccnx::Name locatorPrefix, Ccnx::Name interest);
+ void
+ flushStaleDbCache();
+
private:
Ccnx::CcnxWrapperPtr m_ccnx;
ActionLogPtr m_actionLog;
@@ -73,7 +77,10 @@
boost::filesystem::path m_dbFolder;
int m_freshness;
- Executor m_executor;
+ SchedulerPtr m_scheduler;
+ typedef std::map<Hash, ObjectDbPtr> DbCache;
+ DbCache m_dbCache;
+ Mutex m_dbCacheMutex;
Ccnx::Name m_deviceName;
std::string m_sharedFolderName;
diff --git a/src/object-db.cc b/src/object-db.cc
index 7567c83..05aca34 100644
--- a/src/object-db.cc
+++ b/src/object-db.cc
@@ -46,6 +46,7 @@
";
ObjectDb::ObjectDb (const fs::path &folder, const std::string &hash)
+ : m_lastUsed (time(NULL))
{
fs::path actualFolder = folder / "objects" / hash.substr (0, 2);
fs::create_directories (actualFolder);
@@ -144,6 +145,9 @@
sqlite3_step (stmt);
//_LOG_DEBUG ("After saving object: " << sqlite3_errmsg (m_db));
sqlite3_finalize (stmt);
+
+ // update last used time
+ m_lastUsed = time(NULL);
}
Ccnx::BytesPtr
@@ -169,9 +173,17 @@
sqlite3_finalize (stmt);
+ // update last used time
+ m_lastUsed = time(NULL);
+
return ret;
}
+time_t
+ObjectDb::secondsSinceLastUse()
+{
+ return (time(NULL) - m_lastUsed);
+}
// sqlite3_int64
// ObjectDb::getNumberOfSegments (const Ccnx::Name &deviceName)
diff --git a/src/object-db.h b/src/object-db.h
index f60e504..cabc46d 100644
--- a/src/object-db.h
+++ b/src/object-db.h
@@ -28,6 +28,8 @@
#include <ccnx-name.h>
#include <boost/filesystem.hpp>
#include <boost/shared_ptr.hpp>
+#include <ctime>
+#include <vector>
class ObjectDb
{
@@ -45,6 +47,9 @@
// sqlite3_int64
// getNumberOfSegments (const Ccnx::Name &deviceName);
+ time_t
+ secondsSinceLastUse();
+
static bool
DoesExist (const boost::filesystem::path &folder, const Ccnx::Name &deviceName, const std::string &hash);
@@ -57,6 +62,7 @@
private:
sqlite3 *m_db;
+ time_t m_lastUsed;
};
typedef boost::shared_ptr<ObjectDb> ObjectDbPtr;