Skip to content

Commit 1382e4c

Browse files
authored
Merge pull request #4819 from nextcloud/feature/syncjournaldb-handle-errors
Feature/syncjournaldb handle errors
2 parents be6f204 + b40c2df commit 1382e4c

39 files changed

Lines changed: 297 additions & 142 deletions

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.16)
2-
set(CMAKE_CXX_STANDARD 14)
2+
set(CMAKE_CXX_STANDARD 17)
33
cmake_policy(SET CMP0071 NEW) # Enable use of QtQuick compiler/generated code
44

55
project(client)

src/common/syncjournaldb.cpp

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,7 +1721,9 @@ void SyncJournalDb::deleteStaleFlagsEntries()
17211721
return;
17221722

17231723
SqlQuery delQuery("DELETE FROM flags WHERE path != '' AND path NOT IN (SELECT path from metadata);", _db);
1724-
delQuery.exec();
1724+
if (!delQuery.exec()) {
1725+
sqlFail(QStringLiteral("deleteStaleFlagsEntries"), delQuery);
1726+
}
17251727
}
17261728

17271729
int SyncJournalDb::errorBlackListEntryCount()
@@ -1862,14 +1864,18 @@ void SyncJournalDb::setPollInfo(const SyncJournalDb::PollInfo &info)
18621864
qCDebug(lcDb) << "Deleting Poll job" << info._file;
18631865
SqlQuery query("DELETE FROM async_poll WHERE path=?", _db);
18641866
query.bindValue(1, info._file);
1865-
query.exec();
1867+
if (!query.exec()) {
1868+
sqlFail(QStringLiteral("setPollInfo DELETE FROM async_poll"), query);
1869+
}
18661870
} else {
18671871
SqlQuery query("INSERT OR REPLACE INTO async_poll (path, modtime, filesize, pollpath) VALUES( ? , ? , ? , ? )", _db);
18681872
query.bindValue(1, info._file);
18691873
query.bindValue(2, info._modtime);
18701874
query.bindValue(3, info._fileSize);
18711875
query.bindValue(4, info._url);
1872-
query.exec();
1876+
if (!query.exec()) {
1877+
sqlFail(QStringLiteral("setPollInfo INSERT OR REPLACE INTO async_poll"), query);
1878+
}
18731879
}
18741880
}
18751881

@@ -1955,7 +1961,10 @@ void SyncJournalDb::avoidRenamesOnNextSync(const QByteArray &path)
19551961
SqlQuery query(_db);
19561962
query.prepare("UPDATE metadata SET fileid = '', inode = '0' WHERE " IS_PREFIX_PATH_OR_EQUAL("?1", "path"));
19571963
query.bindValue(1, path);
1958-
query.exec();
1964+
1965+
if (!query.exec()) {
1966+
sqlFail(QStringLiteral("avoidRenamesOnNextSync path: %1").arg(QString::fromUtf8(path)), query);
1967+
}
19591968

19601969
// We also need to remove the ETags so the update phase refreshes the directory paths
19611970
// on the next sync
@@ -1980,7 +1989,10 @@ void SyncJournalDb::schedulePathForRemoteDiscovery(const QByteArray &fileName)
19801989
// Note: CSYNC_FTW_TYPE_DIR == 2
19811990
query.prepare("UPDATE metadata SET md5='_invalid_' WHERE " IS_PREFIX_PATH_OR_EQUAL("path", "?1") " AND type == 2;");
19821991
query.bindValue(1, argument);
1983-
query.exec();
1992+
1993+
if (!query.exec()) {
1994+
sqlFail(QStringLiteral("schedulePathForRemoteDiscovery path: %1").arg(QString::fromUtf8(fileName)), query);
1995+
}
19841996

19851997
// Prevent future overwrite of the etags of this folder and all
19861998
// parent folders for this sync
@@ -2009,7 +2021,10 @@ void SyncJournalDb::forceRemoteDiscoveryNextSyncLocked()
20092021
qCInfo(lcDb) << "Forcing remote re-discovery by deleting folder Etags";
20102022
SqlQuery deleteRemoteFolderEtagsQuery(_db);
20112023
deleteRemoteFolderEtagsQuery.prepare("UPDATE metadata SET md5='_invalid_' WHERE type=2;");
2012-
deleteRemoteFolderEtagsQuery.exec();
2024+
2025+
if (!deleteRemoteFolderEtagsQuery.exec()) {
2026+
sqlFail(QStringLiteral("forceRemoteDiscoveryNextSyncLocked"), deleteRemoteFolderEtagsQuery);
2027+
}
20132028
}
20142029

20152030

