summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Milkie <milkie@10gen.com>2020-07-15 11:04:04 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-15 19:21:42 +0000
commit6377d98fadd8ab5c10eb1e0bb240dc4151fda316 (patch)
treefa28baf703228a2ff79e3d80ef30b0d54d0c6662
parente9bdaa0807b6aa6e3054efc8598030e28fb9c880 (diff)
downloadmongo-6377d98fadd8ab5c10eb1e0bb240dc4151fda316.tar.gz
SERVER-47714 explicitly set the prepare conflict behavior prior to creating a system.profile collection
-rw-r--r--jstests/replsets/profile.js30
-rw-r--r--src/mongo/db/introspect.cpp11
2 files changed, 41 insertions, 0 deletions
diff --git a/jstests/replsets/profile.js b/jstests/replsets/profile.js
new file mode 100644
index 00000000000..06c5a5d8815
--- /dev/null
+++ b/jstests/replsets/profile.js
@@ -0,0 +1,30 @@
+// Confirm that implicitly created profile collections are successful and do not trigger assertions.
+// In order to implicitly create a profile collection with a read, we must set up the server with
+// some data to read without the profiler being active.
+// @tags: [requires_persistence]
+(function() {
+"use strict";
+let rst = new ReplSetTest({nodes: {n0: {profile: "0"}}});
+rst.startSet();
+rst.initiate();
+let primary = rst.getPrimary();
+let primaryDB = primary.getDB('test');
+
+assert.commandWorked(primaryDB.foo.insert({_id: 1}));
+
+const nodeId = rst.getNodeId(primary);
+rst.stop(nodeId);
+rst.start(nodeId, {profile: "2"}, true /* preserves data directory */);
+rst.awaitReplication();
+primary = rst.getPrimary();
+primaryDB = primary.getDB('test');
+
+let oldAssertCounts = primaryDB.serverStatus().asserts;
+assert.eq(0, primaryDB.system.profile.count());
+assert.eq([{_id: 1}], primaryDB.foo.aggregate([]).toArray());
+let newAssertCounts = primaryDB.serverStatus().asserts;
+assert.eq(oldAssertCounts, newAssertCounts);
+assert.eq(1, primaryDB.system.profile.count());
+
+rst.stopSet();
+})();
diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp
index ab0b749c51e..a75b91b8aba 100644
--- a/src/mongo/db/introspect.cpp
+++ b/src/mongo/db/introspect.cpp
@@ -139,6 +139,17 @@ void profile(OperationContext* opCtx, NetworkOp op) {
autoGetDb.reset(new AutoGetDb(opCtx, dbName, MODE_X));
if (autoGetDb->getDb()) {
+ // We are about to enforce prepare conflicts for the OperationContext. But it is
+ // illegal to change the behavior of ignoring prepare conflicts while any
+ // storage transaction is still active. So we need to call abandonSnapshot() to
+ // close any open transactions. This call is also harmless because any previous
+ // reads or writes should have already completed, as profile() is called at the
+ // end of an operation.
+ opCtx->recoveryUnit()->abandonSnapshot();
+ // The profiler performs writes even after read commands. Ignoring prepare
+ // conflicts is not allowed while performing writes, so temporarily enforce
+ // prepare conflicts.
+ EnforcePrepareConflictsBlock enforcePrepare(opCtx);
createProfileCollection(opCtx, autoGetDb->getDb()).transitional_ignore();
}
} else {