/** * Copyright (C) 2018-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, * as published by MongoDB, Inc. * * 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 * Server Side Public License for more details. * * You should have received a copy of the Server Side 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 Server Side 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/db/catalog/health_log_gen.h" #include "mongo/db/db_raii.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/repl/dbcheck_gen.h" #include "mongo/util/md5.hpp" namespace mongo { // Forward declarations. class Collection; class OperationContext; namespace repl { class OpTime; } /** * Get an error message if the check fails. */ std::unique_ptr dbCheckErrorHealthLogEntry(const NamespaceString& nss, const std::string& msg, OplogEntriesEnum operation, const Status& err); /** * Get a HealthLogEntry for a dbCheck batch. */ std::unique_ptr dbCheckBatchEntry(const NamespaceString& nss, int64_t count, int64_t bytes, const std::string& expectedHash, const std::string& foundHash, const BSONKey& minKey, const BSONKey& maxKey, const repl::OpTime& optime); /** * The collection metadata dbCheck sends between nodes. */ struct DbCheckCollectionInformation { std::string collectionName; boost::optional prev; boost::optional next; std::vector indexes; BSONObj options; }; /** * Returns a pair of previous and next UUIDs around the given collections uuid. If there is no * previous or next UUID, return boost::none respectively. */ std::pair, boost::optional> getPrevAndNextUUIDs(OperationContext* opCtx, Collection* collection); /** * Get a HealthLogEntry for a dbCheck collection. */ std::unique_ptr dbCheckCollectionEntry(const NamespaceString& nss, const UUID& uuid, const DbCheckCollectionInformation& expected, const DbCheckCollectionInformation& found, const repl::OpTime& optime); /** * Hashing collections and plans. * * Provides MD5-based hashing of ranges of documents. Note that this class does *not* provide * synchronization: clients must, for example, lock the database to ensure that named collections * exist, and hold at least a MODE_IS lock before asking a `DbCheckHasher` to retrieve any * documents. */ class DbCheckHasher { public: /** * Create a new DbCheckHasher hashing documents within the given limits. * * The check will end when any of the specified limits are reached. Must be called on a * collection with an _id index; otherwise a DBException with code ErrorCodes::IndexNotFound * will be thrown. * * @param collection The collection to hash from. * @param start The first key to hash (exclusive). * @param end The last key to hash (inclusive). * @param maxCount The maximum number of documents to hash. * @param maxBytes The maximum number of bytes to hash. */ DbCheckHasher(OperationContext* opCtx, Collection* collection, const BSONKey& start, const BSONKey& end, int64_t maxCount = std::numeric_limits::max(), int64_t maxBytes = std::numeric_limits::max()); /** * Hash all of our documents. */ Status hashAll(void); /** * Return the total hash of all documents seen so far. */ std::string total(void); /** * Get the last key this hasher has hashed. * * Again, not the same as the `end` passed in; this is MinKey if no documents have been hashed. */ BSONKey lastKey(void) const; int64_t bytesSeen(void) const; int64_t docsSeen(void) const; private: /** * Can we hash `obj` without going over our limits? */ bool _canHash(const BSONObj& obj); OperationContext* _opCtx; std::unique_ptr _exec; md5_state_t _state; BSONKey _maxKey; BSONKey _last = BSONKey::min(); int64_t _maxCount = 0; int64_t _countSeen = 0; int64_t _maxBytes = 0; int64_t _bytesSeen = 0; }; /** * Get the given database in MODE_S, while also blocking stepdown (SERVER-28544) and allowing writes * to "local". */ class AutoGetDbForDbCheck { public: AutoGetDbForDbCheck(OperationContext* opCtx, const NamespaceString& nss); Database* getDb(void) { return agd.getDb(); } private: Lock::DBLock localLock; AutoGetDb agd; }; /** * Get the given collection in MODE_S, except that if the collection is missing it will report that * to the health log, and it takes an IX lock on "local" as a workaround to SERVER-28544. */ class AutoGetCollectionForDbCheck { public: AutoGetCollectionForDbCheck(OperationContext* opCtx, const NamespaceString& nss, const OplogEntriesEnum& type); Collection* getCollection(void) { return _collection; } private: AutoGetDbForDbCheck _agd; Lock::CollectionLock _collLock; Collection* _collection; }; /** * Gather the index information for a collection. */ std::vector collectionIndexInfo(OperationContext* opCtx, Collection* collection); /** * Gather other information for a collection. */ BSONObj collectionOptions(OperationContext* opCtx, Collection* collection); namespace repl { /** * Perform the dbCheck oplog command. * * Returns a `Status` to match the type used for oplog command hooks, but in fact always handles * errors (primarily by writing to the health log), so always returns `Status::OK`. */ Status dbCheckOplogCommand(OperationContext* opCtx, const char* ns, const BSONElement& ui, BSONObj& cmd, const repl::OpTime& optime, const repl::OplogEntry& entry, OplogApplication::Mode mode, boost::optional stableTimestampForRecovery); } // namespace repl } // namespace mongo