diff options
author | Ian Kuehne <ian.kuehne@mongodb.com> | 2017-08-09 13:34:27 -0400 |
---|---|---|
committer | Ian Kuehne <ian.kuehne@mongodb.com> | 2017-08-22 16:51:12 -0400 |
commit | 3ac3be976459d6499bda024fd17388877947d368 (patch) | |
tree | 026e210f786549a22a707a8d9aa717a288832543 /src/mongo | |
parent | d33d4c43a019e17e3afb8be5fa47382f7566e26c (diff) | |
download | mongo-3ac3be976459d6499bda024fd17388877947d368.tar.gz |
SERVER-30646 Fix dbCheck health log entries.
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/dbcheck.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/repl/dbcheck.cpp | 165 | ||||
-rw-r--r-- | src/mongo/db/repl/dbcheck.h | 25 | ||||
-rw-r--r-- | src/mongo/db/repl/dbcheck.idl | 3 |
4 files changed, 137 insertions, 81 deletions
diff --git a/src/mongo/db/commands/dbcheck.cpp b/src/mongo/db/commands/dbcheck.cpp index b23ebd76472..1c3fdcf8b39 100644 --- a/src/mongo/db/commands/dbcheck.cpp +++ b/src/mongo/db/commands/dbcheck.cpp @@ -186,7 +186,7 @@ private: stats.nBytes, stats.md5, stats.md5, - info.start, + start, stats.lastKey, stats.time); HealthLog::get(Client::getCurrent()->getServiceContext()).log(*entry); @@ -238,8 +238,9 @@ private: auto prev = UUIDCatalog::get(opCtx).prev(_dbName, *collection->uuid()); auto next = UUIDCatalog::get(opCtx).next(_dbName, *collection->uuid()); - // Find and report the indices. + // Find and report collection metadata. auto indices = collectionIndexInfo(opCtx, collection); + auto options = collectionOptions(opCtx, collection); DbCheckOplogCollection entry; entry.setNss(collection->ns()); @@ -252,6 +253,7 @@ private: } entry.setType(OplogEntriesEnum::Collection); entry.setIndexes(indices); + entry.setOptions(options); repl::OpTime optime = writeConflictRetry(opCtx, "log dbCheck to oplog", collection->ns().ns(), [&] { @@ -269,16 +271,15 @@ private: return optime; }); - auto hle = dbCheckCollectionEntry(collection->ns(), - collection->ns().coll().toString(), - *collection->uuid(), - entry.getPrev(), - entry.getPrev(), - entry.getNext(), - entry.getNext(), - entry.getIndexes(), - entry.getIndexes(), - optime); + DbCheckCollectionInformation collectionInfo; + collectionInfo.collectionName = collection->ns().coll().toString(); + collectionInfo.prev = entry.getPrev(); + collectionInfo.next = entry.getNext(); + collectionInfo.indexes = entry.getIndexes(); + collectionInfo.options = entry.getOptions(); + + auto hle = dbCheckCollectionEntry( + collection->ns(), *collection->uuid(), collectionInfo, collectionInfo, optime); HealthLog::get(opCtx).log(*hle); diff --git a/src/mongo/db/repl/dbcheck.cpp b/src/mongo/db/repl/dbcheck.cpp index 7efd2107089..873c195a501 100644 --- a/src/mongo/db/repl/dbcheck.cpp +++ b/src/mongo/db/repl/dbcheck.cpp @@ -52,10 +52,6 @@ namespace { * Some utilities for dealing with the expected/found documents in health log entries. */ -bool operator==(const BSONObj& lhs, const BSONObj& rhs) { - return lhs.woCompare(lhs, rhs) == 0; -} - bool operator==(const std::vector<BSONObj>& lhs, const std::vector<BSONObj>& rhs) { return std::equal(lhs.cbegin(), lhs.cend(), @@ -74,6 +70,12 @@ std::pair<bool, BSONObj> expectedFound(const T& expected, const T& found) { return std::pair<bool, BSONObj>(expected == found, obj); } +template <> +std::pair<bool, BSONObj> expectedFound(const BSONObj& expected, const BSONObj& found) { + auto obj = BSON("expected" << expected << "found" << found); + return std::pair<bool, BSONObj>(expected.woCompare(found) == 0, obj); +} + /** * An overload for boost::optionals, which omits boost::none fields. */ @@ -173,37 +175,6 @@ std::unique_ptr<HealthLogEntry> dbCheckBatchEntry(const NamespaceString& nss, return dbCheckHealthLogEntry(nss, severity, msg, OplogEntriesEnum::Batch, data); } -std::unique_ptr<HealthLogEntry> dbCheckCollectionEntry(const NamespaceString& nss, - const std::string& collName, - const UUID& uuid, - const boost::optional<UUID>& expectedPrev, - const boost::optional<UUID>& foundPrev, - const boost::optional<UUID>& expectedNext, - const boost::optional<UUID>& foundNext, - const std::vector<BSONObj>& expectedIndexes, - const std::vector<BSONObj>& foundIndexes, - const repl::OpTime& optime) { - auto names = expectedFound(nss.coll().toString(), collName); - auto prevs = expectedFound<UUID>(expectedPrev, foundPrev); - auto nexts = expectedFound<UUID>(expectedNext, foundNext); - auto indices = expectedFound(expectedIndexes, foundIndexes); - bool match = names.first && prevs.first && nexts.first && indices.first; - auto severity = match ? SeverityEnum::Info : SeverityEnum::Error; - std::string msg = - "dbCheck collection " + (match ? std::string("consistent") : std::string("inconsistent")); - auto data = - BSON("uuid" << uuid.toString() << "found" << true << "name" << names.second << "prev" - << prevs.second - << "next" - << nexts.second - << "indexes" - << indices.second - << "optime" - << optime); - - return dbCheckHealthLogEntry(nss, severity, msg, OplogEntriesEnum::Collection, data); -} - DbCheckHasher::DbCheckHasher(OperationContext* opCtx, Collection* collection, const BSONKey& start, @@ -232,6 +203,75 @@ DbCheckHasher::DbCheckHasher(OperationContext* opCtx, InternalPlanner::IXSCAN_FETCH); } + +template <typename T> +const md5_byte_t* md5Cast(const T* ptr) { + return reinterpret_cast<const md5_byte_t*>(ptr); +} + +void maybeAppend(md5_state_t* state, const boost::optional<UUID>& uuid) { + if (uuid) { + md5_append(state, md5Cast(uuid->toCDR().data()), uuid->toCDR().length()); + } +} + +std::string hashCollectionInfo(const DbCheckCollectionInformation& info) { + md5_state_t state; + md5_init(&state); + + md5_append(&state, md5Cast(info.collectionName.data()), info.collectionName.size()); + + maybeAppend(&state, info.prev); + maybeAppend(&state, info.next); + + for (const auto& index : info.indexes) { + md5_append(&state, md5Cast(index.objdata()), index.objsize()); + } + + md5_append(&state, md5Cast(info.options.objdata()), info.options.objsize()); + + md5digest digest; + + md5_finish(&state, digest); + return digestToString(digest); +} + +std::unique_ptr<HealthLogEntry> dbCheckCollectionEntry(const NamespaceString& nss, + const UUID& uuid, + const DbCheckCollectionInformation& expected, + const DbCheckCollectionInformation& found, + const repl::OpTime& optime) { + auto names = expectedFound(expected.collectionName, found.collectionName); + auto prevs = expectedFound(expected.prev, found.prev); + auto nexts = expectedFound(expected.next, found.next); + auto indices = expectedFound(expected.indexes, found.indexes); + auto options = expectedFound(expected.options, found.options); + bool match = names.first && prevs.first && nexts.first && indices.first && options.first; + auto severity = match ? SeverityEnum::Info : SeverityEnum::Error; + + // Get the hash of all of the other fields. + auto md5s = expectedFound(hashCollectionInfo(expected), hashCollectionInfo(found)); + + std::string msg = + "dbCheck collection " + (match ? std::string("consistent") : std::string("inconsistent")); + auto data = BSON("success" << true << "uuid" << uuid.toString() << "found" << true << "name" + << names.second + << "prev" + << prevs.second + << "next" + << nexts.second + << "indexes" + << indices.second + << "options" + << options.second + << "md5" + << md5s.second + << "optime" + << optime); + + return dbCheckHealthLogEntry(nss, severity, msg, OplogEntriesEnum::Collection, data); +} + Status DbCheckHasher::hashAll(void) { BSONObj currentObj; @@ -251,9 +291,7 @@ Status DbCheckHasher::hashAll(void) { _bytesSeen += currentObj.objsize(); _countSeen += 1; - md5_append(&_state, - reinterpret_cast<const md5_byte_t*>(currentObj.objdata()), - currentObj.objsize()); + md5_append(&_state, md5Cast(currentObj.objdata()), currentObj.objsize()); } // If we got to the end of the collection, set the last key to MaxKey. @@ -324,6 +362,10 @@ std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, Collection* co return result; } +BSONObj collectionOptions(OperationContext* opCtx, Collection* collection) { + return collection->getCatalogEntry()->getCollectionOptions(opCtx).toBSON(); +} + std::unique_ptr<AutoGetCollection> getCollectionForDbCheck(OperationContext* opCtx, const NamespaceString& nss, const OplogEntriesEnum& type) { @@ -426,39 +468,38 @@ Status dbCheckDatabaseOnSecondary(OperationContext* opCtx, return Status::OK(); } - auto dbName = collection->ns().db(); - AutoGetDb agd(opCtx, dbName, MODE_X); + auto db = collection->ns().db(); + AutoGetDb agd(opCtx, db, MODE_X); - auto collName = collection->ns().coll().toString(); + DbCheckCollectionInformation expected; + DbCheckCollectionInformation found; + + expected.collectionName = entry.getNss().coll().toString(); + found.collectionName = collection->ns().coll().toString(); // found/expected previous UUID, - boost::optional<UUID> expectedPrev = entry.getPrev(); - boost::optional<UUID> foundPrev = UUIDCatalog::get(opCtx).prev(dbName, uuid); + expected.prev = entry.getPrev(); + found.prev = UUIDCatalog::get(opCtx).prev(db, uuid); // found/expected next UUID, - auto expectedNext = entry.getNext(); - auto foundNext = UUIDCatalog::get(opCtx).next(dbName, uuid); - - // and found/expected indices. - auto expectedIndexes = entry.getIndexes(); - auto foundIndexes = collectionIndexInfo(opCtx, collection); - - auto logEntry = dbCheckCollectionEntry(entry.getNss(), - collName, - uuid, - expectedPrev, - foundPrev, - expectedNext, - foundNext, - expectedIndexes, - foundIndexes, - optime); + expected.next = entry.getNext(); + found.next = UUIDCatalog::get(opCtx).next(db, uuid); - HealthLog::get(opCtx).log(*logEntry); + // found/expected indices, + expected.indexes = entry.getIndexes(); + found.indexes = collectionIndexInfo(opCtx, collection); + + // and found/expected collection options. + expected.options = entry.getOptions(); + found.options = collectionOptions(opCtx, collection); + + auto hle = dbCheckCollectionEntry(entry.getNss(), uuid, expected, found, optime); + + HealthLog::get(opCtx).log(*hle); return Status::OK(); } -} // namespace +} namespace repl { diff --git a/src/mongo/db/repl/dbcheck.h b/src/mongo/db/repl/dbcheck.h index 0d7d74bb4aa..bea6eae7ca8 100644 --- a/src/mongo/db/repl/dbcheck.h +++ b/src/mongo/db/repl/dbcheck.h @@ -67,17 +67,23 @@ std::unique_ptr<HealthLogEntry> dbCheckBatchEntry(const NamespaceString& nss, const repl::OpTime& optime); /** + * The collection metadata dbCheck sends between nodes. + */ +struct DbCheckCollectionInformation { + std::string collectionName; + boost::optional<UUID> prev; + boost::optional<UUID> next; + std::vector<BSONObj> indexes; + BSONObj options; +}; + +/** * Get a HealthLogEntry for a dbCheck collection. */ std::unique_ptr<HealthLogEntry> dbCheckCollectionEntry(const NamespaceString& nss, - const std::string& foundName, const UUID& uuid, - const boost::optional<UUID>& expectedPrev, - const boost::optional<UUID>& foundPrev, - const boost::optional<UUID>& expectedNext, - const boost::optional<UUID>& foundNext, - const std::vector<BSONObj>& expectedIndexes, - const std::vector<BSONObj>& foundIndexes, + const DbCheckCollectionInformation& expected, + const DbCheckCollectionInformation& found, const repl::OpTime& optime); /** @@ -166,6 +172,11 @@ std::unique_ptr<AutoGetCollection> getCollectionForDbCheck(OperationContext* opC */ std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, Collection* collection); +/** + * Gather other information for a collection. + */ +BSONObj collectionOptions(OperationContext* opCtx, Collection* collection); + namespace repl { /** diff --git a/src/mongo/db/repl/dbcheck.idl b/src/mongo/db/repl/dbcheck.idl index 77bf3b8ad23..93262bf0555 100644 --- a/src/mongo/db/repl/dbcheck.idl +++ b/src/mongo/db/repl/dbcheck.idl @@ -114,3 +114,6 @@ structs: indexes: type: array<object> cpp_name: indexes + options: + type: object + cpp_name: options |