DBus server: add source status and progress for restore (MB#8144)
Generate and send source statuses and progress to dbus clients. For source modes in statuses, 'restore-from-backup' is sent once a source is restored. For progress, the granularity is source level. Thus, the progress is simply calculated based on the number of sources and how many of them that have been completed. To report source status and progress, SyncContext::restore should have a mechanism to give out events to dbus server. Here 'displaySourceProgress' is re-used. Some synthesis events are simulated in restore. To follow up the way of 'displaySourceProgress', a pseudo mode 'SYNC_RESTORE_FROM_BACKUP' is defined for source sync mode. This is treated as a special sync mode only for restore from backup. Also add test code in testRestoreByRef to check source status and progress.
This commit is contained in:
parent
419199562f
commit
1d309f51af
|
@ -907,6 +907,10 @@ class Session : public DBusObjectHelper,
|
|||
/** restore used */
|
||||
string m_restoreDir;
|
||||
bool m_restoreBefore;
|
||||
/** the total number of sources to be restored */
|
||||
int m_restoreSrcTotal;
|
||||
/** the number of sources that have been restored */
|
||||
int m_restoreSrcEnd;
|
||||
|
||||
enum RunOperation {
|
||||
OP_SYNC = 0,
|
||||
|
@ -1855,6 +1859,8 @@ Session::Session(DBusServer &server,
|
|||
m_statusTimer(100),
|
||||
m_progressTimer(50),
|
||||
m_restoreBefore(true),
|
||||
m_restoreSrcTotal(0),
|
||||
m_restoreSrcEnd(0),
|
||||
m_runOperation(OP_SYNC),
|
||||
emitStatus(*this, "StatusChanged"),
|
||||
emitProgress(*this, "ProgressChanged")
|
||||
|
@ -1940,58 +1946,96 @@ void Session::sourceProgress(sysync::TProgressEventEnum type,
|
|||
SyncSource &source,
|
||||
int32_t extra1, int32_t extra2, int32_t extra3)
|
||||
{
|
||||
SourceProgress &progress = m_sourceProgress[source.getName()];
|
||||
SourceStatus &status = m_sourceStatus[source.getName()];
|
||||
switch(type) {
|
||||
case sysync::PEV_SYNCSTART:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
m_progData.setStep(ProgressData::PRO_SYNC_UNINIT);
|
||||
fireProgress();
|
||||
switch(m_runOperation) {
|
||||
case OP_SYNC: {
|
||||
SourceProgress &progress = m_sourceProgress[source.getName()];
|
||||
SourceStatus &status = m_sourceStatus[source.getName()];
|
||||
switch(type) {
|
||||
case sysync::PEV_SYNCSTART:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
m_progData.setStep(ProgressData::PRO_SYNC_UNINIT);
|
||||
fireProgress();
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_SYNCEND:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
status.set(PrettyPrintSyncMode(source.getFinalSyncMode()), "done", extra1);
|
||||
fireStatus(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_PREPARING:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
progress.m_phase = "preparing";
|
||||
progress.m_prepareCount = extra1;
|
||||
progress.m_prepareTotal = extra2;
|
||||
m_progData.itemPrepare();
|
||||
fireProgress(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_ITEMSENT:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
progress.m_phase = "sending";
|
||||
progress.m_sendCount = extra1;
|
||||
progress.m_sendTotal = extra2;
|
||||
fireProgress(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_ITEMRECEIVED:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
progress.m_phase = "receiving";
|
||||
progress.m_receiveCount = extra1;
|
||||
progress.m_receiveTotal = extra2;
|
||||
m_progData.itemReceive(source.getName(), extra1, extra2);
|
||||
fireProgress(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_ALERTED:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
status.set(PrettyPrintSyncMode(source.getFinalSyncMode()), "running", 0);
|
||||
fireStatus(true);
|
||||
m_progData.setStep(ProgressData::PRO_SYNC_DATA);
|
||||
m_progData.addSyncMode(source.getFinalSyncMode());
|
||||
fireProgress();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_SYNCEND:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
status.set(PrettyPrintSyncMode(source.getFinalSyncMode()), "done", extra1);
|
||||
fireStatus(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_PREPARING:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
progress.m_phase = "preparing";
|
||||
progress.m_prepareCount = extra1;
|
||||
progress.m_prepareTotal = extra2;
|
||||
m_progData.itemPrepare();
|
||||
fireProgress(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_ITEMSENT:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
progress.m_phase = "sending";
|
||||
progress.m_sendCount = extra1;
|
||||
progress.m_sendTotal = extra2;
|
||||
fireProgress(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_ITEMRECEIVED:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
progress.m_phase = "receiving";
|
||||
progress.m_receiveCount = extra1;
|
||||
progress.m_receiveTotal = extra2;
|
||||
m_progData.itemReceive(source.getName(), extra1, extra2);
|
||||
fireProgress(true);
|
||||
}
|
||||
break;
|
||||
case sysync::PEV_ALERTED:
|
||||
if(source.getFinalSyncMode() != SYNC_NONE) {
|
||||
status.set(PrettyPrintSyncMode(source.getFinalSyncMode()), "running", 0);
|
||||
fireStatus(true);
|
||||
m_progData.setStep(ProgressData::PRO_SYNC_DATA);
|
||||
m_progData.addSyncMode(source.getFinalSyncMode());
|
||||
fireProgress();
|
||||
}
|
||||
case OP_RESTORE: {
|
||||
switch(type) {
|
||||
case sysync::PEV_ALERTED:
|
||||
// count the total number of sources to be restored
|
||||
m_restoreSrcTotal++;
|
||||
break;
|
||||
case sysync::PEV_SYNCSTART: {
|
||||
if (source.getFinalSyncMode() != SYNC_NONE) {
|
||||
SourceStatus &status = m_sourceStatus[source.getName()];
|
||||
// set statuses as 'restore-from-backup'
|
||||
status.set(PrettyPrintSyncMode(source.getFinalSyncMode()), "running", 0);
|
||||
fireStatus(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sysync::PEV_SYNCEND: {
|
||||
if (source.getFinalSyncMode() != SYNC_NONE) {
|
||||
m_restoreSrcEnd++;
|
||||
SourceStatus &status = m_sourceStatus[source.getName()];
|
||||
status.set(PrettyPrintSyncMode(source.getFinalSyncMode()), "done", 0);
|
||||
m_progress = 100 * m_restoreSrcEnd / m_restoreSrcTotal;
|
||||
fireStatus(true);
|
||||
fireProgress(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2087,6 +2131,14 @@ void Session::restore(const string &dir, bool before, const std::vector<std::str
|
|||
m_restoreDir = dir;
|
||||
m_runOperation = OP_RESTORE;
|
||||
|
||||
// initiate status and progress and sourceProgress is not calculated currently
|
||||
BOOST_FOREACH(const std::string source,
|
||||
m_sync->getSyncSources()) {
|
||||
m_sourceStatus[source];
|
||||
}
|
||||
fireProgress(true);
|
||||
fireStatus(true);
|
||||
|
||||
g_main_loop_quit(loop);
|
||||
}
|
||||
|
||||
|
|
|
@ -1049,51 +1049,57 @@ void SyncContext::displaySourceProgress(sysync::TProgressEventEnum type,
|
|||
/* datastore alerted (extra1=0 for normal, 1 for slow, 2 for first time slow,
|
||||
extra2=1 for resumed session,
|
||||
extra3 0=twoway, 1=fromserver, 2=fromclient */
|
||||
SE_LOG_INFO(NULL, NULL, "%s: %s %s sync%s",
|
||||
source.getName(),
|
||||
extra2 ? "resuming" : "starting",
|
||||
extra1 == 0 ? "normal" :
|
||||
extra1 == 1 ? "slow" :
|
||||
extra1 == 2 ? "first time" :
|
||||
"unknown",
|
||||
extra3 == 0 ? ", two-way" :
|
||||
extra3 == 1 ? " from server" :
|
||||
extra3 == 2 ? " from client" :
|
||||
", unknown direction");
|
||||
|
||||
SyncMode mode = SYNC_NONE;
|
||||
switch (extra1) {
|
||||
case 0:
|
||||
switch (extra3) {
|
||||
// -1 is used for alerting a restore from backup. Synthesis won't use this
|
||||
if (extra1 != -1) {
|
||||
SE_LOG_INFO(NULL, NULL, "%s: %s %s sync%s",
|
||||
source.getName(),
|
||||
extra2 ? "resuming" : "starting",
|
||||
extra1 == 0 ? "normal" :
|
||||
extra1 == 1 ? "slow" :
|
||||
extra1 == 2 ? "first time" :
|
||||
"unknown",
|
||||
extra3 == 0 ? ", two-way" :
|
||||
extra3 == 1 ? " from server" :
|
||||
extra3 == 2 ? " from client" :
|
||||
", unknown direction");
|
||||
|
||||
SyncMode mode = SYNC_NONE;
|
||||
switch (extra1) {
|
||||
case 0:
|
||||
mode = SYNC_TWO_WAY;
|
||||
switch (extra3) {
|
||||
case 0:
|
||||
mode = SYNC_TWO_WAY;
|
||||
break;
|
||||
case 1:
|
||||
mode = SYNC_ONE_WAY_FROM_SERVER;
|
||||
break;
|
||||
case 2:
|
||||
mode = SYNC_ONE_WAY_FROM_CLIENT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
mode = SYNC_ONE_WAY_FROM_SERVER;
|
||||
break;
|
||||
case 2:
|
||||
mode = SYNC_ONE_WAY_FROM_CLIENT;
|
||||
switch (extra3) {
|
||||
case 0:
|
||||
mode = SYNC_SLOW;
|
||||
break;
|
||||
case 1:
|
||||
mode = SYNC_REFRESH_FROM_SERVER;
|
||||
break;
|
||||
case 2:
|
||||
mode = SYNC_REFRESH_FROM_CLIENT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
switch (extra3) {
|
||||
case 0:
|
||||
mode = SYNC_SLOW;
|
||||
break;
|
||||
case 1:
|
||||
mode = SYNC_REFRESH_FROM_SERVER;
|
||||
break;
|
||||
case 2:
|
||||
mode = SYNC_REFRESH_FROM_CLIENT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
source.recordFinalSyncMode(mode);
|
||||
source.recordFirstSync(extra1 == 2);
|
||||
source.recordResumeSync(extra2 == 1);
|
||||
} else {
|
||||
SE_LOG_INFO(NULL, NULL, "%s: restore from backup", source.getName());
|
||||
source.recordFinalSyncMode(SYNC_RESTORE_FROM_BACKUP);
|
||||
}
|
||||
source.recordFinalSyncMode(mode);
|
||||
source.recordFirstSync(extra1 == 2);
|
||||
source.recordResumeSync(extra2 == 1);
|
||||
break;
|
||||
}
|
||||
case sysync::PEV_SYNCSTART:
|
||||
|
@ -1141,6 +1147,10 @@ void SyncContext::displaySourceProgress(sysync::TProgressEventEnum type,
|
|||
extra3=1 for resumed session) */
|
||||
if (source.getFinalSyncMode() == SYNC_NONE) {
|
||||
SE_LOG_INFO(NULL, NULL, "%s: inactive", source.getName());
|
||||
} else if(source.getFinalSyncMode() == SYNC_RESTORE_FROM_BACKUP) {
|
||||
SE_LOG_INFO(NULL, NULL, "%s: restore done %s",
|
||||
source.getName(),
|
||||
extra1 ? "unsuccessfully" : "successfully" );
|
||||
} else {
|
||||
SE_LOG_INFO(NULL, NULL, "%s: %s%s sync done %s",
|
||||
source.getName(),
|
||||
|
@ -2808,6 +2818,8 @@ void SyncContext::restore(const string &dirname, RestoreDatabase database)
|
|||
string datadump = database == DATABASE_BEFORE_SYNC ? "before" : "after";
|
||||
|
||||
BOOST_FOREACH(SyncSource *source, sourceList) {
|
||||
// fake a source alert event
|
||||
displaySourceProgress(sysync::PEV_ALERTED, *source, -1, 0, 0);
|
||||
source->open();
|
||||
}
|
||||
|
||||
|
@ -2826,12 +2838,12 @@ void SyncContext::restore(const string &dirname, RestoreDatabase database)
|
|||
BOOST_FOREACH(SyncSource *source, sourceList) {
|
||||
SyncSourceReport sourcereport;
|
||||
try {
|
||||
SE_LOG_DEBUG(NULL, NULL, "Restoring %s...", source->getName());
|
||||
displaySourceProgress(sysync::PEV_SYNCSTART, *source, 0, 0, 0);
|
||||
sourceList.restoreDatabase(*source,
|
||||
datadump,
|
||||
m_dryrun,
|
||||
sourcereport);
|
||||
SE_LOG_DEBUG(NULL, NULL, "... %s restored.", source->getName());
|
||||
displaySourceProgress(sysync::PEV_SYNCEND, *source, 0, 0, 0);
|
||||
report.addSyncSourceReport(source->getName(), sourcereport);
|
||||
} catch (...) {
|
||||
sourcereport.recordStatus(STATUS_FATAL);
|
||||
|
|
|
@ -56,6 +56,8 @@ std::string PrettyPrintSyncMode(SyncMode mode, bool userVisible)
|
|||
case SYNC_REFRESH_FROM_SERVER:
|
||||
case SA_SYNC_REFRESH_FROM_SERVER:
|
||||
return userVisible ? "refresh-from-server" : "SYNC_REFRESH_FROM_SERVER";
|
||||
case SYNC_RESTORE_FROM_BACKUP:
|
||||
return userVisible ? "restore-from-backup" : "SYNC_RESTORE_FROM_BACKUP";
|
||||
default:
|
||||
std::stringstream res;
|
||||
|
||||
|
|
|
@ -48,7 +48,10 @@ enum SyncMode {
|
|||
SA_SYNC_REFRESH_FROM_CLIENT = 208,
|
||||
SA_SYNC_ONE_WAY_FROM_SERVER = 209,
|
||||
SA_SYNC_REFRESH_FROM_SERVER = 210,
|
||||
|
||||
|
||||
// used by restore backend with backup data, a pseudo mode
|
||||
SYNC_RESTORE_FROM_BACKUP = 211,
|
||||
|
||||
SYNC_LAST = 220,
|
||||
/** error situation (in contrast to SYNC_NONE) */
|
||||
SYNC_INVALID = 255
|
||||
|
|
|
@ -1095,6 +1095,40 @@ class TestSessionAPIsDummy(unittest.TestCase, DBusUtil):
|
|||
self.session.Restore(dir, True, [], utf8_strings=True)
|
||||
loop.run()
|
||||
self.session.Detach()
|
||||
|
||||
# check recorded events in DBusUtil.events, first filter them
|
||||
statuses = []
|
||||
progresses = []
|
||||
for item in DBusUtil.events:
|
||||
if item[0] == "status":
|
||||
statuses.append(item[1])
|
||||
elif item[0] == "progress":
|
||||
progresses.append(item[1])
|
||||
|
||||
lastStatus = ""
|
||||
lastSources = {}
|
||||
statusPairs = {"": 0, "idle": 1, "running" : 2, "done" : 3}
|
||||
for status, error, sources in statuses:
|
||||
self.failIf(status == lastStatus and lastSources == sources)
|
||||
# no error
|
||||
self.failUnlessEqual(error, 0)
|
||||
for sourcename, value in sources.items():
|
||||
# no error
|
||||
self.failUnlessEqual(value[2], 0)
|
||||
# keep order: source status must also be unchanged or the next status
|
||||
if lastSources.has_key(sourcename):
|
||||
lastValue = lastSources[sourcename]
|
||||
self.failUnless(statusPairs[value[1]] >= statusPairs[lastValue[1]])
|
||||
|
||||
lastStatus = status
|
||||
lastSources = sources
|
||||
|
||||
# check increasing progress percentage
|
||||
lastPercent = 0
|
||||
for percent, sources in progresses:
|
||||
self.failIf(percent < lastPercent)
|
||||
lastPercent = percent
|
||||
|
||||
session.SetConfig(False, False, self.config, utf8_strings=True)
|
||||
#restore data after this session
|
||||
session.Restore(dir, False, ["addressbook", "calendar"], utf8_strings=True)
|
||||
|
|
Loading…
Reference in New Issue