blob: ced80fe5918f31ddea1a877ccb45419c54663a4b [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016, Regents of the University of California.
Alexander Afanasyeva199f972013-01-02 19:37:26 -08004 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08005 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
Alexander Afanasyeva199f972013-01-02 19:37:26 -08006 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08007 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
Alexander Afanasyeva199f972013-01-02 19:37:26 -080010 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080011 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Alexander Afanasyeva199f972013-01-02 19:37:26 -080014 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080015 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
Alexander Afanasyeva199f972013-01-02 19:37:26 -080019 */
20
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080021#include "sync-log.hpp"
22#include "logging.hpp"
Zhenkai Zhue851b952013-01-13 22:29:57 -080023#include <utility>
Alexander Afanasyeva199f972013-01-02 19:37:26 -080024
25#include <boost/make_shared.hpp>
Alexander Afanasyevbeee0b42013-01-16 18:25:08 -080026#include <boost/thread.hpp>
Alexander Afanasyeva199f972013-01-02 19:37:26 -080027
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080028INIT_LOGGER("Sync.Log");
Alexander Afanasyev49a30d02013-01-21 21:38:48 -080029
Alexander Afanasyeva199f972013-01-02 19:37:26 -080030using namespace boost;
31using namespace std;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070032using namespace Ndnx;
Alexander Afanasyeva199f972013-01-02 19:37:26 -080033
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080034// static void
35// xTrace(void*, const char* q)
Alexander Afanasyevd7245812013-02-13 21:06:57 -080036// {
37// cout << q << endl;
38// }
Alexander Afanasyevbeee0b42013-01-16 18:25:08 -080039
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080040const std::string INIT_DATABASE = "\
41CREATE TABLE \n\
42 SyncNodes( \n\
43 device_id INTEGER PRIMARY KEY AUTOINCREMENT, \n\
44 device_name BLOB NOT NULL, \n\
45 description TEXT, \n\
46 seq_no INTEGER NOT NULL, \n\
47 last_known_locator BLOB, \n\
48 last_update TIMESTAMP \n\
49 ); \n\
50 \n\
51CREATE TRIGGER SyncNodesUpdater_trigger \n\
52 BEFORE INSERT ON SyncNodes \n\
53 FOR EACH ROW \n\
54 WHEN (SELECT device_id \n\
55 FROM SyncNodes \n\
56 WHERE device_name=NEW.device_name) \n\
57 IS NOT NULL \n\
58 BEGIN \n\
59 UPDATE SyncNodes \n\
60 SET seq_no=max(seq_no,NEW.seq_no) \n\
61 WHERE device_name=NEW.device_name; \n\
62 SELECT RAISE(IGNORE); \n\
63 END; \n\
64 \n\
65CREATE INDEX SyncNodes_device_name ON SyncNodes (device_name); \n\
66 \n\
67CREATE TABLE SyncLog( \n\
68 state_id INTEGER PRIMARY KEY AUTOINCREMENT, \n\
69 state_hash BLOB NOT NULL UNIQUE, \n\
70 last_update TIMESTAMP NOT NULL \n\
71 ); \n\
72 \n\
73CREATE TABLE \n\
74 SyncStateNodes( \n\
75 id INTEGER PRIMARY KEY AUTOINCREMENT, \n\
76 state_id INTEGER NOT NULL \n\
77 REFERENCES SyncLog (state_id) ON UPDATE CASCADE ON DELETE CASCADE, \n\
78 device_id INTEGER NOT NULL \n\
79 REFERENCES SyncNodes (device_id) ON UPDATE CASCADE ON DELETE CASCADE, \n\
80 seq_no INTEGER NOT NULL \n\
81 ); \n\
82 \n\
83CREATE INDEX SyncStateNodes_device_id ON SyncStateNodes (device_id); \n\
84CREATE INDEX SyncStateNodes_state_id ON SyncStateNodes (state_id); \n\
85CREATE INDEX SyncStateNodes_seq_no ON SyncStateNodes (seq_no); \n\
86 \n\
87CREATE TRIGGER SyncLogGuard_trigger \n\
88 BEFORE INSERT ON SyncLog \n\
89 FOR EACH ROW \n\
90 WHEN (SELECT state_hash \n\
91 FROM SyncLog \n\
92 WHERE state_hash=NEW.state_hash) \n\
93 IS NOT NULL \n\
94 BEGIN \n\
95 DELETE FROM SyncLog WHERE state_hash=NEW.state_hash; \n\
96 END; \n\
97";
98
Zhenkai Zhu9501b8b2013-01-17 12:37:00 -080099
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800100SyncLog::SyncLog(const boost::filesystem::path& path, const Ccnx::Name& localName)
101 : DbHelper(path / ".chronoshare", "sync-log.db")
102 , m_localName(localName)
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800103{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800104 sqlite3_exec(m_db, INIT_DATABASE.c_str(), NULL, NULL, NULL);
105 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -0800106
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800107 UpdateDeviceSeqNo(localName, 0);
Alexander Afanasyev66f4c492013-01-20 23:32:50 -0800108
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800109 sqlite3_stmt* stmt;
110 int res = sqlite3_prepare_v2(m_db, "SELECT device_id, seq_no FROM SyncNodes WHERE device_name=?",
111 -1, &stmt, 0);
Alexander Afanasyevd09871f2013-01-04 22:36:37 -0800112
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800113 Ccnx::CcnxCharbufPtr name = m_localName;
114 sqlite3_bind_blob(stmt, 1, name->buf(), name->length(), SQLITE_STATIC);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800115
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800116 if (sqlite3_step(stmt) == SQLITE_ROW) {
117 m_localDeviceId = sqlite3_column_int64(stmt, 0);
118 }
119 else {
120 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Impossible thing in SyncLog::SyncLog"));
121 }
122 sqlite3_finalize(stmt);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800123}
124
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800125sqlite3_int64
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800126SyncLog::GetNextLocalSeqNo()
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800127{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800128 sqlite3_stmt* stmt_seq;
129 sqlite3_prepare_v2(m_db, "SELECT seq_no FROM SyncNodes WHERE device_id = ?", -1, &stmt_seq, 0);
130 sqlite3_bind_int64(stmt_seq, 1, m_localDeviceId);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800131
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800132 if (sqlite3_step(stmt_seq) != SQLITE_ROW) {
133 BOOST_THROW_EXCEPTION(Error::Db()
134 << errmsg_info_str("Impossible thing in SyncLog::GetNextLocalSeqNo"));
135 }
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800136
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800137 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800138
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800139 sqlite3_int64 seq_no = sqlite3_column_int64(stmt_seq, 0) + 1;
140 sqlite3_finalize(stmt_seq);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800141
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800142 UpdateDeviceSeqNo(m_localDeviceId, seq_no);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800143
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800144 return seq_no;
145}
146
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800147HashPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800148SyncLog::RememberStateInStateLog()
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800149{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800150 WriteLock lock(m_stateUpdateMutex);
Alexander Afanasyevbeee0b42013-01-16 18:25:08 -0800151
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800152 int res = sqlite3_exec(m_db, "BEGIN TRANSACTION;", 0, 0, 0);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800153
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800154 res += sqlite3_exec(m_db, "\
Alexander Afanasyev49ab6f82013-01-15 16:58:13 -0800155INSERT INTO SyncLog \
156 (state_hash, last_update) \
157 SELECT \
158 hash(device_name, seq_no), datetime('now') \
159 FROM (SELECT * FROM SyncNodes \
160 ORDER BY device_name); \
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800161",
162 0, 0, 0);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800163
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800164 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, "DbError: " << sqlite3_errmsg(m_db));
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800165
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800166 if (res != SQLITE_OK) {
167 sqlite3_exec(m_db, "ROLLBACK TRANSACTION;", 0, 0, 0);
168 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str(sqlite3_errmsg(m_db)));
169 }
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800170
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800171 sqlite3_int64 rowId = sqlite3_last_insert_rowid(m_db);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800172
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800173 sqlite3_stmt* insertStmt;
174 res += sqlite3_prepare(m_db, "\
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800175INSERT INTO SyncStateNodes \
176 (state_id, device_id, seq_no) \
177 SELECT ?, device_id, seq_no \
178 FROM SyncNodes; \
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800179",
180 -1, &insertStmt, 0);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800181
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800182 res += sqlite3_bind_int64(insertStmt, 1, rowId);
183 sqlite3_step(insertStmt);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800184
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800185 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, "DbError: " << sqlite3_errmsg(m_db));
186 if (res != SQLITE_OK) {
187 sqlite3_exec(m_db, "ROLLBACK TRANSACTION;", 0, 0, 0);
188 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str(sqlite3_errmsg(m_db)));
189 }
190 sqlite3_finalize(insertStmt);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800191
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800192 sqlite3_stmt* getHashStmt;
193 res += sqlite3_prepare(m_db, "\
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800194SELECT state_hash FROM SyncLog WHERE state_id = ?\
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800195",
196 -1, &getHashStmt, 0);
197 res += sqlite3_bind_int64(getHashStmt, 1, rowId);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800198
199 HashPtr retval;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800200 int stepRes = sqlite3_step(getHashStmt);
201 if (stepRes == SQLITE_ROW) {
202 retval =
203 make_shared<Hash>(sqlite3_column_blob(getHashStmt, 0), sqlite3_column_bytes(getHashStmt, 0));
204 }
205 else {
206 sqlite3_exec(m_db, "ROLLBACK TRANSACTION;", 0, 0, 0);
Alexander Afanasyevbeee0b42013-01-16 18:25:08 -0800207
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800208 _LOG_ERROR("DbError: " << sqlite3_errmsg(m_db));
209 BOOST_THROW_EXCEPTION(Error::Db()
210 << errmsg_info_str("Not a valid hash in rememberStateInStateLog"));
211 }
212 sqlite3_finalize(getHashStmt);
213 res += sqlite3_exec(m_db, "COMMIT;", 0, 0, 0);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800214
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800215 if (res != SQLITE_OK) {
216 sqlite3_exec(m_db, "ROLLBACK TRANSACTION;", 0, 0, 0);
217 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Some error with rememberStateInStateLog"));
218 }
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800219
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800220 return retval;
221}
222
223sqlite3_int64
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800224SyncLog::LookupSyncLog(const std::string& stateHash)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800225{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800226 return LookupSyncLog(*Hash::FromString(stateHash));
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800227}
228
229sqlite3_int64
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800230SyncLog::LookupSyncLog(const Hash& stateHash)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800231{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800232 sqlite3_stmt* stmt;
233 int res = sqlite3_prepare(m_db, "SELECT state_id FROM SyncLog WHERE state_hash = ?", -1, &stmt, 0);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800234
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800235 if (res != SQLITE_OK) {
236 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot prepare statement"));
237 }
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800238
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800239 res = sqlite3_bind_blob(stmt, 1, stateHash.GetHash(), stateHash.GetHashBytes(), SQLITE_STATIC);
240 if (res != SQLITE_OK) {
241 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot bind"));
242 }
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800243
244 sqlite3_int64 row = 0; // something bad
245
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800246 if (sqlite3_step(stmt) == SQLITE_ROW) {
247 row = sqlite3_column_int64(stmt, 0);
248 }
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800249
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800250 sqlite3_finalize(stmt);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800251
252 return row;
253}
254
255void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800256SyncLog::UpdateDeviceSeqNo(const Ccnx::Name& name, sqlite3_int64 seqNo)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800257{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800258 sqlite3_stmt* stmt;
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800259 // update is performed using trigger
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800260 int res =
261 sqlite3_prepare(m_db, "INSERT INTO SyncNodes (device_name, seq_no) VALUES (?,?);", -1, &stmt, 0);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800262
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800263 Ccnx::CcnxCharbufPtr nameBuf = name;
264 res += sqlite3_bind_blob(stmt, 1, nameBuf->buf(), nameBuf->length(), SQLITE_STATIC);
265 res += sqlite3_bind_int64(stmt, 2, seqNo);
266 sqlite3_step(stmt);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800267
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800268 if (res != SQLITE_OK) {
269 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Some error with UpdateDeviceSeqNo (name)"));
270 }
271 sqlite3_finalize(stmt);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800272}
273
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800274void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800275SyncLog::UpdateLocalSeqNo(sqlite3_int64 seqNo)
Alexander Afanasyev7326a252013-01-20 23:43:25 -0800276{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800277 return UpdateDeviceSeqNo(m_localDeviceId, seqNo);
Alexander Afanasyev7326a252013-01-20 23:43:25 -0800278}
279
280void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800281SyncLog::UpdateDeviceSeqNo(sqlite3_int64 deviceId, sqlite3_int64 seqNo)
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800282{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800283 sqlite3_stmt* stmt;
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800284 // update is performed using trigger
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800285 int res = sqlite3_prepare(m_db, "UPDATE SyncNodes SET seq_no=MAX(seq_no,?) WHERE device_id=?;",
286 -1, &stmt, 0);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800287
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800288 res += sqlite3_bind_int64(stmt, 1, seqNo);
289 res += sqlite3_bind_int64(stmt, 2, deviceId);
290 sqlite3_step(stmt);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800291
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800292 if (res != SQLITE_OK) {
293 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Some error with UpdateDeviceSeqNo (id)"));
294 }
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800295
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800296 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800297
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800298 sqlite3_finalize(stmt);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800299}
300
Zhenkai Zhue851b952013-01-13 22:29:57 -0800301Name
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800302SyncLog::LookupLocator(const Name& deviceName)
Zhenkai Zhue851b952013-01-13 22:29:57 -0800303{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800304 sqlite3_stmt* stmt;
305 sqlite3_prepare_v2(m_db, "SELECT last_known_locator FROM SyncNodes WHERE device_name=?;", -1,
306 &stmt, 0);
307 Ccnx::CcnxCharbufPtr nameBuf = deviceName;
308 sqlite3_bind_blob(stmt, 1, nameBuf->buf(), nameBuf->length(), SQLITE_STATIC);
309 int res = sqlite3_step(stmt);
Zhenkai Zhue851b952013-01-13 22:29:57 -0800310 Name locator;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800311 switch (res) {
312 case SQLITE_ROW: {
313 locator =
314 Name((const unsigned char*)sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
Zhenkai Zhue851b952013-01-13 22:29:57 -0800315 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800316 case SQLITE_DONE:
317 break;
318 default:
319 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Error in LookupLocator()"));
Zhenkai Zhue851b952013-01-13 22:29:57 -0800320 }
321
322 sqlite3_finalize(stmt);
323
324 return locator;
325}
326
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800327Ccnx::Name
328SyncLog::LookupLocalLocator()
Alexander Afanasyev758f51b2013-01-24 13:48:18 -0800329{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800330 return LookupLocator(m_localName);
Alexander Afanasyev758f51b2013-01-24 13:48:18 -0800331}
332
Zhenkai Zhue851b952013-01-13 22:29:57 -0800333void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800334SyncLog::UpdateLocator(const Name& deviceName, const Name& locator)
Zhenkai Zhue851b952013-01-13 22:29:57 -0800335{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800336 sqlite3_stmt* stmt;
337 sqlite3_prepare_v2(m_db,
338 "UPDATE SyncNodes SET last_known_locator=?,last_update=datetime('now') WHERE device_name=?;",
339 -1, &stmt, 0);
340 Ccnx::CcnxCharbufPtr nameBuf = deviceName;
341 Ccnx::CcnxCharbufPtr locatorBuf = locator;
342 sqlite3_bind_blob(stmt, 1, locatorBuf->buf(), locatorBuf->length(), SQLITE_STATIC);
343 sqlite3_bind_blob(stmt, 2, nameBuf->buf(), nameBuf->length(), SQLITE_STATIC);
344 int res = sqlite3_step(stmt);
Zhenkai Zhue851b952013-01-13 22:29:57 -0800345
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800346 if (res != SQLITE_OK && res != SQLITE_DONE) {
Zhenkai Zhue851b952013-01-13 22:29:57 -0800347 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Error in UpdateLoactor()"));
348 }
349
350 sqlite3_finalize(stmt);
351}
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800352
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800353void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800354SyncLog::UpdateLocalLocator(const Ccnx::Name& forwardingHint)
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800355{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800356 return UpdateLocator(m_localName, forwardingHint);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800357}
358
Alexander Afanasyev6f70a0f2013-01-02 20:44:09 -0800359SyncStateMsgPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800360SyncLog::FindStateDifferences(const std::string& oldHash, const std::string& newHash,
361 bool includeOldSeq)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800362{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800363 return FindStateDifferences(*Hash::FromString(oldHash), *Hash::FromString(newHash), includeOldSeq);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800364}
365
Alexander Afanasyev6f70a0f2013-01-02 20:44:09 -0800366SyncStateMsgPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800367SyncLog::FindStateDifferences(const Hash& oldHash, const Hash& newHash, bool includeOldSeq)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800368{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800369 sqlite3_stmt* stmt;
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800370
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800371 int res = sqlite3_prepare_v2(m_db, "\
Zhenkai Zhue851b952013-01-13 22:29:57 -0800372SELECT sn.device_name, sn.last_known_locator, s_old.seq_no, s_new.seq_no\
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800373 FROM (SELECT * \
374 FROM SyncStateNodes \
375 WHERE state_id=(SELECT state_id \
376 FROM SyncLog \
377 WHERE state_hash=:old_hash)) s_old \
378 LEFT JOIN (SELECT * \
379 FROM SyncStateNodes \
380 WHERE state_id=(SELECT state_id \
381 FROM SyncLog \
382 WHERE state_hash=:new_hash)) s_new \
383 \
384 ON s_old.device_id = s_new.device_id \
385 JOIN SyncNodes sn ON sn.device_id = s_old.device_id \
386 \
387 WHERE s_new.seq_no IS NULL OR \
388 s_old.seq_no != s_new.seq_no \
389 \
390UNION ALL \
391 \
Zhenkai Zhue851b952013-01-13 22:29:57 -0800392SELECT sn.device_name, sn.last_known_locator, s_old.seq_no, s_new.seq_no\
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800393 FROM (SELECT * \
394 FROM SyncStateNodes \
395 WHERE state_id=(SELECT state_id \
396 FROM SyncLog \
397 WHERE state_hash=:new_hash )) s_new \
398 LEFT JOIN (SELECT * \
399 FROM SyncStateNodes \
400 WHERE state_id=(SELECT state_id \
401 FROM SyncLog \
402 WHERE state_hash=:old_hash)) s_old \
403 \
404 ON s_old.device_id = s_new.device_id \
405 JOIN SyncNodes sn ON sn.device_id = s_new.device_id \
406 \
407 WHERE s_old.seq_no IS NULL \
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800408",
409 -1, &stmt, 0);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800410
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800411 if (res != SQLITE_OK) {
412 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Some error with FindStateDifferences"));
413 }
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800414
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800415 res += sqlite3_bind_blob(stmt, 1, oldHash.GetHash(), oldHash.GetHashBytes(), SQLITE_STATIC);
416 res += sqlite3_bind_blob(stmt, 2, newHash.GetHash(), newHash.GetHashBytes(), SQLITE_STATIC);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800417
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800418 SyncStateMsgPtr msg = make_shared<SyncStateMsg>();
Alexander Afanasyeva44a7a22013-01-14 17:37:06 -0800419
420 // sqlite3_trace(m_db, xTrace, NULL);
Alexander Afanasyevdac84922013-01-20 23:32:17 -0800421
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800422 while (sqlite3_step(stmt) == SQLITE_ROW) {
423 SyncState* state = msg->add_state();
Alexander Afanasyev6f70a0f2013-01-02 20:44:09 -0800424
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800425 // set name
426 state->set_name(reinterpret_cast<const char*>(sqlite3_column_blob(stmt, 0)),
427 sqlite3_column_bytes(stmt, 0));
Alexander Afanasyev6f70a0f2013-01-02 20:44:09 -0800428
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800429 // locator is optional, so must check if it is null
430 if (sqlite3_column_type(stmt, 1) == SQLITE_BLOB) {
431 state->set_locator(reinterpret_cast<const char*>(sqlite3_column_blob(stmt, 1)),
432 sqlite3_column_bytes(stmt, 1));
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800433 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800434
435 // set old seq
436 if (includeOldSeq) {
437 if (sqlite3_column_type(stmt, 2) == SQLITE_NULL) {
438 // old seq is zero; we always have an initial action of zero seq
439 // other's do not need to fetch this action
440 state->set_old_seq(0);
441 }
442 else {
443 sqlite3_int64 oldSeqNo = sqlite3_column_int64(stmt, 2);
444 state->set_old_seq(oldSeqNo);
445 }
446 }
447
448 // set new seq
449 if (sqlite3_column_type(stmt, 3) == SQLITE_NULL) {
450 state->set_type(SyncState::DELETE);
451 }
452 else {
453 sqlite3_int64 newSeqNo = sqlite3_column_int64(stmt, 3);
454 state->set_type(SyncState::UPDATE);
455 state->set_seq(newSeqNo);
456 }
457
458 // std::cout << sqlite3_column_text (stmt, 0) <<
459 // ": from " << sqlite3_column_int64 (stmt, 1) <<
460 // " to " << sqlite3_column_int64 (stmt, 2) <<
461 // std::endl;
462 }
463 sqlite3_finalize(stmt);
Alexander Afanasyev6f70a0f2013-01-02 20:44:09 -0800464
Alexander Afanasyeva44a7a22013-01-14 17:37:06 -0800465 // sqlite3_trace(m_db, NULL, NULL);
466
Alexander Afanasyev6f70a0f2013-01-02 20:44:09 -0800467 return msg;
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800468}
Zhenkai Zhu9501b8b2013-01-17 12:37:00 -0800469
470sqlite3_int64
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800471SyncLog::SeqNo(const Name& name)
Zhenkai Zhu9501b8b2013-01-17 12:37:00 -0800472{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800473 sqlite3_stmt* stmt;
Zhenkai Zhu9501b8b2013-01-17 12:37:00 -0800474 sqlite3_int64 seq = -1;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800475 sqlite3_prepare_v2(m_db, "SELECT seq_no FROM SyncNodes WHERE device_name=?;", -1, &stmt, 0);
476 Ccnx::CcnxCharbufPtr nameBuf = name;
477 sqlite3_bind_blob(stmt, 1, nameBuf->buf(), nameBuf->length(), SQLITE_STATIC);
478 if (sqlite3_step(stmt) == SQLITE_ROW) {
479 seq = sqlite3_column_int64(stmt, 0);
Zhenkai Zhu9501b8b2013-01-17 12:37:00 -0800480 }
481
482 return seq;
483}
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800484
485sqlite3_int64
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800486SyncLog::LogSize()
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800487{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800488 sqlite3_stmt* stmt;
489 sqlite3_prepare_v2(m_db, "SELECT count(*) FROM SyncLog", -1, &stmt, 0);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800490
491 sqlite3_int64 retval = -1;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800492 if (sqlite3_step(stmt) == SQLITE_ROW) {
493 retval = sqlite3_column_int64(stmt, 0);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800494 }
495
496 return retval;
497}