Merge remote-tracking branch 'origin/master'
diff --git a/ccnx/ccnx-common.h b/ccnx/ccnx-common.h
index 985965c..6d17116 100644
--- a/ccnx/ccnx-common.h
+++ b/ccnx/ccnx-common.h
@@ -40,10 +40,9 @@
#include <utility>
#include <string.h>
-using namespace std;
namespace Ccnx {
-typedef vector<unsigned char> Bytes;
-typedef vector<string>Comps;
+typedef std::vector<unsigned char> Bytes;
+typedef std::vector<std::string>Comps;
typedef boost::shared_ptr<Bytes> BytesPtr;
@@ -90,12 +89,21 @@
inline BytesPtr
serializeMsg(const Msg &msg)
{
- int size = msg->ByteSize ();
+ int size = msg.ByteSize ();
BytesPtr bytes (new Bytes (size));
- msg->SerializeToArray (head(*bytes), size);
+ msg.SerializeToArray (head(*bytes), size);
return bytes;
}
+template<class Msg>
+inline boost::shared_ptr<Msg>
+deserializeMsg (const Bytes &bytes)
+{
+ boost::shared_ptr<Msg> retval (new Msg ());
+ retval->ParseFromArray (head (bytes), bytes.size ());
+ return retval;
+}
+
// --- Bytes operations end ---
// Exceptions
diff --git a/ccnx/ccnx-name.cpp b/ccnx/ccnx-name.cpp
index 848019a..cc34c23 100644
--- a/ccnx/ccnx-name.cpp
+++ b/ccnx/ccnx-name.cpp
@@ -24,8 +24,9 @@
#include <ctype.h>
#include <boost/algorithm/string/join.hpp>
+using namespace std;
+
namespace Ccnx{
-CcnxCharbufPtr CcnxCharbuf::Null;
void
CcnxCharbuf::init(ccn_charbuf *buf)
@@ -57,6 +58,14 @@
init(other.m_buf);
}
+CcnxCharbuf::CcnxCharbuf(const void *buf, size_t length)
+{
+ m_buf = ccn_charbuf_create ();
+ ccn_charbuf_reserve (m_buf, length);
+ memcpy (m_buf->buf, buf, length);
+ m_buf->length = length;
+}
+
CcnxCharbuf::~CcnxCharbuf()
{
ccn_charbuf_destroy(&m_buf);
@@ -126,6 +135,41 @@
ccn_indexbuf_destroy(&idx);
}
+Name::Name (const CcnxCharbuf &buf)
+{
+ ccn_indexbuf *idx = ccn_indexbuf_create();
+ ccn_name_split (buf.getBuf (), idx);
+
+ const unsigned char *compPtr = NULL;
+ size_t size = 0;
+ int i = 0;
+ while (ccn_name_comp_get(buf.getBuf ()->buf, idx, i, &compPtr, &size) == 0)
+ {
+ Bytes comp;
+ readRaw (comp, compPtr, size);
+ m_comps.push_back(comp);
+ i++;
+ }
+ ccn_indexbuf_destroy(&idx);
+}
+
+Name::Name (const ccn_charbuf *buf)
+{
+ ccn_indexbuf *idx = ccn_indexbuf_create();
+ ccn_name_split (buf, idx);
+
+ const unsigned char *compPtr = NULL;
+ size_t size = 0;
+ int i = 0;
+ while (ccn_name_comp_get(buf->buf, idx, i, &compPtr, &size) == 0)
+ {
+ Bytes comp;
+ readRaw (comp, compPtr, size);
+ m_comps.push_back(comp);
+ i++;
+ }
+ ccn_indexbuf_destroy(&idx);
+}
Name &
Name::operator=(const Name &other)
diff --git a/ccnx/ccnx-name.h b/ccnx/ccnx-name.h
index 92c3054..b32c419 100644
--- a/ccnx/ccnx-name.h
+++ b/ccnx/ccnx-name.h
@@ -37,12 +37,15 @@
CcnxCharbuf();
CcnxCharbuf(ccn_charbuf *buf);
CcnxCharbuf(const CcnxCharbuf &other);
+ CcnxCharbuf(const void *buf, size_t length);
~CcnxCharbuf();
// expose internal data structure, use with caution!!
ccn_charbuf *
getBuf() { return m_buf; }
- static CcnxCharbufPtr Null;
+
+ const ccn_charbuf *
+ getBuf() const { return m_buf; }
const unsigned char *
buf () const
@@ -61,17 +64,19 @@
struct NameException:
- virtual boost::exception, virtual exception {};
+ virtual boost::exception, virtual std::exception {};
class Name
{
public:
Name();
- Name(const string &name);
- Name(const vector<Bytes> &comps);
+ Name(const std::string &name);
+ Name(const std::vector<Bytes> &comps);
Name(const Name &other);
Name(const unsigned char *data, const ccn_indexbuf *comps);
Name (const unsigned char *buf, const size_t length);
+ Name (const CcnxCharbuf &buf);
+ Name (const ccn_charbuf *buf);
virtual ~Name() {}
CcnxCharbufPtr
@@ -86,7 +91,7 @@
appendComp(const Bytes &comp);
Name &
- appendComp(const string &compStr);
+ appendComp(const std::string &compStr);
Name &
appendComp(const void *buf, size_t size);
@@ -114,39 +119,48 @@
Bytes
getComp(int index) const;
- // return string format of the comp
+ // return std::string format of the comp
// if all characters are printable, simply returns the string
// if not, print the bytes in hex string format
- string
+ std::string
getCompAsString(int index) const;
uint64_t
getCompAsInt (int index) const;
+ inline std::string
+ getCompFromBackAsString(int index) const;
+
+ inline uint64_t
+ getCompFromBackAsInt (int index) const;
+
Name
getPartialName(int start, int n = -1) const;
- string
+ inline Name
+ getPartialNameFromBack(int start, int n = -1) const;
+
+ std::string
toString() const;
Name &
operator=(const Name &other);
bool
- operator==(const string &str) const;
+ operator==(const std::string &str) const;
bool
- operator!=(const string &str) const;
+ operator!=(const std::string &str) const;
friend Name
operator+(const Name &n1, const Name &n2);
-protected:
- vector<Bytes> m_comps;
+private:
+ std::vector<Bytes> m_comps;
};
-ostream&
-operator <<(ostream &os, const Name &name);
+std::ostream&
+operator <<(std::ostream &os, const Name &name);
bool
operator ==(const Name &n1, const Name &n2);
@@ -158,6 +172,24 @@
operator <(const Name &n1, const Name &n2);
+std::string
+Name::getCompFromBackAsString(int index) const
+{
+ return getCompAsString (m_comps.size () - 1 - index);
+}
+
+uint64_t
+Name::getCompFromBackAsInt (int index) const
+{
+ return getCompAsInt (m_comps.size () - 1 - index);
+}
+
+Name
+Name::getPartialNameFromBack(int start, int n/* = -1*/) const
+{
+ return getPartialName (m_comps.size () - 1 - start, n);
+}
+
} // Ccnx
#endif
diff --git a/ccnx/ccnx-pco.h b/ccnx/ccnx-pco.h
index cecc763..cdb2a7e 100644
--- a/ccnx/ccnx-pco.h
+++ b/ccnx/ccnx-pco.h
@@ -48,6 +48,9 @@
Name
name() const;
+ inline const Bytes &
+ buf () const;
+
private:
void
init(const unsigned char *data, size_t len);
@@ -58,6 +61,13 @@
Bytes m_bytes;
};
+const Bytes &
+ParsedContentObject::buf () const
+{
+ return m_bytes;
+}
+
+
typedef boost::shared_ptr<ParsedContentObject> PcoPtr;
}
diff --git a/ccnx/ccnx-selectors.cpp b/ccnx/ccnx-selectors.cpp
index 001c1b7..b349cc1 100644
--- a/ccnx/ccnx-selectors.cpp
+++ b/ccnx/ccnx-selectors.cpp
@@ -2,6 +2,8 @@
#include "ccnx-common.h"
#include <boost/lexical_cast.hpp>
+using namespace std;
+
namespace Ccnx {
Selectors::Selectors()
@@ -53,7 +55,7 @@
{
if (isEmpty())
{
- return CcnxCharbuf::Null;
+ return CcnxCharbufPtr ();
}
CcnxCharbufPtr ptr(new CcnxCharbuf());
ccn_charbuf *cbuf = ptr->getBuf();
diff --git a/ccnx/ccnx-selectors.h b/ccnx/ccnx-selectors.h
index 420f33e..56e29b5 100644
--- a/ccnx/ccnx-selectors.h
+++ b/ccnx/ccnx-selectors.h
@@ -27,7 +27,7 @@
namespace Ccnx {
struct InterestSelectorException:
- virtual boost::exception, virtual exception {};
+ virtual boost::exception, virtual std::exception {};
class Selectors
{
diff --git a/ccnx/ccnx-wrapper.cpp b/ccnx/ccnx-wrapper.cpp
index 7f2e567..a8c06a3 100644
--- a/ccnx/ccnx-wrapper.cpp
+++ b/ccnx/ccnx-wrapper.cpp
@@ -325,7 +325,7 @@
CcnxCharbufPtr selectorsPtr = selectors.toCcnxCharbuf();
ccn_charbuf *templ = NULL;
- if (selectorsPtr != CcnxCharbuf::Null)
+ if (selectorsPtr)
{
templ = selectorsPtr->getBuf();
}
diff --git a/ccnx/ccnx-wrapper.h b/ccnx/ccnx-wrapper.h
index cfd030b..c1c9b9b 100644
--- a/ccnx/ccnx-wrapper.h
+++ b/ccnx/ccnx-wrapper.h
@@ -94,7 +94,7 @@
boost::thread m_thread;
bool m_running;
bool m_connected;
- map<Name, InterestCallback> m_registeredInterests;
+ std::map<Name, InterestCallback> m_registeredInterests;
};
typedef boost::shared_ptr<CcnxWrapper> CcnxWrapperPtr;
diff --git a/log4cxx.properties b/log4cxx.properties
index 89f14d6..cd28cd6 100644
--- a/log4cxx.properties
+++ b/log4cxx.properties
@@ -1,5 +1,5 @@
# Set root logger level to DEBUG and its only appender to A1.
-log4j.rootLogger=ERROR, A1
+log4j.rootLogger=TRACE, A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
@@ -11,11 +11,11 @@
#log4j.appender.A1.layout.ConversionPattern=%d{hh:mm:ss,SSS} %-14t %-14c %m%n
log4j.appender.A1.layout.ConversionPattern=%d{ss,SSS} %-5p %-12c %m%n
-log4j.logger.Sync = DEBUG
-log4j.logger.Sync.Log = ERROR
+#log4j.logger.Sync = DEBUG
+#log4j.logger.Sync.Log = ERROR
#log4j.logger.SyncInterestTable = TRACE
#log4j.logger.AppDataFetch = TRACE
-log4j.logger.Test = TRACE
+#log4j.logger.Test = TRACE
#log4j.logger.bgpparser=TRACE
#log4j.logger.bgpparser.AttributeType=ERROR
#log4j.logger.bgpparser.MRTCommonHeader=ERROR
diff --git a/src/action-log.cc b/src/action-log.cc
index 5c4f592..becbfe3 100644
--- a/src/action-log.cc
+++ b/src/action-log.cc
@@ -22,6 +22,8 @@
#include "action-log.h"
#include "logging.h"
+#include <boost/make_shared.hpp>
+
using namespace boost;
using namespace std;
using namespace Ccnx;
@@ -30,7 +32,7 @@
const std::string INIT_DATABASE = "\
CREATE TABLE ActionLog ( \n\
- device_id INTEGER NOT NULL, \n\
+ device_name BLOB NOT NULL, \n\
seq_no INTEGER NOT NULL, \n\
\n\
action CHAR(1) NOT NULL, /* 0 for \"update\", 1 for \"delete\". */ \n\
@@ -46,43 +48,38 @@
file_chmod INTEGER, \n\
file_seg_num INTEGER, /* NULL if action is \"delete\" */ \n\
\n\
- parent_device_id INTEGER, \n\
- parent_seq_no INTEGER, \n\
+ parent_device_name BLOB, \n\
+ parent_seq_no INTEGER, \n\
\n\
action_name TEXT, \n\
action_content_object BLOB, \n\
\n\
- PRIMARY KEY (device_id, seq_no), \n\
+ PRIMARY KEY (device_name, seq_no), \n\
\n\
- FOREIGN KEY (parent_device_id, parent_seq_no) \n\
- REFERENCES ActionLog (device_id, seq_no) \n\
+ FOREIGN KEY (parent_device_name, parent_seq_no) \n\
+ REFERENCES ActionLog (device_name, seq_no) \n\
ON UPDATE RESTRICT \n\
ON DELETE SET NULL \n\
); \n\
\n\
-CREATE INDEX ActionLog_filename_version ON ActionLog (filename,version); \n\
-CREATE INDEX ActionLog_parent ON ActionLog (parent_device_id, parent_seq_no); \n\
+CREATE INDEX ActionLog_filename_version ON ActionLog (filename,version); \n\
+CREATE INDEX ActionLog_parent ON ActionLog (parent_device_name, parent_seq_no); \n\
CREATE INDEX ActionLog_action_name ON ActionLog (action_name); \n\
\n\
CREATE TRIGGER ActionLogInsert_trigger \n\
AFTER INSERT ON ActionLog \n\
FOR EACH ROW \n\
- WHEN (SELECT device_id \n\
+ WHEN (SELECT device_name \n\
FROM ActionLog \n\
WHERE filename=NEW.filename AND \n\
version > NEW.version) IS NULL AND \n\
- (SELECT a.device_id \n\
- FROM ActionLog a \n\
- LEFT JOIN SyncNodes s ON s.device_id=a.device_id \n\
+ (SELECT device_name \n\
+ FROM ActionLog \n\
WHERE filename=NEW.filename AND \n\
version = NEW.version AND \n\
- a.device_id != NEW.device_id AND \n\
- s.device_name > (SELECT device_name \n\
- FROM SyncNodes \n\
- WHERE device_id=NEW.device_id)) IS NULL \n\
+ device_name > NEW.device_name) IS NULL \n\
BEGIN \n\
- SELECT apply_action ((SELECT device_name FROM SyncNodes where device_id=NEW.device_id), \
- NEW.device_id, NEW.seq_no, \
+ SELECT apply_action (NEW.device_name, NEW.seq_no, \
NEW.action,NEW.filename,NEW.file_hash, \
strftime('%s', NEW.file_atime),strftime('%s', NEW.file_mtime),strftime('%s', NEW.file_ctime), \
NEW.file_chmod, NEW.file_seg_num); /* function that applies action and adds record the FileState */ \n \
@@ -91,7 +88,7 @@
CREATE TABLE FileState ( \n\
type INTEGER NOT NULL, /* 0 - newest, 1 - oldest */ \n\
filename TEXT NOT NULL, \n\
- device_id INTEGER NOT NULL, \n\
+ device_name BLOB NOT NULL, \n\
seq_no INTEGER NOT NULL, \n\
file_hash BLOB, /* NULL if action is \"delete\" */ \n\
file_atime TIMESTAMP, \n\
@@ -103,14 +100,14 @@
PRIMARY KEY (type, filename) \n\
); \n\
\n\
-CREATE INDEX FileState_device_id_seq_no ON FileState (device_id, seq_no); \n\
+CREATE INDEX FileState_device_name_seq_no ON FileState (device_name, seq_no); \n\
";
ActionLog::ActionLog (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &path,
SyncLogPtr syncLog,
- const std::string &localName, const std::string &sharedFolder)
- : DbHelper (path)
+ const std::string &sharedFolder)
+ : DbHelper (path / ".chronoshare", "action-log.db")
, m_syncLog (syncLog)
, m_ccnx (ccnx)
, m_sharedFolderName (sharedFolder)
@@ -128,14 +125,14 @@
}
}
-tuple<sqlite3_int64, sqlite3_int64, sqlite3_int64, string>
-ActionLog::GetExistingRecord (const std::string &filename)
+tuple<sqlite3_int64 /*version*/, Ccnx::CcnxCharbufPtr /*device name*/, sqlite3_int64 /*seq_no*/>
+ActionLog::GetLatestActionForFile (const std::string &filename)
{
// check if something already exists
sqlite3_stmt *stmt;
- int res = sqlite3_prepare_v2 (m_db, "SELECT a.version,a.device_id,a.seq_no,a.action,s.device_name "
- "FROM ActionLog a JOIN SyncNodes s ON s.device_id = a.device_id "
- "WHERE filename=? ORDER BY a.version DESC LIMIT 1", -1, &stmt, 0);
+ int res = sqlite3_prepare_v2 (m_db, "SELECT version,device_name,seq_no,action "
+ "FROM ActionLog "
+ "WHERE filename=? ORDER BY version DESC LIMIT 1", -1, &stmt, 0);
if (res != SQLITE_OK)
{
@@ -143,78 +140,68 @@
<< errmsg_info_str ("Some error with GetExistingRecord"));
}
- // with parent with version number + 1
- sqlite3_int64 version = 0;
- sqlite3_int64 parent_device_id = -1;
+ sqlite3_int64 version = -1;
+ CcnxCharbufPtr parent_device_name;
sqlite3_int64 parent_seq_no = -1;
- string parent_device_name;
sqlite3_bind_text (stmt, 1, filename.c_str (), filename.size (), SQLITE_STATIC);
if (sqlite3_step (stmt) == SQLITE_ROW)
{
- version = sqlite3_column_int64 (stmt, 0) + 1;
+ version = sqlite3_column_int64 (stmt, 0);
if (sqlite3_column_int (stmt, 3) == 0) // prevent "linking" if the file was previously deleted
{
- parent_device_id = sqlite3_column_int64 (stmt, 1);
+ parent_device_name = make_shared<CcnxCharbuf> (sqlite3_column_blob (stmt, 1), sqlite3_column_bytes (stmt, 1));
parent_seq_no = sqlite3_column_int64 (stmt, 2);
- parent_device_name = string(reinterpret_cast<const char*> (sqlite3_column_blob (stmt, 4)), sqlite3_column_bytes (stmt, 4));
}
}
sqlite3_finalize (stmt);
- return make_tuple (version, parent_device_id, parent_seq_no, parent_device_name);
+ return make_tuple (version, parent_device_name, parent_seq_no);
}
// local add action. remote action is extracted from content object
void
-ActionLog::AddActionUpdate (const std::string &filename,
- const Hash &hash,
- time_t wtime,
- int mode,
- int seg_num)
+ActionLog::AddLocalActionUpdate (const std::string &filename,
+ const Hash &hash,
+ time_t wtime,
+ int mode,
+ int seg_num)
{
sqlite3_exec (m_db, "BEGIN TRANSACTION;", 0,0,0);
- sqlite3_int64 seq_no = m_syncLog->GetNextLocalSeqNo ();
- sqlite3_int64 version = 0;
- sqlite3_int64 parent_device_id = -1;
- string parent_device_name;
- sqlite3_int64 parent_seq_no = -1;
+ CcnxCharbufPtr device_name = m_syncLog->GetLocalName ().toCcnxCharbuf ();
+ sqlite3_int64 seq_no = m_syncLog->GetNextLocalSeqNo ();
+ sqlite3_int64 version;
+ CcnxCharbufPtr parent_device_name;
+ sqlite3_int64 parent_seq_no = -1;
- sqlite3_int64 action_time = time (0);
+ sqlite3_int64 action_time = time (0);
- tie (version, parent_device_id, parent_seq_no, parent_device_name) = GetExistingRecord (filename);
+ tie (version, parent_device_name, parent_seq_no) = GetLatestActionForFile (filename);
+ version ++;
sqlite3_stmt *stmt;
int res = sqlite3_prepare_v2 (m_db, "INSERT INTO ActionLog "
- "(device_id, seq_no, action, filename, version, action_timestamp, "
+ "(device_name, seq_no, action, filename, version, action_timestamp, "
"file_hash, file_atime, file_mtime, file_ctime, file_chmod, file_seg_num, "
- "parent_device_id, parent_seq_no, "
+ "parent_device_name, parent_seq_no, "
"action_name, action_content_object) "
"VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
- " ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?,"
+ " ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?,?, "
" ?, ?, "
" ?, ?);", -1, &stmt, 0);
- // cout << "INSERT INTO ActionLog "
- // "(device_id, seq_no, action, filename, version, action_timestamp, "
- // "file_hash, file_atime, file_mtime, file_ctime, file_chmod, "
- // "parent_device_id, parent_seq_no) "
- // "VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
- // " ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?,"
- // " ?, ?)" << endl;
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
if (res != SQLITE_OK)
{
BOOST_THROW_EXCEPTION (Error::Db ()
<< errmsg_info_str (sqlite3_errmsg (m_db))
);
- // << errmsg_info_str ("Some error with prepare AddActionUpdate"));
}
-
- sqlite3_bind_int64 (stmt, 1, m_syncLog->GetLocalSyncNodeId ());
+ sqlite3_bind_blob (stmt, 1, device_name->buf (), device_name->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 2, seq_no);
sqlite3_bind_int (stmt, 3, 0);
sqlite3_bind_text (stmt, 4, filename.c_str (), filename.size (), SQLITE_TRANSIENT);
@@ -229,18 +216,11 @@
sqlite3_bind_int (stmt, 11, mode);
sqlite3_bind_int (stmt, 12, seg_num);
- if (parent_device_id > 0 && parent_seq_no > 0)
+ if (parent_device_name && parent_seq_no > 0)
{
- sqlite3_bind_int64 (stmt, 13, parent_device_id);
+ sqlite3_bind_blob (stmt, 13, parent_device_name->buf (), parent_device_name->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 14, parent_seq_no);
}
- else
- {
- sqlite3_bind_null (stmt, 13);
- sqlite3_bind_null (stmt, 14);
- }
-
- // missing part: creating ContentObject for the action !!!
ActionItem item;
item.set_action (ActionItem::UPDATE);
@@ -254,12 +234,11 @@
item.set_mode (mode);
item.set_seg_num (seg_num);
- if (parent_device_id > 0 && parent_seq_no > 0)
+ if (parent_device_name && parent_seq_no > 0)
{
- cout << Name (reinterpret_cast<const unsigned char *> (parent_device_name.c_str ()),
- parent_device_name.size ()) << endl;
+ // cout << Name (*parent_device_name) << endl;
- item.set_parent_device_name (parent_device_name);
+ item.set_parent_device_name (parent_device_name->buf (), parent_device_name->length ());
item.set_parent_seq_no (parent_seq_no);
}
@@ -268,66 +247,72 @@
string item_msg;
item.SerializeToString (&item_msg);
Name actionName = Name (m_syncLog->GetLocalName ())("action")(m_sharedFolderName)(seq_no);
+ _LOG_DEBUG ("ActionName: " << actionName);
Bytes actionData = m_ccnx->createContentObject (actionName, item_msg.c_str (), item_msg.size ());
CcnxCharbufPtr namePtr = actionName.toCcnxCharbuf ();
- sqlite3_bind_blob (stmt, 14, namePtr->buf (), namePtr->length (), SQLITE_TRANSIENT);
- sqlite3_bind_blob (stmt, 15, &actionData[0], actionData.size (), SQLITE_TRANSIENT);
+ _LOG_DEBUG (" >>>>>>> " << namePtr->buf () << " " << namePtr->length ());
+
+ sqlite3_bind_blob (stmt, 15, namePtr->buf (), namePtr->length (), SQLITE_TRANSIENT);
+ sqlite3_bind_blob (stmt, 16, head (actionData), actionData.size (), SQLITE_TRANSIENT);
sqlite3_step (stmt);
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+
sqlite3_finalize (stmt);
sqlite3_exec (m_db, "END TRANSACTION;", 0,0,0);
}
-void
-ActionLog::AddActionMove (const std::string &oldFile, const std::string &newFile)
-{
- // not supported yet
- BOOST_THROW_EXCEPTION (Error::Db ()
- << errmsg_info_str ("Move operation is not yet supported"));
-}
+// void
+// ActionLog::AddActionMove (const std::string &oldFile, const std::string &newFile)
+// {
+// // not supported yet
+// BOOST_THROW_EXCEPTION (Error::Db ()
+// << errmsg_info_str ("Move operation is not yet supported"));
+// }
void
-ActionLog::AddActionDelete (const std::string &filename)
+ActionLog::AddLocalActionDelete (const std::string &filename)
{
sqlite3_exec (m_db, "BEGIN TRANSACTION;", 0,0,0);
- sqlite3_int64 version = 0;
- sqlite3_int64 parent_device_id = -1;
- string parent_device_name;
- sqlite3_int64 parent_seq_no = -1;
+ CcnxCharbufPtr device_name = m_syncLog->GetLocalName ().toCcnxCharbuf ();
+ sqlite3_int64 version;
+ CcnxCharbufPtr parent_device_name;
+ sqlite3_int64 parent_seq_no = -1;
sqlite3_int64 action_time = time (0);
- tie (version, parent_device_id, parent_seq_no, parent_device_name) = GetExistingRecord (filename);
- if (parent_device_id < 0) // no records exist or file was already deleted
+ tie (version, parent_device_name, parent_seq_no) = GetLatestActionForFile (filename);
+ if (!parent_device_name) // no records exist or file was already deleted
{
sqlite3_exec (m_db, "END TRANSACTION;", 0,0,0);
return;
}
+ version ++;
sqlite3_int64 seq_no = m_syncLog->GetNextLocalSeqNo ();
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (m_db, "INSERT INTO ActionLog "
- "(device_id, seq_no, action, filename, version, action_timestamp, "
- "parent_device_id, parent_seq_no, "
+ "(device_name, seq_no, action, filename, version, action_timestamp, "
+ "parent_device_name, parent_seq_no, "
"action_name, action_content_object) "
"VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
" ?, ?,"
" ?, ?)", -1, &stmt, 0);
- sqlite3_bind_int64 (stmt, 1, m_syncLog->GetLocalSyncNodeId ());
+ sqlite3_bind_blob (stmt, 1, device_name->buf (), device_name->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 2, seq_no);
sqlite3_bind_int (stmt, 3, 1);
sqlite3_bind_text (stmt, 4, filename.c_str (), filename.size (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 5, version);
sqlite3_bind_int64 (stmt, 6, action_time);
- sqlite3_bind_int64 (stmt, 7, parent_device_id);
+ sqlite3_bind_blob (stmt, 7, parent_device_name->buf (), parent_device_name->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 8, parent_seq_no);
@@ -336,7 +321,7 @@
item.set_filename (filename);
item.set_version (version);
item.set_timestamp (action_time);
- item.set_parent_device_name (parent_device_name);
+ item.set_parent_device_name (parent_device_name->buf (), parent_device_name->length ());
item.set_parent_seq_no (parent_seq_no);
string item_msg;
@@ -351,8 +336,9 @@
sqlite3_step (stmt);
- // cout << Ccnx::Name (reinterpret_cast<const unsigned char *> (parent_device_name.c_str ()),
- // parent_device_name.size ()) << endl;
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+
+ // cout << Ccnx::Name (parent_device_name) << endl;
// assign name to the action, serialize action, and create content object
@@ -362,53 +348,226 @@
}
+PcoPtr
+ActionLog::LookupActionPco (const Ccnx::Name &deviceName, sqlite3_int64 seqno)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "SELECT action_content_object FROM ActionLog WHERE device_name=? AND seq_no=?", -1, &stmt, 0);
+
+ CcnxCharbufPtr name = deviceName.toCcnxCharbuf ();
+
+ sqlite3_bind_blob (stmt, 1, name->buf (), name->length (), SQLITE_STATIC);
+ sqlite3_bind_int64 (stmt, 2, seqno);
+
+ PcoPtr retval;
+ if (sqlite3_step (stmt) == SQLITE_ROW)
+ {
+ // _LOG_DEBUG (sqlite3_column_blob (stmt, 0) << ", " << sqlite3_column_bytes (stmt, 0));
+ retval = make_shared<ParsedContentObject> (reinterpret_cast<const unsigned char *> (sqlite3_column_blob (stmt, 0)), sqlite3_column_bytes (stmt, 0));
+ }
+ else
+ {
+ _LOG_TRACE ("No action found for deviceName [" << deviceName << "] and seqno:" << seqno);
+ }
+ // _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+ sqlite3_finalize (stmt);
+
+ return retval;
+}
+
+ActionItemPtr
+ActionLog::LookupAction (const Ccnx::Name &deviceName, sqlite3_int64 seqno)
+{
+ PcoPtr pco = LookupActionPco (deviceName, seqno);
+ if (!pco) return ActionItemPtr ();
+
+ ActionItemPtr action = deserializeMsg<ActionItem> (pco->content ());
+
+ return action;
+}
+
+Ccnx::PcoPtr
+ActionLog::LookupActionPco (const Ccnx::Name &actionName)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "SELECT action_content_object FROM ActionLog WHERE action_name=?", -1, &stmt, 0);
+
+ _LOG_DEBUG (actionName);
+ CcnxCharbufPtr name = actionName.toCcnxCharbuf ();
+
+ _LOG_DEBUG (" <<<<<<< " << name->buf () << " " << name->length ());
+
+ sqlite3_bind_blob (stmt, 1, name->buf (), name->length (), SQLITE_STATIC);
+
+ PcoPtr retval;
+ if (sqlite3_step (stmt) == SQLITE_ROW)
+ {
+ // _LOG_DEBUG (sqlite3_column_blob (stmt, 0) << ", " << sqlite3_column_bytes (stmt, 0));
+ retval = make_shared<ParsedContentObject> (reinterpret_cast<const unsigned char *> (sqlite3_column_blob (stmt, 0)), sqlite3_column_bytes (stmt, 0));
+ }
+ else
+ {
+ _LOG_TRACE ("No action found for name: " << actionName);
+ }
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+ sqlite3_finalize (stmt);
+
+ return retval;
+}
+
+ActionItemPtr
+ActionLog::LookupAction (const Ccnx::Name &actionName)
+{
+ PcoPtr pco = LookupActionPco (actionName);
+ if (!pco) return ActionItemPtr ();
+
+ ActionItemPtr action = deserializeMsg<ActionItem> (pco->content ());
+
+ return action;
+}
+
+void
+ActionLog::AddRemoteAction (const Ccnx::Name &deviceName, sqlite3_int64 seqno, Ccnx::PcoPtr actionPco)
+{
+ if (!actionPco)
+ {
+ BOOST_THROW_EXCEPTION (Error::ActionLog () << errmsg_info_str ("actionPco is not valid"));
+ }
+ ActionItemPtr action = deserializeMsg<ActionItem> (actionPco->content ());
+
+ if (!action)
+ {
+ BOOST_THROW_EXCEPTION (Error::ActionLog () << errmsg_info_str ("action cannot be decoded"));
+ }
+
+ sqlite3_stmt *stmt;
+ int res = sqlite3_prepare_v2 (m_db, "INSERT INTO ActionLog "
+ "(device_name, seq_no, action, filename, version, action_timestamp, "
+ "file_hash, file_atime, file_mtime, file_ctime, file_chmod, file_seg_num, "
+ "parent_device_name, parent_seq_no, "
+ "action_name, action_content_object) "
+ "VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
+ " ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?,?, "
+ " ?, ?, "
+ " ?, ?);", -1, &stmt, 0);
+
+ CcnxCharbufPtr device_name = deviceName.toCcnxCharbuf ();
+ sqlite3_bind_blob (stmt, 1, device_name->buf (), device_name->length (), SQLITE_STATIC);
+ sqlite3_bind_int64 (stmt, 2, seqno);
+
+ sqlite3_bind_int (stmt, 3, action->action ());
+ sqlite3_bind_text (stmt, 4, action->filename ().c_str (), action->filename ().size (), SQLITE_STATIC);
+ sqlite3_bind_int64 (stmt, 5, action->version ());
+ sqlite3_bind_int64 (stmt, 6, action->timestamp ());
+
+ if (action->action () == ActionItem::UPDATE)
+ {
+ sqlite3_bind_blob (stmt, 7, action->file_hash ().c_str (), action->file_hash ().size (), SQLITE_STATIC);
+
+ // sqlite3_bind_int64 (stmt, 8, atime); // NULL
+ sqlite3_bind_int64 (stmt, 9, action->mtime ());
+ // sqlite3_bind_int64 (stmt, 10, ctime); // NULL
+
+ sqlite3_bind_int (stmt, 11, action->mode ());
+ sqlite3_bind_int (stmt, 12, action->seg_num ());
+ }
+
+ if (action->has_parent_device_name ())
+ {
+ sqlite3_bind_blob (stmt, 13, action->parent_device_name ().c_str (), action->parent_device_name ().size (), SQLITE_TRANSIENT);
+ sqlite3_bind_int64 (stmt, 14, action->parent_seq_no ());
+ }
+
+ Name actionName = Name (deviceName)("action")(m_sharedFolderName)(seqno);
+ CcnxCharbufPtr namePtr = actionName.toCcnxCharbuf ();
+
+ sqlite3_bind_blob (stmt, 15, namePtr->buf (), namePtr->length (), SQLITE_STATIC);
+ sqlite3_bind_blob (stmt, 16, head (actionPco->buf ()), actionPco->buf ().size (), SQLITE_STATIC);
+ sqlite3_step (stmt);
+
+ // if action needs to be applied to file state, the trigger will take care of it
+
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
+
+ sqlite3_finalize (stmt);
+}
+
+void
+ActionLog::AddRemoteAction (Ccnx::PcoPtr actionPco)
+{
+ Name name = actionPco->name ();
+ // <device_name>/"action"/<shared_folder_name_one_component>/<seqno>
+
+ uint64_t seqno = name.getCompFromBackAsInt (0);
+ string sharedFolder = name.getCompFromBackAsString (1);
+
+ if (sharedFolder != m_sharedFolderName)
+ {
+ BOOST_THROW_EXCEPTION (Error::ActionLog () << errmsg_info_str ("Action doesn't belong to this shared folder"));
+ }
+
+ string action = name.getCompFromBackAsString (2);
+
+ if (action != "action")
+ {
+ BOOST_THROW_EXCEPTION (Error::ActionLog () << errmsg_info_str ("not an action"));
+ }
+ Name deviceName = name.getPartialName (0, name.size ()-3);
+
+ _LOG_DEBUG ("From [" << name << "] extracted deviceName: " << deviceName << ", sharedFolder: " << sharedFolder << ", seqno: " << seqno);
+
+ AddRemoteAction (deviceName, seqno, actionPco);
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+// SHOULD BE MOVED TO SEPARATE FILESTATE CLASS "EVENTUALLY"
+///////////////////////////////////////////////////////////////////////////////////
+
void
ActionLog::apply_action_xFun (sqlite3_context *context, int argc, sqlite3_value **argv)
{
ActionLog *the = reinterpret_cast<ActionLog*> (sqlite3_user_data (context));
- if (argc != 11)
+ if (argc != 10)
{
- sqlite3_result_error (context, "``apply_action'' expects 11 arguments", -1);
+ sqlite3_result_error (context, "``apply_action'' expects 10 arguments", -1);
return;
}
- // cout << "apply_function called with " << argc << endl;
+ CcnxCharbuf device_name (sqlite3_value_blob (argv[0]), sqlite3_value_bytes (argv[0]));
+ sqlite3_int64 seq_no = sqlite3_value_int64 (argv[1]);
+ int action = sqlite3_value_int (argv[2]);
+ string filename = reinterpret_cast<const char*> (sqlite3_value_text (argv[3]));
- // cout << "device_name: " << sqlite3_value_text (argv[0]) << endl;
- // cout << "action: " << sqlite3_value_int (argv[1]) << endl;
- // cout << "filename: " << sqlite3_value_text (argv[2]) << endl;
-
- string device_name (reinterpret_cast<const char*> (sqlite3_value_blob (argv[0])), sqlite3_value_bytes (argv[0]));
- sqlite3_int64 device_id = sqlite3_value_int64 (argv[1]);
- sqlite3_int64 seq_no = sqlite3_value_int64 (argv[2]);
- int action = sqlite3_value_int (argv[3]);
- string filename = reinterpret_cast<const char*> (sqlite3_value_text (argv[4]));
+ _LOG_TRACE ("apply_function called with " << argc);
+ _LOG_TRACE ("device_name: " << Name (device_name)
+ << ", action: " << action
+ << ", file: " << filename);
if (action == 0) // update
{
- Hash hash (sqlite3_value_blob (argv[5]), sqlite3_value_bytes (argv[5]));
- time_t atime = static_cast<time_t> (sqlite3_value_int64 (argv[6]));
- time_t mtime = static_cast<time_t> (sqlite3_value_int64 (argv[7]));
- time_t ctime = static_cast<time_t> (sqlite3_value_int64 (argv[8]));
- int mode = sqlite3_value_int (argv[9]);
- int seg_num = sqlite3_value_int (argv[10]);
+ Hash hash (sqlite3_value_blob (argv[4]), sqlite3_value_bytes (argv[4]));
+ time_t atime = static_cast<time_t> (sqlite3_value_int64 (argv[5]));
+ time_t mtime = static_cast<time_t> (sqlite3_value_int64 (argv[6]));
+ time_t ctime = static_cast<time_t> (sqlite3_value_int64 (argv[7]));
+ int mode = sqlite3_value_int (argv[8]);
+ int seg_num = sqlite3_value_int (argv[9]);
- cout << "Update " << filename << " " << atime << " " << mtime << " " << ctime << " " << hash << endl;
+ _LOG_DEBUG ("Update " << filename << " " << atime << " " << mtime << " " << ctime << " " << hash);
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (the->m_db, "UPDATE FileState "
"SET "
- "device_id=?, seq_no=?, "
+ "device_name=?, seq_no=?, "
"file_hash=?,"
"file_atime=datetime(?, 'unixepoch'),"
"file_mtime=datetime(?, 'unixepoch'),"
"file_ctime=datetime(?, 'unixepoch'),"
- "file_chmod=? "
+ "file_chmod=?, "
"file_seg_num=? "
"WHERE type=0 AND filename=?", -1, &stmt, 0);
- sqlite3_bind_int64 (stmt, 1, device_id);
+ sqlite3_bind_blob (stmt, 1, device_name.buf (), device_name.length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 2, seq_no);
sqlite3_bind_blob (stmt, 3, hash.GetHash (), hash.GetHashBytes (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 4, atime);
@@ -420,7 +579,8 @@
sqlite3_step (stmt);
- // cout << sqlite3_errmsg (the->m_db) << endl;
+ _LOG_DEBUG_COND (sqlite3_errcode (the->m_db) != SQLITE_OK,
+ sqlite3_errmsg (the->m_db));
sqlite3_finalize (stmt);
@@ -429,21 +589,23 @@
{
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (the->m_db, "INSERT INTO FileState "
- "(type,filename,device_id,seq_no,file_hash,file_atime,file_mtime,file_ctime,file_chmod) "
+ "(type,filename,device_name,seq_no,file_hash,file_atime,file_mtime,file_ctime,file_chmod,file_seg_num) "
"VALUES (0, ?, ?, ?, ?, "
- "datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?)", -1, &stmt, 0);
+ "datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?, ?)", -1, &stmt, 0);
sqlite3_bind_text (stmt, 1, filename.c_str (), -1, SQLITE_TRANSIENT);
- sqlite3_bind_int64 (stmt, 2, device_id);
+ sqlite3_bind_blob (stmt, 2, device_name.buf (), device_name.length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 3, seq_no);
sqlite3_bind_blob (stmt, 4, hash.GetHash (), hash.GetHashBytes (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 5, atime);
sqlite3_bind_int64 (stmt, 6, mtime);
sqlite3_bind_int64 (stmt, 7, ctime);
sqlite3_bind_int (stmt, 8, mode);
+ sqlite3_bind_int (stmt, 9, seg_num);
sqlite3_step (stmt);
- // cout << sqlite3_errmsg (the->m_db) << endl;
+ _LOG_DEBUG_COND (sqlite3_errcode (the->m_db) != SQLITE_OK,
+ sqlite3_errmsg (the->m_db));
sqlite3_finalize (stmt);
}
}
@@ -453,7 +615,7 @@
sqlite3_prepare_v2 (the->m_db, "DELETE FROM FileState WHERE type=0 AND filename=?", -1, &stmt, 0);
sqlite3_bind_text (stmt, 1, filename.c_str (), -1, SQLITE_STATIC);
- cout << "Delete " << filename << endl;
+ _LOG_DEBUG ("Delete " << filename);
sqlite3_step (stmt);
sqlite3_finalize (stmt);
@@ -462,17 +624,39 @@
sqlite3_result_null (context);
}
+/**
+ * @todo Implement checking modification time and permissions
+ */
bool
-ActionLog::KnownFileState(const std::string &filename, const Hash &hash)
+ActionLog::KnownFileState(const std::string &filename, const Hash &hash
+ /*, time_t mtime, int chmod*/)
{
sqlite3_stmt *stmt;
sqlite3_prepare_v2 (m_db, "SELECT * FROM FileState WHERE filename = ? AND file_hash = ?;", -1, &stmt, 0);
sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 2, hash.GetHash (), hash.GetHashBytes (), SQLITE_STATIC);
+
+ bool retval = false;
if (sqlite3_step (stmt) == SQLITE_ROW)
{
- return true;
+ retval = true;
+ }
+ sqlite3_finalize (stmt);
+
+ return retval;
+}
+
+sqlite3_int64
+ActionLog::LogSize ()
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "SELECT count(*) FROM ActionLog", -1, &stmt, 0);
+
+ sqlite3_int64 retval = -1;
+ if (sqlite3_step (stmt) == SQLITE_ROW)
+ {
+ retval = sqlite3_column_int64 (stmt, 0);
}
- return false;
+ return retval;
}
diff --git a/src/action-log.h b/src/action-log.h
index 1654215..4123713 100644
--- a/src/action-log.h
+++ b/src/action-log.h
@@ -24,40 +24,83 @@
#include "db-helper.h"
#include "sync-log.h"
+#include "action-item.pb.h"
+#include "ccnx-wrapper.h"
+#include "ccnx-pco.h"
#include <boost/tuple/tuple.hpp>
-#include <action-item.pb.h>
-#include <ccnx-wrapper.h>
class ActionLog;
typedef boost::shared_ptr<ActionLog> ActionLogPtr;
+typedef boost::shared_ptr<ActionItem> ActionItemPtr;
class ActionLog : public DbHelper
{
public:
ActionLog (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &path,
SyncLogPtr syncLog,
- const std::string &localName, const std::string &sharedFolder);
+ const std::string &sharedFolder);
+
+ //////////////////////////
+ // Local operations //
+ //////////////////////////
+ void
+ AddLocalActionUpdate (const std::string &filename,
+ const Hash &hash,
+ time_t wtime,
+ int mode,
+ int seg_num);
+
+ // void
+ // AddActionMove (const std::string &oldFile, const std::string &newFile);
void
- AddActionUpdate (const std::string &filename,
- const Hash &hash,
- time_t wtime,
- int mode,
- int seg_num);
-
- void
- AddActionMove (const std::string &oldFile, const std::string &newFile);
-
- void
- AddActionDelete (const std::string &filename);
+ AddLocalActionDelete (const std::string &filename);
bool
KnownFileState(const std::string &filename, const Hash &hash);
+ //////////////////////////
+ // Remote operations //
+ //////////////////////////
+
+ void
+ AddRemoteAction (const Ccnx::Name &deviceName, sqlite3_int64 seqno, Ccnx::PcoPtr actionPco);
+
+ /**
+ * @brief Add remote action using just action's parsed content object
+ *
+ * This function extracts device name and sequence number from the content object's and calls the overloaded method
+ */
+ void
+ AddRemoteAction (Ccnx::PcoPtr actionPco);
+
+ ///////////////////////////
+ // General operations //
+ ///////////////////////////
+
+ Ccnx::PcoPtr
+ LookupActionPco (const Ccnx::Name &deviceName, sqlite3_int64 seqno);
+
+ Ccnx::PcoPtr
+ LookupActionPco (const Ccnx::Name &actionName);
+
+ ActionItemPtr
+ LookupAction (const Ccnx::Name &deviceName, sqlite3_int64 seqno);
+
+ ActionItemPtr
+ LookupAction (const Ccnx::Name &actionName);
+
+
+
+public:
+ // for test purposes
+ sqlite3_int64
+ LogSize ();
+
private:
- boost::tuple<sqlite3_int64, sqlite3_int64, sqlite3_int64, std::string>
- GetExistingRecord (const std::string &filename);
+ boost::tuple<sqlite3_int64 /*version*/, Ccnx::CcnxCharbufPtr /*device name*/, sqlite3_int64 /*seq_no*/>
+ GetLatestActionForFile (const std::string &filename);
static void
apply_action_xFun (sqlite3_context *context, int argc, sqlite3_value **argv);
@@ -66,7 +109,12 @@
SyncLogPtr m_syncLog;
Ccnx::CcnxWrapperPtr m_ccnx;
- Ccnx::Name m_sharedFolderName;
+ std::string m_sharedFolderName;
};
+namespace Error {
+struct ActionLog : virtual boost::exception, virtual std::exception { };
+}
+
+
#endif // ACTION_LOG_H
diff --git a/src/db-helper.cc b/src/db-helper.cc
index 95ccc7a..ac63cdf 100644
--- a/src/db-helper.cc
+++ b/src/db-helper.cc
@@ -32,19 +32,18 @@
namespace fs = boost::filesystem;
const std::string INIT_DATABASE = "\
-PRAGMA foreign_keys = ON; \n\
+ PRAGMA foreign_keys = ON; \
";
-DbHelper::DbHelper (const fs::path &path)
+DbHelper::DbHelper (const fs::path &path, const std::string &dbname)
{
- fs::path chronoshareDirectory = path / ".chronoshare";
- fs::create_directories (chronoshareDirectory);
+ fs::create_directories (path);
- int res = sqlite3_open((chronoshareDirectory / "state.db").c_str (), &m_db);
+ int res = sqlite3_open((path / dbname).c_str (), &m_db);
if (res != SQLITE_OK)
{
BOOST_THROW_EXCEPTION (Error::Db ()
- << errmsg_info_str ("Cannot open/create dabatabase: [" + (chronoshareDirectory / "state.db").string () + "]"));
+ << errmsg_info_str ("Cannot open/create dabatabase: [" + (path / dbname).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 a32df64..24f8c3f 100644
--- a/src/db-helper.h
+++ b/src/db-helper.h
@@ -30,14 +30,14 @@
#include "hash-helper.h"
#include <boost/filesystem.hpp>
-typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str;
+typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str;
class DbHelper
{
public:
- DbHelper (const boost::filesystem::path &path);
+ DbHelper (const boost::filesystem::path &path, const std::string &dbname);
virtual ~DbHelper ();
-
+
private:
static void
hash_xStep (sqlite3_context *context, int argc, sqlite3_value **argv);
diff --git a/src/dispatcher.cc b/src/dispatcher.cc
index 24340c6..d7e570a 100644
--- a/src/dispatcher.cc
+++ b/src/dispatcher.cc
@@ -40,8 +40,8 @@
, m_server(NULL)
{
m_syncLog = make_shared<SyncLog>(path, localUserName);
- m_actionLog = make_shared<ActionLog>(m_ccnx, path, m_syncLog, localUserName, sharedFolder);
- Name syncPrefix(BROADCAST_DOMAIN + sharedFolder);
+ m_actionLog = make_shared<ActionLog>(m_ccnx, path, m_syncLog, sharedFolder);
+ Name syncPrefix = Name(BROADCAST_DOMAIN)(sharedFolder);
m_server = new ContentServer(m_ccnx, m_actionLog, rootDir);
m_server->registerPrefix(localPrefix);
@@ -114,7 +114,7 @@
if (filesystem::exists(absolutePath))
{
HashPtr hash = Hash::FromFileContent(absolutePath);
- if (m_actionLog->KnownFileState(relativeFilePath.string(), *hash))
+ if (m_actionLog->KnownFileState(relativeFilePath.generic_string(), *hash))
{
// the file state is known; i.e. the detected changed file is identical to
// the file state kept in FileState table
@@ -124,13 +124,16 @@
else
{
uintmax_t fileSize = filesystem::file_size(absolutePath);
- int seg_num = fileSize / MAX_FILE_SEGMENT_SIZE + ((fileSize % MAX_FILE_SEGMENT_SIZE == 0) ? 0 : 1);
+ int seg_num;
+ tie (hash, seg_num) = m_objectManager.localFileToObjects (absolutePath, m_localUserName);
+
time_t wtime = filesystem::last_write_time(absolutePath);
filesystem::file_status stat = filesystem::status(absolutePath);
int mode = stat.permissions();
- m_actionLog->AddActionUpdate (relativeFilePath.string(), *hash, wtime, mode, seg_num);
+
+ m_actionLog->AddLocalActionUpdate (relativeFilePath.generic_string(), *hash, wtime, mode, seg_num);
// publish the file
- m_objectManager.localFileToObjects(relativeFilePath, m_localUserName);
+
// notify SyncCore to propagate the change
m_core->localStateChanged();
}
@@ -143,7 +146,7 @@
}
case DELETE:
{
- m_actionLog->AddActionDelete (relativeFilePath.string());
+ m_actionLog->AddLocalActionDelete (relativeFilePath.generic_string());
// notify SyncCore to propagate the change
m_core->localStateChanged();
break;
diff --git a/src/file-item.proto b/src/file-item.proto
new file mode 100644
index 0000000..937226b
--- /dev/null
+++ b/src/file-item.proto
@@ -0,0 +1,18 @@
+message FileItem
+{
+ enum FileType
+ {
+ LATEST = 0;
+ OLDEST = 1;
+ }
+ required FileType type = 1;
+
+ required string filename = 2;
+ required bytes device_name = 3;
+ required uint64 seq_no = 4;
+
+ required bytes file_hash = 5;
+ required uint32 mtime = 6;
+ required uint32 mode = 7;
+ required uint64 seg_num = 8;
+}
diff --git a/src/object-db.cc b/src/object-db.cc
index 0d1a2a6..2243b99 100644
--- a/src/object-db.cc
+++ b/src/object-db.cc
@@ -24,6 +24,9 @@
#include <boost/make_shared.hpp>
#include "db-helper.h"
#include <sys/stat.h>
+#include "logging.h"
+
+INIT_LOGGER ("Object.Db");
using namespace std;
using namespace Ccnx;
@@ -46,7 +49,7 @@
{
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)
{
@@ -54,7 +57,7 @@
<< 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
@@ -64,7 +67,7 @@
{
// std::cerr << "DEBUG: " << errmsg << std::endl;
sqlite3_free (errmsg);
- }
+ }
}
bool
@@ -89,16 +92,15 @@
int countAll = sqlite3_column_int (stmt, 0);
int countNonNull = sqlite3_column_int (stmt, 1);
- cout << countAll << ", " << countNonNull << endl;
+ _LOG_DEBUG ("Total segments: " << countAll << ", non-empty segments: " << countNonNull);
if (countAll > 0 && countAll==countNonNull)
{
- cout << "2" << endl;
retval = true;
}
}
- sqlite3_finalize (stmt);
+ sqlite3_finalize (stmt);
}
sqlite3_close (db);
@@ -123,8 +125,8 @@
"(device_name, segment, content_object) "
"VALUES (?, ?, ?)", -1, &stmt, 0);
- cout << deviceName << endl;
-
+ _LOG_DEBUG ("Saving content object for [" << deviceName << ", seqno: " << segment << ", size: " << data.size () << "]");
+
CcnxCharbufPtr buf = deviceName.toCcnxCharbuf ();
sqlite3_bind_blob (stmt, 1, buf->buf (), buf->length (), SQLITE_TRANSIENT);
sqlite3_bind_int64 (stmt, 2, segment);
@@ -145,7 +147,7 @@
sqlite3_bind_int64 (stmt, 2, segment);
BytesPtr ret;
-
+
int res = sqlite3_step (stmt);
if (res == SQLITE_ROW)
{
@@ -165,13 +167,13 @@
// ObjectDb::getNumberOfSegments (const Ccnx::Name &deviceName)
// {
// sqlite3_stmt *stmt;
-// sqlite3_prepare_v2 (m_db, "SELECT count(*) FROM File WHERE device_name=?", -1, &stmt, 0);
+// sqlite3_prepare_v2 (m_db, "SELECT count(*) FROM File WHERE device_name=?", -1, &stmt, 0);
// bool retval = false;
// int res = sqlite3_step (stmt);
// if (res == SQLITE_ROW)
// {
-// retval = true;
+// retval = true;
// }
// sqlite3_finalize (stmt);
diff --git a/src/object-manager.cc b/src/object-manager.cc
index bb19842..f822120 100644
--- a/src/object-manager.cc
+++ b/src/object-manager.cc
@@ -24,6 +24,7 @@
#include "ccnx-common.h"
#include "ccnx-pco.h"
#include "object-db.h"
+#include "logging.h"
#include <sys/stat.h>
@@ -32,6 +33,8 @@
#include <boost/throw_exception.hpp>
#include <boost/filesystem/fstream.hpp>
+INIT_LOGGER ("Object.Manager");
+
using namespace Ccnx;
using namespace boost;
using namespace std;
@@ -50,7 +53,7 @@
{
}
-HashPtr
+boost::tuple<HashPtr /*object-db name*/, size_t /* number of segments*/>
ObjectManager::localFileToObjects (const fs::path &file, const Ccnx::Name &deviceName)
{
HashPtr fileHash = Hash::FromFileContent (file);
@@ -74,7 +77,7 @@
segment ++;
}
- return fileHash;
+ return make_tuple (fileHash, segment);
}
bool
@@ -83,8 +86,7 @@
string hashStr = lexical_cast<string> (fileHash);
if (!ObjectDb::DoesExist (m_folder, deviceName, hashStr))
{
- cout << "Brr" << endl;
- // file does not exist or not all segments are available
+ _LOG_ERROR ("ObjectDb for [" << m_folder << ", " << deviceName << ", " << hashStr << "] does not exist or not all segments are available");
return false;
}
diff --git a/src/object-manager.h b/src/object-manager.h
index f0cd6e6..ff26f30 100644
--- a/src/object-manager.h
+++ b/src/object-manager.h
@@ -26,6 +26,7 @@
#include <ccnx-wrapper.h>
#include <hash-helper.h>
#include <boost/filesystem.hpp>
+#include <boost/tuple/tuple.hpp>
// everything related to managing object files
@@ -35,12 +36,12 @@
ObjectManager (Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path &folder);
virtual ~ObjectManager ();
- HashPtr
+ boost::tuple<HashPtr /*object-db name*/, size_t /* number of segments*/>
localFileToObjects (const boost::filesystem::path &file, const Ccnx::Name &deviceName);
bool
objectsToLocalFile (/*in*/const Ccnx::Name &deviceName, /*in*/const Hash &hash, /*out*/ const boost::filesystem::path &file);
-
+
private:
Ccnx::CcnxWrapperPtr m_ccnx;
boost::filesystem::path m_folder;
diff --git a/src/sync-core.cc b/src/sync-core.cc
index d85093b..9d2003d 100644
--- a/src/sync-core.cc
+++ b/src/sync-core.cc
@@ -82,7 +82,7 @@
// reply sync Interest with oldHash as last component
Name syncName = Name (m_syncPrefix)(oldHash->GetHash(), oldHash->GetHashBytes());
- BytesPtr syncData = serializeMsg (msg);
+ BytesPtr syncData = serializeMsg (*msg);
m_ccnx->publishData(syncName, *syncData, FRESHNESS);
_LOG_TRACE (m_log->GetLocalName () << " publishes: " << *oldHash);
@@ -125,7 +125,7 @@
// we know the hash, should reply everything
SyncStateMsgPtr msg = m_log->FindStateDifferences(*(Hash::Origin), *m_rootHash);
- BytesPtr syncData = serializeMsg (msg);
+ BytesPtr syncData = serializeMsg (*msg);
m_ccnx->publishData(name, *syncData, FRESHNESS);
_LOG_TRACE (m_log->GetLocalName () << " publishes " << hash);
_LOG_TRACE (msg);
@@ -153,7 +153,7 @@
_LOG_TRACE ("found hash in sync log");
SyncStateMsgPtr msg = m_log->FindStateDifferences(*hash, *m_rootHash);
- BytesPtr syncData = serializeMsg (msg);
+ BytesPtr syncData = serializeMsg (*msg);
m_ccnx->publishData(name, *syncData, FRESHNESS);
_LOG_TRACE (m_log->GetLocalName () << " publishes: " << *hash);
_LOG_TRACE (msg);
diff --git a/src/sync-log.cc b/src/sync-log.cc
index 5623a83..671162e 100644
--- a/src/sync-log.cc
+++ b/src/sync-log.cc
@@ -97,8 +97,8 @@
";
-SyncLog::SyncLog (const boost::filesystem::path &path, const std::string &localName)
- : DbHelper (path)
+SyncLog::SyncLog (const boost::filesystem::path &path, const Ccnx::Name &localName)
+ : DbHelper (path / ".chronoshare", "sync-log.db")
, m_localName (localName)
{
sqlite3_exec (m_db, INIT_DATABASE.c_str (), NULL, NULL, NULL);
@@ -154,9 +154,11 @@
if (sqlite3_step (stmt_seq) != SQLITE_ROW)
{
BOOST_THROW_EXCEPTION (Error::Db ()
- << errmsg_info_str ("Impossible thing in ActionLog::AddActionUpdate"));
+ << errmsg_info_str ("Impossible thing in SyncLog::GetNextLocalSeqNo"));
}
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
sqlite3_int64 seq_no = sqlite3_column_int64 (stmt_seq, 0) + 1;
sqlite3_finalize (stmt_seq);
@@ -328,6 +330,9 @@
BOOST_THROW_EXCEPTION (Error::Db ()
<< errmsg_info_str ("Some error with UpdateDeviceSeqNo (id)"));
}
+
+ _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK, sqlite3_errmsg (m_db));
+
sqlite3_finalize (stmt);
}
@@ -513,3 +518,19 @@
return seq;
}
+
+sqlite3_int64
+SyncLog::LogSize ()
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "SELECT count(*) FROM SyncLog", -1, &stmt, 0);
+
+ sqlite3_int64 retval = -1;
+ if (sqlite3_step (stmt) == SQLITE_ROW)
+ {
+ retval = sqlite3_column_int64 (stmt, 0);
+ }
+
+ return retval;
+}
+
diff --git a/src/sync-log.h b/src/sync-log.h
index 1ab25e9..7aed587 100644
--- a/src/sync-log.h
+++ b/src/sync-log.h
@@ -33,7 +33,7 @@
class SyncLog : public DbHelper
{
public:
- SyncLog (const boost::filesystem::path &path, const std::string &localName);
+ SyncLog (const boost::filesystem::path &path, const Ccnx::Name &localName);
/**
* @brief Get local username
@@ -41,12 +41,6 @@
inline const Ccnx::Name &
GetLocalName () const;
- /**
- * @brief Get database ID of the local sync node (make sense only for the local database)
- */
- inline const sqlite3_int64
- GetLocalSyncNodeId () const;
-
sqlite3_int64
GetNextLocalSeqNo (); // side effect: local seq_no will be increased
@@ -92,11 +86,13 @@
sqlite3_int64
SeqNo(const Ccnx::Name &name);
+ sqlite3_int64
+ LogSize ();
+
protected:
void
UpdateDeviceSeqNo (sqlite3_int64 deviceId, sqlite3_int64 seqNo);
-
protected:
Ccnx::Name m_localName;
@@ -116,11 +112,4 @@
return m_localName;
}
-const sqlite3_int64
-SyncLog::GetLocalSyncNodeId () const
-{
- return m_localDeviceId;
-}
-
-
#endif // SYNC_LOG_H
diff --git a/test/test-action-log.cc b/test/test-action-log.cc
new file mode 100644
index 0000000..985af5c
--- /dev/null
+++ b/test/test-action-log.cc
@@ -0,0 +1,139 @@
+/* -*- 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 <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "logging.h"
+#include "action-log.h"
+
+#include <unistd.h>
+#include <iostream>
+#include <boost/filesystem.hpp>
+#include <boost/make_shared.hpp>
+
+using namespace std;
+using namespace boost;
+using namespace Ccnx;
+namespace fs = boost::filesystem;
+
+BOOST_AUTO_TEST_SUITE(TestActionLog)
+
+BOOST_AUTO_TEST_CASE (ActionLogTest)
+{
+ INIT_LOGGERS ();
+
+ Name localName ("/alex");
+
+ fs::path tmpdir = fs::unique_path (fs::temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
+ SyncLogPtr syncLog = make_shared<SyncLog> (tmpdir, localName);
+ CcnxWrapperPtr ccnx = make_shared<CcnxWrapper> ();
+
+ ActionLogPtr actionLog = make_shared<ActionLog> (ccnx, tmpdir, syncLog, "top-secret");
+
+// const std::string &filename,
+// const Hash &hash,
+// time_t wtime,
+// int mode,
+// int seg_num
+ BOOST_CHECK_EQUAL (syncLog->SeqNo (localName), 0);
+
+ BOOST_CHECK_EQUAL (syncLog->LogSize (), 0);
+ BOOST_CHECK_EQUAL (actionLog->LogSize (), 0);
+
+ actionLog->AddLocalActionUpdate ("file.txt", *Hash::FromString ("2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c"),
+ time (NULL), 0755, 10);
+
+ BOOST_CHECK_EQUAL (syncLog->SeqNo (localName), 1);
+ BOOST_CHECK_EQUAL (syncLog->LogSize (), 0);
+ BOOST_CHECK_EQUAL (actionLog->LogSize (), 1);
+
+ HashPtr hash = syncLog->RememberStateInStateLog ();
+ BOOST_CHECK_EQUAL (syncLog->LogSize (), 1);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "3410477233f98d6c3f9a6f8da24494bf5a65e1a7c9f4f66b228128bd4e020558");
+
+ PcoPtr pco = actionLog->LookupActionPco (localName, 0);
+ BOOST_CHECK_EQUAL ((bool)pco, false);
+
+ pco = actionLog->LookupActionPco (localName, 1);
+ BOOST_CHECK_EQUAL ((bool)pco, true);
+
+ BOOST_CHECK_EQUAL (pco->name (), "/alex/action/top-secret/%00%01");
+
+ ActionItemPtr action = actionLog->LookupAction (Name ("/alex/action/top-secret")(0));
+ BOOST_CHECK_EQUAL ((bool)action, false);
+
+ action = actionLog->LookupAction (Name ("/alex/action/top-secret")(1));
+ BOOST_CHECK_EQUAL ((bool)action, true);
+
+ BOOST_CHECK_EQUAL (action->version (), 0);
+ BOOST_CHECK_EQUAL (action->action (), 0);
+
+ BOOST_CHECK_EQUAL (action->filename (), "file.txt");
+ BOOST_CHECK_EQUAL (action->seg_num (), 10);
+ BOOST_CHECK_EQUAL (action->file_hash ().size (), 32);
+ BOOST_CHECK_EQUAL (action->mode (), 0755);
+
+ BOOST_CHECK_EQUAL (action->has_parent_device_name (), false);
+ BOOST_CHECK_EQUAL (action->has_parent_seq_no (), false);
+
+ actionLog->AddLocalActionUpdate ("file.txt", *Hash::FromString ("2ff304769cdb0125ac039e6fe7575f8576dceffc62618a431715aaf6eea2bf1c"),
+ time (NULL), 0755, 10);
+ BOOST_CHECK_EQUAL (syncLog->SeqNo (localName), 2);
+ BOOST_CHECK_EQUAL (syncLog->LogSize (), 1);
+ BOOST_CHECK_EQUAL (actionLog->LogSize (), 2);
+
+ action = actionLog->LookupAction (Name ("/alex"), 2);
+ BOOST_CHECK_EQUAL ((bool)action, true);
+
+ BOOST_CHECK_EQUAL (action->has_parent_device_name (), true);
+ BOOST_CHECK_EQUAL (action->has_parent_seq_no (), true);
+
+ BOOST_CHECK_EQUAL (action->parent_seq_no (), 1);
+ BOOST_CHECK_EQUAL (action->version (), 1);
+
+ BOOST_CHECK_NO_THROW (actionLog->AddRemoteAction (pco));
+ BOOST_CHECK_EQUAL (actionLog->LogSize (), 2);
+
+ // create a real remote action
+ ActionItem item;
+ item.set_action (ActionItem::UPDATE);
+ item.set_filename ("file.txt");
+ item.set_version (2);
+ item.set_timestamp (time (NULL));
+
+ BytesPtr item_msg = serializeMsg (item);
+ Name actionName = Name ("/zhenkai")("action")("top-secret")(1);
+ Bytes actionData = ccnx->createContentObject (actionName, head (*item_msg), item_msg->size ());
+
+ pco = make_shared<ParsedContentObject> (actionData);
+ BOOST_CHECK_NO_THROW (actionLog->AddRemoteAction (pco));
+ BOOST_CHECK_EQUAL (actionLog->LogSize (), 3);
+
+ remove_all (tmpdir);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+ // catch (boost::exception &err)
+ // {
+ // cout << *boost::get_error_info<errmsg_info_str> (err) << endl;
+ // }
diff --git a/test/test-object-manager.cc b/test/test-object-manager.cc
index 78337b3..8f2ef2c 100644
--- a/test/test-object-manager.cc
+++ b/test/test-object-manager.cc
@@ -19,6 +19,7 @@
* Zhenkai Zhu <zhenkai@cs.ucla.edu>
*/
+#include "logging.h"
#include "object-manager.h"
#include <boost/filesystem.hpp>
@@ -30,25 +31,31 @@
#include <iostream>
#include <iterator>
+INIT_LOGGER ("Test.ObjectManager");
+
using namespace Ccnx;
using namespace std;
using namespace boost;
namespace fs = boost::filesystem;
-BOOST_AUTO_TEST_SUITE(ObjectManagerTests)
+BOOST_AUTO_TEST_SUITE(TestObjectManager)
BOOST_AUTO_TEST_CASE (ObjectManagerTest)
{
+ INIT_LOGGERS ();
+
fs::path tmpdir = fs::unique_path (fs::temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
- cout << tmpdir << endl;
+ _LOG_DEBUG ("tmpdir: " << tmpdir);
Name deviceName ("/device");
-
+
CcnxWrapperPtr ccnx = make_shared<CcnxWrapper> ();
ObjectManager manager (ccnx, tmpdir);
- HashPtr hash = manager.localFileToObjects (fs::path("test") / "test-object-manager.cc", deviceName);
+ tuple<HashPtr,int> hash_semgents = manager.localFileToObjects (fs::path("test") / "test-object-manager.cc", deviceName);
- bool ok = manager.objectsToLocalFile (deviceName, *hash, tmpdir / "test.cc");
+ BOOST_CHECK_EQUAL (hash_semgents.get<1> (), 3);
+
+ bool ok = manager.objectsToLocalFile (deviceName, *hash_semgents.get<0> (), tmpdir / "test.cc");
BOOST_CHECK_EQUAL (ok, true);
{
@@ -61,7 +68,7 @@
BOOST_CHECK_EQUAL_COLLECTIONS (origFileI, eof, newFileI, eof);
}
-
+
remove_all (tmpdir);
}
diff --git a/test/test-sync-log.cc b/test/test-sync-log.cc
index 311f937..09443e9 100644
--- a/test/test-sync-log.cc
+++ b/test/test-sync-log.cc
@@ -42,7 +42,7 @@
INIT_LOGGERS ();
fs::path tmpdir = fs::unique_path (fs::temp_directory_path () / "%%%%-%%%%-%%%%-%%%%");
- SyncLog db (tmpdir, "/alex");
+ SyncLog db (tmpdir, Name ("/alex"));
HashPtr hash = db.RememberStateInStateLog ();
// should be empty