Skip to content

Commit

Permalink
[buteo-sync-plugins-social] Implement rudimentary connection-loss han…
Browse files Browse the repository at this point in the history
…dling. Contributes to MER#885

This commit adds basic handling for connection loss during sync.
In most cases, it detects the connection loss and then skips any
database commit during finalisation.

In some cases where this is not possible, it commits as much data
as possible to ensure that the device remains usable, and then marks
the account for clean sync on next cycle.

Contributes to MER#885
  • Loading branch information
Chris Adams committed Apr 20, 2015
1 parent f3f7932 commit e2e6ce5
Show file tree
Hide file tree
Showing 15 changed files with 463 additions and 123 deletions.
17 changes: 11 additions & 6 deletions src/common/socialdbuteoplugin.cpp
Expand Up @@ -187,9 +187,11 @@ bool SocialdButeoPlugin::startSync()
return false;
}

void SocialdButeoPlugin::abortSync(Sync::SyncStatus)
void SocialdButeoPlugin::abortSync(Sync::SyncStatus status)
{
// TODO
// note: it seems buteo automatically calls abortSync on network connectivity loss...
SOCIALD_LOG_INFO("aborting sync with status:" << status);
m_socialNetworkSyncAdaptor->abortSync(status);
}

bool SocialdButeoPlugin::cleanUp()
Expand All @@ -213,12 +215,15 @@ Buteo::SyncResults SocialdButeoPlugin::getSyncResults() const
return m_syncResults;
}

void SocialdButeoPlugin::connectivityStateChanged(Sync::ConnectivityType, bool)
void SocialdButeoPlugin::connectivityStateChanged(Sync::ConnectivityType type, bool state)
{
// TODO, see TransportTracker.cpp:149
// See TransportTracker.cpp:149 for example
// Sync::CONNECTIVITY_INTERNET, true|false
// Kill all ongoing on false
// "Free" single shot sync on wlan?
SOCIALD_LOG_INFO("notified of connectivity change:" << type << state);
if (type == Sync::CONNECTIVITY_INTERNET && state == false) {
// we lost connectivity during sync.
abortSync(Sync::SYNC_CONNECTION_ERROR);
}
}

void SocialdButeoPlugin::syncStatusChanged()
Expand Down
26 changes: 26 additions & 0 deletions src/common/socialnetworksyncadaptor.cpp
Expand Up @@ -69,6 +69,8 @@ SocialNetworkSyncAdaptor::SocialNetworkSyncAdaptor(const QString &serviceName,
, m_accountSyncProfile(NULL)
, m_syncDb(new SocialNetworkSyncDatabase())
, m_status(SocialNetworkSyncAdaptor::Invalid)
, m_enabled(false)
, m_syncAborted(false)
, m_serviceName(serviceName)
{
}
Expand Down Expand Up @@ -101,13 +103,25 @@ QString SocialNetworkSyncAdaptor::serviceName() const
return m_serviceName;
}

bool SocialNetworkSyncAdaptor::syncAborted() const
{
return m_syncAborted;
}

void SocialNetworkSyncAdaptor::sync(const QString &dataType, int accountId)
{
Q_UNUSED(dataType)
Q_UNUSED(accountId)
SOCIALD_LOG_ERROR("sync() must be overridden by derived types");
}

void SocialNetworkSyncAdaptor::abortSync(Sync::SyncStatus status)
{
SOCIALD_LOG_INFO("forcing timeout of outstanding replies due to abort:" << status);
m_syncAborted = true;
triggerReplyTimeouts();
}

