diff options
Diffstat (limited to 's/chunk.h')
-rw-r--r-- | s/chunk.h | 279 |
1 files changed, 158 insertions, 121 deletions
@@ -1,9 +1,4 @@ -// shard.h - -/* - A "shard" is a database (replica pair typically) which represents - one partition of the overall database. -*/ +// @file chunk.h /** * Copyright (C) 2008 10gen Inc. @@ -24,16 +19,17 @@ #pragma once #include "../pch.h" -#include "../client/dbclient.h" -#include "../client/model.h" + #include "../bson/util/atomic_int.h" +#include "../client/dbclient.h" +#include "../client/distlock.h" + #include "shardkey.h" #include "shard.h" -#include "config.h" #include "util.h" namespace mongo { - + class DBConfig; class Chunk; class ChunkRange; @@ -46,130 +42,187 @@ namespace mongo { // key is max for each Chunk or ChunkRange typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap; typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap; - + + typedef shared_ptr<ChunkManager> ChunkManagerPtr; + /** config.chunks { ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "localhost:30001" } - + x is in a shard iff min <= x < max - */ + */ class Chunk : boost::noncopyable, public boost::enable_shared_from_this<Chunk> { public: - Chunk( ChunkManager * info ); Chunk( ChunkManager * info , const BSONObj& min, const BSONObj& max, const Shard& shard); - - const BSONObj& getMin() const { return _min; } - const BSONObj& getMax() const { return _max; } - - void setMin(const BSONObj& o){ - _min = o; - } - void setMax(const BSONObj& o){ - _max = o; - } - - string getns() const; - Shard getShard() const { return _shard; } + // + // serialization support + // - void setShard( const Shard& shard ); - - bool contains( const BSONObj& obj ) const; + void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=0); + void unserialize(const BSONObj& from); - string toString() const; + // + // chunk boundary support + // - friend ostream& operator << (ostream& out, const Chunk& c){ return (out << c.toString()); } + const BSONObj& getMin() const { return _min; } + const BSONObj& getMax() const { return _max; } + void setMin(const BSONObj& o) { _min = o; } + void setMax(const BSONObj& o) { _max = o; } - bool operator==(const Chunk& s) const; - - bool operator!=(const Chunk& s) const{ - return ! ( *this == s ); - } - // if min/max key is pos/neg infinity bool minIsInf() const; bool maxIsInf() const; - BSONObj pickSplitPoint() const; - ChunkPtr split(); + bool contains( const BSONObj& obj ) const; - void pickSplitVector( vector<BSONObj>* splitPoints ) const; - ChunkPtr multiSplit( const vector<BSONObj>& splitPoints ); + string genID() const; + static string genID( const string& ns , const BSONObj& min ); + + // + // chunk version support + // + + void appendShortVersion( const char * name , BSONObjBuilder& b ); + + ShardChunkVersion getLastmod() const { return _lastmod; } + void setLastmod( ShardChunkVersion v ) { _lastmod = v; } + + // + // split support + // - /** - * @return size of shard in bytes - * talks to mongod to do this - */ - long getPhysicalSize() const; - - int countObjects(int maxcount=0) const; - /** * if the amount of data written nears the max size of a shard * then we check the real size, and if its too big, we split + * @return if something was split */ bool splitIfShould( long dataWritten ); - - /* + + /** + * Splits this chunk at a non-specificed split key to be chosen by the mongod holding this chunk. + * + * @param force if set to true, will split the chunk regardless if the split is really necessary size wise + * if set to false, will only split if the chunk has reached the currently desired maximum size + * @param res the object containing details about the split execution + * @return if found a key, return a pointer to the first chunk, otherwise return a null pointer + */ + ChunkPtr singleSplit( bool force , BSONObj& res ); + + /** + * Splits this chunk at the given key (or keys) + * + * @param splitPoints the vector of keys that should be used to divide this chunk + * @param res the object containing details about the split execution + * @return shared pointer to the first new Chunk or null pointer if failed + */ + ChunkPtr multiSplit( const vector<BSONObj>& splitPoints , BSONObj& res ); + + /** + * Asks the mongod holding this chunk to find a key that approximately divides this chunk in two + * + * @param medianKey the key that divides this chunk, if there is one, or empty + */ + void pickMedianKey( BSONObj& medianKey ) const; + + /** + * @param splitPoints vector to be filled in + * @param chunkSize chunk size to target in bytes + * @param maxPoints limits the number of split points that are needed, zero is max (optional) + * @param maxObjs limits the number of objects in each chunk, zero is as max (optional) + */ + void pickSplitVector( vector<BSONObj>& splitPoints , int chunkSize , int maxPoints = 0, int maxObjs = 0) const; + + // + // migration support + // + + /** * moves either this shard or newShard if it makes sense too + * * @return whether or not a shard was moved */ bool moveIfShould( ChunkPtr newShard = ChunkPtr() ); - bool moveAndCommit( const Shard& to , string& errmsg ); + /** + * Issues a migrate request for this chunk + * + * @param to shard to move this chunk to + * @param chunSize maximum number of bytes beyond which the migrate should no go trhough + * @param res the object containing details about the migrate execution + * @return true if move was successful + */ + bool moveAndCommit( const Shard& to , long long chunkSize , BSONObj& res ); - const char * getNS(){ return "config.chunks"; } - void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=0); - void unserialize(const BSONObj& from); - string modelServer() const; - - void appendShortVersion( const char * name , BSONObjBuilder& b ); + /** + * @return size of shard in bytes + * talks to mongod to do this + */ + long getPhysicalSize() const; + + // + // chunk size support + int countObjects(int maxcount=0) const; + + // + // public constants + // + + static string chunkMetadataNS; static int MaxChunkSize; - string genID() const; - static string genID( const string& ns , const BSONObj& min ); + // + // accessors and helpers + // - const ChunkManager* getManager() const { return _manager; } - - bool getModified() { return _modified; } - void setModified( bool modified ) { _modified = modified; } + string toString() const; - ShardChunkVersion getVersionOnConfigServer() const; - private: + friend ostream& operator << (ostream& out, const Chunk& c) { return (out << c.toString()); } + bool operator==(const Chunk& s) const; + bool operator!=(const Chunk& s) const { return ! ( *this == s ); } - bool _splitIfShould( long dataWritten ); + string getns() const; + const char * getNS() { return "config.chunks"; } + Shard getShard() const { return _shard; } + const ChunkManager* getManager() const { return _manager; } + private: // main shard info - + ChunkManager * _manager; - ShardKeyPattern skey() const; BSONObj _min; BSONObj _max; Shard _shard; ShardChunkVersion _lastmod; - bool _modified; - // transient stuff long _dataWritten; - + // methods, etc.. - - void _split( BSONObj& middle ); - friend class ChunkManager; - friend class ShardObjUnitTest; + /** + * if sort 1, return lowest key + * if sort -1, return highest key + * will return empty object if have none + */ + BSONObj _getExtremeKey( int sort ) const; + + /** initializes _dataWritten with a random value so that a mongos restart wouldn't cause delay in splitting */ + void _setDataWritten(); + + ShardKeyPattern skey() const; }; - class ChunkRange{ + class ChunkRange { public: - const ChunkManager* getManager() const{ return _manager; } - Shard getShard() const{ return _shard; } + const ChunkManager* getManager() const { return _manager; } + Shard getShard() const { return _shard; } const BSONObj& getMin() const { return _min; } const BSONObj& getMax() const { return _max; } @@ -181,11 +234,10 @@ namespace mongo { : _manager(begin->second->getManager()) , _shard(begin->second->getShard()) , _min(begin->second->getMin()) - , _max(prior(end)->second->getMax()) - { + , _max(prior(end)->second->getMax()) { assert( begin != end ); - DEV while (begin != end){ + DEV while (begin != end) { assert(begin->second->getManager() == _manager); assert(begin->second->getShard() == _shard); ++begin; @@ -197,14 +249,13 @@ namespace mongo { : _manager(min.getManager()) , _shard(min.getShard()) , _min(min.getMin()) - , _max(max.getMax()) - { + , _max(max.getMax()) { assert(min.getShard() == max.getShard()); assert(min.getManager() == max.getManager()); assert(min.getMax() == max.getMin()); } - friend ostream& operator<<(ostream& out, const ChunkRange& cr){ + friend ostream& operator<<(ostream& out, const ChunkRange& cr) { return (out << "ChunkRange(min=" << cr._min << ", max=" << cr._max << ", shard=" << cr._shard <<")"); } @@ -239,7 +290,7 @@ namespace mongo { }; /* config.sharding - { ns: 'alleyinsider.fs.chunks' , + { ns: 'alleyinsider.fs.chunks' , key: { ts : 1 } , shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200 , server : b } ] } @@ -247,75 +298,61 @@ namespace mongo { class ChunkManager { public: - ChunkManager( DBConfig * config , string ns , ShardKeyPattern pattern , bool unique ); + ChunkManager( string ns , ShardKeyPattern pattern , bool unique ); virtual ~ChunkManager(); string getns() const { return _ns; } - + int numChunks() const { rwlock lk( _lock , false ); return _chunkMap.size(); } bool hasShardKey( const BSONObj& obj ); + void createFirstChunk( const Shard& shard ); ChunkPtr findChunk( const BSONObj& obj , bool retry = false ); ChunkPtr findChunkOnServer( const Shard& shard ) const; - - ShardKeyPattern& getShardKey(){ return _key; } + const ShardKeyPattern& getShardKey() const { return _key; } - bool isUnique(){ return _unique; } + bool isUnique() const { return _unique; } void maybeChunkCollection(); - + void getShardsForQuery( set<Shard>& shards , const BSONObj& query ); void getAllShards( set<Shard>& all ); void getShardsForRange(set<Shard>& shards, const BSONObj& min, const BSONObj& max); // [min, max) - void save( bool major ); - string toString() const; ShardChunkVersion getVersion( const Shard& shard ) const; ShardChunkVersion getVersion() const; - /** - * actually does a query on the server - * doesn't look at any local data - */ - ShardChunkVersion getVersionOnConfigServer() const; - /** * this is just an increasing number of how many ChunkManagers we have so we know if something has been updated */ - unsigned long long getSequenceNumber(){ - return _sequenceNumber; - } - - void getInfo( BSONObjBuilder& b ){ + unsigned long long getSequenceNumber() const { return _sequenceNumber; } + + void getInfo( BSONObjBuilder& b ) { b.append( "key" , _key.key() ); b.appendBool( "unique" , _unique ); } - + /** * @param me - so i don't get deleted before i'm done */ void drop( ChunkManagerPtr me ); void _printChunks() const; - + + int getCurrentDesiredChunkSize() const; + private: - void _reload(); void _reload_inlock(); void _load(); - void save_inlock( bool major ); - ShardChunkVersion getVersion_inlock() const; void ensureIndex_inlock(); - - DBConfig * _config; + string _ns; ShardKeyPattern _key; bool _unique; - - map<string,unsigned long long> _maxMarkers; ChunkMap _chunkMap; ChunkRangeManager _chunkRanges; @@ -323,11 +360,9 @@ namespace mongo { set<Shard> _shards; unsigned long long _sequenceNumber; - - mutable RWLock _lock; - // This should only be called from Chunk after it has been migrated - void _migrationNotification(Chunk* c); + mutable RWLock _lock; + DistributedLock _nsLock; friend class Chunk; friend class ChunkRangeManager; // only needed for CRM::assertValid() @@ -362,12 +397,14 @@ namespace mongo { /* struct chunk_lock { chunk_lock( const Chunk* c ){ - + } - + Chunk _c; }; */ inline string Chunk::genID() const { return genID(_manager->getns(), _min); } + bool setShardVersion( DBClientBase & conn , const string& ns , ShardChunkVersion version , bool authoritative , BSONObj& result ); + } // namespace mongo |