Skip to content

Commit a668053

Browse files
Klaas FreitagTheOneRing
Klaas Freitag
andauthored
Poll interval from capabilities (#8777)
* Add remotePollInterval capability. * Use public const int rather than define for default value. * Honour pollinterval from account capabilities for poll frequency. With this, admins can change the remote poll interval of desktop clients with the capability settings. * Use more efficient invocation of the etag job slot. * Consider capability value to be in milliseconds. * Make format check happy. * Add a ElapsedTimer to measure time since last Etag check. Also, do the check if one of the folders is due to sync every second. That way we get a more accurate sync frequency. The check is very lightweight. * Extend remotePollInterval config method to accept default value. With that it is possible to read the value for the remotepollinterval from the capabilities. * Add changelog entry for #8777. * Changes from clang-format * Fix changelog entry, punctuation at end. * do not go for assumptions how long the request takes. No magic number. * Change some method interfaces to seconds rather than microseconds. Feedback from review. * Again considering more review feedback * Remove additional 5s check already performed in ConfigFile::remotePollInterval Co-authored-by: Hannah von Reth <[email protected]>
1 parent 49b415b commit a668053

File tree

9 files changed

+78
-28
lines changed

9 files changed

+78
-28
lines changed

changelog/unreleased/8780

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Enhancement: Consider a remote poll interval coming with the server capabilities
2+
3+
This way, admins can configure the remote sync poll interval of clients through
4+
the capabilities settings of the server. Note that the setting in the server
5+
capabilities needs to be done in milliseconds. Default is 30 seconds.
6+
7+
https://github.com/owncloud/client/issues/5947
8+
https://github.com/owncloud/client/issues/8780
9+
https://github.com/owncloud/client/pull/8777

src/gui/accountstate.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ void AccountState::checkConnectivity(bool blockJobs)
266266

267267
// IF the account is connected the connection check can be skipped
268268
// if the last successful etag check job is not so long ago.
269-
const auto polltime = std::chrono::duration_cast<std::chrono::seconds>(ConfigFile().remotePollInterval());
269+
const auto pta = account()->capabilities().remotePollInterval();
270+
const auto polltime = std::chrono::duration_cast<std::chrono::seconds>(ConfigFile().remotePollInterval(pta));
270271
const auto elapsed = _timeOfLastETagCheck.secsTo(QDateTime::currentDateTimeUtc());
271272
if (!blockJobs && isConnected() && _timeOfLastETagCheck.isValid()
272273
&& elapsed <= polltime.count()) {

src/gui/folder.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Folder::Folder(const FolderDefinition &definition,
6868
{
6969
_timeSinceLastSyncStart.start();
7070
_timeSinceLastSyncDone.start();
71+
_timeSinceLastEtagCheckDone.start();
7172

7273
SyncResult::Status status = SyncResult::NotYetStarted;
7374
if (definition.paused) {
@@ -285,6 +286,27 @@ bool Folder::canSync() const
285286
return !syncPaused() && accountState()->isConnected();
286287
}
287288

289+
bool Folder::dueToSync() const
290+
{
291+
// conditions taken from previous folderman implementation
292+
if (isSyncRunning() || etagJob() || isBusy() || !canSync()) {
293+
return false;
294+
}
295+
296+
ConfigFile cfg;
297+
// the default poll time of 30 seconds as it had been in the client forever.
298+
// Now with https://github.com/owncloud/client/pull/8777 also the server capabilities are considered.
299+
const auto pta = accountState()->account()->capabilities().remotePollInterval();
300+
const auto polltime = cfg.remotePollInterval(pta);
301+
302+
const auto timeSinceLastSync = std::chrono::milliseconds(_timeSinceLastEtagCheckDone.elapsed());
303+
qCInfo(lcFolder) << "dueToSync:" << alias() << timeSinceLastSync.count() << " < " << polltime.count();
304+
if (timeSinceLastSync >= polltime) {
305+
return true;
306+
}
307+
return false;
308+
}
309+
288310
void Folder::setSyncPaused(bool paused)
289311
{
290312
if (paused == _definition.paused) {
@@ -343,6 +365,7 @@ void Folder::slotRunEtagJob()
343365
_requestEtagJob->setTimeout(60 * 1000);
344366
// check if the etag is different when retrieved
345367
QObject::connect(_requestEtagJob.data(), &RequestEtagJob::etagRetreived, this, &Folder::etagRetreived);
368+
QObject::connect(_requestEtagJob.data(), &RequestEtagJob::finishedWithResult, this, [=](const HttpResult<QByteArray>) { _timeSinceLastEtagCheckDone.start(); });
346369
FolderMan::instance()->slotScheduleETagJob(alias(), _requestEtagJob);
347370
// The _requestEtagJob is auto deleting itself on finish. Our guard pointer _requestEtagJob will then be null.
348371
}

src/gui/folder.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ class Folder : public QObject
183183
*/
184184
bool canSync() const;
185185

186+
/**
187+
* Returns true if the folder needs sync poll interval wise, and can
188+
* sync due to its internal state
189+
*/
190+
bool dueToSync() const;
191+
186192
void prepareToSync();
187193

188194
/**
@@ -224,7 +230,7 @@ class Folder : public QObject
224230
SyncEngine &syncEngine() { return *_engine; }
225231
Vfs &vfs() { return *_vfs; }
226232

227-
RequestEtagJob *etagJob() { return _requestEtagJob; }
233+
RequestEtagJob *etagJob() const { return _requestEtagJob; }
228234
std::chrono::milliseconds msecSinceLastSync() const { return std::chrono::milliseconds(_timeSinceLastSyncDone.elapsed()); }
229235
std::chrono::milliseconds msecLastSyncDuration() const { return _lastSyncDuration; }
230236
int consecutiveFollowUpSyncs() const { return _consecutiveFollowUpSyncs; }
@@ -307,6 +313,8 @@ class Folder : public QObject
307313

308314
public slots:
309315

316+
void slotRunEtagJob();
317+
310318
/**
311319
* terminate the current sync run
312320
*/
@@ -373,7 +381,6 @@ private slots:
373381
void slotTransmissionProgress(const ProgressInfo &pi);
374382
void slotItemCompleted(const SyncFileItemPtr &);
375383

376-
void slotRunEtagJob();
377384
void etagRetreived(const QByteArray &, const QDateTime &tp);
378385
void etagRetrievedFromSyncEngine(const QByteArray &, const QDateTime &time);
379386

@@ -445,6 +452,7 @@ private slots:
445452
QScopedPointer<SyncEngine> _engine;
446453
QPointer<RequestEtagJob> _requestEtagJob;
447454
QByteArray _lastEtag;
455+
QElapsedTimer _timeSinceLastEtagCheckDone;
448456
QElapsedTimer _timeSinceLastSyncDone;
449457
QElapsedTimer _timeSinceLastSyncStart;
450458
QElapsedTimer _timeSinceLastFullLocalDiscovery;

src/gui/folderman.cpp

+8-17
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ FolderMan::FolderMan(QObject *parent)
112112

113113
_socketApi.reset(new SocketApi);
114114

115-
ConfigFile cfg;
116-
std::chrono::milliseconds polltime = cfg.remotePollInterval();
117-
qCInfo(lcFolderMan) << "setting remote poll timer interval to" << polltime.count() << "msec";
118-
_etagPollTimer.setInterval(polltime.count());
115+
// Set the remote poll interval fixed to 10 seconds.
116+
// That does not mean that it polls every 10 seconds, but it checks every 10 secs
117+
// if one of the folders is due to sync.
118+
_etagPollTimer.setInterval(1000);
119119
QObject::connect(&_etagPollTimer, &QTimer::timeout, this, &FolderMan::slotEtagPollTimerTimeout);
120120
_etagPollTimer.start();
121121

@@ -833,29 +833,19 @@ void FolderMan::slotStartScheduledFolderSync()
833833

834834
void FolderMan::slotEtagPollTimerTimeout()
835835
{
836-
ConfigFile cfg;
837-
auto polltime = cfg.remotePollInterval();
838-
839836
for (auto *f : qAsConst(_folderMap)) {
840837
if (!f) {
841838
continue;
842839
}
843-
if (f->isSyncRunning()) {
844-
continue;
845-
}
846840
if (_scheduledFolders.contains(f)) {
847841
continue;
848842
}
849843
if (_disabledFolders.contains(f)) {
850844
continue;
851845
}
852-
if (f->etagJob() || f->isBusy() || !f->canSync()) {
853-
continue;
854-
}
855-
if (f->msecSinceLastSync() < polltime) {
856-
continue;
846+
if (f->dueToSync()) {
847+
QMetaObject::invokeMethod(f, &Folder::slotRunEtagJob, Qt::QueuedConnection);
857848
}
858-
QMetaObject::invokeMethod(f, "slotRunEtagJob", Qt::QueuedConnection);
859849
}
860850
}
861851

@@ -916,7 +906,8 @@ void FolderMan::slotScheduleFolderByTime()
916906
auto msecsSinceSync = f->msecSinceLastSync();
917907

918908
// Possibly it's just time for a new sync run
919-
bool forceSyncIntervalExpired = msecsSinceSync > ConfigFile().forceSyncInterval();
909+
const auto pta = f->accountState()->account()->capabilities().remotePollInterval();
910+
bool forceSyncIntervalExpired = msecsSinceSync > ConfigFile().forceSyncInterval(pta);
920911
if (forceSyncIntervalExpired) {
921912
qCInfo(lcFolderMan) << "Scheduling folder" << f->alias()
922913
<< "because it has been" << msecsSinceSync.count() << "ms "

src/libsync/capabilities.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ int Capabilities::defaultPermissions() const
103103
return _fileSharingCapabilities.value(QStringLiteral("default_permissions"), 1).toInt();
104104
}
105105

106+
std::chrono::seconds Capabilities::remotePollInterval() const
107+
{
108+
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::milliseconds(_capabilities.value(QStringLiteral("core")).toMap().value(QStringLiteral("pollinterval")).toInt()));
109+
}
110+
106111
bool Capabilities::notificationsAvailable() const
107112
{
108113
// We require the OCS style API in 9.x, can't deal with the REST one only found in 8.2

src/libsync/capabilities.h

+6
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ class OWNCLOUDSYNC_EXPORT Capabilities
7575
bool sharePublicLinkEnforceExpireDate() const;
7676
bool sharePublicLinkMultiple() const;
7777
bool shareResharing() const;
78+
/** Remote Poll interval.
79+
*
80+
* returns the requested poll interval in seconds to be used by the client.
81+
* @returns 0 if no capability is set.
82+
*/
83+
std::chrono::seconds remotePollInterval() const;
7884

7985
// TODO: return SharePermission
8086
int defaultPermissions() const;

src/libsync/configfile.cpp

+13-6
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#include <QOperatingSystemVersion>
4141
#include <QStandardPaths>
4242

43-
#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds
4443
#define DEFAULT_MAX_LOG_LINES 20000
4544

4645
namespace OCC {
@@ -94,6 +93,7 @@ const QString moveToTrashC() { return QStringLiteral("moveToTrash"); }
9493
}
9594

9695
QString ConfigFile::_confDir = QString();
96+
const std::chrono::seconds DefaultRemotePollInterval { 30 }; // default remote poll time in milliseconds
9797

9898
static chrono::milliseconds millisecondsValue(const QSettings &setting, const QString &key,
9999
chrono::milliseconds defaultValue)
@@ -404,7 +404,7 @@ bool ConfigFile::dataExists(const QString &group, const QString &key) const
404404
return settings.contains(key);
405405
}
406406

407-
chrono::milliseconds ConfigFile::remotePollInterval(const QString &connection) const
407+
chrono::milliseconds ConfigFile::remotePollInterval(std::chrono::seconds defaultVal, const QString &connection) const
408408
{
409409
QString con(connection);
410410
if (connection.isEmpty())
@@ -413,11 +413,18 @@ chrono::milliseconds ConfigFile::remotePollInterval(const QString &connection) c
413413
QSettings settings(configFile(), QSettings::IniFormat);
414414
settings.beginGroup(con);
415415

416-
auto defaultPollInterval = chrono::milliseconds(DEFAULT_REMOTE_POLL_INTERVAL);
416+
auto defaultPollInterval { DefaultRemotePollInterval };
417+
418+
// The server default-capabilities is set to 60, which is, if interpreted in milliseconds,
419+
// pretty small. If the value is above 5 seconds, it was set intentionally.
420+
// Server admins have to set the value in Milliseconds!
421+
if (defaultVal > chrono::seconds(5)) {
422+
defaultPollInterval = defaultVal;
423+
}
417424
auto remoteInterval = millisecondsValue(settings, remotePollIntervalC(), defaultPollInterval);
418425
if (remoteInterval < chrono::seconds(5)) {
419-
qCWarning(lcConfigFile) << "Remote Interval is less than 5 seconds, reverting to" << DEFAULT_REMOTE_POLL_INTERVAL;
420426
remoteInterval = defaultPollInterval;
427+
qCWarning(lcConfigFile) << "Remote Interval is less than 5 seconds, reverting to" << remoteInterval.count();
421428
}
422429
return remoteInterval;
423430
}
@@ -438,9 +445,9 @@ void ConfigFile::setRemotePollInterval(chrono::milliseconds interval, const QStr
438445
settings.sync();
439446
}
440447

441-
chrono::milliseconds ConfigFile::forceSyncInterval(const QString &connection) const
448+
chrono::milliseconds ConfigFile::forceSyncInterval(std::chrono::seconds remoteFromCapabilities, const QString &connection) const
442449
{
443-
auto pollInterval = remotePollInterval(connection);
450+
auto pollInterval = remotePollInterval(remoteFromCapabilities, connection);
444451

445452
QString con(connection);
446453
if (connection.isEmpty())

src/libsync/configfile.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ class OWNCLOUDSYNC_EXPORT ConfigFile
6464
bool passwordStorageAllowed(const QString &connection = QString());
6565

6666
/* Server poll interval in milliseconds */
67-
std::chrono::milliseconds remotePollInterval(const QString &connection = QString()) const;
67+
std::chrono::milliseconds remotePollInterval(std::chrono::seconds defaultVal, const QString &connection = QString()) const;
6868
/* Set poll interval. Value in milliseconds has to be larger than 5000 */
6969
void setRemotePollInterval(std::chrono::milliseconds interval, const QString &connection = QString());
7070

7171
/* Interval to check for new notifications */
7272
std::chrono::milliseconds notificationRefreshInterval(const QString &connection = QString()) const;
7373

7474
/* Force sync interval, in milliseconds */
75-
std::chrono::milliseconds forceSyncInterval(const QString &connection = QString()) const;
75+
std::chrono::milliseconds forceSyncInterval(std::chrono::seconds remoteFromCapabilities, const QString &connection = QString()) const;
7676

7777
/**
7878
* Interval in milliseconds within which full local discovery is required

0 commit comments

Comments
 (0)