Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poll interval from capabilities #8777

Merged
merged 15 commits into from
Aug 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelog/unreleased/8780
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Enhancement: Consider a remote poll interval coming with the server capabilities

This way, admins can configure the remote sync poll interval of clients through
the capabilities settings of the server. Note that the setting in the server
capabilities needs to be done in milliseconds. Default is 30 seconds.
dragotin marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the current implementation in core, see https://github.com/owncloud/core/blob/eebd754771a99bc44820eb67a6d57cea238e6b86/lib/private/OCS/CoreCapabilities.php#L54
the default setting is 60, see code below

public function getCapabilities() {
		return [
			'core' => [
				'pollinterval' => $this->config->getSystemValue('pollinterval', 60),

Either there is some math magic behind in desktop, or the changelog text needs to be revised.

@jnweiger @TheOneRing @michaelstingl

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either there is some math magic behind in desktop, or the changelog text needs to be revised.

I don't see the problem. Please elaborate.

Copy link
Contributor

@mmattel mmattel Aug 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the text more clear I propose the following:

Note, the default client value is 30 seconds, if there is no change in the server sided default polling interval settings of 60 seconds. Any change on the server sided config polling interval setting, which must be made in milliseconds and has a higher value than 5000, is treated as a new client polling interval value.


https://github.com/owncloud/client/issues/5947
https://github.com/owncloud/client/issues/8780
https://github.com/owncloud/client/pull/8777
3 changes: 2 additions & 1 deletion src/gui/accountstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ void AccountState::checkConnectivity(bool blockJobs)

// IF the account is connected the connection check can be skipped
// if the last successful etag check job is not so long ago.
const auto polltime = std::chrono::duration_cast<std::chrono::seconds>(ConfigFile().remotePollInterval());
const auto pta = account()->capabilities().remotePollInterval();
const auto polltime = std::chrono::duration_cast<std::chrono::seconds>(ConfigFile().remotePollInterval(pta));
const auto elapsed = _timeOfLastETagCheck.secsTo(QDateTime::currentDateTimeUtc());
if (!blockJobs && isConnected() && _timeOfLastETagCheck.isValid()
&& elapsed <= polltime.count()) {
Expand Down
23 changes: 23 additions & 0 deletions src/gui/folder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Folder::Folder(const FolderDefinition &definition,
{
_timeSinceLastSyncStart.start();
_timeSinceLastSyncDone.start();
_timeSinceLastEtagCheckDone.start();

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

bool Folder::dueToSync() const
{
// conditions taken from previous folderman implementation
if (isSyncRunning() || etagJob() || isBusy() || !canSync()) {
return false;
}

ConfigFile cfg;
// the default poll time of 30 seconds as it had been in the client forever.
// Now with https://github.com/owncloud/client/pull/8777 also the server capabilities are considered.
const auto pta = accountState()->account()->capabilities().remotePollInterval();
const auto polltime = cfg.remotePollInterval(pta);

const auto timeSinceLastSync = std::chrono::milliseconds(_timeSinceLastEtagCheckDone.elapsed());
qCInfo(lcFolder) << "dueToSync:" << alias() << timeSinceLastSync.count() << " < " << polltime.count();
if (timeSinceLastSync >= polltime) {
return true;
}
return false;
}

void Folder::setSyncPaused(bool paused)
{
if (paused == _definition.paused) {
Expand Down Expand Up @@ -343,6 +365,7 @@ void Folder::slotRunEtagJob()
_requestEtagJob->setTimeout(60 * 1000);
// check if the etag is different when retrieved
QObject::connect(_requestEtagJob.data(), &RequestEtagJob::etagRetreived, this, &Folder::etagRetreived);
QObject::connect(_requestEtagJob.data(), &RequestEtagJob::finishedWithResult, this, [=](const HttpResult<QByteArray>) { _timeSinceLastEtagCheckDone.start(); });
FolderMan::instance()->slotScheduleETagJob(alias(), _requestEtagJob);
// The _requestEtagJob is auto deleting itself on finish. Our guard pointer _requestEtagJob will then be null.
}
Expand Down
12 changes: 10 additions & 2 deletions src/gui/folder.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ class Folder : public QObject
*/
bool canSync() const;

/**
* Returns true if the folder needs sync poll interval wise, and can
* sync due to its internal state
*/
bool dueToSync() const;

void prepareToSync();

/**
Expand Down Expand Up @@ -224,7 +230,7 @@ class Folder : public QObject
SyncEngine &syncEngine() { return *_engine; }
Vfs &vfs() { return *_vfs; }

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

public slots:

void slotRunEtagJob();

/**
* terminate the current sync run
*/
Expand Down Expand Up @@ -373,7 +381,6 @@ private slots:
void slotTransmissionProgress(const ProgressInfo &pi);
void slotItemCompleted(const SyncFileItemPtr &);

void slotRunEtagJob();
void etagRetreived(const QByteArray &, const QDateTime &tp);
void etagRetrievedFromSyncEngine(const QByteArray &, const QDateTime &time);

Expand Down Expand Up @@ -445,6 +452,7 @@ private slots:
QScopedPointer<SyncEngine> _engine;
QPointer<RequestEtagJob> _requestEtagJob;
QByteArray _lastEtag;
QElapsedTimer _timeSinceLastEtagCheckDone;
QElapsedTimer _timeSinceLastSyncDone;
QElapsedTimer _timeSinceLastSyncStart;
QElapsedTimer _timeSinceLastFullLocalDiscovery;
Expand Down
25 changes: 8 additions & 17 deletions src/gui/folderman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ FolderMan::FolderMan(QObject *parent)

_socketApi.reset(new SocketApi);

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

Expand Down Expand Up @@ -833,29 +833,19 @@ void FolderMan::slotStartScheduledFolderSync()

void FolderMan::slotEtagPollTimerTimeout()
{
ConfigFile cfg;
auto polltime = cfg.remotePollInterval();

for (auto *f : qAsConst(_folderMap)) {
if (!f) {
continue;
}
if (f->isSyncRunning()) {
continue;
}
if (_scheduledFolders.contains(f)) {
continue;
}
if (_disabledFolders.contains(f)) {
continue;
}
if (f->etagJob() || f->isBusy() || !f->canSync()) {
continue;
}
if (f->msecSinceLastSync() < polltime) {
continue;
if (f->dueToSync()) {
QMetaObject::invokeMethod(f, &Folder::slotRunEtagJob, Qt::QueuedConnection);
}
QMetaObject::invokeMethod(f, "slotRunEtagJob", Qt::QueuedConnection);
}
}

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

// Possibly it's just time for a new sync run
bool forceSyncIntervalExpired = msecsSinceSync > ConfigFile().forceSyncInterval();
const auto pta = f->accountState()->account()->capabilities().remotePollInterval();
bool forceSyncIntervalExpired = msecsSinceSync > ConfigFile().forceSyncInterval(pta);
if (forceSyncIntervalExpired) {
qCInfo(lcFolderMan) << "Scheduling folder" << f->alias()
<< "because it has been" << msecsSinceSync.count() << "ms "
Expand Down
5 changes: 5 additions & 0 deletions src/libsync/capabilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ int Capabilities::defaultPermissions() const
return _fileSharingCapabilities.value(QStringLiteral("default_permissions"), 1).toInt();
}

std::chrono::seconds Capabilities::remotePollInterval() const
{
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::milliseconds(_capabilities.value(QStringLiteral("core")).toMap().value(QStringLiteral("pollinterval")).toInt()));
}

bool Capabilities::notificationsAvailable() const
{
// We require the OCS style API in 9.x, can't deal with the REST one only found in 8.2
Expand Down
6 changes: 6 additions & 0 deletions src/libsync/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ class OWNCLOUDSYNC_EXPORT Capabilities
bool sharePublicLinkEnforceExpireDate() const;
bool sharePublicLinkMultiple() const;
bool shareResharing() const;
/** Remote Poll interval.
*
* returns the requested poll interval in seconds to be used by the client.
* @returns 0 if no capability is set.
*/
std::chrono::seconds remotePollInterval() const;

// TODO: return SharePermission
int defaultPermissions() const;
Expand Down
19 changes: 13 additions & 6 deletions src/libsync/configfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
#include <QOperatingSystemVersion>
#include <QStandardPaths>

#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds
#define DEFAULT_MAX_LOG_LINES 20000

namespace OCC {
Expand Down Expand Up @@ -94,6 +93,7 @@ const QString moveToTrashC() { return QStringLiteral("moveToTrash"); }
}

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

static chrono::milliseconds millisecondsValue(const QSettings &setting, const QString &key,
chrono::milliseconds defaultValue)
Expand Down Expand Up @@ -404,7 +404,7 @@ bool ConfigFile::dataExists(const QString &group, const QString &key) const
return settings.contains(key);
}

chrono::milliseconds ConfigFile::remotePollInterval(const QString &connection) const
chrono::milliseconds ConfigFile::remotePollInterval(std::chrono::seconds defaultVal, const QString &connection) const
{
QString con(connection);
if (connection.isEmpty())
Expand All @@ -413,11 +413,18 @@ chrono::milliseconds ConfigFile::remotePollInterval(const QString &connection) c
QSettings settings(configFile(), QSettings::IniFormat);
settings.beginGroup(con);

auto defaultPollInterval = chrono::milliseconds(DEFAULT_REMOTE_POLL_INTERVAL);
auto defaultPollInterval { DefaultRemotePollInterval };
TheOneRing marked this conversation as resolved.
Show resolved Hide resolved

// The server default-capabilities is set to 60, which is, if interpreted in milliseconds,
// pretty small. If the value is above 5 seconds, it was set intentionally.
// Server admins have to set the value in Milliseconds!
if (defaultVal > chrono::seconds(5)) {
defaultPollInterval = defaultVal;
}
auto remoteInterval = millisecondsValue(settings, remotePollIntervalC(), defaultPollInterval);
if (remoteInterval < chrono::seconds(5)) {
qCWarning(lcConfigFile) << "Remote Interval is less than 5 seconds, reverting to" << DEFAULT_REMOTE_POLL_INTERVAL;
remoteInterval = defaultPollInterval;
qCWarning(lcConfigFile) << "Remote Interval is less than 5 seconds, reverting to" << remoteInterval.count();
}
return remoteInterval;
}
Expand All @@ -438,9 +445,9 @@ void ConfigFile::setRemotePollInterval(chrono::milliseconds interval, const QStr
settings.sync();
}

chrono::milliseconds ConfigFile::forceSyncInterval(const QString &connection) const
chrono::milliseconds ConfigFile::forceSyncInterval(std::chrono::seconds remoteFromCapabilities, const QString &connection) const
{
auto pollInterval = remotePollInterval(connection);
auto pollInterval = remotePollInterval(remoteFromCapabilities, connection);

QString con(connection);
if (connection.isEmpty())
Expand Down
4 changes: 2 additions & 2 deletions src/libsync/configfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ class OWNCLOUDSYNC_EXPORT ConfigFile
bool passwordStorageAllowed(const QString &connection = QString());

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

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

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

/**
* Interval in milliseconds within which full local discovery is required
Expand Down