2013-10-03 17:27:29 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <QFile>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QDebug>
|
2014-10-21 17:41:11 +04:00
|
|
|
#include <QElapsedTimer>
|
2014-10-22 12:20:38 +04:00
|
|
|
#include "ownsql.h"
|
2013-10-03 17:27:29 +04:00
|
|
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
|
|
|
#include "syncjournaldb.h"
|
|
|
|
#include "syncjournalfilerecord.h"
|
2014-01-29 14:39:14 +04:00
|
|
|
#include "utility.h"
|
2014-04-25 15:31:44 +04:00
|
|
|
#include "version.h"
|
2014-10-21 17:58:56 +04:00
|
|
|
#include "filesystem.h"
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2014-01-15 15:20:03 +04:00
|
|
|
#include "../../csync/src/std/c_jhash.h"
|
|
|
|
|
2014-11-10 00:34:07 +03:00
|
|
|
namespace OCC {
|
2013-10-03 17:27:29 +04:00
|
|
|
|
|
|
|
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
|
2015-05-13 14:15:53 +03:00
|
|
|
QObject(parent), _transaction(0)
|
2013-10-03 17:27:29 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
_dbFile = path;
|
|
|
|
if( !_dbFile.endsWith('/') ) {
|
|
|
|
_dbFile.append('/');
|
|
|
|
}
|
|
|
|
_dbFile.append(".csync_journal.db");
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2013-10-04 16:44:57 +04:00
|
|
|
bool SyncJournalDb::exists()
|
|
|
|
{
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
2013-10-04 16:44:57 +04:00
|
|
|
return (!_dbFile.isEmpty() && QFile::exists(_dbFile));
|
|
|
|
}
|
|
|
|
|
2014-10-13 16:14:43 +04:00
|
|
|
QString SyncJournalDb::databaseFilePath()
|
|
|
|
{
|
|
|
|
return _dbFile;
|
|
|
|
}
|
|
|
|
|
2014-10-21 17:41:11 +04:00
|
|
|
// Note that this does not change the size of the -wal file, but it is supposed to make
|
|
|
|
// the normal .db faster since the changes from the wal will be incorporated into it.
|
|
|
|
// Then the next sync (and the SocketAPI) will have a faster access.
|
|
|
|
void SyncJournalDb::walCheckpoint()
|
|
|
|
{
|
|
|
|
QElapsedTimer t;
|
|
|
|
t.start();
|
|
|
|
SqlQuery pragma1(_db);
|
|
|
|
pragma1.prepare("PRAGMA wal_checkpoint(FULL);");
|
|
|
|
if (!pragma1.exec()) {
|
|
|
|
qDebug() << pragma1.error();
|
|
|
|
} else {
|
|
|
|
qDebug() << Q_FUNC_INFO << "took" << t.elapsed() << "msec";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
void SyncJournalDb::startTransaction()
|
|
|
|
{
|
|
|
|
if( _transaction == 0 ) {
|
|
|
|
if( !_db.transaction() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << "ERROR starting transaction: " << _db.error();
|
2013-11-21 14:13:58 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
_transaction = 1;
|
2014-10-17 13:35:06 +04:00
|
|
|
// qDebug() << "XXX Transaction start!";
|
2013-11-21 14:13:58 +04:00
|
|
|
} else {
|
2015-10-05 06:20:09 +03:00
|
|
|
qDebug() << "Database Transaction is running, not starting another one!";
|
2013-11-21 14:13:58 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::commitTransaction()
|
|
|
|
{
|
|
|
|
if( _transaction == 1 ) {
|
|
|
|
if( ! _db.commit() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << "ERROR committing to the database: " << _db.error();
|
2013-11-21 14:13:58 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
_transaction = 0;
|
2014-10-17 13:35:06 +04:00
|
|
|
// qDebug() << "XXX Transaction END!";
|
2013-11-21 14:13:58 +04:00
|
|
|
} else {
|
|
|
|
qDebug() << "No database Transaction to commit";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
bool SyncJournalDb::sqlFail( const QString& log, const SqlQuery& query )
|
2013-11-21 14:13:58 +04:00
|
|
|
{
|
|
|
|
commitTransaction();
|
2014-10-14 13:14:57 +04:00
|
|
|
qWarning() << "SQL Error" << log << query.error();
|
2014-09-15 20:03:44 +04:00
|
|
|
Q_ASSERT(!"SQL ERROR");
|
2014-09-15 16:27:39 +04:00
|
|
|
_db.close();
|
2013-11-21 14:13:58 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-11 14:40:48 +03:00
|
|
|
static QString defaultJournalMode(const QString & dbPath)
|
|
|
|
{
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
// See #2693: Some exFAT file systems seem unable to cope with the
|
|
|
|
// WAL journaling mode. They work fine with DELETE.
|
|
|
|
QString fileSystem = FileSystem::fileSystemForPath(dbPath);
|
2016-01-19 11:58:00 +03:00
|
|
|
qDebug() << "Detected filesystem" << fileSystem << "for" << dbPath;
|
2015-02-11 14:40:48 +03:00
|
|
|
if (fileSystem.contains("FAT")) {
|
2016-01-19 11:58:00 +03:00
|
|
|
qDebug() << "Filesystem contains FAT - using DELETE journal mode";
|
2015-02-11 14:40:48 +03:00
|
|
|
return "DELETE";
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
Q_UNUSED(dbPath)
|
|
|
|
#endif
|
|
|
|
return "WAL";
|
|
|
|
}
|
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
bool SyncJournalDb::checkConnect()
|
|
|
|
{
|
|
|
|
if( _db.isOpen() ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-10-20 16:25:22 +04:00
|
|
|
if( _dbFile.isEmpty()) {
|
|
|
|
qDebug() << "Database filename" + _dbFile + " is empty";
|
2013-10-03 17:27:29 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-21 22:25:15 +04:00
|
|
|
bool isNewDb = !QFile::exists(_dbFile);
|
|
|
|
|
2014-10-20 17:51:50 +04:00
|
|
|
// The database file is created by this call (SQLITE_OPEN_CREATE)
|
2014-12-04 15:55:58 +03:00
|
|
|
if( !_db.openOrCreateReadWrite(_dbFile) ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString error = _db.error();
|
|
|
|
qDebug() << "Error opening the db: " << error;
|
|
|
|
return false;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2014-10-20 16:25:22 +04:00
|
|
|
if( !QFile::exists(_dbFile) ) {
|
|
|
|
qDebug() << "Database file" + _dbFile + " does not exist";
|
|
|
|
return false;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery pragma1(_db);
|
2014-10-11 19:33:08 +04:00
|
|
|
pragma1.prepare("SELECT sqlite_version();");
|
|
|
|
if (!pragma1.exec()) {
|
|
|
|
return sqlFail("SELECT sqlite_version()", pragma1);
|
|
|
|
} else {
|
|
|
|
pragma1.next();
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << "sqlite3 version" << pragma1.stringValue(0);
|
2014-10-11 19:33:08 +04:00
|
|
|
}
|
2013-11-19 14:28:08 +04:00
|
|
|
|
2015-02-11 14:40:48 +03:00
|
|
|
// Allow forcing the journal mode for debugging
|
2015-01-29 12:10:09 +03:00
|
|
|
static QString env_journal_mode = QString::fromLocal8Bit(qgetenv("OWNCLOUD_SQLITE_JOURNAL_MODE"));
|
|
|
|
QString journal_mode = env_journal_mode;
|
|
|
|
if (journal_mode.isEmpty()) {
|
2015-02-11 14:40:48 +03:00
|
|
|
journal_mode = defaultJournalMode(_dbFile);
|
2015-01-29 12:10:09 +03:00
|
|
|
}
|
|
|
|
pragma1.prepare(QString("PRAGMA journal_mode=%1;").arg(journal_mode));
|
2014-10-21 00:38:10 +04:00
|
|
|
if (!pragma1.exec()) {
|
2015-01-29 12:10:09 +03:00
|
|
|
return sqlFail("Set PRAGMA journal_mode", pragma1);
|
2014-10-21 00:38:10 +04:00
|
|
|
} else {
|
|
|
|
pragma1.next();
|
|
|
|
qDebug() << "sqlite3 journal_mode=" << pragma1.stringValue(0);
|
2015-01-29 12:10:09 +03:00
|
|
|
}
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2015-01-29 12:10:09 +03:00
|
|
|
// For debugging purposes, allow temp_store to be set
|
|
|
|
static QString env_temp_store = QString::fromLocal8Bit(qgetenv("OWNCLOUD_SQLITE_TEMP_STORE"));
|
|
|
|
if (!env_temp_store.isEmpty()) {
|
|
|
|
pragma1.prepare(QString("PRAGMA temp_store = %1;").arg(env_temp_store));
|
|
|
|
if (!pragma1.exec()) {
|
|
|
|
return sqlFail("Set PRAGMA temp_store", pragma1);
|
|
|
|
}
|
|
|
|
qDebug() << "sqlite3 with temp_store =" << env_temp_store;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
pragma1.prepare("PRAGMA synchronous = 1;");
|
|
|
|
if (!pragma1.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Set PRAGMA synchronous", pragma1);
|
2013-11-18 13:02:15 +04:00
|
|
|
}
|
|
|
|
pragma1.prepare("PRAGMA case_sensitive_like = ON;");
|
|
|
|
if (!pragma1.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Set PRAGMA case_sensitivity", pragma1);
|
2013-11-18 13:02:15 +04:00
|
|
|
}
|
2013-10-04 00:41:12 +04:00
|
|
|
|
2015-10-05 06:20:09 +03:00
|
|
|
/* Because insert is so slow, we do everything in a transaction, and only need one call to commit */
|
2013-11-21 14:13:58 +04:00
|
|
|
startTransaction();
|
2013-11-18 13:02:15 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery createQuery(_db);
|
2013-11-18 13:02:15 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS metadata("
|
|
|
|
"phash INTEGER(8),"
|
|
|
|
"pathlen INTEGER,"
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"inode INTEGER,"
|
|
|
|
"uid INTEGER,"
|
|
|
|
"gid INTEGER,"
|
|
|
|
"mode INTEGER,"
|
|
|
|
"modtime INTEGER(8),"
|
|
|
|
"type INTEGER,"
|
|
|
|
"md5 VARCHAR(32)," /* This is the etag. Called md5 for compatibility */
|
2015-11-23 13:53:06 +03:00
|
|
|
// updateDatabaseStructure() will add
|
|
|
|
// fileid
|
|
|
|
// remotePerm
|
|
|
|
// filesize
|
|
|
|
// ignoredChildrenRemote
|
|
|
|
// contentChecksum
|
|
|
|
// contentChecksumTypeId
|
2013-11-18 13:02:15 +04:00
|
|
|
"PRIMARY KEY(phash)"
|
|
|
|
");");
|
|
|
|
|
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table metadata", createQuery);
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS downloadinfo("
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"tmpfile VARCHAR(4096),"
|
|
|
|
"etag VARCHAR(32),"
|
|
|
|
"errorcount INTEGER,"
|
|
|
|
"PRIMARY KEY(path)"
|
|
|
|
");");
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table downloadinfo", createQuery);
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS uploadinfo("
|
2013-10-16 13:59:54 +04:00
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"chunk INTEGER,"
|
|
|
|
"transferid INTEGER,"
|
|
|
|
"errorcount INTEGER,"
|
|
|
|
"size INTEGER(8),"
|
|
|
|
"modtime INTEGER(8),"
|
|
|
|
"PRIMARY KEY(path)"
|
2013-11-18 13:02:15 +04:00
|
|
|
");");
|
2013-10-04 00:41:12 +04:00
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table uploadinfo", createQuery);
|
2013-11-15 20:42:48 +04:00
|
|
|
}
|
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
// create the blacklist table.
|
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS blacklist ("
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"lastTryEtag VARCHAR[32],"
|
|
|
|
"lastTryModtime INTEGER[8],"
|
2013-11-21 14:13:58 +04:00
|
|
|
"retrycount INTEGER,"
|
2013-11-20 16:44:01 +04:00
|
|
|
"errorstring VARCHAR[4096],"
|
|
|
|
"PRIMARY KEY(path)"
|
|
|
|
");");
|
|
|
|
|
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table blacklist", createQuery);
|
2013-11-20 16:44:01 +04:00
|
|
|
}
|
|
|
|
|
2014-11-08 13:01:37 +03:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS poll("
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"modtime INTEGER(8),"
|
|
|
|
"pollpath VARCHAR(4096));");
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Create table poll", createQuery);
|
|
|
|
}
|
|
|
|
|
2015-05-20 17:28:06 +03:00
|
|
|
// create the selectivesync table.
|
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS selectivesync ("
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"type INTEGER"
|
|
|
|
");");
|
|
|
|
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Create table selectivesync", createQuery);
|
|
|
|
}
|
|
|
|
|
2015-10-28 13:00:03 +03:00
|
|
|
// create the checksumtype table.
|
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS checksumtype("
|
|
|
|
"id INTEGER PRIMARY KEY,"
|
|
|
|
"name TEXT UNIQUE"
|
|
|
|
");");
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Create table version", createQuery);
|
|
|
|
}
|
2015-05-20 17:28:06 +03:00
|
|
|
|
2014-11-08 13:01:37 +03:00
|
|
|
|
2014-04-25 15:31:44 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS version("
|
|
|
|
"major INTEGER(8),"
|
|
|
|
"minor INTEGER(8),"
|
|
|
|
"patch INTEGER(8),"
|
|
|
|
"custom VARCHAR(256)"
|
|
|
|
");");
|
|
|
|
if (!createQuery.exec()) {
|
2014-10-06 20:36:32 +04:00
|
|
|
return sqlFail("Create table version", createQuery);
|
2014-04-25 15:31:44 +04:00
|
|
|
}
|
|
|
|
|
2015-05-13 14:15:53 +03:00
|
|
|
bool forceRemoteDiscovery = false;
|
2015-05-04 13:14:35 +03:00
|
|
|
|
2014-10-22 12:59:58 +04:00
|
|
|
SqlQuery versionQuery("SELECT major, minor, patch FROM version;", _db);
|
2014-04-25 15:31:44 +04:00
|
|
|
if (!versionQuery.next()) {
|
|
|
|
// If there was no entry in the table, it means we are likely upgrading from 1.5
|
2014-10-21 22:25:15 +04:00
|
|
|
if (!isNewDb) {
|
2015-05-13 14:15:53 +03:00
|
|
|
qDebug() << Q_FUNC_INFO << "possibleUpgradeFromMirall_1_5 detected!";
|
|
|
|
forceRemoteDiscovery = true;
|
2014-10-21 22:25:15 +04:00
|
|
|
}
|
2014-10-22 12:59:58 +04:00
|
|
|
createQuery.prepare("INSERT INTO version VALUES (?1, ?2, ?3, ?4);");
|
|
|
|
createQuery.bindValue(1, MIRALL_VERSION_MAJOR);
|
|
|
|
createQuery.bindValue(2, MIRALL_VERSION_MINOR);
|
|
|
|
createQuery.bindValue(3, MIRALL_VERSION_PATCH);
|
2015-05-05 18:06:28 +03:00
|
|
|
createQuery.bindValue(4, MIRALL_VERSION_BUILD);
|
2014-10-22 12:59:58 +04:00
|
|
|
createQuery.exec();
|
|
|
|
|
2014-04-25 15:31:44 +04:00
|
|
|
} else {
|
2014-10-22 12:59:58 +04:00
|
|
|
int major = versionQuery.intValue(0);
|
|
|
|
int minor = versionQuery.intValue(1);
|
|
|
|
int patch = versionQuery.intValue(2);
|
|
|
|
|
2015-05-13 13:54:49 +03:00
|
|
|
if( major == 1 && minor == 8 && (patch == 0 || patch == 1) ) {
|
|
|
|
qDebug() << Q_FUNC_INFO << "possibleUpgradeFromMirall_1_8_0_or_1 detected!";
|
2015-05-13 14:15:53 +03:00
|
|
|
forceRemoteDiscovery = true;
|
2015-05-04 13:14:35 +03:00
|
|
|
}
|
2014-10-22 12:59:58 +04:00
|
|
|
// Not comparing the BUILD id here, correct?
|
|
|
|
if( !(major == MIRALL_VERSION_MAJOR && minor == MIRALL_VERSION_MINOR && patch == MIRALL_VERSION_PATCH) ) {
|
|
|
|
createQuery.prepare("UPDATE version SET major=?1, minor=?2, patch =?3, custom=?4 "
|
|
|
|
"WHERE major=?5 AND minor=?6 AND patch=?7;");
|
|
|
|
createQuery.bindValue(1, MIRALL_VERSION_MAJOR);
|
|
|
|
createQuery.bindValue(2, MIRALL_VERSION_MINOR);
|
|
|
|
createQuery.bindValue(3, MIRALL_VERSION_PATCH);
|
|
|
|
createQuery.bindValue(4, MIRALL_VERSION_BUILD);
|
|
|
|
createQuery.bindValue(5, major);
|
|
|
|
createQuery.bindValue(6, minor);
|
|
|
|
createQuery.bindValue(7, patch);
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Update version", createQuery);
|
|
|
|
}
|
2014-10-20 18:50:55 +04:00
|
|
|
|
2014-10-22 12:59:58 +04:00
|
|
|
}
|
2014-04-25 15:31:44 +04:00
|
|
|
}
|
|
|
|
|
2013-11-25 18:11:37 +04:00
|
|
|
commitInternal("checkConnect");
|
2013-11-21 14:13:58 +04:00
|
|
|
|
2013-10-25 15:30:45 +04:00
|
|
|
bool rc = updateDatabaseStructure();
|
2014-09-18 13:44:47 +04:00
|
|
|
if( !rc ) {
|
|
|
|
qDebug() << "WARN: Failed to update the database structure!";
|
|
|
|
}
|
2013-11-15 14:21:27 +04:00
|
|
|
|
2015-05-13 14:15:53 +03:00
|
|
|
/*
|
2015-10-05 06:20:09 +03:00
|
|
|
* If we are upgrading from a client version older than 1.5,
|
2015-05-13 14:15:53 +03:00
|
|
|
* we cannot read from the database because we need to fetch the files id and etags.
|
|
|
|
*
|
|
|
|
* If 1.8.0 caused missing data in the local tree, so we also don't read from DB
|
|
|
|
* to get back the files that were gone.
|
|
|
|
* In 1.8.1 we had a fix to re-get the data, but this one here is better
|
|
|
|
*/
|
|
|
|
if (forceRemoteDiscovery) {
|
2015-06-19 14:51:55 +03:00
|
|
|
forceRemoteDiscoveryNextSyncLocked();
|
2015-05-13 13:54:49 +03:00
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_getFileRecordQuery.reset(new SqlQuery(_db));
|
2015-10-28 13:00:03 +03:00
|
|
|
_getFileRecordQuery->prepare(
|
|
|
|
"SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize,"
|
2015-11-23 13:53:06 +03:00
|
|
|
" ignoredChildrenRemote, contentChecksum, contentchecksumtype.name"
|
2015-10-28 13:00:03 +03:00
|
|
|
" FROM metadata"
|
2015-11-23 13:53:06 +03:00
|
|
|
" LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id"
|
2015-10-28 13:00:03 +03:00
|
|
|
" WHERE phash=?1" );
|
2013-11-15 14:21:27 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_setFileRecordQuery.reset(new SqlQuery(_db) );
|
2014-08-27 16:00:20 +04:00
|
|
|
_setFileRecordQuery->prepare("INSERT OR REPLACE INTO metadata "
|
2015-11-23 13:53:06 +03:00
|
|
|
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote, contentChecksum, contentChecksumTypeId) "
|
2015-10-28 13:00:03 +03:00
|
|
|
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14, ?15, ?16);" );
|
2013-11-15 14:21:27 +04:00
|
|
|
|
2015-10-28 13:00:03 +03:00
|
|
|
_setFileRecordChecksumQuery.reset(new SqlQuery(_db) );
|
2015-10-28 16:42:44 +03:00
|
|
|
_setFileRecordChecksumQuery->prepare(
|
|
|
|
"UPDATE metadata"
|
2015-11-23 13:53:06 +03:00
|
|
|
" SET contentChecksum = ?2, contentChecksumTypeId = ?3"
|
2015-10-28 16:42:44 +03:00
|
|
|
" WHERE phash == ?1;");
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_getDownloadInfoQuery.reset(new SqlQuery(_db) );
|
2014-08-27 16:00:20 +04:00
|
|
|
_getDownloadInfoQuery->prepare( "SELECT tmpfile, etag, errorcount FROM "
|
2014-10-14 22:51:51 +04:00
|
|
|
"downloadinfo WHERE path=?1" );
|
2013-11-15 14:21:27 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_setDownloadInfoQuery.reset(new SqlQuery(_db) );
|
2014-08-27 16:00:20 +04:00
|
|
|
_setDownloadInfoQuery->prepare( "INSERT OR REPLACE INTO downloadinfo "
|
|
|
|
"(path, tmpfile, etag, errorcount) "
|
2014-10-14 22:51:51 +04:00
|
|
|
"VALUES ( ?1 , ?2, ?3, ?4 )" );
|
2013-11-15 14:21:27 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_deleteDownloadInfoQuery.reset(new SqlQuery(_db) );
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteDownloadInfoQuery->prepare( "DELETE FROM downloadinfo WHERE path=?1" );
|
2013-11-15 14:21:27 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_getUploadInfoQuery.reset(new SqlQuery(_db));
|
2014-08-27 16:00:20 +04:00
|
|
|
_getUploadInfoQuery->prepare( "SELECT chunk, transferid, errorcount, size, modtime FROM "
|
2014-10-14 22:51:51 +04:00
|
|
|
"uploadinfo WHERE path=?1" );
|
2013-11-15 14:21:27 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_setUploadInfoQuery.reset(new SqlQuery(_db));
|
2014-08-27 16:00:20 +04:00
|
|
|
_setUploadInfoQuery->prepare( "INSERT OR REPLACE INTO uploadinfo "
|
|
|
|
"(path, chunk, transferid, errorcount, size, modtime) "
|
2014-10-14 22:51:51 +04:00
|
|
|
"VALUES ( ?1 , ?2, ?3 , ?4 , ?5, ?6 )");
|
2013-11-18 16:02:09 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_deleteUploadInfoQuery.reset(new SqlQuery(_db));
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteUploadInfoQuery->prepare("DELETE FROM uploadinfo WHERE path=?1" );
|
2013-11-18 16:02:09 +04:00
|
|
|
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_deleteFileRecordPhash.reset(new SqlQuery(_db));
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteFileRecordPhash->prepare("DELETE FROM metadata WHERE phash=?1");
|
2014-08-27 16:00:20 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
_deleteFileRecordRecursively.reset(new SqlQuery(_db));
|
2014-08-27 16:00:20 +04:00
|
|
|
_deleteFileRecordRecursively->prepare("DELETE FROM metadata WHERE path LIKE(?||'/%')");
|
|
|
|
|
2014-10-09 16:49:51 +04:00
|
|
|
QString sql( "SELECT lastTryEtag, lastTryModtime, retrycount, errorstring, lastTryTime, ignoreDuration "
|
2014-10-14 22:51:51 +04:00
|
|
|
"FROM blacklist WHERE path=?1");
|
2014-10-06 20:37:53 +04:00
|
|
|
if( Utility::fsCasePreserving() ) {
|
|
|
|
// if the file system is case preserving we have to check the blacklist
|
|
|
|
// case insensitively
|
|
|
|
sql += QLatin1String(" COLLATE NOCASE");
|
|
|
|
}
|
2015-01-16 12:17:19 +03:00
|
|
|
_getErrorBlacklistQuery.reset(new SqlQuery(_db));
|
|
|
|
_getErrorBlacklistQuery->prepare(sql);
|
2014-10-09 16:49:51 +04:00
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
_setErrorBlacklistQuery.reset(new SqlQuery(_db));
|
|
|
|
_setErrorBlacklistQuery->prepare("INSERT OR REPLACE INTO blacklist "
|
2014-10-09 16:49:51 +04:00
|
|
|
"(path, lastTryEtag, lastTryModtime, retrycount, errorstring, lastTryTime, ignoreDuration) "
|
|
|
|
"VALUES ( ?1, ?2, ?3, ?4, ?5, ?6, ?7)");
|
2013-11-18 16:02:09 +04:00
|
|
|
|
2015-05-20 17:28:06 +03:00
|
|
|
_getSelectiveSyncListQuery.reset(new SqlQuery(_db));
|
|
|
|
_getSelectiveSyncListQuery->prepare("SELECT path FROM selectivesync WHERE type=?1");
|
|
|
|
|
2015-10-28 13:00:03 +03:00
|
|
|
_getChecksumTypeIdQuery.reset(new SqlQuery(_db));
|
|
|
|
_getChecksumTypeIdQuery->prepare("SELECT id FROM checksumtype WHERE name=?1");
|
|
|
|
|
2015-11-23 13:53:06 +03:00
|
|
|
_getChecksumTypeQuery.reset(new SqlQuery(_db));
|
|
|
|
_getChecksumTypeQuery->prepare("SELECT name FROM checksumtype WHERE id=?1");
|
|
|
|
|
2015-10-28 13:00:03 +03:00
|
|
|
_insertChecksumTypeQuery.reset(new SqlQuery(_db));
|
|
|
|
_insertChecksumTypeQuery->prepare("INSERT OR IGNORE INTO checksumtype (name) VALUES (?1)");
|
|
|
|
|
2014-10-20 18:50:55 +04:00
|
|
|
// don't start a new transaction now
|
|
|
|
commitInternal(QString("checkConnect End"), false);
|
2013-11-18 16:02:09 +04:00
|
|
|
|
2014-11-20 14:30:04 +03:00
|
|
|
// Hide 'em all!
|
|
|
|
FileSystem::setFileHidden(databaseFilePath(), true);
|
|
|
|
FileSystem::setFileHidden(databaseFilePath() + "-wal", true);
|
|
|
|
FileSystem::setFileHidden(databaseFilePath() + "-shm", true);
|
2015-01-29 12:10:09 +03:00
|
|
|
FileSystem::setFileHidden(databaseFilePath() + "-journal", true);
|
2014-11-20 14:30:04 +03:00
|
|
|
|
2013-10-25 15:30:45 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-11-18 12:58:02 +04:00
|
|
|
void SyncJournalDb::close()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
2014-10-20 18:50:55 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << _dbFile;
|
2013-11-18 12:58:02 +04:00
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
commitTransaction();
|
|
|
|
|
2013-11-18 12:58:02 +04:00
|
|
|
_getFileRecordQuery.reset(0);
|
|
|
|
_setFileRecordQuery.reset(0);
|
2015-10-30 16:03:08 +03:00
|
|
|
_setFileRecordChecksumQuery.reset(0);
|
2013-11-18 12:58:02 +04:00
|
|
|
_getDownloadInfoQuery.reset(0);
|
|
|
|
_setDownloadInfoQuery.reset(0);
|
|
|
|
_deleteDownloadInfoQuery.reset(0);
|
|
|
|
_getUploadInfoQuery.reset(0);
|
|
|
|
_setUploadInfoQuery.reset(0);
|
|
|
|
_deleteUploadInfoQuery.reset(0);
|
2013-11-18 16:02:09 +04:00
|
|
|
_deleteFileRecordPhash.reset(0);
|
|
|
|
_deleteFileRecordRecursively.reset(0);
|
2015-01-16 12:17:19 +03:00
|
|
|
_getErrorBlacklistQuery.reset(0);
|
2015-01-30 17:35:42 +03:00
|
|
|
_setErrorBlacklistQuery.reset(0);
|
2015-08-06 15:28:02 +03:00
|
|
|
_getSelectiveSyncListQuery.reset(0);
|
2015-10-30 16:03:08 +03:00
|
|
|
_getChecksumTypeIdQuery.reset(0);
|
2015-11-23 13:53:06 +03:00
|
|
|
_getChecksumTypeQuery.reset(0);
|
2015-10-30 16:03:08 +03:00
|
|
|
_insertChecksumTypeQuery.reset(0);
|
2013-11-20 21:19:14 +04:00
|
|
|
|
2013-11-18 12:58:02 +04:00
|
|
|
_db.close();
|
2014-08-07 14:10:32 +04:00
|
|
|
_avoidReadFromDbOnNextSyncFilter.clear();
|
2013-11-18 12:58:02 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-25 15:30:45 +04:00
|
|
|
bool SyncJournalDb::updateDatabaseStructure()
|
2014-10-09 16:49:51 +04:00
|
|
|
{
|
|
|
|
if (!updateMetadataTableStructure())
|
|
|
|
return false;
|
2015-01-16 12:17:19 +03:00
|
|
|
if (!updateErrorBlacklistTableStructure())
|
2014-10-09 16:49:51 +04:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SyncJournalDb::updateMetadataTableStructure()
|
2013-10-25 15:30:45 +04:00
|
|
|
{
|
|
|
|
QStringList columns = tableColumns("metadata");
|
2013-11-20 16:44:01 +04:00
|
|
|
bool re = true;
|
2013-10-25 15:30:45 +04:00
|
|
|
|
|
|
|
// check if the file_id column is there and create it if not
|
2013-11-21 14:13:58 +04:00
|
|
|
if( !checkConnect() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-18 13:44:47 +04:00
|
|
|
if( columns.indexOf(QLatin1String("fileid")) == -1 ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2013-11-18 16:02:09 +04:00
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN fileid VARCHAR(128);");
|
2014-09-18 13:44:47 +04:00
|
|
|
if( !query.exec() ) {
|
2014-10-09 16:49:51 +04:00
|
|
|
sqlFail("updateMetadataTableStructure: Add column fileid", query);
|
2014-09-18 13:44:47 +04:00
|
|
|
re = false;
|
2014-08-27 16:00:20 +04:00
|
|
|
}
|
2013-11-18 16:02:09 +04:00
|
|
|
|
|
|
|
query.prepare("CREATE INDEX metadata_file_id ON metadata(fileid);");
|
2014-09-18 13:44:47 +04:00
|
|
|
if( ! query.exec() ) {
|
2014-10-09 16:49:51 +04:00
|
|
|
sqlFail("updateMetadataTableStructure: create index fileid", query);
|
2014-09-18 13:44:47 +04:00
|
|
|
re = false;
|
2014-08-27 16:00:20 +04:00
|
|
|
}
|
2014-08-14 15:22:43 +04:00
|
|
|
commitInternal("update database structure: add fileid col");
|
2013-10-25 15:30:45 +04:00
|
|
|
}
|
2014-06-06 17:24:17 +04:00
|
|
|
if( columns.indexOf(QLatin1String("remotePerm")) == -1 ) {
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2014-06-06 17:24:17 +04:00
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN remotePerm VARCHAR(128);");
|
2014-09-18 13:44:47 +04:00
|
|
|
if( !query.exec()) {
|
2014-10-09 16:49:51 +04:00
|
|
|
sqlFail("updateMetadataTableStructure: add column remotePerm", query);
|
2014-09-18 13:44:47 +04:00
|
|
|
re = false;
|
2014-08-27 16:00:20 +04:00
|
|
|
}
|
2014-10-09 16:49:51 +04:00
|
|
|
commitInternal("update database structure (remotePerm)");
|
2014-06-06 17:24:17 +04:00
|
|
|
}
|
2014-09-05 15:03:33 +04:00
|
|
|
if( columns.indexOf(QLatin1String("filesize")) == -1 )
|
|
|
|
{
|
|
|
|
SqlQuery query(_db);
|
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN filesize BIGINT;");
|
|
|
|
if( !query.exec()) {
|
|
|
|
sqlFail("updateDatabaseStructure: add column filesize", query);
|
|
|
|
re = false;
|
|
|
|
}
|
|
|
|
commitInternal("update database structure: add filesize col");
|
|
|
|
}
|
2013-11-20 16:44:01 +04:00
|
|
|
|
2014-08-14 15:22:43 +04:00
|
|
|
if( 1 ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2014-08-14 15:52:44 +04:00
|
|
|
query.prepare("CREATE INDEX IF NOT EXISTS metadata_inode ON metadata(inode);");
|
2014-09-18 13:44:47 +04:00
|
|
|
if( !query.exec()) {
|
2014-10-09 16:49:51 +04:00
|
|
|
sqlFail("updateMetadataTableStructure: create index inode", query);
|
2014-09-18 13:44:47 +04:00
|
|
|
re = false;
|
2014-08-27 16:00:20 +04:00
|
|
|
}
|
2014-08-14 15:22:43 +04:00
|
|
|
commitInternal("update database structure: add inode index");
|
|
|
|
|
2014-08-14 15:52:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if( 1 ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2015-10-21 16:44:16 +03:00
|
|
|
query.prepare("CREATE INDEX IF NOT EXISTS metadata_path ON metadata(path);");
|
2014-09-18 13:44:47 +04:00
|
|
|
if( !query.exec()) {
|
2015-10-21 16:44:16 +03:00
|
|
|
sqlFail("updateMetadataTableStructure: create index path", query);
|
2014-09-18 13:44:47 +04:00
|
|
|
re = false;
|
2014-08-27 16:00:20 +04:00
|
|
|
}
|
2015-10-21 16:44:16 +03:00
|
|
|
commitInternal("update database structure: add path index");
|
2014-08-14 15:52:44 +04:00
|
|
|
|
2014-08-14 15:22:43 +04:00
|
|
|
}
|
2015-07-09 16:57:56 +03:00
|
|
|
|
|
|
|
if( columns.indexOf(QLatin1String("ignoredChildrenRemote")) == -1 ) {
|
|
|
|
SqlQuery query(_db);
|
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN ignoredChildrenRemote INT;");
|
|
|
|
if( !query.exec()) {
|
|
|
|
sqlFail("updateMetadataTableStructure: add ignoredChildrenRemote column", query);
|
|
|
|
re = false;
|
|
|
|
}
|
|
|
|
commitInternal("update database structure: add ignoredChildrenRemote col");
|
|
|
|
}
|
2015-10-14 16:03:19 +03:00
|
|
|
|
2015-11-23 13:53:06 +03:00
|
|
|
if( columns.indexOf(QLatin1String("contentChecksum")) == -1 ) {
|
2015-10-28 13:00:03 +03:00
|
|
|
SqlQuery query(_db);
|
2015-11-23 13:53:06 +03:00
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN contentChecksum TEXT;");
|
2015-10-28 13:00:03 +03:00
|
|
|
if( !query.exec()) {
|
2015-11-23 13:53:06 +03:00
|
|
|
sqlFail("updateMetadataTableStructure: add contentChecksum column", query);
|
2015-10-28 13:00:03 +03:00
|
|
|
re = false;
|
|
|
|
}
|
2015-11-23 13:53:06 +03:00
|
|
|
commitInternal("update database structure: add contentChecksum col");
|
2015-10-28 13:00:03 +03:00
|
|
|
}
|
2015-11-23 13:53:06 +03:00
|
|
|
if( columns.indexOf(QLatin1String("contentChecksumTypeId")) == -1 ) {
|
2015-10-14 16:03:19 +03:00
|
|
|
SqlQuery query(_db);
|
2015-11-23 13:53:06 +03:00
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN contentChecksumTypeId INTEGER;");
|
2015-10-14 16:03:19 +03:00
|
|
|
if( !query.exec()) {
|
2015-11-23 13:53:06 +03:00
|
|
|
sqlFail("updateMetadataTableStructure: add contentChecksumTypeId column", query);
|
2015-10-14 16:03:19 +03:00
|
|
|
re = false;
|
|
|
|
}
|
2015-11-23 13:53:06 +03:00
|
|
|
commitInternal("update database structure: add contentChecksumTypeId col");
|
2015-10-14 16:03:19 +03:00
|
|
|
}
|
|
|
|
|
2015-10-28 13:00:03 +03:00
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
return re;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
bool SyncJournalDb::updateErrorBlacklistTableStructure()
|
2014-10-09 16:49:51 +04:00
|
|
|
{
|
|
|
|
QStringList columns = tableColumns("blacklist");
|
|
|
|
bool re = true;
|
|
|
|
|
|
|
|
// check if the file_id column is there and create it if not
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( columns.indexOf(QLatin1String("lastTryTime")) == -1 ) {
|
|
|
|
SqlQuery query(_db);
|
|
|
|
query.prepare("ALTER TABLE blacklist ADD COLUMN lastTryTime INTEGER(8);");
|
|
|
|
if( !query.exec() ) {
|
|
|
|
sqlFail("updateBlacklistTableStructure: Add lastTryTime fileid", query);
|
|
|
|
re = false;
|
|
|
|
}
|
|
|
|
query.prepare("ALTER TABLE blacklist ADD COLUMN ignoreDuration INTEGER(8);");
|
|
|
|
if( !query.exec() ) {
|
|
|
|
sqlFail("updateBlacklistTableStructure: Add ignoreDuration fileid", query);
|
|
|
|
re = false;
|
|
|
|
}
|
|
|
|
commitInternal("update database structure: add lastTryTime, ignoreDuration cols");
|
|
|
|
}
|
|
|
|
|
|
|
|
return re;
|
|
|
|
}
|
|
|
|
|
2013-10-25 15:30:45 +04:00
|
|
|
QStringList SyncJournalDb::tableColumns( const QString& table )
|
|
|
|
{
|
|
|
|
QStringList columns;
|
|
|
|
if( !table.isEmpty() ) {
|
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
if( checkConnect() ) {
|
2014-10-14 22:51:51 +04:00
|
|
|
QString q = QString("PRAGMA table_info('%1');").arg(table);
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2013-11-21 14:13:58 +04:00
|
|
|
query.prepare(q);
|
2013-10-25 15:30:45 +04:00
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
if(!query.exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = query.error();
|
2013-11-21 14:13:58 +04:00
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;;
|
|
|
|
return columns;
|
|
|
|
}
|
2013-10-25 15:30:45 +04:00
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
while( query.next() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
columns.append( query.stringValue(1) );
|
2013-11-21 14:13:58 +04:00
|
|
|
}
|
2013-10-25 15:30:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
qDebug() << "Columns in the current journal: " << columns;
|
|
|
|
|
|
|
|
return columns;
|
|
|
|
}
|
|
|
|
|
2014-10-13 16:14:43 +04:00
|
|
|
qint64 SyncJournalDb::getPHash(const QString& file)
|
2013-10-03 17:27:29 +04:00
|
|
|
{
|
|
|
|
QByteArray utf8File = file.toUtf8();
|
2013-10-03 20:52:02 +04:00
|
|
|
int64_t h;
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2013-10-03 19:48:04 +04:00
|
|
|
if( file.isEmpty() ) {
|
2013-10-03 20:52:02 +04:00
|
|
|
return -1;
|
2013-10-03 19:48:04 +04:00
|
|
|
}
|
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
int len = utf8File.length();
|
|
|
|
|
|
|
|
h = c_jhash64((uint8_t *) utf8File.data(), len, 0);
|
2013-10-03 20:52:02 +04:00
|
|
|
return h;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2014-08-07 14:10:32 +04:00
|
|
|
bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& _record )
|
2013-10-03 19:48:04 +04:00
|
|
|
{
|
2014-08-07 14:10:32 +04:00
|
|
|
SyncJournalFileRecord record = _record;
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
2014-08-07 14:10:32 +04:00
|
|
|
|
|
|
|
if (!_avoidReadFromDbOnNextSyncFilter.isEmpty()) {
|
|
|
|
// If we are a directory that should not be read from db next time, don't write the etag
|
|
|
|
QString prefix = record._path + "/";
|
|
|
|
foreach(const QString &it, _avoidReadFromDbOnNextSyncFilter) {
|
|
|
|
if (it.startsWith(prefix)) {
|
|
|
|
qDebug() << "Filtered writing the etag of" << prefix << "because it is a prefix of" << it;
|
|
|
|
record._etag = "_invalid_";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-04 00:41:12 +04:00
|
|
|
qlonglong phash = getPHash(record._path);
|
2013-10-03 19:48:04 +04:00
|
|
|
if( checkConnect() ) {
|
2013-10-04 00:41:12 +04:00
|
|
|
QByteArray arr = record._path.toUtf8();
|
|
|
|
int plen = arr.length();
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
QString etag( record._etag );
|
|
|
|
if( etag.isEmpty() ) etag = "";
|
|
|
|
QString fileId( record._fileId);
|
|
|
|
if( fileId.isEmpty() ) fileId = "";
|
2014-06-06 17:24:17 +04:00
|
|
|
QString remotePerm (record._remotePerm);
|
2014-06-06 19:05:55 +04:00
|
|
|
if (remotePerm.isEmpty()) remotePerm = QString(); // have NULL in DB (vs empty)
|
2015-11-23 13:53:06 +03:00
|
|
|
int contentChecksumTypeId = mapChecksumType(record._contentChecksumType);
|
2014-10-23 17:15:47 +04:00
|
|
|
_setFileRecordQuery->reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
_setFileRecordQuery->bindValue(1, QString::number(phash));
|
|
|
|
_setFileRecordQuery->bindValue(2, plen);
|
|
|
|
_setFileRecordQuery->bindValue(3, record._path );
|
|
|
|
_setFileRecordQuery->bindValue(4, record._inode );
|
|
|
|
_setFileRecordQuery->bindValue(5, 0 ); // uid Not used
|
|
|
|
_setFileRecordQuery->bindValue(6, 0 ); // gid Not used
|
2015-11-11 11:32:13 +03:00
|
|
|
_setFileRecordQuery->bindValue(7, 0 ); // mode Not used
|
2014-10-14 22:51:51 +04:00
|
|
|
_setFileRecordQuery->bindValue(8, QString::number(Utility::qDateTimeToTime_t(record._modtime)));
|
|
|
|
_setFileRecordQuery->bindValue(9, QString::number(record._type) );
|
|
|
|
_setFileRecordQuery->bindValue(10, etag );
|
|
|
|
_setFileRecordQuery->bindValue(11, fileId );
|
|
|
|
_setFileRecordQuery->bindValue(12, remotePerm );
|
2014-09-05 15:03:33 +04:00
|
|
|
_setFileRecordQuery->bindValue(13, record._fileSize );
|
2015-07-13 16:41:11 +03:00
|
|
|
_setFileRecordQuery->bindValue(14, record._serverHasIgnoredFiles ? 1:0);
|
2015-11-23 13:53:06 +03:00
|
|
|
_setFileRecordQuery->bindValue(15, record._contentChecksum );
|
|
|
|
_setFileRecordQuery->bindValue(16, contentChecksumTypeId );
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
if( !_setFileRecordQuery->exec() ) {
|
|
|
|
qWarning() << "Error SQL statement setFileRecord: " << _setFileRecordQuery->lastQuery() << " :"
|
2014-10-14 13:14:57 +04:00
|
|
|
<< _setFileRecordQuery->error();
|
2013-10-04 00:41:12 +04:00
|
|
|
return false;
|
2013-10-03 19:48:04 +04:00
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _setFileRecordQuery->lastQuery() << phash << plen << record._path << record._inode
|
2014-01-29 14:39:14 +04:00
|
|
|
<< QString::number(Utility::qDateTimeToTime_t(record._modtime)) << QString::number(record._type)
|
2015-10-14 16:03:19 +03:00
|
|
|
<< record._etag << record._fileId << record._remotePerm << record._fileSize << (record._serverHasIgnoredFiles ? 1:0)
|
2015-11-23 13:53:06 +03:00
|
|
|
<< record._contentChecksum << record._contentChecksumType << contentChecksumTypeId;
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2014-10-24 12:11:00 +04:00
|
|
|
_setFileRecordQuery->reset();
|
2013-10-04 00:41:12 +04:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
qDebug() << "Failed to connect database.";
|
|
|
|
return false; // checkConnect failed.
|
|
|
|
}
|
|
|
|
}
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2013-10-28 13:47:10 +04:00
|
|
|
bool SyncJournalDb::deleteFileRecord(const QString& filename, bool recursively)
|
2013-10-04 00:41:12 +04:00
|
|
|
{
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2013-10-04 00:41:12 +04:00
|
|
|
if( checkConnect() ) {
|
2013-12-06 19:37:30 +04:00
|
|
|
// if (!recursively) {
|
|
|
|
// always delete the actual file.
|
|
|
|
|
|
|
|
qlonglong phash = getPHash(filename);
|
2014-10-23 17:15:47 +04:00
|
|
|
_deleteFileRecordPhash->reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteFileRecordPhash->bindValue( 1, QString::number(phash) );
|
2013-12-06 19:37:30 +04:00
|
|
|
|
|
|
|
if( !_deleteFileRecordPhash->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: "
|
|
|
|
<< _deleteFileRecordPhash->lastQuery()
|
2014-10-14 13:14:57 +04:00
|
|
|
<< " : " << _deleteFileRecordPhash->error();
|
2013-12-06 19:37:30 +04:00
|
|
|
return false;
|
|
|
|
}
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << _deleteFileRecordPhash->lastQuery() << phash << filename;
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteFileRecordPhash->reset();
|
2013-12-06 19:37:30 +04:00
|
|
|
if( recursively) {
|
2014-10-23 17:15:47 +04:00
|
|
|
_deleteFileRecordRecursively->reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteFileRecordRecursively->bindValue(1, filename);
|
2013-11-18 16:02:09 +04:00
|
|
|
if( !_deleteFileRecordRecursively->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: "
|
|
|
|
<< _deleteFileRecordRecursively->lastQuery()
|
2014-10-14 13:14:57 +04:00
|
|
|
<< " : " << _deleteFileRecordRecursively->error();
|
2013-10-28 13:47:10 +04:00
|
|
|
return false;
|
|
|
|
}
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << _deleteFileRecordRecursively->lastQuery() << filename;
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteFileRecordRecursively->reset();
|
2013-10-03 19:48:04 +04:00
|
|
|
}
|
2013-11-18 16:02:09 +04:00
|
|
|
return true;
|
2013-10-03 19:48:04 +04:00
|
|
|
} else {
|
|
|
|
qDebug() << "Failed to connect database.";
|
|
|
|
return false; // checkConnect failed.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-04 00:41:12 +04:00
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
|
|
|
|
{
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-10-03 21:52:09 +04:00
|
|
|
qlonglong phash = getPHash( filename );
|
2013-10-03 17:27:29 +04:00
|
|
|
SyncJournalFileRecord rec;
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
2014-10-23 17:15:47 +04:00
|
|
|
_getFileRecordQuery->reset();
|
2014-10-14 13:14:57 +04:00
|
|
|
_getFileRecordQuery->bindValue(1, QString::number(phash));
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if (!_getFileRecordQuery->exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = _getFileRecordQuery->error();
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << "Error creating prepared statement: " << _getFileRecordQuery->lastQuery() << ", Error:" << err;;
|
2013-10-03 21:52:09 +04:00
|
|
|
return rec;
|
|
|
|
}
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( _getFileRecordQuery->next() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
rec._path = _getFileRecordQuery->stringValue(0);
|
|
|
|
rec._inode = _getFileRecordQuery->intValue(1);
|
2014-06-04 18:01:05 +04:00
|
|
|
//rec._uid = _getFileRecordQuery->value(2).toInt(&ok); Not Used
|
|
|
|
//rec._gid = _getFileRecordQuery->value(3).toInt(&ok); Not Used
|
2015-11-11 11:32:13 +03:00
|
|
|
//rec._mode = _getFileRecordQuery->intValue(4);
|
2014-10-14 13:14:57 +04:00
|
|
|
rec._modtime = Utility::qDateTimeFromTime_t(_getFileRecordQuery->int64Value(5));
|
|
|
|
rec._type = _getFileRecordQuery->intValue(6);
|
|
|
|
rec._etag = _getFileRecordQuery->baValue(7);
|
|
|
|
rec._fileId = _getFileRecordQuery->baValue(8);
|
|
|
|
rec._remotePerm = _getFileRecordQuery->baValue(9);
|
2014-09-05 15:03:33 +04:00
|
|
|
rec._fileSize = _getFileRecordQuery->int64Value(10);
|
2015-07-13 16:41:11 +03:00
|
|
|
rec._serverHasIgnoredFiles = (_getFileRecordQuery->intValue(11) > 0);
|
2015-11-23 13:53:06 +03:00
|
|
|
rec._contentChecksum = _getFileRecordQuery->baValue(12);
|
2015-10-28 13:00:03 +03:00
|
|
|
if( !_getFileRecordQuery->nullValue(13) ) {
|
2015-11-23 13:53:06 +03:00
|
|
|
rec._contentChecksumType = _getFileRecordQuery->baValue(13);
|
2015-10-28 13:00:03 +03:00
|
|
|
}
|
2013-10-03 20:52:02 +04:00
|
|
|
} else {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = _getFileRecordQuery->error();
|
2014-10-16 13:22:57 +04:00
|
|
|
qDebug() << "No journal entry found for " << filename;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
2014-10-24 12:11:00 +04:00
|
|
|
_getFileRecordQuery->reset();
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
return rec;
|
|
|
|
}
|
|
|
|
|
2015-04-08 11:50:08 +03:00
|
|
|
bool SyncJournalDb::postSyncCleanup(const QSet<QString>& filepathsToKeep,
|
|
|
|
const QSet<QString>& prefixesToKeep)
|
2013-11-11 14:11:45 +04:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-11-11 14:11:45 +04:00
|
|
|
return false;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-11-11 14:11:45 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2013-11-18 16:02:09 +04:00
|
|
|
query.prepare("SELECT phash, path FROM metadata order by path");
|
2013-11-11 14:11:45 +04:00
|
|
|
|
|
|
|
if (!query.exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = query.error();
|
2013-11-11 14:11:45 +04:00
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList superfluousItems;
|
|
|
|
|
|
|
|
while(query.next()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
const QString file = query.stringValue(1);
|
2015-04-08 11:50:08 +03:00
|
|
|
bool keep = filepathsToKeep.contains(file);
|
|
|
|
if( !keep ) {
|
|
|
|
foreach( const QString & prefix, prefixesToKeep ) {
|
|
|
|
if( file.startsWith(prefix) ) {
|
|
|
|
keep = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( !keep ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
superfluousItems.append(query.stringValue(0));
|
2013-11-11 14:11:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( superfluousItems.count() ) {
|
|
|
|
QString sql = "DELETE FROM metadata WHERE phash in ("+ superfluousItems.join(",")+")";
|
|
|
|
qDebug() << "Sync Journal cleanup: " << sql;
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery delQuery(_db);
|
2013-11-18 16:02:09 +04:00
|
|
|
delQuery.prepare(sql);
|
2013-11-11 14:11:45 +04:00
|
|
|
if( !delQuery.exec() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = delQuery.error();
|
2013-11-11 14:11:45 +04:00
|
|
|
qDebug() << "Error removing superfluous journal entries: " << delQuery.lastQuery() << ", Error:" << err;;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-10-21 17:41:11 +04:00
|
|
|
|
2015-10-05 06:20:09 +03:00
|
|
|
// Incorporate results back into main DB
|
2014-10-21 17:41:11 +04:00
|
|
|
walCheckpoint();
|
|
|
|
|
2013-11-11 14:11:45 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-04 16:44:57 +04:00
|
|
|
int SyncJournalDb::getFileRecordCount()
|
|
|
|
{
|
2013-11-18 13:02:15 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-11-18 13:02:15 +04:00
|
|
|
return -1;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-10-04 16:44:57 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2013-11-18 16:02:09 +04:00
|
|
|
query.prepare("SELECT COUNT(*) FROM metadata");
|
2013-10-04 16:44:57 +04:00
|
|
|
|
|
|
|
if (!query.exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = query.error();
|
2013-10-04 16:44:57 +04:00
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query.next()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
int count = query.intValue(0);
|
2013-10-04 16:44:57 +04:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 16:42:44 +03:00
|
|
|
bool SyncJournalDb::updateFileRecordChecksum(const QString& filename,
|
2015-11-23 13:53:06 +03:00
|
|
|
const QByteArray& contentChecksum,
|
|
|
|
const QByteArray& contentChecksumType)
|
2015-10-14 16:45:44 +03:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
qlonglong phash = getPHash(filename);
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
qDebug() << "Failed to connect database.";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-23 13:53:06 +03:00
|
|
|
int checksumTypeId = mapChecksumType(contentChecksumType);
|
2015-10-28 13:00:03 +03:00
|
|
|
auto & query = _setFileRecordChecksumQuery;
|
2015-10-14 16:45:44 +03:00
|
|
|
|
|
|
|
query->reset();
|
|
|
|
query->bindValue(1, QString::number(phash));
|
2015-11-23 13:53:06 +03:00
|
|
|
query->bindValue(2, contentChecksum);
|
2015-10-28 13:00:03 +03:00
|
|
|
query->bindValue(3, checksumTypeId);
|
2015-10-14 16:45:44 +03:00
|
|
|
|
|
|
|
if( !query->exec() ) {
|
2015-10-28 16:42:44 +03:00
|
|
|
qWarning() << "Error SQL statement setFileRecordChecksumQuery: "
|
2015-10-14 16:45:44 +03:00
|
|
|
<< query->lastQuery() << " :"
|
|
|
|
<< query->error();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-23 13:53:06 +03:00
|
|
|
qDebug() << query->lastQuery() << phash << contentChecksum
|
|
|
|
<< contentChecksumType << checksumTypeId;
|
2015-10-14 16:45:44 +03:00
|
|
|
|
|
|
|
query->reset();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-11-10 17:05:00 +03:00
|
|
|
bool SyncJournalDb::setFileRecordMetadata(const SyncJournalFileRecord& record)
|
2015-10-28 16:42:44 +03:00
|
|
|
{
|
2015-11-10 17:05:00 +03:00
|
|
|
SyncJournalFileRecord existing = getFileRecord(record._path);
|
|
|
|
|
|
|
|
// If there's no existing record, just insert the new one.
|
|
|
|
if (existing._path.isEmpty()) {
|
|
|
|
return setFileRecord(record);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the metadata on the existing record.
|
|
|
|
existing._inode = record._inode;
|
|
|
|
existing._modtime = record._modtime;
|
|
|
|
existing._type = record._type;
|
|
|
|
existing._etag = record._etag;
|
|
|
|
existing._fileId = record._fileId;
|
|
|
|
existing._remotePerm = record._remotePerm;
|
|
|
|
existing._fileSize = record._fileSize;
|
|
|
|
existing._serverHasIgnoredFiles = record._serverHasIgnoredFiles;
|
|
|
|
return setFileRecord(existing);
|
2015-10-28 16:42:44 +03:00
|
|
|
}
|
|
|
|
|
2014-10-16 17:10:25 +04:00
|
|
|
static void toDownloadInfo(SqlQuery &query, SyncJournalDb::DownloadInfo * res)
|
2014-09-03 14:11:03 +04:00
|
|
|
{
|
|
|
|
bool ok = true;
|
2014-10-14 13:14:57 +04:00
|
|
|
res->_tmpfile = query.stringValue(0);
|
|
|
|
res->_etag = query.baValue(1);
|
|
|
|
res->_errorCount = query.intValue(2);
|
2014-09-03 14:11:03 +04:00
|
|
|
res->_valid = ok;
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
static bool deleteBatch(SqlQuery & query, const QStringList & entries, const QString & name)
|
2014-09-03 14:11:03 +04:00
|
|
|
{
|
|
|
|
if (entries.isEmpty())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
qDebug() << "Removing stale " << qPrintable(name) << " entries: " << entries.join(", ");
|
2014-10-14 13:14:57 +04:00
|
|
|
// FIXME: Was ported from execBatch, check if correct!
|
|
|
|
foreach( const QString& entry, entries ) {
|
2014-10-21 18:37:51 +04:00
|
|
|
query.reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
query.bindValue(1, entry);
|
2014-10-14 13:14:57 +04:00
|
|
|
if (!query.exec()) {
|
|
|
|
QString err = query.error();
|
|
|
|
qDebug() << "Error removing stale " << qPrintable(name) << " entries: "
|
|
|
|
<< query.lastQuery() << ", Error:" << err;
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-03 14:11:03 +04:00
|
|
|
}
|
2014-10-21 18:37:51 +04:00
|
|
|
query.reset(); // viel hilft viel ;-)
|
|
|
|
|
2014-09-03 14:11:03 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-16 13:59:54 +04:00
|
|
|
SyncJournalDb::DownloadInfo SyncJournalDb::getDownloadInfo(const QString& file)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
DownloadInfo res;
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
2014-10-23 17:15:47 +04:00
|
|
|
_getDownloadInfoQuery->reset();
|
2014-10-14 13:14:57 +04:00
|
|
|
_getDownloadInfoQuery->bindValue(1, file);
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if (!_getDownloadInfoQuery->exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = _getDownloadInfoQuery->error();
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << "Database error for file " << file << " : " << _getDownloadInfoQuery->lastQuery() << ", Error:" << err;;
|
2013-10-16 13:59:54 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( _getDownloadInfoQuery->next() ) {
|
2014-09-03 14:11:03 +04:00
|
|
|
toDownloadInfo(*_getDownloadInfoQuery, &res);
|
2014-10-16 17:10:25 +04:00
|
|
|
} else {
|
|
|
|
res._valid = false;
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
2014-10-14 22:51:51 +04:00
|
|
|
_getDownloadInfoQuery->reset();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::setDownloadInfo(const QString& file, const SyncJournalDb::DownloadInfo& i)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-10-16 13:59:54 +04:00
|
|
|
|
|
|
|
if (i._valid) {
|
2014-10-23 17:15:47 +04:00
|
|
|
_setDownloadInfoQuery->reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
_setDownloadInfoQuery->bindValue(1, file);
|
|
|
|
_setDownloadInfoQuery->bindValue(2, i._tmpfile);
|
|
|
|
_setDownloadInfoQuery->bindValue(3, i._etag );
|
|
|
|
_setDownloadInfoQuery->bindValue(4, i._errorCount );
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( !_setDownloadInfoQuery->exec() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qWarning() << "Exec error of SQL statement: " << _setDownloadInfoQuery->lastQuery() << " :" << _setDownloadInfoQuery->error();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _setDownloadInfoQuery->lastQuery() << file << i._tmpfile << i._etag << i._errorCount;
|
2014-10-14 22:51:51 +04:00
|
|
|
_setDownloadInfoQuery->reset();
|
2013-11-13 14:16:00 +04:00
|
|
|
|
2013-10-16 13:59:54 +04:00
|
|
|
} else {
|
2014-10-23 17:15:47 +04:00
|
|
|
_deleteDownloadInfoQuery->reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteDownloadInfoQuery->bindValue( 1, file );
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( !_deleteDownloadInfoQuery->exec() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qWarning() << "Exec error of SQL statement: " << _deleteDownloadInfoQuery->lastQuery() << " : " << _deleteDownloadInfoQuery->error();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << _deleteDownloadInfoQuery->lastQuery() << file;
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteDownloadInfoQuery->reset();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-03 14:11:03 +04:00
|
|
|
QVector<SyncJournalDb::DownloadInfo> SyncJournalDb::getAndDeleteStaleDownloadInfos(const QSet<QString>& keep)
|
|
|
|
{
|
2014-09-05 14:48:45 +04:00
|
|
|
QVector<SyncJournalDb::DownloadInfo> empty_result;
|
2014-09-03 14:11:03 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if (!checkConnect()) {
|
2014-09-05 14:48:45 +04:00
|
|
|
return empty_result;
|
2014-09-03 14:11:03 +04:00
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2014-09-03 14:11:03 +04:00
|
|
|
// The selected values *must* match the ones expected by toDownloadInfo().
|
|
|
|
query.prepare("SELECT tmpfile, etag, errorcount, path FROM downloadinfo");
|
|
|
|
|
|
|
|
if (!query.exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = query.error();
|
2014-09-03 14:11:03 +04:00
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;
|
2014-09-05 14:48:45 +04:00
|
|
|
return empty_result;
|
2014-09-03 14:11:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList superfluousPaths;
|
|
|
|
QVector<SyncJournalDb::DownloadInfo> deleted_entries;
|
|
|
|
|
|
|
|
while (query.next()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
const QString file = query.stringValue(3); // path
|
2014-09-03 14:11:03 +04:00
|
|
|
if (!keep.contains(file)) {
|
|
|
|
superfluousPaths.append(file);
|
|
|
|
DownloadInfo info;
|
|
|
|
toDownloadInfo(query, &info);
|
|
|
|
deleted_entries.append(info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!deleteBatch(*_deleteDownloadInfoQuery, superfluousPaths, "downloadinfo"))
|
2014-09-05 14:48:45 +04:00
|
|
|
return empty_result;
|
2014-09-03 14:11:03 +04:00
|
|
|
|
|
|
|
return deleted_entries;
|
|
|
|
}
|
|
|
|
|
2014-11-05 16:52:57 +03:00
|
|
|
int SyncJournalDb::downloadInfoCount()
|
|
|
|
{
|
|
|
|
int re = 0;
|
|
|
|
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( checkConnect() ) {
|
|
|
|
SqlQuery query("SELECT count(*) FROM downloadinfo", _db);
|
|
|
|
|
|
|
|
if( ! query.exec() ) {
|
|
|
|
sqlFail("Count number of downloadinfo entries failed", query);
|
|
|
|
}
|
|
|
|
if( query.next() ) {
|
|
|
|
re = query.intValue(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return re;
|
|
|
|
}
|
|
|
|
|
2013-10-16 13:59:54 +04:00
|
|
|
SyncJournalDb::UploadInfo SyncJournalDb::getUploadInfo(const QString& file)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
UploadInfo res;
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
|
|
|
|
2014-10-23 17:15:47 +04:00
|
|
|
_getUploadInfoQuery->reset();
|
2014-10-14 13:14:57 +04:00
|
|
|
_getUploadInfoQuery->bindValue(1, file);
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
if (!_getUploadInfoQuery->exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = _getUploadInfoQuery->error();
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << "Database error for file " << file << " : " << _getUploadInfoQuery->lastQuery() << ", Error:" << err;
|
2013-10-16 13:59:54 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( _getUploadInfoQuery->next() ) {
|
2013-10-16 13:59:54 +04:00
|
|
|
bool ok = true;
|
2014-10-14 13:14:57 +04:00
|
|
|
res._chunk = _getUploadInfoQuery->intValue(0);
|
|
|
|
res._transferid = _getUploadInfoQuery->intValue(1);
|
|
|
|
res._errorCount = _getUploadInfoQuery->intValue(2);
|
|
|
|
res._size = _getUploadInfoQuery->int64Value(3);
|
|
|
|
res._modtime = Utility::qDateTimeFromTime_t(_getUploadInfoQuery->int64Value(4));
|
2013-10-16 13:59:54 +04:00
|
|
|
res._valid = ok;
|
|
|
|
}
|
2014-10-14 22:51:51 +04:00
|
|
|
_getUploadInfoQuery->reset();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::setUploadInfo(const QString& file, const SyncJournalDb::UploadInfo& i)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-10-16 13:59:54 +04:00
|
|
|
|
|
|
|
if (i._valid) {
|
2014-10-23 17:15:47 +04:00
|
|
|
_setUploadInfoQuery->reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
_setUploadInfoQuery->bindValue(1, file);
|
|
|
|
_setUploadInfoQuery->bindValue(2, i._chunk);
|
|
|
|
_setUploadInfoQuery->bindValue(3, i._transferid );
|
|
|
|
_setUploadInfoQuery->bindValue(4, i._errorCount );
|
|
|
|
_setUploadInfoQuery->bindValue(5, i._size );
|
|
|
|
_setUploadInfoQuery->bindValue(6, Utility::qDateTimeToTime_t(i._modtime) );
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
if( !_setUploadInfoQuery->exec() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qWarning() << "Exec error of SQL statement: " << _setUploadInfoQuery->lastQuery() << " :" << _setUploadInfoQuery->error();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _setUploadInfoQuery->lastQuery() << file << i._chunk << i._transferid << i._errorCount;
|
2014-10-14 22:51:51 +04:00
|
|
|
_setUploadInfoQuery->reset();
|
2013-10-16 13:59:54 +04:00
|
|
|
} else {
|
2014-10-23 17:15:47 +04:00
|
|
|
_deleteUploadInfoQuery->reset();
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteUploadInfoQuery->bindValue(1, file);
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( !_deleteUploadInfoQuery->exec() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qWarning() << "Exec error of SQL statement: " << _deleteUploadInfoQuery->lastQuery() << " : " << _deleteUploadInfoQuery->error();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << _deleteUploadInfoQuery->lastQuery() << file;
|
2014-10-14 22:51:51 +04:00
|
|
|
_deleteUploadInfoQuery->reset();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-03 14:11:03 +04:00
|
|
|
bool SyncJournalDb::deleteStaleUploadInfos(const QSet<QString> &keep)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if (!checkConnect()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2014-09-03 14:11:03 +04:00
|
|
|
query.prepare("SELECT path FROM uploadinfo");
|
|
|
|
|
|
|
|
if (!query.exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = query.error();
|
2014-09-03 14:11:03 +04:00
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList superfluousPaths;
|
|
|
|
|
|
|
|
while (query.next()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
const QString file = query.stringValue(0);
|
2014-09-03 14:11:03 +04:00
|
|
|
if (!keep.contains(file)) {
|
|
|
|
superfluousPaths.append(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return deleteBatch(*_deleteUploadInfoQuery, superfluousPaths, "uploadinfo");
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
SyncJournalErrorBlacklistRecord SyncJournalDb::errorBlacklistEntry( const QString& file )
|
2013-11-20 16:44:01 +04:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
2015-01-16 12:17:19 +03:00
|
|
|
SyncJournalErrorBlacklistRecord entry;
|
2013-11-20 16:44:01 +04:00
|
|
|
|
|
|
|
if( file.isEmpty() ) return entry;
|
|
|
|
|
|
|
|
// SELECT lastTryEtag, lastTryModtime, retrycount, errorstring
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
2015-01-16 12:17:19 +03:00
|
|
|
_getErrorBlacklistQuery->reset();
|
|
|
|
_getErrorBlacklistQuery->bindValue( 1, file );
|
|
|
|
if( _getErrorBlacklistQuery->exec() ){
|
|
|
|
if( _getErrorBlacklistQuery->next() ) {
|
|
|
|
entry._lastTryEtag = _getErrorBlacklistQuery->baValue(0);
|
|
|
|
entry._lastTryModtime = _getErrorBlacklistQuery->int64Value(1);
|
|
|
|
entry._retryCount = _getErrorBlacklistQuery->intValue(2);
|
|
|
|
entry._errorString = _getErrorBlacklistQuery->stringValue(3);
|
|
|
|
entry._lastTryTime = _getErrorBlacklistQuery->int64Value(4);
|
|
|
|
entry._ignoreDuration = _getErrorBlacklistQuery->int64Value(5);
|
2013-11-20 16:44:01 +04:00
|
|
|
entry._file = file;
|
|
|
|
}
|
2015-01-16 12:17:19 +03:00
|
|
|
_getErrorBlacklistQuery->reset();
|
2013-11-20 16:44:01 +04:00
|
|
|
} else {
|
2015-01-16 12:17:19 +03:00
|
|
|
qWarning() << "Exec error blacklist: " << _getErrorBlacklistQuery->lastQuery() << " : "
|
|
|
|
<< _getErrorBlacklistQuery->error();
|
2013-11-20 16:44:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
bool SyncJournalDb::deleteStaleErrorBlacklistEntries(const QSet<QString> &keep)
|
2014-09-03 14:11:03 +04:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if (!checkConnect()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2014-09-03 14:11:03 +04:00
|
|
|
query.prepare("SELECT path FROM blacklist");
|
|
|
|
|
|
|
|
if (!query.exec()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
QString err = query.error();
|
2014-09-03 14:11:03 +04:00
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList superfluousPaths;
|
|
|
|
|
|
|
|
while (query.next()) {
|
2014-10-14 13:14:57 +04:00
|
|
|
const QString file = query.stringValue(0);
|
2014-09-03 14:11:03 +04:00
|
|
|
if (!keep.contains(file)) {
|
|
|
|
superfluousPaths.append(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery delQuery(_db);
|
2014-09-03 14:11:03 +04:00
|
|
|
delQuery.prepare("DELETE FROM blacklist WHERE path = ?");
|
|
|
|
return deleteBatch(delQuery, superfluousPaths, "blacklist");
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
int SyncJournalDb::errorBlackListEntryCount()
|
2013-12-03 17:47:32 +04:00
|
|
|
{
|
|
|
|
int re = 0;
|
|
|
|
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( checkConnect() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query("SELECT count(*) FROM blacklist", _db);
|
|
|
|
|
|
|
|
if( ! query.exec() ) {
|
2013-12-03 17:47:32 +04:00
|
|
|
sqlFail("Count number of blacklist entries failed", query);
|
|
|
|
}
|
|
|
|
if( query.next() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
re = query.intValue(0);
|
2013-12-03 17:47:32 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return re;
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
int SyncJournalDb::wipeErrorBlacklist()
|
2013-12-03 17:03:45 +04:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( checkConnect() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2013-12-03 17:03:45 +04:00
|
|
|
|
2013-12-12 14:38:41 +04:00
|
|
|
query.prepare("DELETE FROM blacklist");
|
2013-12-03 17:03:45 +04:00
|
|
|
|
|
|
|
if( ! query.exec() ) {
|
|
|
|
sqlFail("Deletion of whole blacklist failed", query);
|
2013-12-03 17:47:32 +04:00
|
|
|
return -1;
|
2013-12-03 17:03:45 +04:00
|
|
|
}
|
|
|
|
return query.numRowsAffected();
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
void SyncJournalDb::wipeErrorBlacklistEntry( const QString& file )
|
2013-11-20 16:44:01 +04:00
|
|
|
{
|
2014-10-03 13:35:18 +04:00
|
|
|
if( file.isEmpty() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
2013-11-20 21:19:14 +04:00
|
|
|
if( checkConnect() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2013-11-20 16:44:01 +04:00
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
query.prepare("DELETE FROM blacklist WHERE path=?1");
|
|
|
|
query.bindValue(1, file);
|
2013-11-20 21:19:14 +04:00
|
|
|
if( ! query.exec() ) {
|
2013-12-03 17:03:45 +04:00
|
|
|
sqlFail("Deletion of blacklist item failed.", query);
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2015-10-16 11:05:27 +03:00
|
|
|
qDebug() << query.lastQuery() << file;
|
2013-11-20 16:44:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
void SyncJournalDb::updateErrorBlacklistEntry( const SyncJournalErrorBlacklistRecord& item )
|
2013-11-20 16:44:01 +04:00
|
|
|
{
|
2015-05-20 16:30:19 +03:00
|
|
|
QMutexLocker locker(&_mutex);
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:17:19 +03:00
|
|
|
_setErrorBlacklistQuery->bindValue(1, item._file);
|
|
|
|
_setErrorBlacklistQuery->bindValue(2, item._lastTryEtag);
|
|
|
|
_setErrorBlacklistQuery->bindValue(3, QString::number(item._lastTryModtime));
|
|
|
|
_setErrorBlacklistQuery->bindValue(4, item._retryCount);
|
|
|
|
_setErrorBlacklistQuery->bindValue(5, item._errorString);
|
|
|
|
_setErrorBlacklistQuery->bindValue(6, QString::number(item._lastTryTime));
|
|
|
|
_setErrorBlacklistQuery->bindValue(7, QString::number(item._ignoreDuration));
|
|
|
|
if( !_setErrorBlacklistQuery->exec() ) {
|
|
|
|
QString bug = _setErrorBlacklistQuery->error();
|
2014-10-09 16:49:51 +04:00
|
|
|
qDebug() << "SQL exec blacklistitem insert or replace failed: "<< bug;
|
|
|
|
}
|
|
|
|
qDebug() << "set blacklist entry for " << item._file << item._retryCount
|
|
|
|
<< item._errorString << item._lastTryTime << item._ignoreDuration
|
|
|
|
<< item._lastTryModtime << item._lastTryEtag;
|
2015-01-16 12:17:19 +03:00
|
|
|
_setErrorBlacklistQuery->reset();
|
2013-11-25 18:11:37 +04:00
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
}
|
|
|
|
|
2014-11-08 13:01:37 +03:00
|
|
|
QVector< SyncJournalDb::PollInfo > SyncJournalDb::getPollInfos()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
QVector< SyncJournalDb::PollInfo > res;
|
|
|
|
|
|
|
|
if( !checkConnect() )
|
|
|
|
return res;
|
|
|
|
|
|
|
|
SqlQuery query("SELECT path, modtime, pollpath FROM poll",_db);
|
|
|
|
|
|
|
|
if (!query.exec()) {
|
|
|
|
QString err = query.error();
|
|
|
|
qDebug() << "Database error :" << query.lastQuery() << ", Error:" << err;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( query.next() ) {
|
|
|
|
PollInfo info;
|
|
|
|
info._file = query.stringValue(0);
|
|
|
|
info._modtime = query.int64Value(1);
|
|
|
|
info._url = query.stringValue(2);
|
|
|
|
res.append(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
query.finish();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::setPollInfo(const SyncJournalDb::PollInfo& info)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info._url.isEmpty()) {
|
2014-11-24 13:33:42 +03:00
|
|
|
qDebug() << "Deleting Poll job" << info._file;
|
2014-11-08 13:01:37 +03:00
|
|
|
SqlQuery query("DELETE FROM poll WHERE path=?", _db);
|
2014-11-24 13:33:42 +03:00
|
|
|
query.bindValue(1, info._file);
|
2014-11-08 13:01:37 +03:00
|
|
|
if( !query.exec() ) {
|
|
|
|
qDebug() << "SQL error in setPollInfo: "<< query.error();
|
|
|
|
} else {
|
|
|
|
qDebug() << query.lastQuery() << info._file;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SqlQuery query("INSERT OR REPLACE INTO poll (path, modtime, pollpath) VALUES( ? , ? , ? )", _db);
|
2014-11-24 13:33:42 +03:00
|
|
|
query.bindValue(1, info._file);
|
|
|
|
query.bindValue(2, QString::number(info._modtime));
|
|
|
|
query.bindValue(3, info._url);
|
2014-11-08 13:01:37 +03:00
|
|
|
if( !query.exec() ) {
|
|
|
|
qDebug() << "SQL error in setPollInfo: "<< query.error();
|
|
|
|
} else {
|
|
|
|
qDebug() << query.lastQuery() << info._file << info._url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-21 13:22:50 +03:00
|
|
|
QStringList SyncJournalDb::getSelectiveSyncList(SyncJournalDb::SelectiveSyncListType type)
|
2015-05-20 17:28:06 +03:00
|
|
|
{
|
|
|
|
QStringList result;
|
|
|
|
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
_getSelectiveSyncListQuery->reset();
|
|
|
|
_getSelectiveSyncListQuery->bindValue(1, int(type));
|
|
|
|
if (!_getSelectiveSyncListQuery->exec()) {
|
|
|
|
qWarning() << "SQL query failed: "<< _getSelectiveSyncListQuery->error();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
while( _getSelectiveSyncListQuery->next() ) {
|
|
|
|
auto entry = _getSelectiveSyncListQuery->stringValue(0);
|
|
|
|
if (!entry.endsWith(QLatin1Char('/'))) {
|
|
|
|
entry.append(QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
result.append(entry);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::setSelectiveSyncList(SyncJournalDb::SelectiveSyncListType type, const QStringList& list)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//first, delete all entries of this type
|
|
|
|
SqlQuery delQuery("DELETE FROM selectivesync WHERE type == ?1", _db);
|
|
|
|
delQuery.bindValue(1, int(type));
|
|
|
|
if( !delQuery.exec() ) {
|
|
|
|
qWarning() << "SQL error when deleting selective sync list" << list << delQuery.error();
|
|
|
|
}
|
|
|
|
|
|
|
|
SqlQuery insQuery("INSERT INTO selectivesync VALUES (?1, ?2)" , _db);
|
|
|
|
foreach(const auto &path, list) {
|
2015-06-10 17:22:14 +03:00
|
|
|
insQuery.reset();
|
2015-05-20 17:28:06 +03:00
|
|
|
insQuery.bindValue(1, path);
|
|
|
|
insQuery.bindValue(2, int(type));
|
|
|
|
if (!insQuery.exec()) {
|
|
|
|
qWarning() << "SQL error when inserting into selective sync" << type << path << delQuery.error();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-12 16:44:55 +04:00
|
|
|
void SyncJournalDb::avoidRenamesOnNextSync(const QString& path)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2014-10-16 13:22:57 +04:00
|
|
|
query.prepare("UPDATE metadata SET fileid = '', inode = '0' WHERE path == ?1 OR path LIKE(?2||'/%')");
|
2014-02-19 18:23:36 +04:00
|
|
|
query.bindValue(1, path);
|
2014-10-16 13:22:57 +04:00
|
|
|
query.bindValue(2, path);
|
2014-02-12 16:44:55 +04:00
|
|
|
if( !query.exec() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << "SQL error in avoidRenamesOnNextSync: "<< query.error();
|
2014-02-12 16:44:55 +04:00
|
|
|
} else {
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << query.lastQuery() << path << "(" << query.numRowsAffected() << " rows)";
|
2014-02-12 16:44:55 +04:00
|
|
|
}
|
2014-08-07 12:14:14 +04:00
|
|
|
|
|
|
|
// We also need to remove the ETags so the update phase refreshes the directory paths
|
|
|
|
// on the next sync
|
|
|
|
locker.unlock();
|
|
|
|
avoidReadFromDbOnNextSync(path);
|
2014-02-12 16:44:55 +04:00
|
|
|
}
|
|
|
|
|
2014-06-03 19:22:40 +04:00
|
|
|
void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName)
|
|
|
|
{
|
2015-10-05 06:20:09 +03:00
|
|
|
// Make sure that on the next sync, fileName is not read from the DB but uses the PROPFIND to
|
|
|
|
// get the info from the server
|
2014-06-03 19:22:40 +04:00
|
|
|
// We achieve that by clearing the etag of the parents directory recursively
|
|
|
|
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-14 13:14:57 +04:00
|
|
|
SqlQuery query(_db);
|
2015-10-05 06:20:09 +03:00
|
|
|
// This query will match entries for which the path is a prefix of fileName
|
2014-10-16 13:22:57 +04:00
|
|
|
query.prepare("UPDATE metadata SET md5='_invalid_' WHERE ?1 LIKE(path||'/%') AND type == 2;"); // CSYNC_FTW_TYPE_DIR == 2
|
2014-10-14 22:51:51 +04:00
|
|
|
query.bindValue(1, fileName);
|
2014-06-03 19:22:40 +04:00
|
|
|
if( !query.exec() ) {
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << "SQL error in avoidRenamesOnNextSync: "<< query.error();
|
2014-06-03 19:22:40 +04:00
|
|
|
} else {
|
2014-10-14 13:14:57 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << query.lastQuery() << fileName << "(" << query.numRowsAffected() << " rows)";
|
2014-06-03 19:22:40 +04:00
|
|
|
}
|
2014-08-07 14:10:32 +04:00
|
|
|
|
|
|
|
// Prevent future overwrite of the etag for this sync
|
|
|
|
_avoidReadFromDbOnNextSyncFilter.append(fileName);
|
2014-06-03 19:22:40 +04:00
|
|
|
}
|
2014-02-12 16:44:55 +04:00
|
|
|
|
2015-06-19 14:51:55 +03:00
|
|
|
void SyncJournalDb::forceRemoteDiscoveryNextSync()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
forceRemoteDiscoveryNextSyncLocked();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::forceRemoteDiscoveryNextSyncLocked()
|
|
|
|
{
|
|
|
|
qDebug() << "Forcing remote re-discovery by deleting folder Etags";
|
|
|
|
SqlQuery deleteRemoteFolderEtagsQuery(_db);
|
|
|
|
deleteRemoteFolderEtagsQuery.prepare("UPDATE metadata SET md5='_invalid_' WHERE type=2;");
|
|
|
|
if( !deleteRemoteFolderEtagsQuery.exec() ) {
|
|
|
|
qDebug() << "ERROR: Query failed" << deleteRemoteFolderEtagsQuery.error();
|
|
|
|
} else {
|
|
|
|
qDebug() << "Cleared" << deleteRemoteFolderEtagsQuery.numRowsAffected() << "folder ETags";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-23 13:53:06 +03:00
|
|
|
|
|
|
|
QByteArray SyncJournalDb::getChecksumType(int checksumTypeId)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return QByteArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the id
|
|
|
|
auto & query = *_getChecksumTypeQuery;
|
|
|
|
query.reset();
|
|
|
|
query.bindValue(1, checksumTypeId);
|
|
|
|
if( !query.exec() ) {
|
|
|
|
qWarning() << "Error SQL statement getChecksumType: "
|
|
|
|
<< query.lastQuery() << " :"
|
|
|
|
<< query.error();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !query.next() ) {
|
|
|
|
qDebug() << "No checksum type mapping found for" << checksumTypeId;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return query.baValue(0);
|
|
|
|
}
|
|
|
|
|
2015-10-28 13:00:03 +03:00
|
|
|
int SyncJournalDb::mapChecksumType(const QByteArray& checksumType)
|
|
|
|
{
|
|
|
|
if (checksumType.isEmpty()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the checksum type is in the db
|
|
|
|
_insertChecksumTypeQuery->reset();
|
|
|
|
_insertChecksumTypeQuery->bindValue(1, checksumType);
|
|
|
|
if( !_insertChecksumTypeQuery->exec() ) {
|
|
|
|
qWarning() << "Error SQL statement insertChecksumType: "
|
|
|
|
<< _insertChecksumTypeQuery->lastQuery() << " :"
|
|
|
|
<< _insertChecksumTypeQuery->error();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the id
|
|
|
|
_getChecksumTypeIdQuery->reset();
|
|
|
|
_getChecksumTypeIdQuery->bindValue(1, checksumType);
|
|
|
|
if( !_getChecksumTypeIdQuery->exec() ) {
|
|
|
|
qWarning() << "Error SQL statement getChecksumTypeId: "
|
|
|
|
<< _getChecksumTypeIdQuery->lastQuery() << " :"
|
|
|
|
<< _getChecksumTypeIdQuery->error();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !_getChecksumTypeIdQuery->next() ) {
|
|
|
|
qDebug() << "No checksum type mapping found for" << checksumType;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return _getChecksumTypeIdQuery->intValue(0);
|
|
|
|
}
|
|
|
|
|
2015-06-19 14:51:55 +03:00
|
|
|
|
2013-11-25 18:11:37 +04:00
|
|
|
void SyncJournalDb::commit(const QString& context, bool startTrans)
|
|
|
|
{
|
|
|
|
QMutexLocker lock(&_mutex);
|
|
|
|
commitInternal(context, startTrans);
|
|
|
|
}
|
|
|
|
|
2014-10-20 19:20:58 +04:00
|
|
|
void SyncJournalDb::commitIfNeededAndStartNewTransaction(const QString &context)
|
|
|
|
{
|
|
|
|
QMutexLocker lock(&_mutex);
|
|
|
|
if( _transaction == 1 ) {
|
|
|
|
commitInternal(context, true);
|
|
|
|
} else {
|
|
|
|
startTransaction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-25 18:11:37 +04:00
|
|
|
|
|
|
|
void SyncJournalDb::commitInternal(const QString& context, bool startTrans )
|
2013-11-18 12:59:59 +04:00
|
|
|
{
|
2014-10-13 19:28:47 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << "Transaction commit " << context << (startTrans ? "and starting new transaction" : "");
|
2013-11-21 14:13:58 +04:00
|
|
|
commitTransaction();
|
|
|
|
|
|
|
|
if( startTrans ) {
|
|
|
|
startTransaction();
|
2013-11-18 12:59:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SyncJournalDb::~SyncJournalDb()
|
|
|
|
{
|
2013-11-25 18:07:58 +04:00
|
|
|
close();
|
2013-11-18 12:59:59 +04:00
|
|
|
}
|
|
|
|
|
2014-04-01 15:41:47 +04:00
|
|
|
bool SyncJournalDb::isConnected()
|
|
|
|
{
|
|
|
|
QMutexLocker lock(&_mutex);
|
|
|
|
return checkConnect();
|
|
|
|
}
|
|
|
|
|
2014-10-23 17:15:47 +04:00
|
|
|
bool operator==(const SyncJournalDb::DownloadInfo & lhs,
|
|
|
|
const SyncJournalDb::DownloadInfo & rhs)
|
|
|
|
{
|
|
|
|
return lhs._errorCount == rhs._errorCount
|
|
|
|
&& lhs._etag == rhs._etag
|
|
|
|
&& lhs._tmpfile == rhs._tmpfile
|
|
|
|
&& lhs._valid == rhs._valid;
|
2014-04-01 15:41:47 +04:00
|
|
|
|
2014-10-23 17:15:47 +04:00
|
|
|
}
|
2014-04-01 15:41:47 +04:00
|
|
|
|
2014-10-23 17:15:47 +04:00
|
|
|
bool operator==(const SyncJournalDb::UploadInfo & lhs,
|
|
|
|
const SyncJournalDb::UploadInfo & rhs)
|
|
|
|
{
|
|
|
|
return lhs._errorCount == rhs._errorCount
|
|
|
|
&& lhs._chunk == rhs._chunk
|
|
|
|
&& lhs._modtime == rhs._modtime
|
|
|
|
&& lhs._valid == rhs._valid
|
|
|
|
&& lhs._size == rhs._size
|
|
|
|
&& lhs._transferid == rhs._transferid;
|
|
|
|
}
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2014-11-10 00:34:07 +03:00
|
|
|
} // namespace OCC
|