sync core compiles
diff --git a/src/db-helper.cc b/src/db-helper.cc
index c5455e8..0e08612 100644
--- a/src/db-helper.cc
+++ b/src/db-helper.cc
@@ -37,7 +37,7 @@
device_name BLOB NOT NULL, \n\
description TEXT, \n\
seq_no INTEGER NOT NULL, \n\
- last_known_tdi TEXT, \n\
+ last_known_locator BLOB, \n\
last_update TIMESTAMP \n\
); \n\
\n\
diff --git a/src/hash-helper.cc b/src/hash-helper.cc
index dbb70a3..d92e6b0 100644
--- a/src/hash-helper.cc
+++ b/src/hash-helper.cc
@@ -103,6 +103,9 @@
return os;
}
+unsigned char Hash::_origin = 0;
+HashPtr Hash::Origin(new Hash(&Hash::_origin, sizeof(unsigned char)));
+
HashPtr
Hash::FromString (const std::string &hashInTextEncoding)
{
diff --git a/src/hash-helper.h b/src/hash-helper.h
index d4f750d..638a93a 100644
--- a/src/hash-helper.h
+++ b/src/hash-helper.h
@@ -37,6 +37,8 @@
class Hash
{
public:
+ static unsigned char _origin;
+ static HashPtr Origin;
Hash (const void *buf, unsigned int length)
: m_length (length)
{
diff --git a/src/sync-core.cc b/src/sync-core.cc
index 21201aa..32a1243 100644
--- a/src/sync-core.cc
+++ b/src/sync-core.cc
@@ -21,8 +21,12 @@
#include "sync-core.h"
-SyncCore::SyncCore
- : m_log(path, userName)
+const string SyncCore::RECOVER = "RECOVER";
+const double SyncCore::WAIT = 0.2;
+const double SyncCore::RANDOM_PERCENT = 0.5;
+
+SyncCore::SyncCore(const string &path, const Name &userName, const Name &localPrefix, const Name &syncPrefix, const StateMsgCallback &callback, CcnxWrapperPtr handle, SchedulerPtr scheduler)
+ : m_log(path, userName.toString())
, m_localPrefix(localPrefix)
, m_syncPrefix(syncPrefix)
, m_stateMsgCallback(callback)
@@ -30,16 +34,40 @@
, m_scheduler(scheduler)
{
m_rootHash = m_log.RememberStateInStateLog();
- m_interestClosure = new Closure(0, boost::bind(&SyncCore::handleSyncData, this, _1, _2), boost::bind(&SyncCore::handleSyncInterestTimeout, this, _1));
+ m_syncClosure = new Closure(0, boost::bind(&SyncCore::handleSyncData, this, _1, _2), boost::bind(&SyncCore::handleSyncInterestTimeout, this, _1));
+ m_recoverClosure = new Closure(0, boost::bind(&SyncCore::handleRecoverData, this, _1, _2), boost::bind(&SyncCore::handleRecoverInterestTimeout, this, _1));
+ m_handle->setInterestFilter(m_syncPrefix, boost::bind(&SyncCore::handleInterest, this, _1));
+ m_log.initYP(m_yp);
m_scheduler->start();
sendSyncInterest();
}
SyncCore::~SyncCore()
{
- m_scheduler->stop();
- delete m_interestClosure;
- m_interestClosure = 0;
+ m_scheduler->shutdown();
+ if (m_syncClosure != 0)
+ {
+ delete m_syncClosure;
+ m_syncClosure = 0;
+ }
+
+ if (m_recoverClosure != 0)
+ {
+ delete m_recoverClosure;
+ m_recoverClosure = 0;
+ }
+}
+
+Name
+SyncCore::yp(const Name &deviceName)
+{
+ Name locator;
+ ReadLock(m_ypMutex);
+ if (m_yp.find(deviceName) != m_yp.end())
+ {
+ locator = m_yp[deviceName];
+ }
+ return locator;
}
void
@@ -51,13 +79,15 @@
}
void
-SyncCore::updateLocalState(seqno_t seqno)
+SyncCore::updateLocalState(sqlite3_int64 seqno)
{
- m_log.UpdateDeviceSeqNo(seqno);
+ m_log.UpdateDeviceSeqNo(m_userName, seqno);
+ // choose to update locator everytime
+ m_log.UpdateLocator(m_userName, m_localPrefix);
HashPtr oldHash = m_rootHash;
m_rootHash = m_log.RememberStateInStateLog();
- SyncStateMsgPtr msg = m_log.FindStateDifferences(oldHash, m_rootHash);
+ SyncStateMsgPtr msg = m_log.FindStateDifferences(*oldHash, *m_rootHash);
// reply sync Interest with oldHash as last component
Name syncName = constructSyncName(oldHash);
@@ -68,14 +98,76 @@
// no hurry in sending out new Sync Interest; if others send the new Sync Interest first, no problem, we know the new root hash already;
// this is trying to avoid the situation that the order of SyncData and new Sync Interest gets reversed at receivers
ostringstream ss;
- ss << m_rootHash;
+ ss << *m_rootHash;
TaskPtr task(new OneTimeTask(boost::bind(&SyncCore::sendSyncInterest, this), ss.str(), m_scheduler, 0.05));
m_scheduler->addTask(task);
}
void
+SyncCore::handleInterest(const Name &name)
+{
+ int size = name.size();
+ int prefixSize = m_syncPrefix.size();
+ if (size == prefixSize + 1)
+ {
+ // this is normal sync interest
+ handleSyncInterest(name);
+ }
+ else if (size == prefixSize + 2 && name.getCompAsString(m_syncPrefix.size()) == RECOVER)
+ {
+ // this is recovery interest
+ handleRecoverInterest(name);
+ }
+}
+
+void
+SyncCore::handleRecoverInterest(const Name &name)
+{
+ Bytes hashBytes = name.getComp(name.size() - 1);
+ // this is the hash unkonwn to the sender of the interest
+ Hash hash(head(hashBytes), hashBytes.size());
+ if (m_log.LookupSyncLog(hash) > 0)
+ {
+ // we know the hash, should reply everything
+ SyncStateMsgPtr msg = m_log.FindStateDifferences(*(Hash::Origin), *m_rootHash);
+ Bytes syncData;
+ msgToBytes(msg, syncData);
+ m_handle->publishData(name, syncData, FRESHNESS);
+ }
+ else
+ {
+ // we don't recognize this hash, can not help
+ }
+}
+
+void
SyncCore::handleSyncInterest(const Name &name)
{
+ Bytes hashBytes = name.getComp(name.size() - 1);
+ HashPtr hash(new Hash(head(hashBytes), hashBytes.size()));
+ if (*hash == *m_rootHash)
+ {
+ // we have the same hash; nothing needs to be done
+ return;
+ }
+ else if (m_log.LookupSyncLog(*hash) > 0)
+ {
+ // we know something more
+ SyncStateMsgPtr msg = m_log.FindStateDifferences(*hash, *m_rootHash);
+
+ Bytes syncData;
+ msgToBytes(msg, syncData);
+ m_handle->publishData(name, syncData, FRESHNESS);
+ }
+ else
+ {
+ // we don't recognize the hash, send recover Interest if still don't know the hash after a randomized wait period
+ ostringstream ss;
+ ss << *hash;
+ IntervalGeneratorPtr generator(new RandomIntervalGenerator(WAIT, RANDOM_PERCENT, RandomIntervalGenerator::UP));
+ TaskPtr task(new PeriodicTask(boost::bind(&SyncCore::recover, this, hash), ss.str(), m_scheduler, generator, 1));
+ m_scheduler->addTask(task);
+ }
}
Closure::TimeoutCallbackReturnValue
@@ -83,18 +175,44 @@
{
// sendInterestInterest with the current root hash;
sendSyncInterest();
- return Closure::OK;
+ return Closure::RESULT_OK;
+}
+
+Closure::TimeoutCallbackReturnValue
+SyncCore::handleRecoverInterestTimeout(const Name &name)
+{
+ // We do not re-express recovery interest for now
+ // if difference is not resolved, the sync interest will trigger
+ // recovery anyway; so it's not so important to have recovery interest
+ // re-expressed
+ return Closure::RESULT_OK;
+}
+
+void
+SyncCore::handleRecoverData(const Name &name, const Bytes &content)
+{
+ handleStateData(content);
}
void
SyncCore::handleSyncData(const Name &name, const Bytes &content)
{
+ // suppress recover in interest - data out of order case
+ handleStateData(content);
+
+ // resume outstanding sync interest
+ sendSyncInterest();
+}
+
+void
+SyncCore::handleStateData(const Bytes &content)
+{
SyncStateMsgPtr msg(new SyncStateMsg);
bool success = msg->ParseFromArray(head(content), content.size());
if(!success)
{
// ignore misformed SyncData
- cerr << "Misformed SyncData with name: " << name << endl;
+ cerr << "Misformed SyncData"<< endl;
return;
}
@@ -103,32 +221,83 @@
while (index < size)
{
SyncState state = msg->state(index);
+ string devStr = state.name();
+ Name deviceName((const unsigned char *)devStr.c_str(), devStr.size());
+ if (state.type() == SyncState::UPDATE)
+ {
+ sqlite3_int64 seqno = state.seq();
+ m_log.UpdateDeviceSeqNo(deviceName, seqno);
+ if (state.has_locator())
+ {
+ string locStr = state.locator();
+ Name locatorName((const unsigned char *)locStr.c_str(), locStr.size());
+ m_log.UpdateLocator(deviceName, locatorName);
+ WriteLock(m_ypMutex);
+ m_yp[deviceName] = locatorName;
+ }
+ }
+ else
+ {
+ deregister(deviceName);
+ }
index++;
}
+ // find the actuall difference and invoke callback on the actual difference
+ HashPtr oldHash = m_rootHash;
+ m_rootHash = m_log.RememberStateInStateLog();
+ SyncStateMsgPtr diff = m_log.FindStateDifferences(*oldHash, *m_rootHash);
+ m_stateMsgCallback(diff);
}
void
SyncCore::sendSyncInterest()
{
Name syncInterest = constructSyncName(m_rootHash);
- sendInterest(syncInterest, m_interestClosure);
+ m_handle->sendInterest(syncInterest, m_syncClosure);
+}
+
+void
+SyncCore::recover(const HashPtr &hash)
+{
+ if (!(*hash == *m_rootHash) && m_log.LookupSyncLog(*hash) <= 0)
+ {
+ // unfortunately we still don't recognize this hash
+ Bytes bytes;
+ readRaw(bytes, (const unsigned char *)hash->GetHash(), hash->GetHashBytes());
+ Name recoverInterest = m_syncPrefix;
+ recoverInterest.appendComp(RECOVER);
+ // append the unknown hash
+ recoverInterest.appendComp(bytes);
+ m_handle->sendInterest(recoverInterest, m_recoverClosure);
+ }
+ else
+ {
+ // we already learned the hash; cheers!
+ }
+}
+
+void
+SyncCore::deregister(const Name &name)
+{
+ // Do nothing for now
+ // TODO: handle deregistering
}
Name
SyncCore::constructSyncName(const HashPtr &hash)
{
Bytes bytes;
- readRaw(bytes, (const unsigned char*)hash->GetHash(), hash->GetHashBytes);
+ readRaw(bytes, (const unsigned char*)hash->GetHash(), hash->GetHashBytes());
Name syncName = m_syncPrefix;
- syncName.append(bytes);
+ syncName.appendComp(bytes);
return syncName;
}
void
SyncCore::msgToBytes(const SyncStateMsgPtr &msg, Bytes &bytes)
{
- int size = msg.ByteSize();
+ int size = msg->ByteSize();
bytes.resize(size);
- msg.SerializeToArray(head(bytes), size);
+ msg->SerializeToArray(head(bytes), size);
}
diff --git a/src/sync-core.h b/src/sync-core.h
index b06b8b8..afe5e05 100644
--- a/src/sync-core.h
+++ b/src/sync-core.h
@@ -35,13 +35,15 @@
{
public:
typedef boost::function<void (const SyncStateMsgPtr & stateMsg) > StateMsgCallback;
- typedef sqlite3_int64 seqno_t;
- typedef Map<Name, Name> YellowPage;
+ typedef map<Name, Name> YellowPage;
typedef boost::shared_mutex Mutex;
typedef boost::shared_lock<Mutex> ReadLock;
typedef boost::unique_lock<Mutex> WriteLock;
- static const int FRESHNESS = 2;
+ static const int FRESHNESS = 2; // seconds
+ static const string RECOVER;
+ static const double WAIT; // seconds;
+ static const double RANDOM_PERCENT; // seconds;
public:
SyncCore(const string &path // path where SyncLog is stored
@@ -59,27 +61,45 @@
updateLocalPrefix(const Name &localPrefix);
void
- updateLocalState(seqno_t);
+ updateLocalState(sqlite3_int64);
Name
yp(const Name &name);
void
- handleSyncInterest(const Name &name);
-
- Closure::TimeoutCallbackReturnValue
- handleSyncInterestTimeout(const Name &name);
+ handleInterest(const Name &name);
void
handleSyncData(const Name &name, const Bytes &content);
void
- deregister();
+ handleRecoverData(const Name &name, const Bytes &content);
+
+ Closure::TimeoutCallbackReturnValue
+ handleSyncInterestTimeout(const Name &name);
+
+ Closure::TimeoutCallbackReturnValue
+ handleRecoverInterestTimeout(const Name &name);
+
+ void
+ deregister(const Name &name);
+
+ void
+ recover(const HashPtr &hash);
protected:
void
sendSyncInterest();
+ void
+ handleSyncInterest(const Name &name);
+
+ void
+ handleRecoverInterest(const Name &name);
+
+ void
+ handleStateData(const Bytes &content);
+
Name
constructSyncName(const HashPtr &hash);
@@ -97,7 +117,8 @@
YellowPage m_yp;
Mutex m_ypMutex;
CcnxWrapperPtr m_handle;
- Closure *m_interestClosure;
+ Closure *m_syncClosure;
+ Closure *m_recoverClosure;
};
diff --git a/src/sync-log.cc b/src/sync-log.cc
index 4b0984a..f3ba3d0 100644
--- a/src/sync-log.cc
+++ b/src/sync-log.cc
@@ -20,17 +20,19 @@
*/
#include "sync-log.h"
+#include <utility>
#include <boost/make_shared.hpp>
using namespace boost;
using namespace std;
+using namespace Ccnx;
SyncLog::SyncLog (const boost::filesystem::path &path, const std::string &localName)
: DbHelper (path)
, m_localName (localName)
{
- UpdateDeviceSeqno (localName, 0);
+ UpdateDeviceSeqNo (localName, 0);
sqlite3_stmt *stmt;
int res = sqlite3_prepare_v2 (m_db, "SELECT device_id, seq_no FROM SyncNodes WHERE device_name=?", -1, &stmt, 0);
@@ -50,6 +52,25 @@
sqlite3_finalize (stmt);
}
+void
+SyncLog::initYP(map<Name, Name> &yp)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2(m_db, "SELECT device_name, last_known_locator FROM SyncNodes;", -1, &stmt, 0);
+
+ while (sqlite3_step(stmt) == SQLITE_ROW)
+ {
+ Name deviceName((const unsigned char *)sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
+ Name locator;
+ if (sqlite3_column_type(stmt, 1) == SQLITE_BLOB)
+ {
+ locator = Name((const unsigned char *)sqlite3_column_blob(stmt, 1), sqlite3_column_bytes(stmt, 1));
+ }
+ yp.insert(make_pair(deviceName, locator));
+ }
+
+ sqlite3_finalize(stmt);
+}
sqlite3_int64
SyncLog::GetNextLocalSeqNo ()
@@ -177,7 +198,7 @@
}
void
-SyncLog::UpdateDeviceSeqno (const Ccnx::Name &name, sqlite3_int64 seqNo)
+SyncLog::UpdateDeviceSeqNo (const Ccnx::Name &name, sqlite3_int64 seqNo)
{
sqlite3_stmt *stmt;
// update is performed using trigger
@@ -192,7 +213,7 @@
if (res != SQLITE_OK)
{
BOOST_THROW_EXCEPTION (Error::Db ()
- << errmsg_info_str ("Some error with UpdateDeviceSeqno (name)"));
+ << errmsg_info_str ("Some error with UpdateDeviceSeqNo (name)"));
}
sqlite3_finalize (stmt);
}
@@ -217,6 +238,49 @@
sqlite3_finalize (stmt);
}
+Name
+SyncLog::LookupLocator(const Name &deviceName)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "SELECT last_known_locator FROM SyncNodes WHERE device_name=?;", -1, &stmt, 0);
+ Ccnx::CcnxCharbufPtr nameBuf = deviceName;
+ sqlite3_bind_blob (stmt, 1, nameBuf->buf(), nameBuf->length(), SQLITE_STATIC);
+ int res = sqlite3_step (stmt);
+ Name locator;
+ switch (res)
+ {
+ case SQLITE_ROW:
+ {
+ locator = Name((const unsigned char *)sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
+ }
+ case SQLITE_DONE: break;
+ default:
+ BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Error in LookupLocator()"));
+ }
+
+ sqlite3_finalize(stmt);
+
+ return locator;
+}
+
+void
+SyncLog::UpdateLocator(const Name &deviceName, const Name &locator)
+{
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2 (m_db, "UPDATE SyncNodes SET last_known_locator=? WHERE device_name=?;", -1, &stmt, 0);
+ Ccnx::CcnxCharbufPtr nameBuf = deviceName;
+ Ccnx::CcnxCharbufPtr locatorBuf = locator;
+ sqlite3_bind_blob (stmt, 1, nameBuf->buf(), nameBuf->length(), SQLITE_STATIC);
+ sqlite3_bind_blob (stmt, 2, locatorBuf->buf(), locatorBuf->length(), SQLITE_STATIC);
+ int res = sqlite3_step (stmt);
+
+ if (res != SQLITE_OK && res != SQLITE_DONE)
+ {
+ BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Error in UpdateLoactor()"));
+ }
+
+ sqlite3_finalize(stmt);
+}
SyncStateMsgPtr
SyncLog::FindStateDifferences (const std::string &oldHash, const std::string &newHash)
@@ -230,7 +294,7 @@
sqlite3_stmt *stmt;
int res = sqlite3_prepare_v2 (m_db, "\
-SELECT sn.device_name, s_old.seq_no, s_new.seq_no \
+SELECT sn.device_name, sn.last_known_locator, s_old.seq_no, s_new.seq_no\
FROM (SELECT * \
FROM SyncStateNodes \
WHERE state_id=(SELECT state_id \
@@ -250,7 +314,7 @@
\
UNION ALL \
\
-SELECT sn.device_name, s_old.seq_no, s_new.seq_no \
+SELECT sn.device_name, sn.last_known_locator, s_old.seq_no, s_new.seq_no\
FROM (SELECT * \
FROM SyncStateNodes \
WHERE state_id=(SELECT state_id \
@@ -285,7 +349,13 @@
state->set_name (reinterpret_cast<const char*> (sqlite3_column_blob (stmt, 0), sqlite3_column_bytes (stmt, 0)));
- sqlite3_int64 newSeqNo = sqlite3_column_int64 (stmt, 2);
+ // locator is optional, so must check if it is null
+ if (sqlite3_column_type(stmt, 1) == SQLITE_BLOB)
+ {
+ state->set_locator (reinterpret_cast<const char*> (sqlite3_column_blob (stmt, 1), sqlite3_column_bytes (stmt, 1)));
+ }
+
+ sqlite3_int64 newSeqNo = sqlite3_column_int64 (stmt, 3);
if (newSeqNo > 0)
{
state->set_type (SyncState::UPDATE);
diff --git a/src/sync-log.h b/src/sync-log.h
index c75fcf7..d066991 100644
--- a/src/sync-log.h
+++ b/src/sync-log.h
@@ -25,6 +25,7 @@
#include "db-helper.h"
#include <sync-state.pb.h>
#include <ccnx-name.h>
+#include <map>
typedef boost::shared_ptr<SyncStateMsg> SyncStateMsgPtr;
@@ -33,21 +34,22 @@
public:
SyncLog (const boost::filesystem::path &path, const std::string &localName);
+ // fill in the map with device-name <-> locator pairs
+ void
+ initYP(map<Ccnx::Name, Ccnx::Name> &yp);
+
sqlite3_int64
GetNextLocalSeqNo (); // side effect: local seq_no will be increased
- void
- UpdateDeviceSeqNo (sqlite3_int64 deviceId, sqlite3_int64 seqNo);
-
// done
void
- UpdateDeviceSeqno (const Ccnx::Name &name, sqlite3_int64 seqNo);
+ UpdateDeviceSeqNo (const Ccnx::Name &name, sqlite3_int64 seqNo);
- // std::string
- // LookupForwardingAlias (const std::string &deviceName);
+ Ccnx::Name
+ LookupLocator (const Ccnx::Name &deviceName);
- // void
- // UpdateForwardingAlias ();
+ void
+ UpdateLocator (const Ccnx::Name &deviceName, const Ccnx::Name &locator);
// done
/**
@@ -72,6 +74,11 @@
FindStateDifferences (const Hash &oldHash, const Hash &newHash);
protected:
+ void
+ UpdateDeviceSeqNo (sqlite3_int64 deviceId, sqlite3_int64 seqNo);
+
+
+protected:
// std::string m_localName;
Ccnx::Name m_localName;
diff --git a/src/sync-state.proto b/src/sync-state.proto
index 2aafb0c..26095e1 100644
--- a/src/sync-state.proto
+++ b/src/sync-state.proto
@@ -10,6 +10,7 @@
required ActionType type = 2;
optional uint64 seq = 3;
+ optional bytes locator = 4;
}
message SyncStateMsg
diff --git a/test/database-test.cc b/test/database-test.cc
index dcbcc2b..c9058e9 100644
--- a/test/database-test.cc
+++ b/test/database-test.cc
@@ -45,20 +45,20 @@
// should be empty
BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "7a6f2c1eefd539560d2dc3e5542868a79810d0867db15d9b87e41ec105899405");
- db.UpdateDeviceSeqno (Name ("Alex"), 1);
+ db.UpdateDeviceSeqNo (Name ("Alex"), 1);
hash = db.RememberStateInStateLog ();
BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "bf19308cb2c2ddab7bcce66e9074cd0eed74893be0813ca67a95e97c55d65896");
- db.UpdateDeviceSeqno (Name ("Alex"), 2);
+ db.UpdateDeviceSeqNo (Name ("Alex"), 2);
hash = db.RememberStateInStateLog ();
BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "86b51f1f98662583b295b61385ae4450ff8fac955981f1ca4381144ab1d7a4e0");
- db.UpdateDeviceSeqno (Name ("Alex"), 2);
+ db.UpdateDeviceSeqNo (Name ("Alex"), 2);
hash = db.RememberStateInStateLog ();
BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "86b51f1f98662583b295b61385ae4450ff8fac955981f1ca4381144ab1d7a4e0");
- db.UpdateDeviceSeqno (Name ("Alex"), 1);
+ db.UpdateDeviceSeqNo (Name ("Alex"), 1);
hash = db.RememberStateInStateLog ();
BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "86b51f1f98662583b295b61385ae4450ff8fac955981f1ca4381144ab1d7a4e0");
@@ -70,7 +70,7 @@
// db.FindStateDifferences ("86b51f1f98662583b295b61385ae4450ff8fac955981f1ca4381144ab1d7a4e0",
// "869c38c6dffe8911ced320aecc6d9244904d13d3e8cd21081311f2129b4557ce");
- // db.UpdateDeviceSeqno (Name ("Bob"), 1);
+ // db.UpdateDeviceSeqNo (Name ("Bob"), 1);
// hash = db.RememberStateInStateLog ();
// BOOST_CHECK_EQUAL (lexical_cast<string> (*hash), "d001d4680fd9adcb48e34a795e3cc3d5d36f209fbab34fd57f70f362c2085310");
diff --git a/wscript b/wscript
index 6872b0b..69e49b9 100644
--- a/wscript
+++ b/wscript
@@ -99,6 +99,7 @@
'src/action-log.cc',
'src/action-item.proto',
'src/sync-state.proto',
+ 'src/sync-core.cc',
],
use = "BOOST SQLITE3 SSL common",
includes = ['include', 'src'],