SyncEngine: Introduce overall errors that are not tied to a file #5746

For now we use them for:
* csync errors: This allows them to appear in the sync issues tab
* insufficient local disk space, as a summary of individual file errors

Insufficient remote space will use them too, as might other issues that
are bigger than a single sync item.
This commit is contained in:
Christian Kamm 2017-06-28 12:45:54 +02:00 коммит произвёл ckamm
Родитель d34dbbdb0b
Коммит 5ca743dd25
10 изменённых файлов: 107 добавлений и 13 удалений

Просмотреть файл

@ -106,6 +106,7 @@ Folder::Folder(const FolderDefinition &definition,
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString))); connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector &)), connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector &)),
SLOT(slotLogPropagationStart())); SLOT(slotLogPropagationStart()));
connect(_engine.data(), SIGNAL(summaryError(QString)), SLOT(slotSyncError(QString)));
_scheduleSelfTimer.setSingleShot(true); _scheduleSelfTimer.setSingleShot(true);
_scheduleSelfTimer.setInterval(SyncEngine::minimumFileAgeForUpload); _scheduleSelfTimer.setInterval(SyncEngine::minimumFileAgeForUpload);
@ -721,10 +722,10 @@ void Folder::setDirtyNetworkLimits()
_engine->setNetworkLimits(uploadLimit, downloadLimit); _engine->setNetworkLimits(uploadLimit, downloadLimit);
} }
void Folder::slotSyncError(const QString &message)
void Folder::slotSyncError(const QString &err)
{ {
_syncResult.appendErrorString(err); _syncResult.appendErrorString(message);
emit ProgressDispatcher::instance()->syncError(alias(), message);
} }
void Folder::slotSyncStarted() void Folder::slotSyncStarted()

Просмотреть файл

@ -278,11 +278,16 @@ public slots:
private slots: private slots:
void slotSyncStarted(); void slotSyncStarted();
void slotSyncError(const QString &);
void slotCsyncUnavailable();
void slotSyncFinished(bool); void slotSyncFinished(bool);
/** Adds a error message that's not tied to a specific item.
*/
void slotSyncError(const QString &message);
void slotCsyncUnavailable();
void slotFolderDiscovered(bool local, QString folderName); void slotFolderDiscovered(bool local, QString folderName);
void slotTransmissionProgress(const ProgressInfo &pi); void slotTransmissionProgress(const ProgressInfo &pi);
void slotItemCompleted(const SyncFileItemPtr &); void slotItemCompleted(const SyncFileItemPtr &);

Просмотреть файл

@ -49,6 +49,8 @@ IssuesWidget::IssuesWidget(QWidget *parent)
this, SLOT(slotProgressInfo(QString, ProgressInfo))); this, SLOT(slotProgressInfo(QString, ProgressInfo)));
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString, SyncFileItemPtr)), connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString, SyncFileItemPtr)),
this, SLOT(slotItemCompleted(QString, SyncFileItemPtr))); this, SLOT(slotItemCompleted(QString, SyncFileItemPtr)));
connect(ProgressDispatcher::instance(), SIGNAL(syncError(QString, QString)),
this, SLOT(addLine(QString, QString)));
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem *, int)), SLOT(slotOpenFile(QTreeWidgetItem *, int))); connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem *, int)), SLOT(slotOpenFile(QTreeWidgetItem *, int)));
connect(_ui->copyIssuesButton, SIGNAL(clicked()), SIGNAL(copyToClipboard())); connect(_ui->copyIssuesButton, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
@ -132,6 +134,15 @@ void IssuesWidget::cleanItems(const QString &folder)
emit(issueCountUpdated(_ui->_treeWidget->topLevelItemCount())); emit(issueCountUpdated(_ui->_treeWidget->topLevelItemCount()));
} }
void IssuesWidget::addItem(QTreeWidgetItem *item)
{
if (!item)
return;
_ui->_treeWidget->insertTopLevelItem(0, item);
item->setHidden(!shouldBeVisible(item, currentAccountFilter(), currentFolderFilter()));
emit issueCountUpdated(_ui->_treeWidget->topLevelItemCount());
}
void IssuesWidget::slotOpenFile(QTreeWidgetItem *item, int) void IssuesWidget::slotOpenFile(QTreeWidgetItem *item, int)
{ {
QString folderName = item->data(2, Qt::UserRole).toString(); QString folderName = item->data(2, Qt::UserRole).toString();
@ -164,10 +175,7 @@ void IssuesWidget::slotItemCompleted(const QString &folder, const SyncFileItemPt
QTreeWidgetItem *line = ProtocolWidget::createCompletedTreewidgetItem(folder, *item); QTreeWidgetItem *line = ProtocolWidget::createCompletedTreewidgetItem(folder, *item);
if (!line) if (!line)
return; return;
addItem(line);
_ui->_treeWidget->insertTopLevelItem(0, line);
line->setHidden(!shouldBeVisible(line, currentAccountFilter(), currentFolderFilter()));
emit issueCountUpdated(_ui->_treeWidget->topLevelItemCount());
} }
void IssuesWidget::slotRefreshIssues() void IssuesWidget::slotRefreshIssues()
@ -328,4 +336,41 @@ void IssuesWidget::showFolderErrors(const QString &folderAlias)
_ui->showIgnores->setChecked(false); _ui->showIgnores->setChecked(false);
_ui->showWarnings->setChecked(false); _ui->showWarnings->setChecked(false);
} }
void IssuesWidget::addLine(const QString &folderAlias, const QString &message)
{
SyncFileItem::Status status = SyncFileItem::NormalError;
auto folder = FolderMan::instance()->folder(folderAlias);
if (!folder)
return;
QStringList columns;
QDateTime timestamp = QDateTime::currentDateTime();
const QString timeStr = ProtocolWidget::timeString(timestamp);
const QString longTimeStr = ProtocolWidget::timeString(timestamp, QLocale::LongFormat);
columns << timeStr;
columns << tr("<global error>");
columns << folder->shortGuiLocalPath();
columns << message;
QIcon icon;
if (status == SyncFileItem::NormalError
|| status == SyncFileItem::FatalError) {
icon = Theme::instance()->syncStateIcon(SyncResult::Error);
} else if (Progress::isWarningKind(status)) {
icon = Theme::instance()->syncStateIcon(SyncResult::Problem);
}
QTreeWidgetItem *twitem = new QTreeWidgetItem(columns);
twitem->setData(0, Qt::SizeHintRole, QSize(0, ActivityItemDelegate::rowHeight()));
twitem->setIcon(0, icon);
twitem->setToolTip(0, longTimeStr);
twitem->setToolTip(3, message);
twitem->setData(0, Qt::UserRole, status);
twitem->setData(2, Qt::UserRole, folderAlias);
addItem(twitem);
}
} }

