blob: 179be794ca8efb28ebdd222070a249a61ff4e602 [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -08003 * Copyright (c) 2013-2017, 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 "action-log.hpp"
22#include "logging.hpp"
Alexander Afanasyeva199f972013-01-02 19:37:26 -080023
Alexander Afanasyev0995f322013-01-22 13:16:46 -080024#include <boost/make_shared.hpp>
25
Alexander Afanasyeva199f972013-01-02 19:37:26 -080026using namespace boost;
27using namespace std;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070028using namespace Ndnx;
Alexander Afanasyeva199f972013-01-02 19:37:26 -080029
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -080030_LOG_INIT(ActionLog);
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080031
32const std::string INIT_DATABASE = "\
33CREATE TABLE ActionLog ( \n\
Alexander Afanasyev0995f322013-01-22 13:16:46 -080034 device_name BLOB NOT NULL, \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080035 seq_no INTEGER NOT NULL, \n\
36 \n\
37 action CHAR(1) NOT NULL, /* 0 for \"update\", 1 for \"delete\". */ \n\
38 filename TEXT NOT NULL, \n\
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080039 directory TEXT, \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080040 \n\
41 version INTEGER NOT NULL, \n\
42 action_timestamp TIMESTAMP NOT NULL, \n\
43 \n\
44 file_hash BLOB, /* NULL if action is \"delete\" */ \n\
45 file_atime TIMESTAMP, \n\
46 file_mtime TIMESTAMP, \n\
47 file_ctime TIMESTAMP, \n\
48 file_chmod INTEGER, \n\
49 file_seg_num INTEGER, /* NULL if action is \"delete\" */ \n\
50 \n\
Alexander Afanasyev0995f322013-01-22 13:16:46 -080051 parent_device_name BLOB, \n\
52 parent_seq_no INTEGER, \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080053 \n\
54 action_name TEXT, \n\
55 action_content_object BLOB, \n\
56 \n\
Alexander Afanasyev785b0a02013-01-30 10:17:47 -080057 PRIMARY KEY (device_name, seq_no) \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080058); \n\
59 \n\
Alexander Afanasyev0995f322013-01-22 13:16:46 -080060CREATE INDEX ActionLog_filename_version ON ActionLog (filename,version); \n\
61CREATE INDEX ActionLog_parent ON ActionLog (parent_device_name, parent_seq_no); \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080062CREATE INDEX ActionLog_action_name ON ActionLog (action_name); \n\
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080063CREATE INDEX ActionLog_filename_version_hash ON ActionLog (filename,version,file_hash); \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080064 \n\
65CREATE TRIGGER ActionLogInsert_trigger \n\
66 AFTER INSERT ON ActionLog \n\
67 FOR EACH ROW \n\
Alexander Afanasyev0995f322013-01-22 13:16:46 -080068 WHEN (SELECT device_name \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080069 FROM ActionLog \n\
70 WHERE filename=NEW.filename AND \n\
71 version > NEW.version) IS NULL AND \n\
Alexander Afanasyev0995f322013-01-22 13:16:46 -080072 (SELECT device_name \n\
73 FROM ActionLog \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080074 WHERE filename=NEW.filename AND \n\
75 version = NEW.version AND \n\
Alexander Afanasyeva35756b2013-01-22 16:59:11 -080076 device_name > NEW.device_name) IS NULL \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080077 BEGIN \n\
Alexander Afanasyev0995f322013-01-22 13:16:46 -080078 SELECT apply_action (NEW.device_name, NEW.seq_no, \
Alexander Afanasyev6fb5dc62013-02-27 11:34:52 -080079 NEW.action,NEW.filename,NEW.version,NEW.file_hash, \
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080080 strftime('%s', NEW.file_atime),strftime('%s', NEW.file_mtime),strftime('%s', NEW.file_ctime), \
81 NEW.file_chmod, NEW.file_seg_num); /* function that applies action and adds record the FileState */ \n \
82 END; \n\
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080083";
84
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080085// static void
86// xTrace(void*, const char* q)
Alexander Afanasyevd6364ef2013-02-06 13:13:07 -080087// {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080088// _LOG_TRACE("SQLITE: " << q);
Alexander Afanasyevd6364ef2013-02-06 13:13:07 -080089// }
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -080090
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080091ActionLog::ActionLog(Ccnx::CcnxWrapperPtr ccnx, const boost::filesystem::path& path,
92 SyncLogPtr syncLog, const std::string& sharedFolder,
93 const std::string& appName, OnFileAddedOrChangedCallback onFileAddedOrChanged,
94 OnFileRemovedCallback onFileRemoved)
95 : DbHelper(path / ".chronoshare", "action-log.db")
96 , m_syncLog(syncLog)
97 , m_ccnx(ccnx)
98 , m_sharedFolderName(sharedFolder)
99 , m_appName(appName)
100 , m_onFileAddedOrChanged(onFileAddedOrChanged)
101 , m_onFileRemoved(onFileRemoved)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800102{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800103 sqlite3_exec(m_db, "PRAGMA foreign_keys = OFF", NULL, NULL, NULL);
104 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev785b0a02013-01-30 10:17:47 -0800105
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800106 sqlite3_exec(m_db, INIT_DATABASE.c_str(), NULL, NULL, NULL);
107 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev8e2104a2013-01-22 10:56:18 -0800108
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800109 int res =
110 sqlite3_create_function(m_db, "apply_action", -1, SQLITE_ANY, reinterpret_cast<void*>(this),
111 ActionLog::apply_action_xFun, 0, 0);
112 if (res != SQLITE_OK) {
113 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot create function ``apply_action''"));
114 }
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800115
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800116 m_fileState = make_shared<FileState>(path);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800117}
118
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800119tuple<sqlite3_int64 /*version*/, Ccnx::CcnxCharbufPtr /*device name*/, sqlite3_int64 /*seq_no*/>
120ActionLog::GetLatestActionForFile(const std::string& filename)
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800121{
122 // check if something already exists
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800123 sqlite3_stmt* stmt;
124 int res = sqlite3_prepare_v2(m_db, "SELECT version,device_name,seq_no,action "
125 "FROM ActionLog "
126 "WHERE filename=? ORDER BY version DESC LIMIT 1",
127 -1, &stmt, 0);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800128
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800129 if (res != SQLITE_OK) {
130 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Some error with GetExistingRecord"));
131 }
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800132
Alexander Afanasyev0995f322013-01-22 13:16:46 -0800133 sqlite3_int64 version = -1;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700134 NdnxCharbufPtr parent_device_name;
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800135 sqlite3_int64 parent_seq_no = -1;
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800136
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800137 sqlite3_bind_text(stmt, 1, filename.c_str(), filename.size(), SQLITE_STATIC);
138 if (sqlite3_step(stmt) == SQLITE_ROW) {
139 version = sqlite3_column_int64(stmt, 0);
140
141 if (sqlite3_column_int(stmt, 3) == 0) // prevent "linking" if the file was previously deleted
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800142 {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800143 parent_device_name =
144 make_shared<CcnxCharbuf>(sqlite3_column_blob(stmt, 1), sqlite3_column_bytes(stmt, 1));
145 parent_seq_no = sqlite3_column_int64(stmt, 2);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800146 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800147 }
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800148
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800149 sqlite3_finalize(stmt);
150 return make_tuple(version, parent_device_name, parent_seq_no);
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800151}
152
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800153// local add action. remote action is extracted from content object
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800154ActionItemPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800155ActionLog::AddLocalActionUpdate(const std::string& filename,
156 const Hash& hash,
157 time_t wtime,
158 int mode,
159 int seg_num)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800160{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800161 sqlite3_exec(m_db, "BEGIN TRANSACTION;", 0, 0, 0);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800162
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800163 CcnxCharbufPtr device_name = m_syncLog->GetLocalName().toCcnxCharbuf();
164 sqlite3_int64 seq_no = m_syncLog->GetNextLocalSeqNo();
165 sqlite3_int64 version;
166 CcnxCharbufPtr parent_device_name;
167 sqlite3_int64 parent_seq_no = -1;
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800168
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800169 sqlite3_int64 action_time = time(0);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800170
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800171 tie(version, parent_device_name, parent_seq_no) = GetLatestActionForFile(filename);
172 version++;
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800173
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800174 sqlite3_stmt* stmt;
175 int res =
176 sqlite3_prepare_v2(m_db,
177 "INSERT INTO ActionLog "
178 "(device_name, seq_no, action, filename, version, action_timestamp, "
179 "file_hash, file_atime, file_mtime, file_ctime, file_chmod, file_seg_num, "
180 "parent_device_name, parent_seq_no, "
181 "action_name, action_content_object) "
182 "VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
183 " ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?,?, "
184 " ?, ?, "
185 " ?, ?);",
186 -1, &stmt, 0);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800187
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800188 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800189
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800190 if (res != SQLITE_OK) {
191 BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str(sqlite3_errmsg(m_db)));
192 }
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800193
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800194 sqlite3_bind_blob(stmt, 1, device_name->buf(), device_name->length(), SQLITE_STATIC);
195 sqlite3_bind_int64(stmt, 2, seq_no);
196 sqlite3_bind_int(stmt, 3, 0);
197 sqlite3_bind_text(stmt, 4, filename.c_str(), filename.size(), SQLITE_STATIC);
198 sqlite3_bind_int64(stmt, 5, version);
199 sqlite3_bind_int64(stmt, 6, action_time);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800200
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800201 sqlite3_bind_blob(stmt, 7, hash.GetHash(), hash.GetHashBytes(), SQLITE_STATIC);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800202
Alexander Afanasyev68f2a952013-01-08 14:34:16 -0800203 // sqlite3_bind_int64 (stmt, 8, atime); // NULL
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800204 sqlite3_bind_int64(stmt, 9, wtime);
Alexander Afanasyev68f2a952013-01-08 14:34:16 -0800205 // sqlite3_bind_int64 (stmt, 10, ctime); // NULL
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800206 sqlite3_bind_int(stmt, 11, mode);
207 sqlite3_bind_int(stmt, 12, seg_num);
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800208
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800209 if (parent_device_name && parent_seq_no > 0) {
210 sqlite3_bind_blob(stmt, 13, parent_device_name->buf(), parent_device_name->length(),
211 SQLITE_STATIC);
212 sqlite3_bind_int64(stmt, 14, parent_seq_no);
213 }
Alexander Afanasyev433ecda2013-01-02 22:13:45 -0800214
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800215 ActionItemPtr item = make_shared<ActionItem>();
216 item->set_action(ActionItem::UPDATE);
217 item->set_filename(filename);
218 item->set_version(version);
219 item->set_timestamp(action_time);
220 item->set_file_hash(hash.GetHash(), hash.GetHashBytes());
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800221 // item->set_atime (atime);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800222 item->set_mtime(wtime);
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800223 // item->set_ctime (ctime);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800224 item->set_mode(mode);
225 item->set_seg_num(seg_num);
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800226
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800227 if (parent_device_name && parent_seq_no > 0) {
228 // cout << Name (*parent_device_name) << endl;
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800229
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800230 item->set_parent_device_name(parent_device_name->buf(), parent_device_name->length());
231 item->set_parent_seq_no(parent_seq_no);
232 }
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800233
234 // assign name to the action, serialize action, and create content object
Alexander Afanasyevebf75182013-01-07 17:00:24 -0800235
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800236
Alexander Afanasyevebf75182013-01-07 17:00:24 -0800237 string item_msg;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800238 item->SerializeToString(&item_msg);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800239
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800240 // action name: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800241 Name actionName =
242 Name("/")(m_syncLog->GetLocalName())(m_appName)("action")(m_sharedFolderName)(seq_no);
243 _LOG_DEBUG("ActionName: " << actionName);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800244
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800245 Bytes actionData = m_ccnx->createContentObject(actionName, item_msg.c_str(), item_msg.size());
246 CcnxCharbufPtr namePtr = actionName.toCcnxCharbuf();
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800247
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800248 // _LOG_DEBUG (" >>>>>>> " << Name (namePtr->buf () << " " << namePtr->length ());
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800249
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800250 sqlite3_bind_blob(stmt, 15, namePtr->buf(), namePtr->length(), SQLITE_STATIC);
251 sqlite3_bind_blob(stmt, 16, head(actionData), actionData.size(), SQLITE_STATIC);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800252
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800253 sqlite3_step(stmt);
Alexander Afanasyevebf75182013-01-07 17:00:24 -0800254
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800255 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800256
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800257 sqlite3_finalize(stmt);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800258
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800259 // I had a problem including directory_name assignment as part of the initial insert.
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800260 sqlite3_prepare_v2(m_db,
261 "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?",
262 -1, &stmt, 0);
263 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800264
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800265 sqlite3_bind_blob(stmt, 1, device_name->buf(), device_name->length(), SQLITE_STATIC);
266 sqlite3_bind_int64(stmt, 2, seq_no);
267 sqlite3_step(stmt);
268 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800269
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800270 sqlite3_finalize(stmt);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800271
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800272 sqlite3_exec(m_db, "END TRANSACTION;", 0, 0, 0);
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800273
Alexander Afanasyevd6364ef2013-02-06 13:13:07 -0800274 // set complete for local file
275 m_fileState->SetFileComplete(filename);
276
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800277 return item;
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800278}
279
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800280// void
281// ActionLog::AddActionMove (const std::string &oldFile, const std::string &newFile)
282// {
283// // not supported yet
284// BOOST_THROW_EXCEPTION (Error::Db ()
285// << errmsg_info_str ("Move operation is not yet supported"));
286// }
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800287
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800288ActionItemPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800289ActionLog::AddLocalActionDelete(const std::string& filename)
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800290{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800291 _LOG_DEBUG("Adding local action DELETE");
Alexander Afanasyev4a8781c2013-01-29 17:59:44 -0800292
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800293 sqlite3_exec(m_db, "BEGIN TRANSACTION;", 0, 0, 0);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800294
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800295 CcnxCharbufPtr device_name = m_syncLog->GetLocalName().toCcnxCharbuf();
296 sqlite3_int64 version;
297 CcnxCharbufPtr parent_device_name;
298 sqlite3_int64 parent_seq_no = -1;
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800299
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800300 sqlite3_int64 action_time = time(0);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800301
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800302 tie(version, parent_device_name, parent_seq_no) = GetLatestActionForFile(filename);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800303 if (!parent_device_name) // no records exist or file was already deleted
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800304 {
305 _LOG_DEBUG("Nothing to delete... [" << filename << "]");
Alexander Afanasyev4a8781c2013-01-29 17:59:44 -0800306
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800307 // just in case, remove data from FileState
308 sqlite3_stmt* stmt;
309 sqlite3_prepare_v2(m_db, "DELETE FROM FileState WHERE filename = ? ", -1, &stmt, 0);
310 sqlite3_bind_text(stmt, 1, filename.c_str(), filename.size(), SQLITE_STATIC); // file
Alexander Afanasyev4a8781c2013-01-29 17:59:44 -0800311
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800312 sqlite3_step(stmt);
Alexander Afanasyev4a8781c2013-01-29 17:59:44 -0800313
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800314 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyev4a8781c2013-01-29 17:59:44 -0800315
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800316 sqlite3_finalize(stmt);
Alexander Afanasyev4a8781c2013-01-29 17:59:44 -0800317
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800318 sqlite3_exec(m_db, "END TRANSACTION;", 0, 0, 0);
319 return ActionItemPtr();
320 }
321 version++;
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800322
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800323 sqlite3_int64 seq_no = m_syncLog->GetNextLocalSeqNo();
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800324
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800325 sqlite3_stmt* stmt;
326 sqlite3_prepare_v2(m_db, "INSERT INTO ActionLog "
327 "(device_name, seq_no, action, filename, version, action_timestamp, "
328 "parent_device_name, parent_seq_no, "
329 "action_name, action_content_object) "
330 "VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
331 " ?, ?,"
332 " ?, ?)",
333 -1, &stmt, 0);
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800334
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800335 sqlite3_bind_blob(stmt, 1, device_name->buf(), device_name->length(), SQLITE_STATIC);
336 sqlite3_bind_int64(stmt, 2, seq_no);
337 sqlite3_bind_int(stmt, 3, 1);
338 sqlite3_bind_text(stmt, 4, filename.c_str(), filename.size(), SQLITE_STATIC); // file
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800339
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800340 sqlite3_bind_int64(stmt, 5, version);
341 sqlite3_bind_int64(stmt, 6, action_time);
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800342
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800343 sqlite3_bind_blob(stmt, 7, parent_device_name->buf(), parent_device_name->length(), SQLITE_STATIC);
344 sqlite3_bind_int64(stmt, 8, parent_seq_no);
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800345
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800346 ActionItemPtr item = make_shared<ActionItem>();
347 item->set_action(ActionItem::DELETE);
348 item->set_filename(filename);
349 item->set_version(version);
350 item->set_timestamp(action_time);
351 item->set_parent_device_name(parent_device_name->buf(), parent_device_name->length());
352 item->set_parent_seq_no(parent_seq_no);
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800353
Alexander Afanasyevc9eb68f2013-01-07 13:40:00 -0800354 string item_msg;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800355 item->SerializeToString(&item_msg);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800356
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800357 // action name: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800358 Name actionName =
359 Name("/")(m_syncLog->GetLocalName())(m_appName)("action")(m_sharedFolderName)(seq_no);
360 _LOG_DEBUG("ActionName: " << actionName);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800361
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800362 Bytes actionData = m_ccnx->createContentObject(actionName, item_msg.c_str(), item_msg.size());
363 CcnxCharbufPtr namePtr = actionName.toCcnxCharbuf();
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800364
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800365 sqlite3_bind_blob(stmt, 9, namePtr->buf(), namePtr->length(), SQLITE_STATIC);
366 sqlite3_bind_blob(stmt, 10, &actionData[0], actionData.size(), SQLITE_STATIC);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800367
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800368 sqlite3_step(stmt);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800369
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800370 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800371
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700372 // cout << Ndnx::Name (parent_device_name) << endl;
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800373
Alexander Afanasyevb6bc01a2013-01-02 23:34:20 -0800374 // assign name to the action, serialize action, and create content object
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800375
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800376 sqlite3_finalize(stmt);
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800377
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800378 // I had a problem including directory_name assignment as part of the initial insert.
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800379 sqlite3_prepare_v2(m_db,
380 "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?",
381 -1, &stmt, 0);
382 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800383
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800384 sqlite3_bind_blob(stmt, 1, device_name->buf(), device_name->length(), SQLITE_STATIC);
385 sqlite3_bind_int64(stmt, 2, seq_no);
386 sqlite3_step(stmt);
387 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800388
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800389 sqlite3_finalize(stmt);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800390
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800391 sqlite3_exec(m_db, "END TRANSACTION;", 0, 0, 0);
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800392
393 return item;
Alexander Afanasyeva199f972013-01-02 19:37:26 -0800394}
Alexander Afanasyevee7e6132013-01-03 20:03:14 -0800395
396
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800397PcoPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800398ActionLog::LookupActionPco(const Ccnx::Name& deviceName, sqlite3_int64 seqno)
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800399{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800400 sqlite3_stmt* stmt;
401 sqlite3_prepare_v2(m_db,
402 "SELECT action_content_object FROM ActionLog WHERE device_name=? AND seq_no=?",
403 -1, &stmt, 0);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800404
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800405 CcnxCharbufPtr name = deviceName.toCcnxCharbuf();
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800406
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800407 sqlite3_bind_blob(stmt, 1, name->buf(), name->length(), SQLITE_STATIC);
408 sqlite3_bind_int64(stmt, 2, seqno);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800409
410 PcoPtr retval;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800411 if (sqlite3_step(stmt) == SQLITE_ROW) {
412 // _LOG_DEBUG (sqlite3_column_blob (stmt, 0) << ", " << sqlite3_column_bytes (stmt, 0));
413 retval = make_shared<ParsedContentObject>(reinterpret_cast<const unsigned char*>(
414 sqlite3_column_blob(stmt, 0)),
415 sqlite3_column_bytes(stmt, 0));
416 }
417 else {
418 _LOG_TRACE("No action found for deviceName [" << deviceName << "] and seqno:" << seqno);
419 }
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800420 // _LOG_DEBUG_COND (sqlite3_errcode (m_db) != SQLITE_OK && sqlite3_errcode (m_db) != SQLITE_ROW, sqlite3_errmsg (m_db));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800421 sqlite3_finalize(stmt);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800422
423 return retval;
424}
425
426ActionItemPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800427ActionLog::LookupAction(const Ccnx::Name& deviceName, sqlite3_int64 seqno)
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800428{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800429 PcoPtr pco = LookupActionPco(deviceName, seqno);
430 if (!pco)
431 return ActionItemPtr();
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800432
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800433 ActionItemPtr action = deserializeMsg<ActionItem>(pco->content());
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800434
435 return action;
436}
437
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800438Ccnx::PcoPtr
439ActionLog::LookupActionPco(const Ccnx::Name& actionName)
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800440{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800441 sqlite3_stmt* stmt;
442 sqlite3_prepare_v2(m_db, "SELECT action_content_object FROM ActionLog WHERE action_name=?", -1,
443 &stmt, 0);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800444
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800445 _LOG_DEBUG(actionName);
446 CcnxCharbufPtr name = actionName.toCcnxCharbuf();
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800447
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800448 _LOG_DEBUG(" <<<<<<< " << name->buf() << " " << name->length());
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800449
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800450 sqlite3_bind_blob(stmt, 1, name->buf(), name->length(), SQLITE_STATIC);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800451
452 PcoPtr retval;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800453 if (sqlite3_step(stmt) == SQLITE_ROW) {
454 // _LOG_DEBUG (sqlite3_column_blob (stmt, 0) << ", " << sqlite3_column_bytes (stmt, 0));
455 retval = make_shared<ParsedContentObject>(reinterpret_cast<const unsigned char*>(
456 sqlite3_column_blob(stmt, 0)),
457 sqlite3_column_bytes(stmt, 0));
458 }
459 else {
460 _LOG_TRACE("No action found for name: " << actionName);
461 }
462 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_ROW, sqlite3_errmsg(m_db));
463 sqlite3_finalize(stmt);
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800464
465 return retval;
466}
467
468ActionItemPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800469ActionLog::LookupAction(const Ccnx::Name& actionName)
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800470{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800471 PcoPtr pco = LookupActionPco(actionName);
472 if (!pco)
473 return ActionItemPtr();
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800474
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800475 ActionItemPtr action = deserializeMsg<ActionItem>(pco->content());
Alexander Afanasyeva35756b2013-01-22 16:59:11 -0800476
477 return action;
478}
479
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800480FileItemPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800481ActionLog::LookupAction(const std::string& filename, sqlite3_int64 version, const Hash& filehash)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800482{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800483 sqlite3_stmt* stmt;
484 sqlite3_prepare_v2(m_db,
485 "SELECT device_name, seq_no, strftime('%s', file_mtime), file_chmod, file_seg_num, file_hash "
486 " FROM ActionLog "
487 " WHERE action = 0 AND "
488 " filename=? AND "
489 " version=? AND "
490 " is_prefix (?, file_hash)=1",
491 -1, &stmt, 0);
492 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800493
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800494 sqlite3_bind_text(stmt, 1, filename.c_str(), filename.size(), SQLITE_STATIC);
495 sqlite3_bind_int64(stmt, 2, version);
496 sqlite3_bind_blob(stmt, 3, filehash.GetHash(), filehash.GetHashBytes(), SQLITE_STATIC);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800497
498 FileItemPtr fileItem;
499
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800500 if (sqlite3_step(stmt) == SQLITE_ROW) {
501 fileItem = make_shared<FileItem>();
502 fileItem->set_filename(filename);
503 fileItem->set_device_name(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
504 fileItem->set_seq_no(sqlite3_column_int64(stmt, 1));
505 fileItem->set_mtime(sqlite3_column_int64(stmt, 2));
506 fileItem->set_mode(sqlite3_column_int64(stmt, 3));
507 fileItem->set_seg_num(sqlite3_column_int64(stmt, 4));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800508
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800509 fileItem->set_file_hash(sqlite3_column_blob(stmt, 5), sqlite3_column_bytes(stmt, 5));
510 }
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800511
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800512 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE || sqlite3_errcode(m_db) != SQLITE_ROW ||
513 sqlite3_errcode(m_db) != SQLITE_OK,
514 sqlite3_errmsg(m_db));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800515
516 return fileItem;
517}
518
519
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800520ActionItemPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800521ActionLog::AddRemoteAction(const Ccnx::Name& deviceName, sqlite3_int64 seqno, Ccnx::PcoPtr actionPco)
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800522{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800523 if (!actionPco) {
524 _LOG_ERROR("actionPco is not valid");
525 return ActionItemPtr();
526 }
527 ActionItemPtr action = deserializeMsg<ActionItem>(actionPco->content());
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800528
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800529 if (!action) {
530 _LOG_ERROR("action cannot be decoded");
531 return ActionItemPtr();
532 }
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800533
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800534 _LOG_DEBUG("AddRemoteAction: [" << deviceName << "] seqno: " << seqno);
Alexander Afanasyevf695aed2013-01-30 13:28:42 -0800535
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800536 sqlite3_stmt* stmt;
537 int res =
538 sqlite3_prepare_v2(m_db,
539 "INSERT INTO ActionLog "
540 "(device_name, seq_no, action, filename, version, action_timestamp, "
541 "file_hash, file_atime, file_mtime, file_ctime, file_chmod, file_seg_num, "
542 "parent_device_name, parent_seq_no, "
543 "action_name, action_content_object) "
544 "VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
545 " ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?,?, "
546 " ?, ?, "
547 " ?, ?);",
548 -1, &stmt, 0);
549 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800550
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800551 CcnxCharbufPtr device_name = deviceName.toCcnxCharbuf();
552 sqlite3_bind_blob(stmt, 1, device_name->buf(), device_name->length(), SQLITE_STATIC);
553 sqlite3_bind_int64(stmt, 2, seqno);
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800554
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800555 sqlite3_bind_int(stmt, 3, action->action());
556 sqlite3_bind_text(stmt, 4, action->filename().c_str(), action->filename().size(), SQLITE_STATIC);
557 sqlite3_bind_int64(stmt, 5, action->version());
558 sqlite3_bind_int64(stmt, 6, action->timestamp());
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800559
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800560 if (action->action() == ActionItem::UPDATE) {
561 sqlite3_bind_blob(stmt, 7, action->file_hash().c_str(), action->file_hash().size(),
562 SQLITE_STATIC);
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800563
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800564 // sqlite3_bind_int64 (stmt, 8, atime); // NULL
565 sqlite3_bind_int64(stmt, 9, action->mtime());
566 // sqlite3_bind_int64 (stmt, 10, ctime); // NULL
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800567
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800568 sqlite3_bind_int(stmt, 11, action->mode());
569 sqlite3_bind_int(stmt, 12, action->seg_num());
570 }
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800571
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800572 if (action->has_parent_device_name()) {
573 sqlite3_bind_blob(stmt, 13, action->parent_device_name().c_str(),
574 action->parent_device_name().size(), SQLITE_STATIC);
575 sqlite3_bind_int64(stmt, 14, action->parent_seq_no());
576 }
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800577
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800578 Name actionName = Name(deviceName)("action")(m_sharedFolderName)(seqno);
579 CcnxCharbufPtr namePtr = actionName.toCcnxCharbuf();
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800580
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800581 sqlite3_bind_blob(stmt, 15, namePtr->buf(), namePtr->length(), SQLITE_STATIC);
582 sqlite3_bind_blob(stmt, 16, head(actionPco->buf()), actionPco->buf().size(), SQLITE_STATIC);
583 sqlite3_step(stmt);
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800584
585 // if action needs to be applied to file state, the trigger will take care of it
586
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800587 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800588
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800589 sqlite3_finalize(stmt);
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800590
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800591 // I had a problem including directory_name assignment as part of the initial insert.
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800592 sqlite3_prepare_v2(m_db,
593 "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?",
594 -1, &stmt, 0);
595 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800596
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800597 sqlite3_bind_blob(stmt, 1, device_name->buf(), device_name->length(), SQLITE_STATIC);
598 sqlite3_bind_int64(stmt, 2, seqno);
599 sqlite3_step(stmt);
600 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800601
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800602 sqlite3_finalize(stmt);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800603
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800604 return action;
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800605}
606
Alexander Afanasyevf9978f82013-01-23 16:30:31 -0800607ActionItemPtr
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800608ActionLog::AddRemoteAction(Ccnx::PcoPtr actionPco)
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800609{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800610 Name name = actionPco->name();
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800611 // action name: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800612
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800613 uint64_t seqno = name.getCompFromBackAsInt(0);
614 string sharedFolder = name.getCompFromBackAsString(1);
Alexander Afanasyev08aa70a2013-01-22 22:16:25 -0800615
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800616 if (sharedFolder != m_sharedFolderName) {
617 _LOG_ERROR("Action doesn't belong to this shared folder");
618 return ActionItemPtr();
619 }
Alexander Afanasyev08aa70a2013-01-22 22:16:25 -0800620
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800621 string action = name.getCompFromBackAsString(2);
Alexander Afanasyev08aa70a2013-01-22 22:16:25 -0800622
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800623 if (action != "action") {
624 _LOG_ERROR("not an action");
625 return ActionItemPtr();
626 }
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800627
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800628 string appName = name.getCompFromBackAsString(3);
629 if (appName != m_appName) {
630 _LOG_ERROR("Action doesn't belong to this application");
631 return ActionItemPtr();
632 }
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800633
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800634 Name deviceName = name.getPartialName(0, name.size() - 4);
Alexander Afanasyev08aa70a2013-01-22 22:16:25 -0800635
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800636 _LOG_DEBUG("From [" << name << "] extracted deviceName: " << deviceName << ", sharedFolder: "
637 << sharedFolder
638 << ", seqno: "
639 << seqno);
Alexander Afanasyev08aa70a2013-01-22 22:16:25 -0800640
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800641 return AddRemoteAction(deviceName, seqno, actionPco);
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800642}
643
Alexander Afanasyevf2c16e02013-01-23 18:08:04 -0800644sqlite3_int64
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800645ActionLog::LogSize()
Alexander Afanasyevf2c16e02013-01-23 18:08:04 -0800646{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800647 sqlite3_stmt* stmt;
648 sqlite3_prepare_v2(m_db, "SELECT count(*) FROM ActionLog", -1, &stmt, 0);
Alexander Afanasyevf2c16e02013-01-23 18:08:04 -0800649
650 sqlite3_int64 retval = -1;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800651 if (sqlite3_step(stmt) == SQLITE_ROW) {
652 retval = sqlite3_column_int64(stmt, 0);
Alexander Afanasyevf2c16e02013-01-23 18:08:04 -0800653 }
654
655 return retval;
656}
657
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800658
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800659bool
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800660ActionLog::LookupActionsInFolderRecursively(
661 const boost::function<void(const Ccnx::Name& name, sqlite3_int64 seq_no, const ActionItem&)>& visitor,
662 const std::string& folder, int offset /*=0*/, int limit /*=-1*/)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800663{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800664 _LOG_DEBUG("LookupActionsInFolderRecursively: [" << folder << "]");
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800665
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800666 if (limit >= 0)
667 limit += 1; // to check if there is more data
668
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800669 sqlite3_stmt* stmt;
670 if (folder != "") {
671 /// @todo Do something to improve efficiency of this query. Right now it is basically scanning the whole database
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800672
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800673 sqlite3_prepare_v2(m_db,
674 "SELECT device_name,seq_no,action,filename,directory,version,strftime('%s', action_timestamp), "
675 " file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num, "
676 " parent_device_name,parent_seq_no "
677 " FROM ActionLog "
678 " WHERE is_dir_prefix (?, directory)=1 "
679 " ORDER BY action_timestamp DESC "
680 " LIMIT ? OFFSET ?",
681 -1, &stmt,
682 0); // there is a small ambiguity with is_prefix matching, but should be ok for now
683 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800684
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800685 sqlite3_bind_text(stmt, 1, folder.c_str(), folder.size(), SQLITE_STATIC);
686 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800687
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800688 sqlite3_bind_int(stmt, 2, limit);
689 sqlite3_bind_int(stmt, 3, offset);
690 }
691 else {
692 sqlite3_prepare_v2(m_db,
693 "SELECT device_name,seq_no,action,filename,directory,version,strftime('%s', action_timestamp), "
694 " file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num, "
695 " parent_device_name,parent_seq_no "
696 " FROM ActionLog "
697 " ORDER BY action_timestamp DESC "
698 " LIMIT ? OFFSET ?",
699 -1, &stmt, 0);
700 sqlite3_bind_int(stmt, 1, limit);
701 sqlite3_bind_int(stmt, 2, offset);
702 }
703
704 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
705
706 while (sqlite3_step(stmt) == SQLITE_ROW) {
707 if (limit == 1)
708 break;
709
710 ActionItem action;
711
712 Ccnx::Name device_name(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
713 sqlite3_int64 seq_no = sqlite3_column_int64(stmt, 1);
714 action.set_action(static_cast<ActionItem_ActionType>(sqlite3_column_int(stmt, 2)));
715 action.set_filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)),
716 sqlite3_column_bytes(stmt, 3));
717 std::string directory(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)),
718 sqlite3_column_bytes(stmt, 4));
719 action.set_version(sqlite3_column_int64(stmt, 5));
720 action.set_timestamp(sqlite3_column_int64(stmt, 6));
721
722 if (action.action() == 0) {
723 action.set_file_hash(sqlite3_column_blob(stmt, 7), sqlite3_column_bytes(stmt, 7));
724 action.set_mtime(sqlite3_column_int(stmt, 8));
725 action.set_mode(sqlite3_column_int(stmt, 9));
726 action.set_seg_num(sqlite3_column_int64(stmt, 10));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800727 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800728 if (sqlite3_column_bytes(stmt, 11) > 0) {
729 action.set_parent_device_name(sqlite3_column_blob(stmt, 11), sqlite3_column_bytes(stmt, 11));
730 action.set_parent_seq_no(sqlite3_column_int64(stmt, 12));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800731 }
732
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800733 visitor(device_name, seq_no, action);
734 limit--;
735 }
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800736
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800737 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800738
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800739 sqlite3_finalize(stmt);
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800740
741 return (limit == 1); // more data is available
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800742}
743
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800744/**
745 * @todo Figure out the way to minimize code duplication
746 */
747bool
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800748ActionLog::LookupActionsForFile(
749 const boost::function<void(const Ccnx::Name& name, sqlite3_int64 seq_no, const ActionItem&)>& visitor,
750 const std::string& file, int offset /*=0*/, int limit /*=-1*/)
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800751{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800752 _LOG_DEBUG("LookupActionsInFolderRecursively: [" << file << "]");
753 if (file.empty())
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800754 return false;
755
756 if (limit >= 0)
757 limit += 1; // to check if there is more data
758
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800759 sqlite3_stmt* stmt;
760 sqlite3_prepare_v2(m_db,
761 "SELECT device_name,seq_no,action,filename,directory,version,strftime('%s', action_timestamp), "
762 " file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num, "
763 " parent_device_name,parent_seq_no "
764 " FROM ActionLog "
765 " WHERE filename=? "
766 " ORDER BY action_timestamp DESC "
767 " LIMIT ? OFFSET ?",
768 -1, &stmt,
769 0); // there is a small ambiguity with is_prefix matching, but should be ok for now
770 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800771
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800772 sqlite3_bind_text(stmt, 1, file.c_str(), file.size(), SQLITE_STATIC);
773 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800774
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800775 sqlite3_bind_int(stmt, 2, limit);
776 sqlite3_bind_int(stmt, 3, offset);
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800777
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800778 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800779
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800780 while (sqlite3_step(stmt) == SQLITE_ROW) {
781 if (limit == 1)
782 break;
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800783
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800784 ActionItem action;
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800785
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800786 Ccnx::Name device_name(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
787 sqlite3_int64 seq_no = sqlite3_column_int64(stmt, 1);
788 action.set_action(static_cast<ActionItem_ActionType>(sqlite3_column_int(stmt, 2)));
789 action.set_filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)),
790 sqlite3_column_bytes(stmt, 3));
791 std::string directory(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)),
792 sqlite3_column_bytes(stmt, 4));
793 action.set_version(sqlite3_column_int64(stmt, 5));
794 action.set_timestamp(sqlite3_column_int64(stmt, 6));
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800795
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800796 if (action.action() == 0) {
797 action.set_file_hash(sqlite3_column_blob(stmt, 7), sqlite3_column_bytes(stmt, 7));
798 action.set_mtime(sqlite3_column_int(stmt, 8));
799 action.set_mode(sqlite3_column_int(stmt, 9));
800 action.set_seg_num(sqlite3_column_int64(stmt, 10));
801 }
802 if (sqlite3_column_bytes(stmt, 11) > 0) {
803 action.set_parent_device_name(sqlite3_column_blob(stmt, 11), sqlite3_column_bytes(stmt, 11));
804 action.set_parent_seq_no(sqlite3_column_int64(stmt, 12));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800805 }
806
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800807 visitor(device_name, seq_no, action);
808 limit--;
809 }
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800810
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800811 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
812
813 sqlite3_finalize(stmt);
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800814
815 return (limit == 1); // more data is available
816}
817
818
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800819void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800820ActionLog::LookupRecentFileActions(const boost::function<void(const string&, int, int)>& visitor,
821 int limit)
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800822{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800823 sqlite3_stmt* stmt;
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800824
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800825 sqlite3_prepare_v2(m_db,
826 "SELECT AL.filename, AL.action"
827 " FROM ActionLog AL"
828 " JOIN "
829 " (SELECT filename, MAX(action_timestamp) AS action_timestamp "
830 " FROM ActionLog "
831 " GROUP BY filename ) AS GAL"
832 " ON AL.filename = GAL.filename AND AL.action_timestamp = GAL.action_timestamp "
833 " ORDER BY AL.action_timestamp DESC "
834 " LIMIT ?;",
835 -1, &stmt, 0);
836 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db));
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800837 sqlite3_bind_int(stmt, 1, limit);
838 int index = 0;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800839 while (sqlite3_step(stmt) == SQLITE_ROW) {
840 std::string filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)),
841 sqlite3_column_bytes(stmt, 0));
842 int action = sqlite3_column_int(stmt, 1);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800843 visitor(filename, action, index);
844 index++;
845 }
846
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800847 _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db));
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800848
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800849 sqlite3_finalize(stmt);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800850}
851
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800852
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800853///////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyevd6364ef2013-02-06 13:13:07 -0800854///////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev053e5ac2013-01-22 20:59:13 -0800855///////////////////////////////////////////////////////////////////////////////////
856
857void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800858ActionLog::apply_action_xFun(sqlite3_context* context, int argc, sqlite3_value** argv)
Alexander Afanasyevee7e6132013-01-03 20:03:14 -0800859{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800860 ActionLog* the = reinterpret_cast<ActionLog*>(sqlite3_user_data(context));
Alexander Afanasyevee7e6132013-01-03 20:03:14 -0800861
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800862 if (argc != 11) {
863 sqlite3_result_error(context, "``apply_action'' expects 10 arguments", -1);
864 return;
865 }
Alexander Afanasyevee7e6132013-01-03 20:03:14 -0800866
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800867 CcnxCharbuf device_name(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0]));
868 sqlite3_int64 seq_no = sqlite3_value_int64(argv[1]);
869 int action = sqlite3_value_int(argv[2]);
870 string filename = reinterpret_cast<const char*>(sqlite3_value_text(argv[3]));
871 sqlite3_int64 version = sqlite3_value_int64(argv[4]);
Alexander Afanasyeva2f77e92013-01-03 22:46:52 -0800872
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800873 _LOG_TRACE("apply_function called with " << argc);
874 _LOG_TRACE("device_name: " << Name(device_name) << ", action: " << action << ", file: " << filename);
Alexander Afanasyeva2f77e92013-01-03 22:46:52 -0800875
876 if (action == 0) // update
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800877 {
878 Hash hash(sqlite3_value_blob(argv[5]), sqlite3_value_bytes(argv[5]));
879 time_t atime = static_cast<time_t>(sqlite3_value_int64(argv[6]));
880 time_t mtime = static_cast<time_t>(sqlite3_value_int64(argv[7]));
881 time_t ctime = static_cast<time_t>(sqlite3_value_int64(argv[8]));
882 int mode = sqlite3_value_int(argv[9]);
883 int seg_num = sqlite3_value_int(argv[10]);
Alexander Afanasyeva2f77e92013-01-03 22:46:52 -0800884
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800885 _LOG_DEBUG("Update " << filename << " " << atime << " " << mtime << " " << ctime << " " << hash);
Alexander Afanasyeva2f77e92013-01-03 22:46:52 -0800886
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800887 the->m_fileState->UpdateFile(filename, version, hash, device_name, seq_no, atime, mtime, ctime,
888 mode, seg_num);
Alexander Afanasyeva2f77e92013-01-03 22:46:52 -0800889
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800890 // no callback here
891 }
Alexander Afanasyeva2f77e92013-01-03 22:46:52 -0800892 else if (action == 1) // delete
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800893 {
894 the->m_fileState->DeleteFile(filename);
Alexander Afanasyev0c545ed2013-01-26 00:12:32 -0800895
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800896 the->m_onFileRemoved(filename);
897 }
Alexander Afanasyev49a30d02013-01-21 21:38:48 -0800898
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800899 sqlite3_result_null(context);
Alexander Afanasyevee7e6132013-01-03 20:03:14 -0800900}