/**
* 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 "mongo/base/disallow_copying.h"
#include "mongo/db/namespace_string.h"
#include "mongo/executor/task_executor.h"
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/util/concurrency/notification.h"
#include "mongo/util/time_support.h"
namespace mongo {
class BSONObj;
class Collection;
class OperationContext;
class CollectionRangeDeleter {
MONGO_DISALLOW_COPYING(CollectionRangeDeleter);
public:
/**
* This is an object n that asynchronously changes state when a scheduled range deletion
* completes or fails. Call n.ready() to discover if the event has already occurred. Call
* n.waitStatus(opCtx) to sleep waiting for the event, and get its result. If the wait is
* interrupted, waitStatus throws.
*
* It is an error to destroy a returned CleanupNotification object n unless either n.ready()
* is true or n.abandon() has been called. After n.abandon(), n is in a moved-from state.
*/
class DeleteNotification {
public:
DeleteNotification();
DeleteNotification(Status status);
// The following default declarations are needed because the presence of a non-trivial
// destructor forbids the compiler to generate the declarations itself, but the definitions
// it generates are fine.
DeleteNotification(DeleteNotification&& notifn) = default;
DeleteNotification& operator=(DeleteNotification&& notifn) = default;
DeleteNotification(DeleteNotification const& notifn) = default;
DeleteNotification& operator=(DeleteNotification const& notifn) = default;
~DeleteNotification() {
// Can be null only if moved from
dassert(!_notification || *_notification || _notification.use_count() == 1);
}
void notify(Status status) const {
_notification->set(status);
}
/**
* Sleeps waiting for notification, and returns notify's argument. On interruption, throws;
* calling waitStatus afterward returns failed status.
*/
Status waitStatus(OperationContext* opCtx);
bool ready() const {
return bool(*_notification);
}
void abandon() {
_notification = nullptr;
}
bool operator==(DeleteNotification const& other) const {
return _notification == other._notification;
}
bool operator!=(DeleteNotification const& other) const {
return _notification != other._notification;
}
private:
std::shared_ptr> _notification;
};
struct Deletion {
Deletion(ChunkRange r, Date_t when) : range(std::move(r)), whenToDelete(when) {}
ChunkRange range;
Date_t whenToDelete; // A value of Date_t{} means immediately.
DeleteNotification notification{};
};
CollectionRangeDeleter();
~CollectionRangeDeleter();
//
// All of the following members must be called only while the containing MetadataManager's lock
// is held (or in its destructor), except cleanUpNextRange.
//
/**
* Splices range's elements to the list to be cleaned up by the deleter thread. Deletions d
* with d.delay == true are added to the delayed queue, and scheduled at time `later`.
* Returns the time to begin deletions, if needed, or boost::none if deletions are already
* scheduled.
*/
boost::optional add(std::list ranges);
/**
* Reports whether the argument range overlaps any of the ranges to clean. If there is overlap,
* it returns a notification that will be signaled when the currently newest overlapping range
* completes or fails. If there is no overlap, the result is boost::none. After a successful
* removal, the caller should call again to ensure no other range overlaps the argument.
* (See CollectionShardingState::waitForClean and MetadataManager::trackOrphanedDataCleanup for
* an example use.)
*/
boost::optional overlaps(ChunkRange const& range) const;
/**
* Reports the number of ranges remaining to be cleaned up.
*/
size_t size() const;
bool isEmpty() const;
/*
* Notifies with the specified status anything waiting on ranges scheduled, and then discards
* the ranges and notifications. Is called in the destructor.
*/
void clear(Status status);
/*
* Append a representation of self to the specified builder.
*/
void append(BSONObjBuilder* builder) const;
/**
* If any range deletions are scheduled, deletes up to maxToDelete documents, notifying
* watchers of ranges as they are done being deleted. It performs its own collection locking, so
* it must be called without locks.
*
* If it should be scheduled to run again because there might be more documents to delete,
* returns the time to begin, or boost::none otherwise.
*
* Argument 'forTestOnly' is used in unit tests that exercise the CollectionRangeDeleter class,
* so that they do not need to set up CollectionShardingState and MetadataManager objects.
*/
static boost::optional cleanUpNextRange(OperationContext*,
NamespaceString const& nss,
OID const& epoch,
int maxToDelete,
CollectionRangeDeleter* forTestOnly = nullptr);
private:
/**
* Performs the deletion of up to maxToDelete entries within the range in progress. Must be
* called under the collection lock.
*
* Returns the number of documents deleted, 0 if done with the range, or bad status if deleting
* the range failed.
*/
StatusWith _doDeletion(OperationContext* opCtx,
Collection* collection,
const BSONObj& keyPattern,
ChunkRange const& range,
int maxToDelete);
/**
* Removes the latest-scheduled range from the ranges to be cleaned up, and notifies any
* interested callers of this->overlaps(range) with specified status.
*/
void _pop(Status status);
/**
* Ranges scheduled for deletion. The front of the list will be in active process of deletion.
* As each range is completed, its notification is signaled before it is popped.
*/
std::list _orphans;
std::list _delayedOrphans;
};
} // namespace mongo