Initial stuff for sqllite version of object-db. Changing to boost::filesystem
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