/**
* Copyright (C) 2017 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/base/status.h"
#include "mongo/base/status_with.h"
#include "mongo/db/namespace_string.h"
#include "mongo/util/duration.h"
#include "mongo/util/uuid.h"
namespace mongo {
class BSONElement;
class OperationContext;
namespace repl {
class StorageInterface;
/**
* RollbackFixUpInfo represents information derived from processing local oplog entries that have to
* be rolled back. This information may be supplemented by requesting additional data from the sync
* source if the local oplog entry is not reversible on its own. For example, when rolling back a
* document deletion, the oplog entry contains the _id of the deleted document but not the complete
* document that was removed. We have to request the most recent copy of the document by collection
* UUID and document _id in order to restore the deleted document.
*
* This rollback fix-up information is persisted in "local.system.rollback.*" collections. See
* description of "kRollback*Namespace" constants.
*/
class RollbackFixUpInfo {
private:
MONGO_DISALLOW_COPYING(RollbackFixUpInfo);
public:
/**
* Contains documents affected by rolling back CRUD operations on documents.
*/
static const NamespaceString kRollbackDocsNamespace;
/**
* Contains mappings of collection UUID -> namespace.
* This collection is used to roll back create, drop and rename operations.
* For drops and renames, the namespace in the mapping will be the full namespace to restore
* in the database catalog.
* For collection creation, the namespace will be set to empty to indicate that the collection
* should be dropped.
*/
static const NamespaceString kRollbackCollectionUuidNamespace;
/**
* Contains mappings of collection UUID -> collection options.
* This collection is used to roll back non-TTL collMod changes to collections.
*/
static const NamespaceString kRollbackCollectionOptionsNamespace;
/**
* Contains mappings of (collection UUID, index name) -> index info.
* This collection is used to roll back create, drop and TTL changes to indexes.
*/
static const NamespaceString kRollbackIndexNamespace;
/**
* Creates an instance of RollbackFixUpInfo.
*/
explicit RollbackFixUpInfo(StorageInterface* storageInterface);
/**
* Processes an oplog entry representing an insert/delete/update operation on a single document
* in a collection. Stores information about this operation into "kRollbackDocsNamespace".
* This allows us to roll back the operation later.
* For delete and update operations, we will also fetch a more recent copy of the document
* affected by this operation and store it in the same collection.
*
* "docId" is the _id field of the modified document.
*
* "dbName" is required for the find command request used to fetch the document from the sync
* source.
*
* For index creation operations, which are represented in the oplog as insert operations in
* "*.system.indexes", use processCreateIndexOplogEntry() instead.
*/
enum class SingleDocumentOpType { kInsert, kDelete, kUpdate };
class SingleDocumentOperationDescription;
Status processSingleDocumentOplogEntry(OperationContext* opCtx,
const UUID& collectionUuid,
const BSONElement& docId,
SingleDocumentOpType opType,
const std::string& dbName);
/**
* Processes an oplog entry representing a create collection command. Stores information about
* this operation into "kRollbackCollectionUuidNamespace" to allow us to roll back this
* operation later by dropping the collection from the catalog by UUID.
*
* The mapping in the "kRollbackCollectionUuidNamespace" collection will contain the
* empty namespace.
*/
class CollectionUuidDescription;
Status processCreateCollectionOplogEntry(OperationContext* opCtx, const UUID& collectionUuid);
/**
* Processes an oplog entry representing a drop collection command. Stores information about
* this operation into "kRollbackCollectionUuidNamespace" to allow us to roll back this
* operation later by restoring the UUID mapping in the catalog.
*/
Status processDropCollectionOplogEntry(OperationContext* opCtx,
const UUID& collectionUuid,
const NamespaceString& nss);
/**
* Processes an oplog entry representing a rename collection command. Stores information about
* this operation into "kRollbackCollectionUuidNamespace" to allow us to roll back this
* operation later by restoring the UUID mapping(s) in the catalog.
*
* "targetCollectionUuidAndNss" is derived from the "dropTarget" and "to" fields of the
* renameCollection oplogEntry.
*
* If the target collection did not exist when the rename operation was applied
* (targetCollectionUuidAndNss is valid), this function will insert one document into
* "kRollbackCollectionUuidNamespace":
* source UUID -> namespace mapping.
*
* If the target collection was dropped when the rename operation was applied
* (targetCollectionUuidAndNss is valid), this function will insert two documents into
* "kRollbackCollectionUuidNamespace":
* source UUID -> namespace mapping; and
* dropped target UUID -> namespace mapping
*/
using CollectionUuidAndNss = std::pair;
Status processRenameCollectionOplogEntry(
OperationContext* opCtx,
const UUID& sourceCollectionUuid,
const NamespaceString& sourceNss,
boost::optional targetCollectionUuidAndNss);
/**
* Processes an oplog entry representing a non-TTL collMod command. Stores information about
* this operation into "kRollbackCollectionOptionsNamespace" to allow us to roll back this
* operation later by restoring the collection options in the catalog.
*/
class CollectionOptionsDescription;
Status processCollModOplogEntry(OperationContext* opCtx,
const UUID& collectionUuid,
const BSONObj& optionsObj);
/**
* Processes an oplog entry representing a createIndex command. Stores information about
* this operation into "kRollbackIndexNamespace" to allow us to roll back this
* operation later by dropping the index from the catalog by UUID/index name.
*
* The mapping in the "kRollbackCollectionUuidNamespace" collection will contain the
* empty namespace.
*/
Status processCreateIndexOplogEntry(OperationContext* opCtx,
const UUID& collectionUuid,
const std::string& indexName);
enum class IndexOpType { kCreate, kDrop, kUpdateTTL };
class IndexDescription;
/**
* Processes an oplog entry representing a collMod command that updates the expiration setting
* on a TTL index. Stores information about this operation into "kRollbackIndexNamespace" to
* allow us to roll back this operation later by updating the TTL expiration to the previous
* value.
*/
Status processUpdateIndexTTLOplogEntry(OperationContext* opCtx,
const UUID& collectionUuid,
const std::string& indexName,
Seconds expireAfterSeconds);
/**
* Processes an oplog entry representing a dropIndexes command with a single index. Stores
* information about this operation into "kRollbackIndexNamespace" to allow us to roll back this
* operation later by recreating the index.
*/
Status processDropIndexOplogEntry(OperationContext* opCtx,
const UUID& collectionUuid,
const std::string& indexName,
const BSONObj& infoObj);
private:
/**
* Upserts a single document using the _id field of the document in "update".
*/
Status _upsertById(OperationContext* opCtx, const NamespaceString& nss, const BSONObj& update);
/**
* Upserts an IndexDescription.
*/
Status _upsertIndexDescription(OperationContext* opCtx, const IndexDescription& description);
StorageInterface* const _storageInterface;
};
} // namespace repl
} // namespace mongo