// @file d_logic.h /* * Copyright (C) 2010 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 . */ #pragma once #include "../pch.h" #include "../db/jsobj.h" #include "d_chunk_manager.h" #include "util.h" namespace mongo { class Database; class DiskLoc; typedef ShardChunkVersion ConfigVersion; typedef map NSVersionMap; // -------------- // --- global state --- // -------------- class ShardingState { public: ShardingState(); bool enabled() const { return _enabled; } const string& getConfigServer() const { return _configServer; } void enable( const string& server ); void gotShardName( const string& name ); void gotShardHost( string host ); /** Reverts back to a state where this mongod is not sharded. */ void resetShardingState(); // versioning support bool hasVersion( const string& ns ); bool hasVersion( const string& ns , ConfigVersion& version ); const ConfigVersion getVersion( const string& ns ) const; /** * Uninstalls the manager for a given collection. This should be used when the collection is dropped. * * NOTE: * An existing collection with no chunks on this shard will have a manager on version 0, which is different than a * a dropped collection, which will not have a manager. * * TODO * When sharding state is enabled, absolutely all collections should have a manager. (The non-sharded ones are * a be degenerate case of one-chunk collections). * For now, a dropped collection and an non-sharded one are indistinguishable (SERVER-1849) * * @param ns the collection to be dropped */ void resetVersion( const string& ns ); /** * Requests to access a collection at a certain version. If the collection's manager is not at that version it * will try to update itself to the newest version. The request is only granted if the version is the current or * the newest one. * * @param ns collection to be accessed * @param version (IN) the client belive this collection is on and (OUT) the version the manager is actually in * @return true if the access can be allowed at the provided version */ bool trySetVersion( const string& ns , ConfigVersion& version ); void appendInfo( BSONObjBuilder& b ); // querying support bool needShardChunkManager( const string& ns ) const; ShardChunkManagerPtr getShardChunkManager( const string& ns ); // chunk migrate and split support /** * Creates and installs a new chunk manager for a given collection by "forgetting" about one of its chunks. * The new manager uses the provided version, which has to be higher than the current manager's. * One exception: if the forgotten chunk is the last one in this shard for the collection, version has to be 0. * * If it runs successfully, clients need to grab the new version to access the collection. * * @param ns the collection * @param min max the chunk to eliminate from the current manager * @param version at which the new manager should be at */ void donateChunk( const string& ns , const BSONObj& min , const BSONObj& max , ShardChunkVersion version ); /** * Creates and installs a new chunk manager for a given collection by reclaiming a previously donated chunk. * The previous manager's version has to be provided. * * If it runs successfully, clients that became stale by the previous donateChunk will be able to access the * collection again. * * @param ns the collection * @param min max the chunk to reclaim and add to the current manager * @param version at which the new manager should be at */ void undoDonateChunk( const string& ns , const BSONObj& min , const BSONObj& max , ShardChunkVersion version ); /** * Creates and installs a new chunk manager for a given collection by splitting one of its chunks in two or more. * The version for the first split chunk should be provided. The subsequent chunks' version would be the latter with the * minor portion incremented. * * The effect on clients will depend on the version used. If the major portion is the same as the current shards, * clients shouldn't perceive the split. * * @param ns the collection * @param min max the chunk that should be split * @param splitKeys point in which to split * @param version at which the new manager should be at */ void splitChunk( const string& ns , const BSONObj& min , const BSONObj& max , const vector& splitKeys , ShardChunkVersion version ); bool inCriticalMigrateSection(); private: bool _enabled; string _configServer; string _shardName; string _shardHost; // protects state below mutable mongo::mutex _mutex; // protects accessing the config server // Using a ticket holder so we can have multiple redundant tries at any given time mutable TicketHolder _configServerTickets; // map from a namespace into the ensemble of chunk ranges that are stored in this mongod // a ShardChunkManager carries all state we need for a collection at this shard, including its version information typedef map ChunkManagersMap; ChunkManagersMap _chunks; }; extern ShardingState shardingState; /** * one per connection from mongos * holds version state for each namesapce */ class ShardedConnectionInfo { public: ShardedConnectionInfo(); const OID& getID() const { return _id; } bool hasID() const { return _id.isSet(); } void setID( const OID& id ); const ConfigVersion getVersion( const string& ns ) const; void setVersion( const string& ns , const ConfigVersion& version ); static ShardedConnectionInfo* get( bool create ); static void reset(); static void addHook(); bool inForceVersionOkMode() const { return _forceVersionOk; } void enterForceVersionOkMode() { _forceVersionOk = true; } void leaveForceVersionOkMode() { _forceVersionOk = false; } private: OID _id; NSVersionMap _versions; bool _forceVersionOk; // if this is true, then chunk version #s aren't check, and all ops are allowed static boost::thread_specific_ptr _tl; }; struct ShardForceVersionOkModeBlock { ShardForceVersionOkModeBlock() { info = ShardedConnectionInfo::get( false ); if ( info ) info->enterForceVersionOkMode(); } ~ShardForceVersionOkModeBlock() { if ( info ) info->leaveForceVersionOkMode(); } ShardedConnectionInfo * info; }; // ----------------- // --- core --- // ----------------- unsigned long long extractVersion( BSONElement e , string& errmsg ); /** * @return true if we have any shard info for the ns */ bool haveLocalShardingInfo( const string& ns ); /** * @return true if the current threads shard version is ok, or not in sharded version */ bool shardVersionOk( const string& ns , string& errmsg ); /** * @return true if we took care of the message and nothing else should be done */ struct DbResponse; bool _handlePossibleShardedMessage( Message &m, DbResponse * dbresponse ); /** What does this do? document please? */ inline bool handlePossibleShardedMessage( Message &m, DbResponse * dbresponse ) { if( !shardingState.enabled() ) return false; return _handlePossibleShardedMessage(m, dbresponse); } void logOpForSharding( const char * opstr , const char * ns , const BSONObj& obj , BSONObj * patt ); void aboutToDeleteForSharding( const Database* db , const DiskLoc& dl ); }