// config_migrate.cpp
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "pch.h"
#include "../util/net/message.h"
#include "../util/unittest.h"
#include "../client/connpool.h"
#include "../client/model.h"
#include "../db/pdfile.h"
#include "../db/cmdline.h"
#include "server.h"
#include "config.h"
#include "chunk.h"
namespace mongo {
int ConfigServer::checkConfigVersion( bool upgrade ) {
int cur = dbConfigVersion();
if ( cur == VERSION )
return 0;
if ( cur == 0 ) {
ScopedDbConnection conn( _primary );
conn->insert( "config.version" , BSON( "_id" << 1 << "version" << VERSION ) );
pool.flush();
assert( VERSION == dbConfigVersion( conn.conn() ) );
conn.done();
return 0;
}
if ( cur == 2 ) {
// need to upgrade
assert( VERSION == 3 );
if ( ! upgrade ) {
log() << "newer version of mongo meta data\n"
<< "need to --upgrade after shutting all mongos down"
<< endl;
return -9;
}
ScopedDbConnection conn( _primary );
// do a backup
string backupName;
{
stringstream ss;
ss << "config-backup-" << terseCurrentTime(false);
backupName = ss.str();
}
log() << "backing up config to: " << backupName << endl;
conn->copyDatabase( "config" , backupName );
map hostToShard;
set shards;
// shards
{
unsigned n = 0;
auto_ptr c = conn->query( ShardNS::shard , BSONObj() );
while ( c->more() ) {
BSONObj o = c->next();
string host = o["host"].String();
string name = "";
BSONElement id = o["_id"];
if ( id.type() == String ) {
name = id.String();
}
else {
stringstream ss;
ss << "shard" << hostToShard.size();
name = ss.str();
}
hostToShard[host] = name;
shards.insert( name );
n++;
}
assert( n == hostToShard.size() );
assert( n == shards.size() );
conn->remove( ShardNS::shard , BSONObj() );
for ( map::iterator i=hostToShard.begin(); i != hostToShard.end(); i++ ) {
conn->insert( ShardNS::shard , BSON( "_id" << i->second << "host" << i->first ) );
}
}
// databases
{
auto_ptr c = conn->query( ShardNS::database , BSONObj() );
map newDBs;
unsigned n = 0;
while ( c->more() ) {
BSONObj old = c->next();
n++;
if ( old["name"].eoo() ) {
// already done
newDBs[old["_id"].String()] = old;
continue;
}
BSONObjBuilder b(old.objsize());
b.appendAs( old["name"] , "_id" );
BSONObjIterator i(old);
while ( i.more() ) {
BSONElement e = i.next();
if ( strcmp( "_id" , e.fieldName() ) == 0 ||
strcmp( "name" , e.fieldName() ) == 0 ) {
continue;
}
b.append( e );
}
BSONObj x = b.obj();
log() << old << "\n\t" << x << endl;
newDBs[old["name"].String()] = x;
}
assert( n == newDBs.size() );
conn->remove( ShardNS::database , BSONObj() );
for ( map::iterator i=newDBs.begin(); i!=newDBs.end(); i++ ) {
conn->insert( ShardNS::database , i->second );
}
}
// chunks
{
unsigned num = 0;
map chunks;
auto_ptr c = conn->query( ShardNS::chunk , BSONObj() );
while ( c->more() ) {
BSONObj x = c->next();
BSONObjBuilder b;
string id = Chunk::genID( x["ns"].String() , x["min"].Obj() );
b.append( "_id" , id );
BSONObjIterator i(x);
while ( i.more() ) {
BSONElement e = i.next();
if ( strcmp( e.fieldName() , "_id" ) == 0 )
continue;
b.append( e );
}
BSONObj n = b.obj();
log() << x << "\n\t" << n << endl;
chunks[id] = n;
num++;
}
assert( num == chunks.size() );
conn->remove( ShardNS::chunk , BSONObj() );
for ( map::iterator i=chunks.begin(); i!=chunks.end(); i++ ) {
conn->insert( ShardNS::chunk , i->second );
}
}
conn->update( "config.version" , BSONObj() , BSON( "_id" << 1 << "version" << VERSION ) );
conn.done();
pool.flush();
return 1;
}
log() << "don't know how to upgrade " << cur << " to " << VERSION << endl;
return -8;
}
}