/*!
* \brief SocialNetworkSyncAdaptor::checkAccount
* \param account
Expand Down Expand Up @@ -346,6 +360,18 @@ void SocialNetworkSyncAdaptor::removeReplyTimeout(int accountId, QNetworkReply *
m_networkReplyTimeouts[accountId].remove(reply);
}

void SocialNetworkSyncAdaptor::triggerReplyTimeouts()
{
// if we've lost network connectivity, we should immediately timeout all replies.
Q_FOREACH (int accountId, m_networkReplyTimeouts.keys()) {
Q_FOREACH (QTimer *timer, m_networkReplyTimeouts[accountId]) {
timer->stop();
timer->setInterval(1);
timer->start();
}
}
}

QJsonObject SocialNetworkSyncAdaptor::parseJsonObjectReplyData(const QByteArray &replyData, bool *ok)
{
QJsonDocument jsonDocument = QJsonDocument::fromJson(replyData);
Expand Down
7 changes: 7 additions & 0 deletions src/common/socialnetworksyncadaptor.h
Expand Up @@ -87,8 +87,10 @@ class SocialNetworkSyncAdaptor : public QObject
Status status() const;
bool enabled() const;
QString serviceName() const;

virtual void sync(const QString &dataType, int accountId = 0);
virtual void purgeDataForOldAccount(int accountId, PurgeMode mode = SyncPurge) = 0;
virtual void abortSync(Sync::SyncStatus status);

Q_SIGNALS:
void statusChanged();
Expand All @@ -107,13 +109,17 @@ class SocialNetworkSyncAdaptor : public QObject
void setInitialActive(bool enabled);
void setFinishedInactive();

// whether the sync has been aborted (perhaps due to network connection loss)
bool syncAborted() const;

// Semaphore system
void incrementSemaphore(int accountId);
void decrementSemaphore(int accountId);

// network reply timeouts
void setupReplyTimeout(int accountId, QNetworkReply *reply);
void removeReplyTimeout(int accountId, QNetworkReply *reply);
void triggerReplyTimeouts();

// Parsing methods
static QJsonObject parseJsonObjectReplyData(const QByteArray &replyData, bool *ok);
Expand All @@ -131,6 +137,7 @@ protected Q_SLOTS:
SocialNetworkSyncDatabase *m_syncDb;
SocialNetworkSyncAdaptor::Status m_status;
bool m_enabled;
bool m_syncAborted;
QString m_serviceName;
QMap<int, int> m_accountSyncSemaphores;
QMap<int, QMap<QNetworkReply*, QTimer *> > m_networkReplyTimeouts;
Expand Down
Expand Up @@ -105,6 +105,12 @@ void FacebookCalendarSyncAdaptor::sync(const QString &dataTypeString, int accoun

void FacebookCalendarSyncAdaptor::finalCleanup()
{
if (syncAborted()) {
SOCIALD_LOG_INFO("sync aborted, won't commit database changes");
m_storage->close();
return;
}

// commit changes to db
if (m_storageNeedsSave) {
m_storage->save();
Expand Down Expand Up @@ -140,7 +146,6 @@ void FacebookCalendarSyncAdaptor::finalCleanup()
if (!m_storageNeedsSave || m_storage->save()) {
setGhostEventCleanupPerformed();
}

}

// done.
Expand Down
5 changes: 5 additions & 0 deletions src/facebook/facebook-contacts/facebookcontactsyncadaptor.cpp
Expand Up @@ -765,6 +765,11 @@ bool FacebookContactSyncAdaptor::storeToLocal(const QString &accessToken, int ac
{
Q_UNUSED(accessToken)

if (syncAborted()) {
SOCIALD_LOG_INFO("sync aborted, won't commit database changes");
return false;
}

// steps:
// 1) load current data from backend
// 2) determine delta (add/mod/rem)
Expand Down
Expand Up @@ -72,6 +72,7 @@ private Q_SLOTS:
private:
QContactManager *m_contactManager;
FacebookContactImageDownloader *m_workerObject;

QMap<int, QList<QContact> > m_remoteContacts; // accountId to contacts to save.
QMap<int, QList<QPair<QString, QVariantMap> > > m_queuedAvatarDownloads;

Expand Down
23 changes: 17 additions & 6 deletions src/facebook/facebook-images/facebookimagesyncadaptor.cpp
Expand Up @@ -93,14 +93,19 @@ void FacebookImageSyncAdaptor::beginSync(int accountId, const QString &accessTok
void FacebookImageSyncAdaptor::finalize(int accountId)
{
Q_UNUSED(accountId)
// Remove albums
m_db.removeAlbums(m_cachedAlbums.keys());

// Remove images
m_db.removeImages(m_removedImages);
if (syncAborted()) {
SOCIALD_LOG_INFO("sync aborted, won't commit database changes");
} else {
// Remove albums
m_db.removeAlbums(m_cachedAlbums.keys());

m_db.commit();
m_db.wait();
// Remove images
m_db.removeImages(m_removedImages);

m_db.commit();
m_db.wait();
}
}

void FacebookImageSyncAdaptor::requestData(int accountId,
Expand All @@ -109,6 +114,12 @@ void FacebookImageSyncAdaptor::requestData(int accountId,
const QString &fbUserId,
const QString &fbAlbumId)
{
if (syncAborted()) {
SOCIALD_LOG_DEBUG("skipping data request due to sync abort");
clearRemovalDetectionLists(); // don't perform server-side removal detection during this sync run.
return;
}

QUrl url;
if (!continuationUrl.isEmpty()) {
// fetch the next page.
Expand Down
Expand Up @@ -58,9 +58,13 @@ void FacebookNotificationSyncAdaptor::beginSync(int accountId, const QString &ac
void FacebookNotificationSyncAdaptor::finalize(int accountId)
{
Q_UNUSED(accountId)
m_db.purgeOldNotifications(OLD_NOTIFICATION_LIMIT_IN_DAYS);
m_db.sync();
m_db.wait();
if (syncAborted()) {
SOCIALD_LOG_INFO("sync aborted, won't commit database changes");
} else {
m_db.purgeOldNotifications(OLD_NOTIFICATION_LIMIT_IN_DAYS);
m_db.sync();
m_db.wait();
}
}

void FacebookNotificationSyncAdaptor::requestNotifications(int accountId, const QString &accessToken, const QString &until, const QString &pagingToken)
Expand Down
6 changes: 6 additions & 0 deletions src/facebook/facebook-signon/facebooksignonsyncadaptor.cpp
Expand Up @@ -112,6 +112,12 @@ void FacebookSignonSyncAdaptor::requestFinishedHandler()
reply->deleteLater();
removeReplyTimeout(accountId, reply);

if (syncAborted()) {
SOCIALD_LOG_INFO("sync aborted, skipping signon sync reply handling");
decrementSemaphore(accountId);
return;
}

bool ok = false;
QJsonObject parsed = parseJsonObjectReplyData(replyData, &ok);
if (!isError && ok && parsed.contains(QStringLiteral("id"))) {
Expand Down

0 comments on commit e2e6ce5

Please sign in to comment.