Initial stuff for sqllite version of object-db. Changing to boost::filesystem
diff --git a/client/client.cc b/client/client.cc
index 4d20e98..4f61d52 100644
--- a/client/client.cc
+++ b/client/client.cc
@@ -31,6 +31,7 @@
using namespace std;
using namespace boost;
using namespace ChronoshareClient;
+namespace fs = boost::filesystem;
void
usage ()
@@ -88,19 +89,20 @@
usage ();
}
- struct stat fileStats;
- int ok = stat (argv[2], &fileStats);
- if (ok == 0)
+ fs::path file (argv[2]);
+ fs::file_status fileStatus = fs::status (file);
+ if (is_regular_file (fileStatus))
{
// Alex: the following code is platform specific :(
- HashPtr fileHash = Hash::FromFileContent (argv[2]);
+ HashPtr fileHash = Hash::FromFileContent (file);
- notify->updateFile (argv[2],
+ notify->updateFile (file.generic_string (),
make_pair(reinterpret_cast<const ::Ice::Byte*> (fileHash->GetHash ()),
reinterpret_cast<const ::Ice::Byte*> (fileHash->GetHash ()) +
fileHash->GetHashBytes ()),
- fileStats.st_atime, fileStats.st_mtime, fileStats.st_ctime,
- fileStats.st_mode);
+ fs::last_write_time (file),
+ // fileStats.st_atime, fileStats.st_mtime, fileStats.st_ctime,
+ fileStatus.permissions ());
}
else
{
@@ -124,8 +126,10 @@
usage ();
}
+ fs::path srcFile (argv[2]);
+ fs::path dstFile (argv[3]);
- notify->moveFile (argv[2], argv[3]);
+ notify->moveFile (srcFile.generic_string (), dstFile.generic_string ());
}
else
{
diff --git a/daemon/notify-i.cc b/daemon/notify-i.cc
index 0994aa3..0a3880d 100644
--- a/daemon/notify-i.cc
+++ b/daemon/notify-i.cc
@@ -33,9 +33,7 @@
void
NotifyI::updateFile (const ::std::string &filename,
const ::std::pair<const Ice::Byte*, const Ice::Byte*> &hashRaw,
- ::Ice::Long atime,
- ::Ice::Long mtime,
- ::Ice::Long ctime,
+ ::Ice::Long wtime,
::Ice::Int mode,
const ::Ice::Current&)
{
@@ -44,7 +42,7 @@
cout << "updateFile " << filename << " with hash " << hash << endl;
try
{
- m_actionLog->AddActionUpdate (filename, hash, atime, mtime, ctime, mode);
+ m_actionLog->AddActionUpdate (filename, hash, wtime, mode);
m_actionLog->RememberStateInStateLog ();
}
diff --git a/daemon/notify-i.h b/daemon/notify-i.h
index 9fd7044..426e2a9 100644
--- a/daemon/notify-i.h
+++ b/daemon/notify-i.h
@@ -33,9 +33,7 @@
virtual void
updateFile (const ::std::string &filename,
const ::std::pair<const Ice::Byte*, const Ice::Byte*> &hash,
- ::Ice::Long atime,
- ::Ice::Long mtime,
- ::Ice::Long ctime,
+ ::Ice::Long wtime,
::Ice::Int mode,
const ::Ice::Current& = ::Ice::Current());
diff --git a/include/ccnx-common.h b/include/ccnx-common.h
index 06e7700..031d27d 100644
--- a/include/ccnx-common.h
+++ b/include/ccnx-common.h
@@ -1,3 +1,24 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
#ifndef CCNX_COMMON_H
#define CCNX_COMMON_H
@@ -23,6 +44,8 @@
typedef vector<unsigned char> Bytes;
typedef vector<string>Comps;
+typedef boost::shared_ptr<Bytes> BytesPtr;
+
// --- Bytes operations start ---
void
readRaw(Bytes &bytes, const unsigned char *src, size_t len);
diff --git a/src/action-item.proto b/src/action-item.proto
index 0144a22..3218ef8 100644
--- a/src/action-item.proto
+++ b/src/action-item.proto
@@ -12,9 +12,9 @@
required uint32 timestamp = 6;
optional bytes file_hash = 7;
- optional uint32 atime = 8;
+ // optional uint32 atime = 8;
optional uint32 mtime = 9;
- optional uint32 ctime = 10;
+ // optional uint32 ctime = 10;
optional uint32 mode = 11;
optional bytes parent_device_name = 12;
diff --git a/src/action-log.cc b/src/action-log.cc
index 5456362..cc0d945 100644
--- a/src/action-log.cc
+++ b/src/action-log.cc
@@ -26,7 +26,8 @@
using namespace std;
using namespace Ccnx;
-ActionLog::ActionLog (Ccnx::CcnxWrapperPtr ccnx, const std::string &path, const std::string &localName, const std::string &sharedFolder)
+ActionLog::ActionLog (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &path,
+ const std::string &localName, const std::string &sharedFolder)
: SyncLog (path, localName)
, m_ccnx (ccnx)
, m_sharedFolderName (sharedFolder)
@@ -83,7 +84,7 @@
void
ActionLog::AddActionUpdate (const std::string &filename,
const Hash &hash,
- time_t atime, time_t mtime, time_t ctime,
+ time_t wtime,
int mode)
{
sqlite3_exec (m_db, "BEGIN TRANSACTION;", 0,0,0);
@@ -135,9 +136,9 @@
sqlite3_bind_blob (stmt, 7, hash.GetHash (), hash.GetHashBytes (), SQLITE_TRANSIENT);
- sqlite3_bind_int64 (stmt, 8, atime);
- sqlite3_bind_int64 (stmt, 9, mtime);
- sqlite3_bind_int64 (stmt, 10, ctime);
+ // sqlite3_bind_int64 (stmt, 8, atime); // NULL
+ sqlite3_bind_int64 (stmt, 9, wtime);
+ // sqlite3_bind_int64 (stmt, 10, ctime); // NULL
sqlite3_bind_int (stmt, 11, mode);
if (parent_device_id > 0 && parent_seq_no > 0)
@@ -159,9 +160,9 @@
item.set_version (version);
item.set_timestamp (action_time);
item.set_file_hash (hash.GetHash (), hash.GetHashBytes ());
- item.set_atime (atime);
- item.set_mtime (mtime);
- item.set_ctime (ctime);
+ // item.set_atime (atime);
+ item.set_mtime (wtime);
+ // item.set_ctime (ctime);
item.set_mode (mode);
if (parent_device_id > 0 && parent_seq_no > 0)
diff --git a/src/action-log.h b/src/action-log.h
index 323f6a3..7d778d8 100644
--- a/src/action-log.h
+++ b/src/action-log.h
@@ -32,12 +32,13 @@
class ActionLog : public SyncLog
{
public:
- ActionLog (Ccnx::CcnxWrapperPtr ccnx, const std::string &path, const std::string &localName, const std::string &sharedFolder);
+ ActionLog (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &path,
+ const std::string &localName, const std::string &sharedFolder);
void
AddActionUpdate (const std::string &filename,
const Hash &hash,
- time_t atime, time_t mtime, time_t ctime,
+ time_t wtime,
int mode);
void
diff --git a/src/chronoshare-client.ice b/src/chronoshare-client.ice
index e3bf8e2..c2e056f 100644
--- a/src/chronoshare-client.ice
+++ b/src/chronoshare-client.ice
@@ -25,7 +25,7 @@
interface Notify
{
- void updateFile (string filename, ["cpp:array"] HashBytes fileHash, long atime, long mtime, long ctime, int mode);
+ void updateFile (string filename, ["cpp:array"] HashBytes fileHash, long wtime, int mode);
void moveFile (string origFilename, string newFilename);
diff --git a/src/db-helper.cc b/src/db-helper.cc
index 217c3ee..c5455e8 100644
--- a/src/db-helper.cc
+++ b/src/db-helper.cc
@@ -26,6 +26,7 @@
#include <boost/throw_exception.hpp>
using namespace boost;
+namespace fs = boost::filesystem;
const std::string INIT_DATABASE = "\
PRAGMA foreign_keys = ON; \n\
@@ -162,13 +163,16 @@
CREATE INDEX FileState_device_id_seq_no ON FileState (device_id, seq_no); \n\
";
-DbHelper::DbHelper (const std::string &path)
+DbHelper::DbHelper (const fs::path &path)
{
- int res = sqlite3_open((path+"chronoshare.db").c_str (), &m_db);
+ fs::path chronoshareDirectory = path / ".chronoshare";
+ fs::create_directories (chronoshareDirectory);
+
+ int res = sqlite3_open((chronoshareDirectory / "state.db").c_str (), &m_db);
if (res != SQLITE_OK)
{
BOOST_THROW_EXCEPTION (Error::Db ()
- << errmsg_info_str ("Cannot open/create dabatabase: [" + path + "chronoshare.db" + "]"));
+ << errmsg_info_str ("Cannot open/create dabatabase: [" + (chronoshareDirectory / "state.db").string () + "]"));
}
res = sqlite3_create_function (m_db, "hash", 2, SQLITE_ANY, 0, 0,
diff --git a/src/db-helper.h b/src/db-helper.h
index 51970dd..a32df64 100644
--- a/src/db-helper.h
+++ b/src/db-helper.h
@@ -28,13 +28,14 @@
#include <boost/exception/all.hpp>
#include <string>
#include "hash-helper.h"
+#include <boost/filesystem.hpp>
typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str;
class DbHelper
{
public:
- DbHelper (const std::string &path);
+ DbHelper (const boost::filesystem::path &path);
virtual ~DbHelper ();
private:
diff --git a/src/hash-helper.cc b/src/hash-helper.cc
index 33c0e77..dbb70a3 100644
--- a/src/hash-helper.cc
+++ b/src/hash-helper.cc
@@ -33,11 +33,12 @@
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/archive/iterators/dataflow_exception.hpp>
+#include <boost/filesystem/fstream.hpp>
using namespace boost;
using namespace boost::archive::iterators;
using namespace std;
-
+namespace fs = boost::filesystem;
template<class CharType>
struct hex_from_4_bit
@@ -130,7 +131,7 @@
}
HashPtr
-Hash::FromFileContent (const std::string &filename)
+Hash::FromFileContent (const fs::path &filename)
{
HashPtr retval = make_shared<Hash> (reinterpret_cast<void*> (0), 0);
retval->m_buf = new unsigned char [EVP_MAX_MD_SIZE];
@@ -138,7 +139,7 @@
EVP_MD_CTX *hash_context = EVP_MD_CTX_create ();
EVP_DigestInit_ex (hash_context, HASH_FUNCTION (), 0);
- ifstream iff (filename.c_str (), std::ios::in | std::ios::binary);
+ fs::ifstream iff (filename, std::ios::in | std::ios::binary);
while (iff.good ())
{
char buf[1024];
diff --git a/src/hash-helper.h b/src/hash-helper.h
index ea12f30..d4f750d 100644
--- a/src/hash-helper.h
+++ b/src/hash-helper.h
@@ -26,6 +26,7 @@
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/exception/all.hpp>
+#include <boost/filesystem.hpp>
// Other options: VP_md2, EVP_md5, EVP_sha, EVP_sha1, EVP_sha256, EVP_dss, EVP_dss1, EVP_mdc2, EVP_ripemd160
#define HASH_FUNCTION EVP_sha256
@@ -50,7 +51,7 @@
FromString (const std::string &hashInTextEncoding);
static HashPtr
- FromFileContent (const std::string &hashInTextEncoding);
+ FromFileContent (const boost::filesystem::path &fileName);
~Hash ()
{
diff --git a/src/object-db-file.cpp b/src/object-db-file.cpp
deleted file mode 100644
index 26f8fb3..0000000
--- a/src/object-db-file.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-#include "object-db-file.h"
-#include <assert.h>
-
-char *
-head(const Bytes &bytes)
-{
- return (char *)&bytes[0];
-}
-
-void
-writeBytes(ostream &out, const Bytes &bytes)
-{
- int size = bytes.size();
- writeInt(out, size);
- out.write(head(bytes), size);
-}
-
-void
-readBytes(istream &in, Bytes &bytes)
-{
- int size;
- readInt(in, size);
- bytes.reserve(size);
- in.read(head(bytes), size);
-}
-
-ObjectDBFile::ObjectDBFile(const string &filename)
- : m_size(0)
- , m_cap(0)
- , m_index(0)
- , m_initialized(false)
- , m_filename(filename)
- // This ensures file with filename exists (assuming having write permission)
- // This is needed as file_lock only works with existing file
- , m_ostream(m_filename.c_str(), ios_base::binary | ios_base::app)
- , m_istream(m_filename.c_str(), ios_base::binary | ios_base::binary)
- , m_filelock(m_filename.c_str())
-{
- int magic;
- ReadLock(m_filelock);
- readInt(m_istream, magic);
- if (magic == MAGIC_NUM)
- {
- m_initialized = true;
- readInt(m_istream, m_cap);
- readInt(m_istream, m_size);
- m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
- }
-}
-
-ObjectDBFile::~ObjectDBFile()
-{
- m_istream.close();
- m_ostream.close();
-}
-
-void
-ObjectDBFile::init(int capacity)
-{
- WriteLock(*m_filelock);
- if (m_initialized)
- {
- throwException("Trying to init already initialized ObjectDBFile object" + m_filename);
- }
-
- m_cap = capacity;
- m_size = 0;
-
- int magic = MAGIC_NUM;
- writeInt(m_ostream, magic);
- writeInt(m_ostream, m_cap);
- writeInt(m_ostream, m_size);
- m_initialized = true;
-
- int count = m_cap;
- int offset = 0;
- while (count-- > 0)
- {
- writeInt(m_ostream, offset);
- }
-
- // prepare read pos
- m_istream.seekg(m_ostream.tellp(), ios::beg);
-
- // DEBUG
- assert(m_ostream.tellp() == ((3 + m_cap) * sizeof(int)));
-
-}
-
-// Append is not super efficient as it needs to seek and update the pos for the
-// Content object. However, in our app, it is the case the these objects are wrote
-// once and read multiple times, so it's not a big problem.
-void
-ObjectDBFile::append(const Bytes &co)
-{
- WriteLock(m_filelock);
- checkInit("Trying to append to un-initialized ObjectDBFile: " + m_filename);
-
- if (m_size >= m_cap)
- {
- throwException("Exceed Maximum capacity: " + boost::lexical_cast<string>(m_cap));
- }
-
- // pos for this CO
- int coPos = m_ostream.tellp();
- // index field for this CO
- int indexPos = (3 + m_size) * sizeof(int);
-
- m_size++;
-
- // Update size (is it necessary?) We'll do it for now anyway
- m_ostream.seekp( 2 * sizeof(int), ios::beg);
- writeInt(m_ostream, m_size);
-
- // Write the pos for the CO
- m_ostream.seekp(indexPos, ios::beg);
- writeInt(m_ostream, coPos);
-
- // write the content object
- m_ostream.seekp(coPos, ios::beg);
- writeBytes(m_ostream, co);
-
- // By the end, the write pos is at the end of the file
-}
-
-// forget about caching for now; but ideally, we should cache the next few COs in memory
-// and the request for COs tends to be sequential
-Bytes
-ObjectDBFile::next()
-{
- // Scoped shared lock for cache
- {
- SLock(m_cacheLock);
- // no need to read file if found in cache
- if (m_dummyCache.find(m_index) != m_dummyCache.end())
- {
- int index = m_index;
- m_index++;
- return m_dummyCache[index];
- }
- }
-
- ReadLock(m_filelock);
-
- // m_index not found in cache
- Bytes co;
- if (m_index >= m_size)
- {
- // at the end of file, return empty
- return co;
- }
-
- readBytes(m_istream, co);
- m_index++;
-
- // fill dummy cache with the next CACHE_SIZE COs
- fillDummyCache();
-
- return co;
-}
-
-void
-ObjectDBFile::fillDummyCache()
-{
- ULock(m_cacheLock);
- m_dummyCache.clear();
- int stop = (m_index + CACHE_SIZE < m_size) ? m_index + CACHE_SIZE : m_size;
- // the m_index should not change
- int index = m_index;
- while (index < stop)
- {
- Bytes co;
- readBytes(m_istream, co);
- m_dummyCache.insert(make_pair(index, co));
- index++;
- }
-}
-
-int
-ObjectDBFile::size() const
-{
- return m_size;
-}
-
-void
-ObjectDBFile::updateSize()
-{
- int pos = m_istream.tellg();
- m_istream.seekg(2 * sizeof(int), ios::beg);
- readInt(m_istream, m_size);
- // recover the original pos
- m_istream.seekg(pos, ios::beg);
-}
-
-int
-ObjectDBFile::fSize()
-{
- ReadLock(m_filelock);
- updateSize();
- return m_size;
-}
-
-int
-ObjectDBFile::index()
-{
- ReadLock(m_filelock);
- return m_index;
-}
-
-bool
-ObjectDBFile::seek(int index)
-{
- ReadLock(m_filelock);
- updateSize();
- if (m_size <= index)
- {
- return false;
- }
- m_index = index;
- m_istream.seekg( (3 + m_index) * sizeof(int), ios::beg);
- int pos;
- readInt(m_istream, pos);
- m_istream.seekg(pos, ios::beg);
- return true;
-}
-
-void
-ObjectDBFile::rewind()
-{
- ReadLock(m_filelock);
- m_index = 0;
- // point to the start of the CO fields
- m_istream.seekg( (3 + m_cap) * sizeof(int), ios::beg);
-}
-
-void
-ObjectDBFile::checkInit(const string &msg)
-{
- if (!m_initialized)
- {
- throwException(msg);
- }
-}
diff --git a/src/object-db-file.h b/src/object-db-file.h
deleted file mode 100644
index 1eb1ef8..0000000
--- a/src/object-db-file.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef OBJECT_DB_FILE_H
-#define OBJECT_DB_FILE_H
-
-#include "object-db.h"
-#include <stdio.h>
-#include <fstream>
-#include <sstream>
-#include <deque>
-#include <boost/thread/locks.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/thread/shared_mutex.hpp>
-#include <boost/interprocess/sync/file_lock.hpp>
-#include <boost/interprocess/sync/sharable_lock.hpp>
-#include <boost/interprocess/sync/scoped_lock.hpp>
-
-#define _OVERRIDE
-#ifdef __GNUC__
-#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
- #undef _OVERRIDE
- #define _OVERRIDE override
-#endif // __GNUC__ version
-#endif // __GNUC__
-
-using namespace std;
-
-// This is a file based ObjectDB implementation
-// The assumption is, the Content Objects will be stored sequentially
-
-// To provide random access, we will have a table of "address" for each
-// ContentObject at the beginning of the file.
-// This also requires another assumption, that is the number of COs must
-// be know a priori. This requirement is reasonable for our dropbox-like
-// System, as the file we publish is static file and we can easily know
-// the number of COs before we store them into ObjectDB.
-
-/* How file looks like:
- * |MAGIC_NUM|capacity|size|pos for each CO ...|1st CO|2nd CO| ... |
- */
-
-class ObjectDBFile
-{
-public:
- typedef boost::interprocess::file_lock Filelock;
- typedef boost::interprocess::scoped_lock<Filelock> WriteLock;
- typedef boost::interprocess::sharable_lock<Filelock> ReadLock;
- typedef boost::shared_mutex Mutex;
- typedef boost::shared_lock<Mutex> SLock;
- typedef boost::unique_lock<Mutex> ULock;
-
- ObjectDBFile(const string &filename);
- virtual ~ObjectDBFile();
-
- // reserve the "address" table for n COs; must reserve before
- // write anything (unless reserved quota has not be consumed yet)
- void
- init(int capacity);
-
- bool
- initialized() const { return m_initialized; }
-
- // assume sequential
- virtual void
- append(const Bytes &co) _OVERRIDE;
-
- // get next CO
- virtual Bytes
- next() _OVERRIDE;
-
- // size in terms of number of COs
- // This is the lazy form of size, i.e. it returns the size cached in this object
- // but that may not necessarily equal to the actual size kept in file
- // This is enough if the caller knows for sure that no other thread is changing the
- // file or the caller does not care about the new size.
- virtual int
- size() const _OVERRIDE;
-
- // this returns the actual size (also update the size cache in this object), but it is more costly, and requires file IO
- int
- fSize();
-
- // the index of the CO to be read
- int
- index();
-
- // set the pos to be the desired CO
- // return true if success
- bool
- seek(int index);
-
- // reset pos to be zero
- void
- rewind();
-
-protected:
- // read or write lock should have been grabbed already before the call
- void
- checkInit(const string &msg);
-
- // read lock should have been grabbed already before the call
- void
- updateSize();
-
- // read lock should have been grabbed already before the call
- void
- fillDummyCache();
-
- #define MAGIC_NUM 0xAAAAAAAA
-
-protected:
- string m_filename;
- ifstream m_istream;
- ofstream m_ostream;
- Filelock m_filelock;
- bool m_initialized;
- // capacity in terms of number of COs
- int m_cap;
- int m_size;
- // the index (or seq) of the CO to be read
- int m_index;
-
- // A dummy Cache that holds the next 10 (or all remaining if less than 10)
- // COs after a next() operation
- // If needed and time allows, we can have more complex cache
- #define CACHE_SIZE 10
- map<int, Bytes> m_dummyCache;
- Mutex m_cacheMutex;
-};
-
-void inline
-writeInt(ostream &out, const int &x)
-{
- out.write((const char *)&x, sizeof(int));
-}
-
-void inline
-readInt(istream &in, int &x)
-{
- in.read((char *)&x, sizeof(int));
-}
-
-// write size and then the actual bytes
-// operator << overloading is not used to avoid confusion
-void
-writeBytes(ostream &out, const Bytes &bytes);
-
-// read size and then the actual bytes
-void
-readBytes(istream &in, Bytes &bytes);
-
-char *
-head(const Bytes &bytes);
-
-#endif
diff --git a/src/object-db.cc b/src/object-db.cc
new file mode 100644
index 0000000..8cadf7e
--- /dev/null
+++ b/src/object-db.cc
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "object-db.h"
+#include <iostream>
+#include <boost/make_shared.hpp>
+#include "db-helper.h"
+#include <sys/stat.h>
+
+using namespace std;
+using namespace Ccnx;
+using namespace boost;
+namespace fs = boost::filesystem;
+
+const std::string INIT_DATABASE = "\
+CREATE TABLE \n\
+ File( \n\
+ device_name BLOB NOT NULL, \n\
+ segment INTEGER, \n\
+ content_object BLOB, \n\
+ \
+ PRIMARY KEY (device_name, segment) \n\
+ ); \n\
+";
+
+ObjectDb::ObjectDb (const fs::path &folder, const std::string &hash)
+{
+ fs::path actualFolder = folder / "objects" / hash.substr (0, 2);
+ fs::create_directories (actualFolder);
+
+ int res = sqlite3_open((actualFolder / hash.substr (2, hash.size () - 2)).c_str (), &m_db);
+ if (res != SQLITE_OK)
+ {
+ BOOST_THROW_EXCEPTION (Error::Db ()
+ << errmsg_info_str ("Cannot open/create dabatabase: [" +
+ (actualFolder / hash.substr (2, hash.size () - 2)).string () + "]"));
+ }
+
+ // Alex: determine if tables initialized. if not, initialize... not sure what is the best way to go...
+ // for now, just attempt to create everything
+
+ char *errmsg = 0;
+ res = sqlite3_exec (m_db, INIT_DATABASE.c_str (), NULL, NULL, &errmsg);
+ if (res != SQLITE_OK && errmsg != 0)
+ {
+ std::cerr << "DEBUG: " << errmsg << std::endl;
+ sqlite3_free (errmsg);
+ }
+}
+
+ObjectDb::~ObjectDb ()
+{
+ int res = sqlite3_close (m_db);
+ if (res != SQLITE_OK)
+ {
+ // complain
+ }
+}
+
+void
+ObjectDb::saveContentObject (const Ccnx::Name &deviceName, sqlite3_int64 segment, const Ccnx::Bytes &data)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "INSERT INTO File "
+ "(device_name, segment, content_object) "
+ "VALUES (?, ?, ?)", -1, &stmt, 0);
+
+ CcnxCharbufPtr buf = deviceName.toCcnxCharbuf ();
+ sqlite3_bind_blob (stmt, 1, buf->buf (), buf->length (), SQLITE_TRANSIENT);
+ sqlite3_bind_int64 (stmt, 2, segment);
+ sqlite3_bind_blob (stmt, 3, &data[0], data.size (), SQLITE_TRANSIENT);
+
+ sqlite3_step (stmt);
+ sqlite3_finalize (stmt);
+}
+
+Ccnx::BytesPtr
+ObjectDb::fetchSegment (const Ccnx::Name &deviceName, sqlite3_int64 segment)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "SELECT content_object FROM File WHERE device_name=? AND segment=?", -1, &stmt, 0);
+
+ CcnxCharbufPtr buf = deviceName.toCcnxCharbuf ();
+ sqlite3_bind_blob (stmt, 1, buf->buf (), buf->length (), SQLITE_TRANSIENT);
+ sqlite3_bind_int64 (stmt, 2, segment);
+
+ BytesPtr ret;
+
+ int res = sqlite3_step (stmt);
+ if (res == SQLITE_ROW)
+ {
+ const unsigned char *buf = reinterpret_cast<const unsigned char*> (sqlite3_column_blob (stmt, 0));
+ int bufBytes = sqlite3_column_bytes (stmt, 0);
+
+ ret = make_shared<Bytes> (buf, buf+bufBytes);
+ }
+
+ sqlite3_finalize (stmt);
+
+ return ret;
+}
+
+// sqlite3_int64
+// ObjectDb::getNumberOfSegments (const Ccnx::Name &deviceName)
+// {
+// }
diff --git a/src/object-db.h b/src/object-db.h
index 8c31418..9e824de 100644
--- a/src/object-db.h
+++ b/src/object-db.h
@@ -1,42 +1,51 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
#ifndef OBJECT_DB_H
#define OBJECT_DB_H
-#include <boost/exception/all.hpp>
-#include <vector>
+#include <string>
+#include <sqlite3.h>
+#include <ccnx-common.h>
+#include <ccnx-name.h>
+#include <boost/filesystem.hpp>
-using namespace std;
-
-struct ObjectDBException : virtual boost::exception, virtual exception { };
-typedef boost::error_info<struct tag_errmsg, std::string> error_info_str;
-
-inline void throwException(const string &msg) { boost::throw_exception(ObjectDBException() << error_info_str(msg)); }
-
-typedef unsigned char Byte;
-typedef vector<Byte> Bytes;
-
-// OK. This name is a bit miss-leading, but this ObjectDB is really some storage
-// that stores the Ccnx ContentObjects of a file. So unlike a normal database,
-// this DB is per file.
-
-// The assumption is, the ContentObjects will be write to ObjectDB sequentially
-// This guarantees that when read, the Nth ContentObject read has the sequence number N as the last component of its name
-class ObjectDB
+class ObjectDb
{
public:
- virtual ~ObjectDB(){}
+ // database will be create in <folder>/<first-pair-of-hash-bytes>/<rest-of-hash>
+ ObjectDb (const boost::filesystem::path &folder, const std::string &hash);
+ ~ObjectDb ();
- // assume sequential
- virtual void
- append(const Bytes &co) = 0;
+ void
+ saveContentObject (const Ccnx::Name &deviceName, sqlite3_int64 segment, const Ccnx::Bytes &data);
- // get next CO
- virtual Bytes
- next() = 0;
+ Ccnx::BytesPtr
+ fetchSegment (const Ccnx::Name &deviceName, sqlite3_int64 segment);
- // size in terms of number of COs
- virtual int
- size() = 0;
-
+ // sqlite3_int64
+ // getNumberOfSegments (const Ccnx::Name &deviceName);
+
+private:
+ sqlite3 *m_db;
};
-#endif
+#endif // OBJECT_DB_H
diff --git a/src/object-manager.cc b/src/object-manager.cc
new file mode 100644
index 0000000..a2de9f1
--- /dev/null
+++ b/src/object-manager.cc
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "object-manager.h"
+#include "ccnx-name.h"
+#include "ccnx-common.h"
+#include "object-db.h"
+
+#include <sys/stat.h>
+
+#include <fstream>
+#include <boost/lexical_cast.hpp>
+#include <boost/throw_exception.hpp>
+
+using namespace Ccnx;
+using namespace boost;
+using namespace std;
+namespace fs = boost::filesystem;
+
+const int MAX_FILE_SEGMENT_SIZE = 1024;
+
+ObjectManager::ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const Ccnx::Name &localDeviceName, const fs::path &folder)
+ : m_ccnx (ccnx)
+ , m_localDeviceName (localDeviceName)
+ , m_folder (folder / ".chronoshare")
+{
+ fs::create_directories (m_folder);
+}
+
+ObjectManager::~ObjectManager ()
+{
+}
+
+HashPtr
+ObjectManager::storeLocalFile (const fs::path &file)
+{
+ HashPtr fileHash = Hash::FromFileContent (file);
+ ObjectDb fileDb (m_folder, lexical_cast<string> (*fileHash));
+
+ ifstream iff (file.c_str (), std::ios::in | std::ios::binary);
+ int segment = 0;
+ while (iff.good ())
+ {
+ char buf[MAX_FILE_SEGMENT_SIZE];
+ iff.read (buf, MAX_FILE_SEGMENT_SIZE);
+
+
+ Name name (m_localDeviceName);
+ name
+ .appendComp ("file")
+ .appendComp (fileHash->GetHash (), fileHash->GetHashBytes ())
+ .appendComp (segment);
+
+ cout << *fileHash << endl;
+ cout << name << endl;
+
+ segment ++;
+ }
+
+ return fileHash;
+}
diff --git a/src/object-manager.h b/src/object-manager.h
new file mode 100644
index 0000000..4ae719b
--- /dev/null
+++ b/src/object-manager.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012-2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#ifndef OBJECT_MANAGER_H
+#define OBJECT_MANAGER_H
+
+#include <string>
+#include <ccnx-wrapper.h>
+#include <hash-helper.h>
+#include <boost/filesystem.hpp>
+
+// everything related to managing object files
+
+class ObjectManager
+{
+public:
+ ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const Ccnx::Name &localDeviceName, const boost::filesystem::path &folder);
+ virtual ~ObjectManager ();
+
+ HashPtr
+ storeLocalFile (const boost::filesystem::path &file);
+
+private:
+ Ccnx::CcnxWrapperPtr m_ccnx;
+ Ccnx::Name m_localDeviceName;
+ boost::filesystem::path m_folder;
+};
+
+typedef boost::shared_ptr<ObjectManager> ObjectManagerPtr;
+
+namespace Error {
+struct ObjectManager : virtual boost::exception, virtual std::exception { };
+}
+
+#endif // OBJECT_MANAGER_H
diff --git a/src/sync-log.cc b/src/sync-log.cc
index ce5b46c..ca6adf7 100644
--- a/src/sync-log.cc
+++ b/src/sync-log.cc
@@ -26,7 +26,7 @@
using namespace boost;
using namespace std;
-SyncLog::SyncLog (const std::string &path, const std::string &localName)
+SyncLog::SyncLog (const boost::filesystem::path &path, const std::string &localName)
: DbHelper (path)
, m_localName (localName)
{
diff --git a/src/sync-log.h b/src/sync-log.h
index 0316294..c75fcf7 100644
--- a/src/sync-log.h
+++ b/src/sync-log.h
@@ -31,7 +31,7 @@
class SyncLog : public DbHelper
{
public:
- SyncLog (const std::string &path, const std::string &localName);
+ SyncLog (const boost::filesystem::path &path, const std::string &localName);
sqlite3_int64
GetNextLocalSeqNo (); // side effect: local seq_no will be increased
diff --git a/test/database-test.cc b/test/database-test.cc
index a4fe0d6..633c4cf 100644
--- a/test/database-test.cc
+++ b/test/database-test.cc
@@ -26,19 +26,22 @@
#include "action-log.h"
#include <iostream>
#include <ccnx-name.h>
+#include <boost/filesystem.hpp>
using namespace std;
using namespace boost;
using namespace Ccnx;
+namespace fs = boost::filesystem;
BOOST_AUTO_TEST_SUITE(DatabaseTest)
BOOST_AUTO_TEST_CASE (BasicDatabaseTest)
{
- char dir_tmpl [] = "/tmp/tmp-chornoshare-XXXXXXXXXXX";
- string tmp_dir = mkdtemp (dir_tmpl);
- SyncLog db (tmp_dir, "/alex");
+ fs::path tmpdir = fs::unique_path (fs::temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
+ fs::create_directories (tmpdir);
+
+ SyncLog db (tmpdir, "/alex");
HashPtr hash = db.RememberStateInStateLog ();
// should be empty
@@ -77,6 +80,7 @@
// db.FindStateDifferences ("86b51f1f98662583b295b61385ae4450ff8fac955981f1ca4381144ab1d7a4e0",
// "d001d4680fd9adcb48e34a795e3cc3d5d36f209fbab34fd57f70f362c2085310");
+ remove_all (tmpdir);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/test-object-manager.cc b/test/test-object-manager.cc
new file mode 100644
index 0000000..a27fd1b
--- /dev/null
+++ b/test/test-object-manager.cc
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "object-manager.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/test/unit_test.hpp>
+#include <unistd.h>
+#include <boost/make_shared.hpp>
+#include <iostream>
+
+using namespace Ccnx;
+using namespace std;
+using namespace boost;
+using namespace boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(ObjectManagerTests)
+
+BOOST_AUTO_TEST_CASE (ObjectManagerTest)
+{
+ path tmpdir = unique_path (temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
+ create_directories (tmpdir);
+
+ Name deviceName ("/device");
+
+ CcnxWrapperPtr ccnx = make_shared<CcnxWrapper> ();
+ ObjectManager manager (ccnx, deviceName, tmpdir);
+
+
+ remove_all (tmpdir);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/wscript b/wscript
index 609f64d..43d8d8f 100644
--- a/wscript
+++ b/wscript
@@ -33,7 +33,7 @@
conf.load ('ccnx')
conf.load('boost')
- conf.check_boost(lib='system test iostreams regex thread')
+ conf.check_boost(lib='system test iostreams filesystem regex thread')
boost_version = conf.env.BOOST_VERSION.split('_')
if int(boost_version[0]) < 1 or int(boost_version[1]) < 46:
@@ -57,6 +57,16 @@
conf.write_config_header('src/config.h')
def build (bld):
+ common = bld.objects (
+ target = "common",
+ features = ["cxx"],
+ source = ['src/hash-helper.cc',
+ 'src/chronoshare-client.ice',
+ ],
+ use = 'BOOST',
+ includes = ['include', 'src'],
+ )
+
libccnx = bld (
target=CCNXLIB,
features=['cxx', 'cxxshlib'],
@@ -65,21 +75,12 @@
'src/ccnx-pco.cpp',
'src/ccnx-closure.cpp',
'src/ccnx-tunnel.cpp',
- 'src/object-db-file.cpp',
+ 'src/object-db.cc',
+ 'src/object-manager.cc',
'src/ccnx-name.cpp',
'src/ccnx-selectors.cpp',
],
- use = 'BOOST BOOST_THREAD SSL CCNX',
- includes = ['include', ],
- )
-
- common = bld.objects (
- target = "common",
- features = ["cxx"],
- source = ['src/hash-helper.cc',
- 'src/chronoshare-client.ice',
- ],
- use = 'BOOST',
+ use = 'BOOST BOOST_THREAD BOOST_FILESYSTEM SSL SQLITE3 CCNX common',
includes = ['include', 'src'],
)