summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorIan Kuehne <ian.kuehne@mongodb.com>2017-08-09 13:34:27 -0400
committerIan Kuehne <ian.kuehne@mongodb.com>2017-08-22 16:51:12 -0400
commit3ac3be976459d6499bda024fd17388877947d368 (patch)
tree026e210f786549a22a707a8d9aa717a288832543 /src/mongo
parentd33d4c43a019e17e3afb8be5fa47382f7566e26c (diff)
downloadmongo-3ac3be976459d6499bda024fd17388877947d368.tar.gz
SERVER-30646 Fix dbCheck health log entries.
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/commands/dbcheck.cpp25
-rw-r--r--src/mongo/db/repl/dbcheck.cpp165
-rw-r--r--src/mongo/db/repl/dbcheck.h25
-rw-r--r--src/mongo/db/repl/dbcheck.idl3
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