/** * Copyright (C) 2016 MongoDB 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 #include #include "mongo/base/disallow_copying.h" #include "mongo/bson/simple_bsonobj_comparator.h" #include "mongo/db/namespace_string.h" #include "mongo/db/s/collection_metadata.h" #include "mongo/db/service_context.h" #include "mongo/s/catalog/type_chunk.h" #include "mongo/util/concurrency/notification.h" #include "mongo/stdx/memory.h" namespace mongo { class ScopedCollectionMetadata; class MetadataManager { MONGO_DISALLOW_COPYING(MetadataManager); public: MetadataManager(ServiceContext* sc, NamespaceString nss); ~MetadataManager(); /** * An ActiveMetadata must be set before this function can be called. * * Increments the usage counter of the active metadata and returns an RAII object, which * contains the currently active metadata. When the usageCounter goes to zero, the RAII * object going out of scope will call _removeMetadata. */ ScopedCollectionMetadata getActiveMetadata(); /** * Uses the contents of the specified metadata as a way to purge any pending chunks. */ void refreshActiveMetadata(std::unique_ptr newMetadata); /** * Puts the specified range on the list of chunks, which are being received so that the range * deleter process will not clean the partially migrated data. */ void beginReceive(const ChunkRange& range); /** * Removes a range from the list of chunks, which are being received. Used externally to * indicate that a chunk migration failed. */ void forgetReceive(const ChunkRange& range); /** * Gets copy of the set of chunk ranges which are being received for this collection. This * method is intended for testing purposes only and should not be used in any production code. */ RangeMap getCopyOfReceivingChunks(); /** * Adds a new range to be cleaned up. * The newly introduced range must not overlap with the existing ranges. */ std::shared_ptr> addRangeToClean(const ChunkRange& range); /** * Calls removeRangeToClean with Status::OK. */ void removeRangeToClean(const ChunkRange& range) { removeRangeToClean(range, Status::OK()); } /** * Removes the specified range from the ranges to be cleaned up. * The specified deletionStatus will be returned to callers waiting * on whether the deletion succeeded or failed. */ void removeRangeToClean(const ChunkRange& range, Status deletionStatus); /** * Gets copy of the set of chunk ranges which are scheduled for cleanup. * Converts RangeToCleanMap to RangeMap. */ RangeMap getCopyOfRangesToClean(); /** * Appends information on all the chunk ranges in rangesToClean to builder. */ void append(BSONObjBuilder* builder); /** * Returns true if _rangesToClean is not empty. */ bool hasRangesToClean(); /** * Returns true if the exact range is in _rangesToClean. */ bool isInRangesToClean(const ChunkRange& range); /** * Gets and returns, but does not remove, a single ChunkRange from _rangesToClean. * Should not be called if _rangesToClean is empty: it will hit an invariant. */ ChunkRange getNextRangeToClean(); private: friend class ScopedCollectionMetadata; struct CollectionMetadataTracker { public: /** * Creates a new CollectionMetadataTracker, with the usageCounter initialized to zero. */ CollectionMetadataTracker(std::unique_ptr m); std::unique_ptr metadata; uint32_t usageCounter{0}; }; // Class for the value of the _rangesToClean map. Used because callers of addRangeToClean // sometimes need to wait until a range is deleted. Thus, complete(Status) is called // when the range is deleted from _rangesToClean in removeRangeToClean(), letting callers // of addRangeToClean know if the deletion succeeded or failed. class RangeToCleanDescriptor { public: /** * Initializes a RangeToCleanDescriptor with an empty notification. */ RangeToCleanDescriptor(BSONObj max) : _max(max.getOwned()), _notification(std::make_shared>()) {} /** * Gets the maximum value of the range to be deleted. */ const BSONObj& getMax() const { return _max; } // See comment on _notification. std::shared_ptr> getNotification() { return _notification; } /** * Sets the status on _notification. This will tell threads * waiting on the value of status that the deletion succeeded or failed. */ void complete(Status status) { _notification->set(status); } private: // The maximum value of the range to be deleted. BSONObj _max; // This _notification will be set with a value indicating whether the deletion // succeeded or failed. std::shared_ptr> _notification; }; /** * Removes the CollectionMetadata stored in the tracker from the _metadataInUse * list (if it's there). */ void _removeMetadata_inlock(CollectionMetadataTracker* metadataTracker); std::shared_ptr> _addRangeToClean_inlock(const ChunkRange& range); void _removeRangeToClean_inlock(const ChunkRange& range, Status deletionStatus); RangeMap _getCopyOfRangesToClean_inlock(); void _setActiveMetadata_inlock(std::unique_ptr newMetadata); const NamespaceString _nss; // ServiceContext from which to obtain instances of global support objects. ServiceContext* _serviceContext; // Mutex to protect the state below stdx::mutex _managerLock; // Holds the collection metadata, which is currently active std::unique_ptr _activeMetadataTracker; // Holds collection metadata instances, which have previously been active, but are still in use // by still active server operations or cursors std::list> _metadataInUse; // Chunk ranges which are currently assumed to be transferred to the shard. Indexed by the min // key of the range. RangeMap _receivingChunks; // Set of ranges to be deleted. Indexed by the min key of the range. typedef BSONObjIndexedMap RangeToCleanMap; RangeToCleanMap _rangesToClean; }; class ScopedCollectionMetadata { MONGO_DISALLOW_COPYING(ScopedCollectionMetadata); public: /** * Creates an empty ScopedCollectionMetadata. Using the default constructor means that no * metadata is available. */ ScopedCollectionMetadata(); ~ScopedCollectionMetadata(); ScopedCollectionMetadata(ScopedCollectionMetadata&& other); ScopedCollectionMetadata& operator=(ScopedCollectionMetadata&& other); /** * Dereferencing the ScopedCollectionMetadata will dereference the internal CollectionMetadata. */ CollectionMetadata* operator->(); CollectionMetadata* getMetadata(); /** * True if the ScopedCollectionMetadata stores a metadata (is not empty) */ operator bool() const; private: friend ScopedCollectionMetadata MetadataManager::getActiveMetadata(); /** * Increments the counter in the CollectionMetadataTracker. */ ScopedCollectionMetadata(MetadataManager* manager, MetadataManager::CollectionMetadataTracker* tracker); /** * Decrements the usageCounter and conditionally makes a call to _removeMetadata on * the tracker if the count has reached zero. */ void _decrementUsageCounter(); MetadataManager* _manager{nullptr}; MetadataManager::CollectionMetadataTracker* _tracker{nullptr}; }; } // namespace mongo