Просмотреть файл

@ -50,6 +50,7 @@ public:
void showFolderErrors(const QString &folderAlias); void showFolderErrors(const QString &folderAlias);
public slots: public slots:
void addLine(const QString &folderAlias, const QString &message);
void slotProgressInfo(const QString &folder, const ProgressInfo &progress); void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item); void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
void slotOpenFile(QTreeWidgetItem *item, int); void slotOpenFile(QTreeWidgetItem *item, int);
@ -75,6 +76,7 @@ private:
bool shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount, bool shouldBeVisible(QTreeWidgetItem *item, AccountState *filterAccount,
const QString &filterFolderAlias) const; const QString &filterFolderAlias) const;
void cleanItems(const QString &folder); void cleanItems(const QString &folder);
void addItem(QTreeWidgetItem *item);
Ui::IssuesWidget *_ui; Ui::IssuesWidget *_ui;
}; };

Просмотреть файл

@ -238,6 +238,7 @@ void PropagateItemJob::done(SyncFileItem::Status statusArg, const QString &error
_item->_status = SyncFileItem::SoftError; _item->_status = SyncFileItem::SoftError;
} }
// Blacklist handling
switch (_item->_status) { switch (_item->_status) {
case SyncFileItem::SoftError: case SyncFileItem::SoftError:
case SyncFileItem::FatalError: case SyncFileItem::FatalError:

Просмотреть файл

@ -417,7 +417,6 @@ public:
*/ */
DiskSpaceResult diskSpaceCheck() const; DiskSpaceResult diskSpaceCheck() const;
private slots: private slots:
/** Emit the finished signal and make sure it is only emitted once */ /** Emit the finished signal and make sure it is only emitted once */
@ -445,6 +444,8 @@ signals:
*/ */
void touchedFile(const QString &fileName); void touchedFile(const QString &fileName);
void insufficientLocalStorage();
private: private:
AccountPtr _account; AccountPtr _account;
QScopedPointer<PropagateDirectory> _rootJob; QScopedPointer<PropagateDirectory> _rootJob;

Просмотреть файл

@ -249,6 +249,11 @@ signals:
*/ */
void itemCompleted(const QString &folder, const SyncFileItemPtr &item); void itemCompleted(const QString &folder, const SyncFileItemPtr &item);
/**
* @brief A new folder-wide sync error was seen.
*/
void syncError(const QString &folder, const QString &message);
protected: protected:
void setProgressInfo(const QString &folder, const ProgressInfo &progress); void setProgressInfo(const QString &folder, const ProgressInfo &progress);

Просмотреть файл

@ -427,9 +427,12 @@ void PropagateDownloadFile::startDownload()
const auto diskSpaceResult = propagator()->diskSpaceCheck(); const auto diskSpaceResult = propagator()->diskSpaceCheck();
if (diskSpaceResult != OwncloudPropagator::DiskSpaceOk) { if (diskSpaceResult != OwncloudPropagator::DiskSpaceOk) {
if (diskSpaceResult == OwncloudPropagator::DiskSpaceFailure) { if (diskSpaceResult == OwncloudPropagator::DiskSpaceFailure) {
_item->_errorMayBeBlacklisted = true; // Using BlacklistedError here will make the error not pop up in the account
done(SyncFileItem::NormalError, // tab: instead we'll generate a general "disk space low" message and show
tr("The download would reduce free disk space below %1").arg(Utility::octetsToString(freeSpaceLimit()))); // these detail errors only in the error view.
done(SyncFileItem::BlacklistedError,
tr("The download would reduce free local disk space below the limit"));
emit propagator()->insufficientLocalStorage();
} else if (diskSpaceResult == OwncloudPropagator::DiskSpaceCritical) { } else if (diskSpaceResult == OwncloudPropagator::DiskSpaceCritical) {
done(SyncFileItem::FatalError, done(SyncFileItem::FatalError,
tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit()))); tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit())));

Просмотреть файл

@ -24,6 +24,7 @@
#include "csync_private.h" #include "csync_private.h"
#include "filesystem.h" #include "filesystem.h"
#include "propagateremotedelete.h" #include "propagateremotedelete.h"
#include "propagatedownload.h"
#include "asserts.h" #include "asserts.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@ -1025,6 +1026,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
connect(_propagator.data(), SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)), Qt::QueuedConnection); connect(_propagator.data(), SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)), Qt::QueuedConnection);
connect(_propagator.data(), SIGNAL(seenLockedFile(QString)), SIGNAL(seenLockedFile(QString))); connect(_propagator.data(), SIGNAL(seenLockedFile(QString)), SIGNAL(seenLockedFile(QString)));
connect(_propagator.data(), SIGNAL(touchedFile(QString)), SLOT(slotAddTouchedFile(QString))); connect(_propagator.data(), SIGNAL(touchedFile(QString)), SLOT(slotAddTouchedFile(QString)));
connect(_propagator.data(), SIGNAL(insufficientLocalStorage()), SLOT(slotInsufficientLocalStorage()));
// apply the network limits to the propagator // apply the network limits to the propagator
setNetworkLimits(_uploadLimit, _downloadLimit); setNetworkLimits(_uploadLimit, _downloadLimit);
@ -1135,6 +1137,7 @@ void SyncEngine::finalize(bool success)
_seenFiles.clear(); _seenFiles.clear();
_temporarilyUnavailablePaths.clear(); _temporarilyUnavailablePaths.clear();
_renamedFolders.clear(); _renamedFolders.clear();
_uniqueErrors.clear();
_clearTouchedFilesTimer.start(); _clearTouchedFilesTimer.start();
} }
@ -1523,4 +1526,21 @@ void SyncEngine::abort()
} }
} }
void SyncEngine::slotSummaryError(const QString &message)
{
if (_uniqueErrors.contains(message))
return;
_uniqueErrors.insert(message);
emit summaryError(message);
}
void SyncEngine::slotInsufficientLocalStorage()
{
slotSummaryError(
tr("Disk space is low: Downloads that would reduce free space "
"below %1 were skipped.")
.arg(Utility::octetsToString(freeSpaceLimit())));
}
} // namespace OCC } // namespace OCC

Просмотреть файл

@ -121,6 +121,9 @@ signals:
void transmissionProgress(const ProgressInfo &progress); void transmissionProgress(const ProgressInfo &progress);
/// We've produced a new summary error.
void summaryError(const QString &message);
void finished(bool success); void finished(bool success);
void started(); void started();
@ -160,6 +163,11 @@ private slots:
/** Wipes the _touchedFiles hash */ /** Wipes the _touchedFiles hash */
void slotClearTouchedFiles(); void slotClearTouchedFiles();
/** Emit a summary error, unless it was seen before */
void slotSummaryError(const QString &message);
void slotInsufficientLocalStorage();
private: private:
void handleSyncError(CSYNC *ctx, const char *state); void handleSyncError(CSYNC *ctx, const char *state);
@ -267,6 +275,9 @@ private:
/** For clearing the _touchedFiles variable after sync finished */ /** For clearing the _touchedFiles variable after sync finished */
QTimer _clearTouchedFilesTimer; QTimer _clearTouchedFilesTimer;
/** List of unique errors that occurred in a sync run. */
QSet<QString> _uniqueErrors;
}; };
} }