/** * Copyright (C) 2012 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 . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects * for all of the code used other than as permitted herein. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you do not * wish to do so, delete this exception statement from your version. If you * delete this exception statement from all source files in the program, * then also delete it in the license file. */ #pragma once #include "mongo/base/disallow_copying.h" #include "mongo/base/owned_pointer_vector.h" #include "mongo/db/field_ref_set.h" #include "mongo/db/jsobj.h" #include "mongo/db/range_arithmetic.h" #include "mongo/s/catalog/type_chunk.h" #include "mongo/s/chunk_version.h" namespace mongo { class MetadataLoader; class CollectionMetadata; typedef std::shared_ptr CollectionMetadataPtr; /** * The collection metadata has metadata information about a collection, in particular the * sharding information. It's main goal in life is to be capable of answering if a certain * document belongs to it or not. (In some scenarios such as chunk migration, a given * document is in a shard but cannot be accessed.) * * To build a collection from config data, please check the MetadataLoader. The methods * here allow building a new incarnation of a collection's metadata based on an existing * one (e.g, we're splitting in a given collection.). * * This class is immutable once constructed. */ class CollectionMetadata { MONGO_DISALLOW_COPYING(CollectionMetadata); public: ~CollectionMetadata(); // // cloning support // /** * Returns a new metadata's instance based on 'this's state by removing a 'pending' chunk. * * The shard and collection version of the new metadata are unaffected. The caller owns the * new metadata. * * If a new metadata can't be created, returns NULL and fills in 'errMsg', if it was * provided. */ CollectionMetadata* cloneMinusPending(const ChunkType& pending, std::string* errMsg) const; /** * Returns a new metadata's instance based on 'this's state by adding a 'pending' chunk. * * The shard and collection version of the new metadata are unaffected. The caller owns the * new metadata. * * If a new metadata can't be created, returns NULL and fills in 'errMsg', if it was * provided. */ CollectionMetadata* clonePlusPending(const ChunkType& pending, std::string* errMsg) const; /** * Returns a new metadata's instance based on 'this's state by removing 'chunk'. * When cloning away the last chunk, 'newShardVersion' must be zero. In any case, * the caller owns the new metadata when the cloning is successful. * * If a new metadata can't be created, returns NULL and fills in 'errMsg', if it was * provided. */ CollectionMetadata* cloneMigrate(const ChunkType& chunk, const ChunkVersion& newShardVersion, std::string* errMsg) const; /** * Returns a new metadata's instance by splitting an existing 'chunk' at the points * described by 'splitKeys'. The first resulting chunk will have 'newShardVersion' and * subsequent one would have that with the minor version incremented at each chunk. The * caller owns the metadata. * * If a new metadata can't be created, returns NULL and fills in 'errMsg', if it was * provided. * * Note: 'splitKeys' must be sorted in ascending order. */ CollectionMetadata* cloneSplit(const ChunkType& chunk, const std::vector& splitKeys, const ChunkVersion& newShardVersion, std::string* errMsg) const; /** * Returns a new metadata instance by merging a key range which starts and ends at existing * chunks into a single chunk. The range may not have holes. The resulting metadata will * have the 'newShardVersion'. The caller owns the new metadata. * * If a new metadata can't be created, returns NULL and fills in 'errMsg', if it was * provided. */ CollectionMetadata* cloneMerge(const BSONObj& minKey, const BSONObj& maxKey, const ChunkVersion& newShardVersion, std::string* errMsg) const; // // verification logic // /** * Returns true if the document key 'key' is a valid instance of a shard key for this * metadata. The 'key' must contain exactly the same fields as the shard key pattern. */ bool isValidKey(const BSONObj& key) const; /** * Returns true if the document key 'key' belongs to this chunkset. Recall that documents of * an in-flight chunk migration may be present and should not be considered part of the * collection / chunkset yet. Key must be the full shard key. */ bool keyBelongsToMe(const BSONObj& key) const; /** * Returns true if the document key 'key' is or has been migrated to this shard, and may * belong to us after a subsequent config reload. Key must be the full shard key. */ bool keyIsPending(const BSONObj& key) const; /** * Given a key 'lookupKey' in the shard key range, get the next chunk which overlaps or is * greater than this key. Returns true if a chunk exists, false otherwise. * * Passing a key that is not a valid shard key for this range results in undefined behavior. */ bool getNextChunk(const BSONObj& lookupKey, ChunkType* chunk) const; /** * Given a key in the shard key range, get the next range which overlaps or is greater than * this key. * * This allows us to do the following to iterate over all orphan ranges: * * KeyRange range; * BSONObj lookupKey = metadata->getMinKey(); * while( metadata->getNextOrphanRange( lookupKey, &orphanRange ) ) { * // Do stuff with range * lookupKey = orphanRange.maxKey; * } * * @param lookupKey passing a key that does not belong to this metadata is undefined. * @param orphanRange the output range. Note that the NS is not set. */ bool getNextOrphanRange(const BSONObj& lookupKey, KeyRange* orphanRange) const; // // accessors // ChunkVersion getCollVersion() const { return _collVersion; } ChunkVersion getShardVersion() const { return _shardVersion; } BSONObj getKeyPattern() const { return _keyPattern; } const std::vector& getKeyPatternFields() const { return _keyFields.vector(); } BSONObj getMinKey() const; BSONObj getMaxKey() const; std::size_t getNumChunks() const { return _chunksMap.size(); } std::size_t getNumPending() const { return _pendingMap.size(); } // // reporting // /** * BSON output of the metadata information. */ BSONObj toBSON() const; /** * BSON output of the metadata information, into a builder. */ void toBSON(BSONObjBuilder& bb) const; /** * BSON output of the chunks metadata into a BSONArray */ void toBSONChunks(BSONArrayBuilder& bb) const; /** * BSON output of the pending metadata into a BSONArray */ void toBSONPending(BSONArrayBuilder& bb) const; /** * std::string output of the metadata information. */ std::string toString() const; /** * Use the MetadataLoader to fill the empty metadata from the config server, or use * clone*() methods to use existing metadatas to build new ones. * * Unless you are the MetadataLoader or a test you should probably not be using this * directly. */ CollectionMetadata(); /** * TESTING ONLY * * Returns a new metadata's instance based on 'this's state by adding 'chunk'. The new * metadata can never be zero, though (see cloneMinus). The caller owns the new metadata. * * If a new metadata can't be created, returns NULL and fills in 'errMsg', if it was * provided. */ CollectionMetadata* clonePlusChunk(const ChunkType& chunk, const ChunkVersion& newShardVersion, std::string* errMsg) const; private: // Effectively, the MetadataLoader is this class's builder. So we open an exception // and grant it friendship. friend class MetadataLoader; // a version for this collection that identifies the collection incarnation (ie, a // dropped and recreated collection with the same name would have a different version) ChunkVersion _collVersion; // // sharded state below, for when the collection gets sharded // // highest ChunkVersion for which this metadata's information is accurate ChunkVersion _shardVersion; // key pattern for chunks under this range BSONObj _keyPattern; // A vector owning the FieldRefs parsed from the shard-key pattern of field names. OwnedPointerVector _keyFields; // // RangeMaps represent chunks by mapping the min key to the chunk's max key, allowing // efficient lookup and intersection. // // Map of ranges of chunks that are migrating but have not been confirmed added yet RangeMap _pendingMap; // Map of chunks tracked by this shard RangeMap _chunksMap; // A second map from a min key into a range or contiguous chunks. The map is redundant // w.r.t. _chunkMap but we expect high chunk contiguity, especially in small // installations. RangeMap _rangesMap; /** * Returns true if this metadata was loaded with all necessary information. */ bool isValid() const; /** * Try to find chunks that are adjacent and record these intervals in the _rangesMap */ void fillRanges(); /** * Creates the _keyField* local data */ void fillKeyPatternFields(); }; } // namespace mongo