SyncConfig + command line: enabled migration of config contexts

Because of the shared source property name changes
(evolutionsource/user/password -> database*), mixing old and new
configs inside the same context is not possible. Bumped
CONFIG_CONTEXT_MIN_VERSION and CONFIG_CONTEXT_CUR_VERSION to reflect
that and added the necessary code for migrating a context and all
peers inside it.

This is triggered by a) an automatic config migration in release mode
and b) an explicit --migrate of *any peer inside the context* or of
the context itself.
This commit is contained in:
Patrick Ohly 2011-02-01 22:14:22 +01:00
parent 65bd473dc2
commit f6c151b26c
4 changed files with 69 additions and 39 deletions

View file

@ -521,6 +521,17 @@ void Cmdline::finishCopy(const boost::shared_ptr<SyncConfig> &from,
}
}
void Cmdline::migratePeer(const std::string &fromPeer, const std::string &toPeer)
{
boost::shared_ptr<SyncConfig> from(new SyncConfig(fromPeer));
makeObsolete(from);
// hack: move to different target config for createSyncClient()
m_server = toPeer;
boost::shared_ptr<SyncContext> to(createSyncClient());
copyConfig(from, to, set<string>());
finishCopy(from, to);
}
/**
* Finds first instance of delimiter string in other string. In
* addition, it treats "\n\n" in a special way: that delimiter also
@ -733,6 +744,7 @@ bool Cmdline::run() {
// another config (template resp. old one). Migration also moves
// the old config.
boost::shared_ptr<SyncConfig> from;
string origPeer;
if (m_migrate) {
if (!m_sources.empty()) {
m_err << "ERROR: cannot migrate individual sources" << endl;
@ -755,20 +767,34 @@ bool Cmdline::run() {
// a context which itself is too old. In that case,
// the whole context and everything inside it needs to
// be migrated.
if (false && // TODO
!configureContext &&
from->getConfigVersion(CONFIG_LEVEL_CONTEXT, CONFIG_VERSION_MAX) < CONFIG_CONTEXT_MIN_VERSION) {
m_server = string("@") + context;
from.reset(new SyncConfig(m_server));
peer = "";
configureContext = true;
}
// cannot migrate context configs at the moment;
// will have to copy all peers inside it, too
if (configureContext) {
m_err << "ERROR: migrating context config '" << m_server << "' not implemented." << endl;
return false;
if (!configureContext) {
bool obsoleteContext = false;
if (from->getLayout() < SyncConfig::SHARED_LAYOUT) {
// check whether @default context exists and is too old;
// in that case migrate it first
SyncConfig target("@default");
if (target.exists() &&
target.getConfigVersion(CONFIG_LEVEL_CONTEXT, CONFIG_CUR_VERSION) <
CONFIG_CONTEXT_MIN_VERSION) {
// migrate all peers inside @default *and* the one outside
origPeer = m_server;
m_server = "@default";
obsoleteContext = true;
}
} else {
// config already is inside a context; need to check that context
if (from->getConfigVersion(CONFIG_LEVEL_CONTEXT, CONFIG_CUR_VERSION) <
CONFIG_CONTEXT_MIN_VERSION) {
m_server = string("@") + context;
obsoleteContext = true;
}
}
if (obsoleteContext) {
// hack: move to different config and back later
from.reset(new SyncConfig(m_server));
peer = "";
configureContext = true;
}
}
// rename on disk and point "from" to it
@ -933,7 +959,12 @@ bool Cmdline::run() {
// Now also migrate all peers inside context?
if (configureContext && m_migrate) {
// TODO...
BOOST_FOREACH(const string &peer, from->getPeers()) {
migratePeer(peer + from->getContextName(), peer + to->getContextName());
}
if (!origPeer.empty()) {
migratePeer(origPeer, origPeer + to->getContextName());
}
}
} else if (m_remove) {
if (m_dryrun) {
@ -2208,20 +2239,6 @@ protected:
context.setProperty("contextCurVersion", StringPrintf("%d", CONFIG_CONTEXT_CUR_VERSION - 1));
context.flush();
#if 1
// context migration not implemented and not needed yet
SyncContext::setStableRelease(true);
bool caught = false;
try {
SyncConfig config("scheduleworld");
config.prepareConfigForWrite();
} catch (const Exception &ex) {
caught = true;
CPPUNIT_ASSERT_EQUAL(string("migration of config '@default' failed"),
string(ex.what()));
}
CPPUNIT_ASSERT(caught);
#else
SyncContext::setStableRelease(false);
expectMigration("@default");
@ -2235,7 +2252,7 @@ protected:
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("Configured servers:\n"
" scheduleworld = CmdlineTest/syncevolution/default/peers/scheduleworld\n"
" scheduleworld.old = CmdlineTest/syncevolution/default/peers/scheduleworld.old\n",
" scheduleworld.old@default.old = CmdlineTest/syncevolution/default.old/peers/scheduleworld.old\n",
cmdline.m_out.str());
}
@ -2248,9 +2265,11 @@ protected:
// do the same migration with command line
SyncContext::setStableRelease(false);
rm_r(m_testDir + "/syncevolution/default/peers/scheduleworld");
CPPUNIT_ASSERT_EQUAL(0, rename((m_testDir + "/syncevolution/default/peers/scheduleworld.old").c_str(),
(m_testDir + "/syncevolution/default/peers/scheduleworld").c_str()));
rm_r(m_testDir + "/syncevolution/default");
CPPUNIT_ASSERT_EQUAL(0, rename((m_testDir + "/syncevolution/default.old/peers/scheduleworld.old").c_str(),
(m_testDir + "/syncevolution/default.old/peers/scheduleworld").c_str()));
CPPUNIT_ASSERT_EQUAL(0, rename((m_testDir + "/syncevolution/default.old").c_str(),
(m_testDir + "/syncevolution/default").c_str()));
{
TestCmdline cmdline("--migrate", "@default", NULL);
cmdline.doit();
@ -2264,10 +2283,9 @@ protected:
cmdline.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("Configured servers:\n"
" scheduleworld = CmdlineTest/syncevolution/default/peers/scheduleworld\n"
" scheduleworld.old = CmdlineTest/syncevolution/default/peers/scheduleworld.old\n",
" scheduleworld.old@default.old = CmdlineTest/syncevolution/default.old/peers/scheduleworld.old\n",
cmdline.m_out.str());
}
#endif
}

View file

@ -212,6 +212,11 @@ protected:
void finishCopy(const boost::shared_ptr<SyncConfig> &from,
const boost::shared_ptr<SyncContext> &to);
/**
* migrate peer config; target context must be ready
*/
void migratePeer(const std::string &fromPeer, const std::string &toPeer);
/**
* parse sync or source property
*

View file

@ -481,6 +481,12 @@ void SyncConfig::prepareConfigForWrite()
for (ConfigLevel level = CONFIG_LEVEL_ROOT;
level < CONFIG_LEVEL_MAX;
level = (ConfigLevel)(level + 1)) {
if (getLayout() < SHARED_LAYOUT &&
level < CONFIG_LEVEL_PEER) {
// old configs do not have explicit root or context,
// only check peer config itself
continue;
}
if (exists(level)) {
if (getConfigVersion(level, CONFIG_CUR_VERSION) < ConfigVersions[level][CONFIG_MIN_VERSION]) {
// release which created config will no longer be able to read

View file

@ -96,13 +96,14 @@ using namespace std;
* SyncEvolution < 1.2 had no versioning. It's format is 0.
* SyncEvolution 1.2:
* - config peer min/cur version 1, because
* a) of modified libsynthesis binfiles and
* b) evolutionsource->database, evolutionuser/password->databaseUser/Password
* of modified libsynthesis binfiles and
* - context min/cur version 1, because
* evolutionsource->database, evolutionuser/password->databaseUser/Password
*/
static const int CONFIG_ROOT_MIN_VERSION = 0;
static const int CONFIG_ROOT_CUR_VERSION = 0;
static const int CONFIG_CONTEXT_MIN_VERSION = 0;
static const int CONFIG_CONTEXT_CUR_VERSION = 0;
static const int CONFIG_CONTEXT_MIN_VERSION = 1;
static const int CONFIG_CONTEXT_CUR_VERSION = 1;
static const int CONFIG_PEER_MIN_VERSION = 1;
static const int CONFIG_PEER_CUR_VERSION = 1;