From 8f65a14db172570a9dfbaec9e0eda8a1b224c613 Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Tue, 17 Feb 2009 23:31:27 -0500 Subject: [PATCH] shard object cleaning, split, ShardKey api cleaning --- s/shard.cpp | 132 +++++++++++++++++++++++++++++++++++++++++++++---- s/shard.h | 48 +++++++++++++++--- s/shardkey.cpp | 18 ++++++- s/shardkey.h | 8 +-- 4 files changed, 185 insertions(+), 21 deletions(-) diff --git a/s/shard.cpp b/s/shard.cpp index d771049686f..f433ad9553b 100644 --- a/s/shard.cpp +++ b/s/shard.cpp @@ -21,8 +21,19 @@ #include "config.h" namespace mongo { + + // ------- Shard -------- Shard::Shard( ShardInfo * info , BSONObj data ) : _info( info ) , _data( data ){ + _min = _data.getObjectField( "min" ); + _max = _data.getObjectField( "max" ); + } + + Shard::Shard( const Shard& s ){ + _info = s._info; + _data = s._data.copy(); + _min = _data.getObjectField( "min" ); + _max = _data.getObjectField( "max" ); } string ShardInfo::modelServer() { @@ -30,15 +41,85 @@ namespace mongo { return configServer.modelServer(); } - void ShardInfo::serialize(BSONObjBuilder& to) { + bool Shard::contains( const BSONObj& obj ){ + return + _info->getShardKey().compare( getMin() , obj ) <= 0 && + _info->getShardKey().compare( obj , getMax() ) < 0; + } + + void Shard::split(){ + + BSONObj m = _info->getShardKey().middle( getMin() , getMax() ); + + { + BSONObjBuilder l; + l.append( "min" , _min ); + l.append( "max" , m ); + l.append( "server" , getServer() ); + _info->_shards.push_back( new Shard( _info , l.obj() ) ); + } + + { + BSONObjBuilder r; + r.append( "min" , m ); + r.append( "max" , _max ); + r.append( "server" , getServer() ); + _info->_shards.push_back( new Shard( _info , r.obj() ) ); + } + + for ( vector::iterator i=_info->_shards.begin(); i != _info->_shards.end(); i++ ){ + Shard * s = *i; + if ( s == this ){ + _info->_shards.erase( i ); + delete( s ); + break; + } + } + + } + + bool Shard::operator==( const Shard& s ){ + return + _info->getShardKey().compare( _min , s._min ) == 0 && + _info->getShardKey().compare( _max , s._max ) == 0 + ; + } + + + string Shard::toString() const { + return _data.toString(); + } + + // ------- ShardInfo -------- + + ShardInfo::ShardInfo( DBConfig * config ) : _config( config ){ + } + + ShardInfo::~ShardInfo(){ + for ( vector::iterator i=_shards.begin(); i != _shards.end(); i++ ){ + delete( *i ); + } + _shards.clear(); + } + + Shard& ShardInfo::findShard( const BSONObj & obj ){ + for ( vector::iterator i=_shards.begin(); i != _shards.end(); i++ ){ + Shard * s = *i; + if ( s->contains( obj ) ) + return *s; + } + throw UserException( "couldn't find a shard which should be impossible" ); + } + + void ShardInfo::serialize(BSONObjBuilder& to){ to.append( "ns", _ns ); to.append( "key" , _key.key() ); BSONObjBuilder shards; int num=0; - for ( vector::iterator i=_shards.begin(); i != _shards.end(); i++ ){ + for ( vector::iterator i=_shards.begin(); i != _shards.end(); i++ ){ string s = shards.numStr( num++ ); - shards.append( s.c_str() , i->_data ); + shards.append( s.c_str() , (*i)->_data ); } to.append( "shards" , shards.obj() ); } @@ -49,16 +130,17 @@ namespace mongo { _key.init( from.getObjectField( "key" ) ); - _shards.clear(); + assert( _shards.size() == 0 ); + BSONObj shards = from.getObjectField( "shards" ); if ( shards.isEmpty() ){ BSONObjBuilder all; - // TODO: server all.append( "min" , _key.globalMin() ); all.append( "max" , _key.globalMax() ); + all.append( "server" , _config ? _config->getPrimary() : "noserver" ); - _shards.push_back( Shard( this , all.obj() ) ); + _shards.push_back( new Shard( this , all.obj() ) ); } else { int num=0; @@ -67,16 +149,28 @@ namespace mongo { BSONObj next = shards.getObjectField( s.c_str() ); if ( next.isEmpty() ) break; - _shards.push_back( Shard( this , next ) ); + _shards.push_back( new Shard( this , next ) ); } } } + + string ShardInfo::toString() const { + stringstream ss; + ss << "ShardInfo: " << _ns << " key:" << _key.toString() << "\n"; + for ( vector::const_iterator i=_shards.begin(); i!=_shards.end(); i++ ){ + const Shard* s = *i; + ss << "\t" << s->toString() << "\n"; + } + return ss.str(); + } + + void shardObjTest(){ string ns = "alleyinsider.blog.posts"; BSONObj o = BSON( "ns" << ns << "key" << BSON( "num" << 1 ) ); - ShardInfo si; + ShardInfo si(0); si.unserialize( o ); assert( si.getns() == ns ); @@ -89,13 +183,33 @@ namespace mongo { log(2) << a << endl; { - ShardInfo si2; + ShardInfo si2(0); si2.unserialize( a ); BSONObjBuilder b2; si2.serialize( b2 ); assert( b2.obj().jsonString() == a.jsonString() ); } + { + BSONObj num = BSON( "num" << 5 ); + si.findShard( num ); + + assert( si.findShard( BSON( "num" << -1 ) ) == + si.findShard( BSON( "num" << 1 ) ) ); + + log(2) << "before split: " << si << endl; + si.findShard( num ).split(); + log(2) << "after split: " << si << endl; + + log() << "-1 : " << si.findShard( BSON( "num" << -1 ) ) << endl; + log() << " 1 : " << si.findShard( BSON( "num" << 1 ) ) << endl; + assert( si.findShard( BSON( "num" << -1 ) ) != + si.findShard( BSON( "num" << 1 ) ) ); + + } + + + log(1) << "shardObjTest passed" << endl; } diff --git a/s/shard.h b/s/shard.h index 9c5b2859259..a2c278774be 100644 --- a/s/shard.h +++ b/s/shard.h @@ -29,27 +29,45 @@ namespace mongo { + class DBConfig; class ShardInfo; - class Shard { + class Shard : public Stringable { public: - BSONObj getMin(){ - return _data.getObjectField( "min" ); + BSONObj& getMin(){ + return _min; } - BSONObj getMax(){ - return _data.getObjectField( "max" ); + BSONObj& getMax(){ + return _max; } string getServer(){ return _data.getStringField( "server" ); } + bool contains( const BSONObj& obj ); + + void split(); + + virtual string toString() const; + + bool operator==(const Shard& s); + + bool operator!=(const Shard& s){ + return ! ( *this == s ); + } + + Shard( const Shard& s ); + private: Shard( ShardInfo * info , BSONObj data ); ShardInfo * _info; BSONObj _data; + BSONObj _min; + BSONObj _max; + void _split( BSONObj& middle ); friend class ShardInfo; @@ -61,25 +79,39 @@ namespace mongo { shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200 , server : b } ] } */ - class ShardInfo : public Model { + class ShardInfo : public Model , public Stringable { public: + ShardInfo( DBConfig * config ); + virtual ~ShardInfo(); + string getns(){ return _ns; } + + Shard& findShard( const BSONObj & obj ); + + ShardKey& getShardKey(){ + return _key; + } virtual const char * getNS() { return "config.sharding"; } - + virtual void serialize(BSONObjBuilder& to); virtual void unserialize(BSONObj& from); virtual string modelServer(); + + virtual string toString() const; private: + DBConfig * _config; string _ns; ShardKey _key; - vector _shards; + vector _shards; + + friend class Shard; }; void shardObjTest(); diff --git a/s/shardkey.cpp b/s/shardkey.cpp index 796d648b868..fa095faf2a2 100644 --- a/s/shardkey.cpp +++ b/s/shardkey.cpp @@ -58,7 +58,7 @@ namespace mongo { b << _fieldName << (int)(0xfffffff); } - int ShardKey::compare( BSONObj& lObject , BSONObj& rObject ){ + int ShardKey::compare( const BSONObj& lObject , const BSONObj& rObject ) const { uassert( "not valid yet" , _fieldName ); BSONElement lElement = lObject[ _fieldsAndOrder.firstElement().fieldName() ]; @@ -78,6 +78,22 @@ namespace mongo { return 0; } + void ShardKey::middle( BSONObjBuilder & b , BSONObj & lObject , BSONObj & rObject ){ + BSONElement lElement = lObject[ _fieldsAndOrder.firstElement().fieldName() ]; + uassert( "left key doesn't have the shard key" , ! lElement.eoo() ); + uassert( "left key isn't number" , lElement.isNumber() ); + + BSONElement rElement = rObject[ _fieldsAndOrder.firstElement().fieldName() ]; + uassert( "right key doesn't have the shard key" , ! rElement.eoo() ); + uassert( "right key isn't number" , rElement.isNumber() ); + + b.append( _fieldName , ( lElement.number() + rElement.number() ) / 2 ); + } + + string ShardKey::toString() const { + return _fieldsAndOrder.toString(); + } + void shardKeyTest(){ ShardKey k( BSON( "key" << 1 ) ); diff --git a/s/shardkey.h b/s/shardkey.h index d5744fff46f..d82ab845e8b 100644 --- a/s/shardkey.h +++ b/s/shardkey.h @@ -33,15 +33,17 @@ namespace mongo { void globalMax( BSONObjBuilder & b ); BSONObj globalMax(){ BSONObjBuilder b; globalMax( b ); return b.obj(); } - void split( BSONObjBuilder & b , BSONObj & min , BSONObj & max ); - BSONObj split( BSONObj & min , BSONObj & max ){ BSONObjBuilder b; split( b , min , max ); return b.obj(); } + void middle( BSONObjBuilder & b , BSONObj & min , BSONObj & max ); + BSONObj middle( BSONObj & min , BSONObj & max ){ BSONObjBuilder b; middle( b , min , max ); return b.obj(); } - int compare( BSONObj& l , BSONObj& r ); + int compare( const BSONObj& l , const BSONObj& r ) const; BSONObj& key(){ return _fieldsAndOrder; } + virtual string toString() const; + private: void _init(); BSONObj _fieldsAndOrder;