/**
* 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