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;