@@ -2197,10 +2212,12 @@ QByteArray SyncJournalDb::conflictFileBaseName(const QByteArray &conflictName)
21972212
auto conflict = conflictRecord(conflictName);
21982213
QByteArray result;
21992214
if (conflict.isValid()) {
2200-
getFileRecordsByFileId(conflict.baseFileId, [&result](const SyncJournalFileRecord &record) {
2215+
if (!getFileRecordsByFileId(conflict.baseFileId, [&result](const SyncJournalFileRecord &record) {
22012216
if (!record._path.isEmpty())
22022217
result = record._path;
2203-
});
2218+
})) {
2219+
qCWarning(lcDb) << "conflictFileBaseName failed to getFileRecordsByFileId: " << conflictName;
2220+
}
22042221
}
22052222

22062223
if (result.isEmpty()) {
@@ -2214,7 +2231,10 @@ void SyncJournalDb::clearFileTable()
22142231
QMutexLocker lock(&_mutex);
22152232
SqlQuery query(_db);
22162233
query.prepare("DELETE FROM metadata;");
2217-
query.exec();
2234+
2235+
if (!query.exec()) {
2236+
sqlFail(QStringLiteral("clearFileTable"), query);
2237+
}
22182238
}
22192239

22202240
void SyncJournalDb::markVirtualFileForDownloadRecursively(const QByteArray &path)
@@ -2228,15 +2248,21 @@ void SyncJournalDb::markVirtualFileForDownloadRecursively(const QByteArray &path
22282248
"(" IS_PREFIX_PATH_OF("?1", "path") " OR ?1 == '') "
22292249
"AND type=4;", _db);
22302250
query.bindValue(1, path);
2231-
query.exec();
2251+
2252+
if (!query.exec()) {
2253+
sqlFail(QStringLiteral("markVirtualFileForDownloadRecursively UPDATE metadata SET type=5 path: %1").arg(QString::fromUtf8(path)), query);
2254+
}
22322255

22332256
// We also must make sure we do not read the files from the database (same logic as in schedulePathForRemoteDiscovery)
22342257
// This includes all the parents up to the root, but also all the directory within the selected dir.
22352258
static_assert(ItemTypeDirectory == 2, "");
22362259
query.prepare("UPDATE metadata SET md5='_invalid_' WHERE "
22372260
"(" IS_PREFIX_PATH_OF("?1", "path") " OR ?1 == '' OR " IS_PREFIX_PATH_OR_EQUAL("path", "?1") ") AND type == 2;");
22382261
query.bindValue(1, path);
2239-
query.exec();
2262+
2263+
if (!query.exec()) {
2264+
sqlFail(QStringLiteral("markVirtualFileForDownloadRecursively UPDATE metadata SET md5='_invalid_' path: %1").arg(QString::fromUtf8(path)), query);
2265+
}
22402266
}
22412267

22422268
Optional<PinState> SyncJournalDb::PinStateInterface::rawForPath(const QByteArray &path)
@@ -2366,7 +2392,12 @@ SyncJournalDb::PinStateInterface::rawList()
23662392
return {};
23672393

23682394
SqlQuery query("SELECT path, pinState FROM flags;", _db->_db);
2369-
query.exec();
2395+
2396+
if (!query.exec()) {
2397+
qCWarning(lcDb) << "SQL Error" << "PinStateInterface::rawList" << query.error();
2398+
_db->close();
2399+
ASSERT(false);
2400+
}
23702401

23712402
QVector<QPair<QByteArray, PinState>> result;
23722403
forever {

src/common/syncjournaldb.h

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,25 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
5959
static bool maybeMigrateDb(const QString &localPath, const QString &absoluteJournalPath);
6060

6161
// To verify that the record could be found check with SyncJournalFileRecord::isValid()
62-
bool getFileRecord(const QString &filename, SyncJournalFileRecord *rec) { return getFileRecord(filename.toUtf8(), rec); }
63-
bool getFileRecord(const QByteArray &filename, SyncJournalFileRecord *rec);
64-
bool getFileRecordByE2eMangledName(const QString &mangledName, SyncJournalFileRecord *rec);
65-
bool getFileRecordByInode(quint64 inode, SyncJournalFileRecord *rec);
66-
bool getFileRecordsByFileId(const QByteArray &fileId, const std::function<void(const SyncJournalFileRecord &)> &rowCallback);
67-
bool getFilesBelowPath(const QByteArray &path, const std::function<void(const SyncJournalFileRecord&)> &rowCallback);
68-
bool listFilesInPath(const QByteArray &path, const std::function<void(const SyncJournalFileRecord&)> &rowCallback);
69-
Result<void, QString> setFileRecord(const SyncJournalFileRecord &record);
62+
[[nodiscard]] bool getFileRecord(const QString &filename, SyncJournalFileRecord *rec) { return getFileRecord(filename.toUtf8(), rec); }
63+
[[nodiscard]] bool getFileRecord(const QByteArray &filename, SyncJournalFileRecord *rec);
64+
[[nodiscard]] bool getFileRecordByE2eMangledName(const QString &mangledName, SyncJournalFileRecord *rec);
65+
[[nodiscard]] bool getFileRecordByInode(quint64 inode, SyncJournalFileRecord *rec);
66+
[[nodiscard]] bool getFileRecordsByFileId(const QByteArray &fileId, const std::function<void(const SyncJournalFileRecord &)> &rowCallback);
67+
[[nodiscard]] bool getFilesBelowPath(const QByteArray &path, const std::function<void(const SyncJournalFileRecord&)> &rowCallback);
68+
[[nodiscard]] bool listFilesInPath(const QByteArray &path, const std::function<void(const SyncJournalFileRecord&)> &rowCallback);
69+
[[nodiscard]] Result<void, QString> setFileRecord(const SyncJournalFileRecord &record);
7070

7171
void keyValueStoreSet(const QString &key, QVariant value);
72-
qint64 keyValueStoreGetInt(const QString &key, qint64 defaultValue);
72+
[[nodiscard]] qint64 keyValueStoreGetInt(const QString &key, qint64 defaultValue);
7373
void keyValueStoreDelete(const QString &key);
7474

75-
bool deleteFileRecord(const QString &filename, bool recursively = false);
76-
bool updateFileRecordChecksum(const QString &filename,
75+
[[nodiscard]] bool deleteFileRecord(const QString &filename, bool recursively = false);
76+
[[nodiscard]] bool updateFileRecordChecksum(
77+
const QString &filename,
7778
const QByteArray &contentChecksum,
7879
const QByteArray &contentChecksumType);
79-
bool updateLocalMetadata(const QString &filename,
80+
[[nodiscard]] bool updateLocalMetadata(const QString &filename,
8081
qint64 modtime, qint64 size, quint64 inode);
8182

8283
/// Return value for hasHydratedOrDehydratedFiles()
@@ -99,7 +100,7 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
99100
void setErrorBlacklistEntry(const SyncJournalErrorBlacklistRecord &item);
100101
void wipeErrorBlacklistEntry(const QString &file);
101102
void wipeErrorBlacklistCategory(SyncJournalErrorBlacklistRecord::Category category);
102-
int wipeErrorBlacklist();
103+
[[nodiscard]] int wipeErrorBlacklist();
103104
int errorBlackListEntryCount();
104105

105106
struct DownloadInfo
@@ -145,7 +146,7 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
145146
QVector<uint> deleteStaleUploadInfos(const QSet<QString> &keep);
146147

147148
SyncJournalErrorBlacklistRecord errorBlacklistEntry(const QString &);
148-
bool deleteStaleErrorBlacklistEntries(const QSet<QString> &keep);
149+
[[nodiscard]] bool deleteStaleErrorBlacklistEntries(const QSet<QString> &keep);
149150

150151
/// Delete flags table entries that have no metadata correspondent
151152
void deleteStaleFlagsEntries();
@@ -372,9 +373,9 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
372373

373374
private:
374375
int getFileRecordCount();
375-
bool updateDatabaseStructure();
376-
bool updateMetadataTableStructure();
377-
bool updateErrorBlacklistTableStructure();
376+
[[nodiscard]] bool updateDatabaseStructure();
377+
[[nodiscard]] bool updateMetadataTableStructure();
378+
[[nodiscard]] bool updateErrorBlacklistTableStructure();
378379
bool sqlFail(const QString &log, const SqlQuery &query);
379380
void commitInternal(const QString &context, bool startTrans = true);
380381
void startTransaction();
@@ -388,7 +389,7 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
388389
// Returns the integer id of the checksum type
389390
//
390391
// Returns 0 on failure and for empty checksum types.
391-
int mapChecksumType(const QByteArray &checksumType);
392+
[[nodiscard]] int mapChecksumType(const QByteArray &checksumType);
392393

393394
SqlDatabase _db;
394395
QString _dbFile;

src/gui/accountsettings.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,9 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
507507
// It might be an E2EE mangled path, so let's try to demangle it
508508
const auto journal = folder->journalDb();
509509
SyncJournalFileRecord rec;
510-
journal->getFileRecordByE2eMangledName(remotePath, &rec);
510+
if (!journal->getFileRecordByE2eMangledName(remotePath, &rec)) {
511+
qCWarning(lcFolderStatus) << "Could not get file record by E2E Mangled Name from local DB" << remotePath;
512+
}
511513

512514
const auto path = rec.isValid() ? rec._path : remotePath;
513515

src/gui/connectionvalidator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ bool ConnectionValidator::setAndCheckServerVersion(const QString &version)
278278
if (auto job = qobject_cast<AbstractNetworkJob *>(sender())) {
279279
if (auto reply = job->reply()) {
280280
_account->setHttp2Supported(
281-
reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool());
281+
reply->attribute(QNetworkRequest::Http2WasUsedAttribute).toBool());
282282
}
283283
}
284284
#endif

src/gui/folder.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,9 @@ void Folder::slotWatchedPathChanged(const QString &path, ChangeReason reason)
577577

578578

579579
SyncJournalFileRecord record;
580-
_journal.getFileRecord(relativePathBytes, &record);
580+
if (!_journal.getFileRecord(relativePathBytes, &record)) {
581+
qCWarning(lcFolder) << "could not get file from local DB" << relativePathBytes;
582+
}
581583
if (reason != ChangeReason::UnLock) {
582584
// Check that the mtime/size actually changed or there was
583585
// an attribute change (pin state) that caused the notification
@@ -613,7 +615,11 @@ void Folder::implicitlyHydrateFile(const QString &relativepath)
613615

614616
// Set in the database that we should download the file
615617
SyncJournalFileRecord record;
616-
_journal.getFileRecord(relativepath.toUtf8(), &record);
618+
;
619+
if (!_journal.getFileRecord(relativepath.toUtf8(), &record)) {
620+
qCWarning(lcFolder) << "could not get file from local DB" << relativepath;
621+
return;
622+
}
617623
if (!record.isValid()) {
618624
qCInfo(lcFolder) << "Did not find file in db";
619625
return;
@@ -622,8 +628,14 @@ void Folder::implicitlyHydrateFile(const QString &relativepath)
622628
qCInfo(lcFolder) << "The file is not virtual";
623629
return;
624630
}
631+
625632
record._type = ItemTypeVirtualFileDownload;
626-
_journal.setFileRecord(record);
633+
634+
const auto result = _journal.setFileRecord(record);
635+
if (!result) {
636+
qCWarning(lcFolder) << "Error when setting the file record to the database" << record._path << result.error();
637+
return;
638+
}
627639

628640
// Change the file's pin state if it's contradictory to being hydrated
629641
// (suffix-virtual file's pin state is stored at the hydrated path)

src/gui/folderstatusdelegate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ QRect FolderStatusDelegate::optionsButtonRect(QRect within, Qt::LayoutDirection
400400
opt.rect.setSize(QSize(e,e));
401401
QSize size = QApplication::style()->sizeFromContents(QStyle::CT_ToolButton, &opt, opt.rect.size()).expandedTo(QApplication::globalStrut());
402402

403-
int margin = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
403+
int margin = QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
404404
QRect r(QPoint(within.right() - size.width() - margin,
405405
within.top() + within.height() / 2 - size.height() / 2),
406406
size);

src/gui/folderstatusmodel.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,9 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
743743
newInfo._path = relativePath;
744744

745745
SyncJournalFileRecord rec;
746-
parentInfo->_folder->journalDb()->getFileRecordByE2eMangledName(removeTrailingSlash(relativePath), &rec);
746+
if (!parentInfo->_folder->journalDb()->getFileRecordByE2eMangledName(removeTrailingSlash(relativePath), &rec)) {
747+
qCWarning(lcFolderStatus) << "Could not get file record by E2E Mangled Name from local DB" << removeTrailingSlash(relativePath);
748+
}
747749
if (rec.isValid()) {
748750
newInfo._name = removeTrailingSlash(rec._path).split('/').last();
749751
if (rec._isE2eEncrypted && !rec._e2eMangledName.isEmpty()) {

src/gui/socketapi/socketapi.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,9 @@ SyncJournalFileRecord SocketApi::FileData::journalRecord() const
11491149
SyncJournalFileRecord record;
11501150
if (!folder)
11511151
return record;
1152-
folder->journalDb()->getFileRecord(folderRelativePath, &record);
1152+
if (!folder->journalDb()->getFileRecord(folderRelativePath, &record)) {
1153+
qCWarning(lcSocketApi) << "Failed to get journal record for path" << folderRelativePath;
1154+
}
11531155
return record;
11541156
}
11551157

src/gui/tray/activitylistmodel.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
156156
// If this is an E2EE file or folder, pretend we got no path, hiding the share button which is what we want
157157
if (folder) {
158158
SyncJournalFileRecord rec;
159-
folder->journalDb()->getFileRecord(fileName.mid(1), &rec);
159+
if (!folder->journalDb()->getFileRecord(fileName.mid(1), &rec)) {
160+
qCWarning(lcActivity) << "could not get file from local DB" << fileName.mid(1);
161+
}
160162
if (rec.isValid() && (rec._isE2eEncrypted || !rec._e2eMangledName.isEmpty())) {
161163
return QString();
162164
}

0 commit comments

Comments
 (0)