diff options
28 files changed, 143 insertions, 164 deletions
diff --git a/jstests/core/read_after_optime.js b/jstests/core/read_after_optime.js index f67692d955e..4f8d601facf 100644 --- a/jstests/core/read_after_optime.js +++ b/jstests/core/read_after_optime.js @@ -11,7 +11,7 @@ var res = assert.commandFailed(db.runCommand({ find: 'user', filter: { x: 1 }, readConcern: { - afterOpTime: { ts: futureOpTime, term: 0 } + afterOpTime: { ts: futureOpTime, t: 0 } } })); diff --git a/jstests/replsets/read_after_optime.js b/jstests/replsets/read_after_optime.js index fc8407d8566..cb19940ee05 100644 --- a/jstests/replsets/read_after_optime.js +++ b/jstests/replsets/read_after_optime.js @@ -22,7 +22,7 @@ var runTest = function(testDB, primaryConn) { find: 'user', filter: { x: 1 }, readConcern: { - afterOpTime: { ts: twoSecTS, term: 0 } + afterOpTime: { ts: twoSecTS, t: 0 } }, maxTimeMS: 1000 })); @@ -40,7 +40,7 @@ var runTest = function(testDB, primaryConn) { find: 'user', filter: { x: 1 }, readConcern: { - afterOpTime: { ts: twoSecTS, term: 0 }, + afterOpTime: { ts: twoSecTS, t: 0 }, maxTimeMS: 10 * 1000 } })); diff --git a/src/mongo/bson/util/bson_extract.cpp b/src/mongo/bson/util/bson_extract.cpp index 4906d0897a5..54d1e1f47ae 100644 --- a/src/mongo/bson/util/bson_extract.cpp +++ b/src/mongo/bson/util/bson_extract.cpp @@ -32,13 +32,6 @@ namespace mongo { -namespace { - -const char kTermFieldName[] = "term"; -const char kTimestampFieldName[] = "ts"; - -} // namespace - Status bsonExtractField(const BSONObj& object, StringData fieldName, BSONElement* outElement) { BSONElement element = object.getField(fieldName); if (element.eoo()) @@ -113,11 +106,11 @@ Status bsonExtractOpTimeField(const BSONObj& object, StringData fieldName, repl: BSONObj opTimeObj = element.Obj(); Timestamp ts; - status = bsonExtractTimestampField(opTimeObj, kTimestampFieldName, &ts); + status = bsonExtractTimestampField(opTimeObj, repl::OpTime::kTimestampFieldName, &ts); if (!status.isOK()) return status; long long term; - status = bsonExtractIntegerField(opTimeObj, kTermFieldName, &term); + status = bsonExtractIntegerField(opTimeObj, repl::OpTime::kTermFieldName, &term); if (!status.isOK()) return status; *out = repl::OpTime(ts, term); diff --git a/src/mongo/bson/util/bson_extract_test.cpp b/src/mongo/bson/util/bson_extract_test.cpp index 1c7261d1301..95951efb87e 100644 --- a/src/mongo/bson/util/bson_extract_test.cpp +++ b/src/mongo/bson/util/bson_extract_test.cpp @@ -86,7 +86,7 @@ TEST(ExtractBSON, ExtractStringFieldWithDefault) { TEST(ExtractBSON, ExtractOpTimeField) { // Outer object cases. - BSONObj obj = BSON("a" << BSON("ts" << Timestamp(10, 0) << "term" << 2) << "b" + BSONObj obj = BSON("a" << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "b" << "notAnObj"); repl::OpTime opTime; ASSERT_OK(bsonExtractOpTimeField(obj, "a", &opTime)); @@ -97,13 +97,13 @@ TEST(ExtractBSON, ExtractOpTimeField) { // Missing timestamp field. obj = BSON("a" << BSON("ts" << "notATimestamp" - << "term" << 2)); + << "t" << 2)); ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractOpTimeField(obj, "a", &opTime)); // Wrong typed timestamp field. - obj = BSON("a" << BSON("term" << 2)); + obj = BSON("a" << BSON("t" << 2)); ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractOpTimeField(obj, "a", &opTime)); // Missing term field. - obj = BSON("a" << BSON("ts" << Timestamp(10, 0) << "term" + obj = BSON("a" << BSON("ts" << Timestamp(10, 0) << "t" << "notANumber")); ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractOpTimeField(obj, "a", &opTime)); // Wrong typed term field. diff --git a/src/mongo/db/repl/bgsync.cpp b/src/mongo/db/repl/bgsync.cpp index 7a8c76ffb4a..40afe9f7356 100644 --- a/src/mongo/db/repl/bgsync.cpp +++ b/src/mongo/db/repl/bgsync.cpp @@ -101,7 +101,7 @@ Status checkRemoteOplogStart(stdx::function<StatusWith<BSONObj>()> getNextOperat "we are ahead of the sync source, will try to roll back"); } BSONObj o = result.getValue(); - OpTime opTime = fassertStatusOK(28778, OpTime::parseFromBSON(o)); + OpTime opTime = fassertStatusOK(28778, OpTime::parseFromOplogEntry(o)); long long hash = o["h"].numberLong(); if (opTime != lastOpTimeFetched || hash != lastHashFetched) { return Status(ErrorCodes::OplogStartMissing, @@ -509,7 +509,7 @@ void BackgroundSync::_fetcherCallback(const StatusWith<Fetcher::QueryResponse>& { stdx::unique_lock<stdx::mutex> lock(_mutex); _lastFetchedHash = o["h"].numberLong(); - _lastOpTimeFetched = fassertStatusOK(28770, OpTime::parseFromBSON(o)); + _lastOpTimeFetched = fassertStatusOK(28770, OpTime::parseFromOplogEntry(o)); LOG(3) << "lastOpTimeFetched: " << _lastOpTimeFetched; } } diff --git a/src/mongo/db/repl/minvalid.cpp b/src/mongo/db/repl/minvalid.cpp index 5584ea54658..7860d4ac988 100644 --- a/src/mongo/db/repl/minvalid.cpp +++ b/src/mongo/db/repl/minvalid.cpp @@ -111,7 +111,7 @@ OpTime getMinValid(OperationContext* txn) { BSONObj mv; bool found = Helpers::getSingleton(txn, minvalidNS, mv); if (found) { - return fassertStatusOK(28771, OpTime::parseFromBSON(mv)); + return fassertStatusOK(28771, OpTime::parseFromOplogEntry(mv)); } return OpTime(); } diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index b7c3ca23416..99e3dcf0d14 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -314,7 +314,10 @@ void _logOp(OperationContext* txn, BSONObjBuilder b(256); - slot.first.append(&b); + b.append("ts", slot.first.getTimestamp()); + if (slot.first.getTerm() != -1) { + b.append("t", slot.first.getTerm()); + } b.append("h", slot.second); b.append("v", OPLOG_VERSION); b.append("op", opstr); @@ -385,7 +388,7 @@ OpTime writeOpsToOplog(OperationContext* txn, const std::deque<BSONObj>& ops) { checkOplogInsert( _localOplogCollection->insertDocuments(txn, opsVect.begin(), opsVect.end(), false)); lastOptime = - fassertStatusOK(ErrorCodes::InvalidBSON, OpTime::parseFromBSON(opsVect.back())); + fassertStatusOK(ErrorCodes::InvalidBSON, OpTime::parseFromOplogEntry(opsVect.back())); wunit.commit(); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "writeOps", _localOplogCollection->ns().ns()); @@ -896,7 +899,7 @@ void initTimestampFromOplog(OperationContext* txn, const std::string& oplogNS) { if (!lastOp.isEmpty()) { LOG(1) << "replSet setting last Timestamp"; - const OpTime opTime = fassertStatusOK(28696, OpTime::parseFromBSON(lastOp)); + const OpTime opTime = fassertStatusOK(28696, OpTime::parseFromOplogEntry(lastOp)); setNewTimestamp(opTime.getTimestamp()); } } @@ -996,7 +999,7 @@ void SnapshotThread::run() { continue; // oplog is completely empty. const auto op = record->data.releaseToBson(); - opTimeOfSnapshot = fassertStatusOK(28780, OpTime::parseFromBSON(op)); + opTimeOfSnapshot = fassertStatusOK(28780, OpTime::parseFromOplogEntry(op)); invariant(!opTimeOfSnapshot.isNull()); } diff --git a/src/mongo/db/repl/oplogreader.cpp b/src/mongo/db/repl/oplogreader.cpp index 1332e6f7542..ecda101a91f 100644 --- a/src/mongo/db/repl/oplogreader.cpp +++ b/src/mongo/db/repl/oplogreader.cpp @@ -183,7 +183,8 @@ void OplogReader::connectToSyncSource(OperationContext* txn, // Read the first (oldest) op and confirm that it's not newer than our last // fetched op. Otherwise, we have fallen off the back of that source's oplog. BSONObj remoteOldestOp(findOne(rsOplogName.c_str(), Query())); - OpTime remoteOldOpTime = fassertStatusOK(28776, OpTime::parseFromBSON(remoteOldestOp)); + OpTime remoteOldOpTime = + fassertStatusOK(28776, OpTime::parseFromOplogEntry(remoteOldestOp)); // remoteOldOpTime may come from a very old config, so we cannot compare their terms. if (!lastOpTimeFetched.isNull() && diff --git a/src/mongo/db/repl/optime.cpp b/src/mongo/db/repl/optime.cpp index 172302b42c1..92a3c5556ca 100644 --- a/src/mongo/db/repl/optime.cpp +++ b/src/mongo/db/repl/optime.cpp @@ -37,12 +37,9 @@ namespace mongo { namespace repl { -namespace { -const char* kTimestampFieldName = "ts"; -const char* kTermFieldName = "t"; - -} // namespace +const char OpTime::kTimestampFieldName[] = "ts"; +const char OpTime::kTermFieldName[] = "t"; OpTime::OpTime(Timestamp ts, long long term) : _timestamp(std::move(ts)), _term(term) {} @@ -62,16 +59,15 @@ bool OpTime::isNull() const { return _timestamp.isNull(); } -void OpTime::append(BSONObjBuilder* builder) const { - builder->append(kTimestampFieldName, _timestamp); +void OpTime::append(BSONObjBuilder* builder, const std::string& subObjName) const { + BSONObjBuilder opTimeBuilder(builder->subobjStart(subObjName)); + opTimeBuilder.append(kTimestampFieldName, _timestamp); - // Don't add term in protocol version 0. - if (_term != kUninitializedTerm) { - builder->append(kTermFieldName, _term); - } + opTimeBuilder.append(kTermFieldName, _term); + opTimeBuilder.doneFast(); } -StatusWith<OpTime> OpTime::parseFromBSON(const BSONObj& obj) { +StatusWith<OpTime> OpTime::parseFromOplogEntry(const BSONObj& obj) { Timestamp ts; Status status = bsonExtractTimestampField(obj, kTimestampFieldName, &ts); if (!status.isOK()) diff --git a/src/mongo/db/repl/optime.h b/src/mongo/db/repl/optime.h index c530ca51f97..0af26bc8250 100644 --- a/src/mongo/db/repl/optime.h +++ b/src/mongo/db/repl/optime.h @@ -49,6 +49,9 @@ namespace repl { class OpTime { public: + static const char kTimestampFieldName[]; + static const char kTermFieldName[]; + // The term of an OpTime generated by old protocol version. static const long long kUninitializedTerm = -1; @@ -70,11 +73,11 @@ public: /** * Serializes the contents of this optime to the specified builder in the form: - * { ts: <timestamp>, t: term } + * subObjName : { ts: <timestamp>, t: <term> } */ - void append(BSONObjBuilder* builder) const; + void append(BSONObjBuilder* builder, const std::string& subObjName) const; - static StatusWith<OpTime> parseFromBSON(const BSONObj& obj); + static StatusWith<OpTime> parseFromOplogEntry(const BSONObj& obj); std::string toString() const; diff --git a/src/mongo/db/repl/read_concern_args.cpp b/src/mongo/db/repl/read_concern_args.cpp index 42c7dab7361..1389a7380a1 100644 --- a/src/mongo/db/repl/read_concern_args.cpp +++ b/src/mongo/db/repl/read_concern_args.cpp @@ -50,9 +50,7 @@ const char kLinearizableReadConcernStr[] = "linearizable"; } // unnamed namespace const string ReadConcernArgs::kReadConcernFieldName("readConcern"); -const string ReadConcernArgs::kOpTimeFieldName("afterOpTime"); -const string ReadConcernArgs::kOpTimestampFieldName("ts"); -const string ReadConcernArgs::kOpTermFieldName("term"); +const string ReadConcernArgs::kAfterOpTimeFieldName("afterOpTime"); const string ReadConcernArgs::kLevelFieldName("level"); ReadConcernArgs::ReadConcernArgs() = default; @@ -83,9 +81,9 @@ Status ReadConcernArgs::initialize(const BSONObj& cmdObj) { BSONObj readConcernObj = readConcernElem.Obj(); - if (readConcernObj.hasField(kOpTimeFieldName)) { + if (readConcernObj.hasField(kAfterOpTimeFieldName)) { OpTime opTime; - auto opTimeStatus = bsonExtractOpTimeField(readConcernObj, kOpTimeFieldName, &opTime); + auto opTimeStatus = bsonExtractOpTimeField(readConcernObj, kAfterOpTimeFieldName, &opTime); if (!opTimeStatus.isOK()) { return opTimeStatus; } @@ -138,10 +136,7 @@ void ReadConcernArgs::appendInfo(BSONObjBuilder* builder) { } if (_opTime) { - BSONObjBuilder afterBuilder(rcBuilder.subobjStart(kOpTimeFieldName)); - afterBuilder.append(kOpTimestampFieldName, _opTime->getTimestamp()); - afterBuilder.append(kOpTermFieldName, _opTime->getTerm()); - afterBuilder.done(); + _opTime->append(&rcBuilder, kAfterOpTimeFieldName); } rcBuilder.done(); diff --git a/src/mongo/db/repl/read_concern_args.h b/src/mongo/db/repl/read_concern_args.h index c6f3605a9fb..a010d9c8793 100644 --- a/src/mongo/db/repl/read_concern_args.h +++ b/src/mongo/db/repl/read_concern_args.h @@ -46,9 +46,7 @@ enum class ReadConcernLevel { kLocalReadConcern, kMajorityReadConcern, kLineariz class ReadConcernArgs { public: static const std::string kReadConcernFieldName; - static const std::string kOpTermFieldName; - static const std::string kOpTimeFieldName; - static const std::string kOpTimestampFieldName; + static const std::string kAfterOpTimeFieldName; static const std::string kLevelFieldName; ReadConcernArgs(); diff --git a/src/mongo/db/repl/read_concern_args_test.cpp b/src/mongo/db/repl/read_concern_args_test.cpp index 96077da684c..34fa0d41037 100644 --- a/src/mongo/db/repl/read_concern_args_test.cpp +++ b/src/mongo/db/repl/read_concern_args_test.cpp @@ -36,12 +36,12 @@ namespace { TEST(ReadAfterParse, ReadAfterOnly) { ReadConcernArgs readAfterOpTime; - ASSERT_OK(readAfterOpTime.initialize( - BSON("find" - << "test" << ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTimestampFieldName - << Timestamp(20, 30) << ReadConcernArgs::kOpTermFieldName << 2))))); + ASSERT_OK(readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kAfterOpTimeFieldName + << BSON(OpTime::kTimestampFieldName + << Timestamp(20, 30) + << OpTime::kTermFieldName << 2))))); ASSERT_EQ(Timestamp(20, 30), readAfterOpTime.getOpTime().getTimestamp()); ASSERT_EQ(2, readAfterOpTime.getOpTime().getTerm()); @@ -64,9 +64,9 @@ TEST(ReadAfterParse, ReadCommittedFullSpecification) { ASSERT_OK(readAfterOpTime.initialize( BSON("find" << "test" << ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTimestampFieldName - << Timestamp(20, 30) << ReadConcernArgs::kOpTermFieldName << 2) + << BSON(ReadConcernArgs::kAfterOpTimeFieldName + << BSON(OpTime::kTimestampFieldName << Timestamp(20, 30) + << OpTime::kTermFieldName << 2) << ReadConcernArgs::kLevelFieldName << "majority")))); ASSERT_EQ(Timestamp(20, 30), readAfterOpTime.getOpTime().getTimestamp()); @@ -96,7 +96,7 @@ TEST(ReadAfterParse, BadOpTimeType) { ASSERT_NOT_OK( readAfterOpTime.initialize(BSON("find" << "test" << ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName << 2)))); + << BSON(ReadConcernArgs::kAfterOpTimeFieldName << 2)))); } TEST(ReadAfterParse, OpTimeNotNeededForValidReadConcern) { @@ -111,9 +111,8 @@ TEST(ReadAfterParse, NoOpTimeTS) { ASSERT_NOT_OK( readAfterOpTime.initialize(BSON("find" << "test" << ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTimestampFieldName - << 2))))); + << BSON(ReadConcernArgs::kAfterOpTimeFieldName + << BSON(OpTime::kTimestampFieldName << 2))))); } TEST(ReadAfterParse, NoOpTimeTerm) { @@ -121,28 +120,30 @@ TEST(ReadAfterParse, NoOpTimeTerm) { ASSERT_NOT_OK( readAfterOpTime.initialize(BSON("find" << "test" << ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTermFieldName << 2))))); + << BSON(ReadConcernArgs::kAfterOpTimeFieldName + << BSON(OpTime::kTermFieldName << 2))))); } TEST(ReadAfterParse, BadOpTimeTSType) { ReadConcernArgs readAfterOpTime; - ASSERT_NOT_OK(readAfterOpTime.initialize( - BSON("find" - << "test" << ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTimestampFieldName - << BSON("x" << 1) << ReadConcernArgs::kOpTermFieldName << 2))))); + ASSERT_NOT_OK( + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kAfterOpTimeFieldName + << BSON(OpTime::kTimestampFieldName + << BSON("x" << 1) << OpTime::kTermFieldName + << 2))))); } TEST(ReadAfterParse, BadOpTimeTermType) { ReadConcernArgs readAfterOpTime; - ASSERT_NOT_OK(readAfterOpTime.initialize( - BSON("find" - << "test" << ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTimestampFieldName - << Timestamp(1, 0) << ReadConcernArgs::kOpTermFieldName << "y"))))); + ASSERT_NOT_OK( + readAfterOpTime.initialize(BSON("find" + << "test" << ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kAfterOpTimeFieldName + << BSON(OpTime::kTimestampFieldName + << Timestamp(1, 0) << OpTime::kTermFieldName + << "y"))))); } TEST(ReadAfterParse, BadLevelType) { @@ -177,11 +178,10 @@ TEST(ReadAfterSerialize, ReadAfterOnly) { ReadConcernArgs readAfterOpTime(OpTime(Timestamp(20, 30), 2), boost::none); readAfterOpTime.appendInfo(&builder); - BSONObj expectedObj( - BSON(ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTimestampFieldName - << Timestamp(20, 30) << ReadConcernArgs::kOpTermFieldName << 2)))); + BSONObj expectedObj(BSON(ReadConcernArgs::kReadConcernFieldName + << BSON(ReadConcernArgs::kAfterOpTimeFieldName << BSON( + OpTime::kTimestampFieldName + << Timestamp(20, 30) << OpTime::kTermFieldName << 2)))); ASSERT_EQ(expectedObj, builder.done()); } @@ -203,12 +203,11 @@ TEST(ReadAfterSerialize, FullSpecification) { ReadConcernLevel::kMajorityReadConcern); readAfterOpTime.appendInfo(&builder); - BSONObj expectedObj( - BSON(ReadConcernArgs::kReadConcernFieldName - << BSON(ReadConcernArgs::kLevelFieldName - << "majority" << ReadConcernArgs::kOpTimeFieldName - << BSON(ReadConcernArgs::kOpTimestampFieldName - << Timestamp(20, 30) << ReadConcernArgs::kOpTermFieldName << 2)))); + BSONObj expectedObj(BSON(ReadConcernArgs::kReadConcernFieldName << BSON( + ReadConcernArgs::kLevelFieldName + << "majority" << ReadConcernArgs::kAfterOpTimeFieldName + << BSON(OpTime::kTimestampFieldName + << Timestamp(20, 30) << OpTime::kTermFieldName << 2)))); ASSERT_EQ(expectedObj, builder.done()); } diff --git a/src/mongo/db/repl/repl_set_heartbeat_response.cpp b/src/mongo/db/repl/repl_set_heartbeat_response.cpp index 1acccd49d03..bb3d4918c02 100644 --- a/src/mongo/db/repl/repl_set_heartbeat_response.cpp +++ b/src/mongo/db/repl/repl_set_heartbeat_response.cpp @@ -119,10 +119,7 @@ void ReplSetHeartbeatResponse::addToBSON(BSONObjBuilder* builder, bool isProtoco } if (_opTimeSet) { if (isProtocolVersionV1) { - BSONObjBuilder opTime(builder->subobjStart(kOpTimeFieldName)); - opTime.append(kTimestampFieldName, _opTime.getTimestamp()); - opTime.append(kTermFieldName, _opTime.getTerm()); - opTime.done(); + _opTime.append(builder, kOpTimeFieldName); } else { builder->appendDate(kOpTimeFieldName, Date_t::fromMillisSinceEpoch(_opTime.getTimestamp().asLL())); diff --git a/src/mongo/db/repl/repl_set_request_votes_args.cpp b/src/mongo/db/repl/repl_set_request_votes_args.cpp index 51a049131a2..9001272d94b 100644 --- a/src/mongo/db/repl/repl_set_request_votes_args.cpp +++ b/src/mongo/db/repl/repl_set_request_votes_args.cpp @@ -42,7 +42,6 @@ const std::string kConfigVersionFieldName = "configVersion"; const std::string kDryRunFieldName = "dryRun"; const std::string kLastCommittedOpFieldName = "lastCommittedOp"; const std::string kOkFieldName = "ok"; -const std::string kOpTimeFieldName = "ts"; const std::string kReasonFieldName = "reason"; const std::string kSetNameFieldName = "setName"; const std::string kTermFieldName = "term"; @@ -54,7 +53,6 @@ const std::string kLegalArgsFieldNames[] = { kConfigVersionFieldName, kDryRunFieldName, kLastCommittedOpFieldName, - kOpTimeFieldName, kSetNameFieldName, kTermFieldName, }; @@ -129,10 +127,7 @@ void ReplSetRequestVotesArgs::addToBSON(BSONObjBuilder* builder) const { builder->append(kTermFieldName, _term); builder->appendIntOrLL(kCandidateIdFieldName, _candidateId); builder->appendIntOrLL(kConfigVersionFieldName, _cfgver); - BSONObjBuilder lastCommittedOp(builder->subobjStart(kLastCommittedOpFieldName)); - lastCommittedOp.append(kOpTimeFieldName, _lastCommittedOp.getTimestamp()); - lastCommittedOp.append(kTermFieldName, _lastCommittedOp.getTerm()); - lastCommittedOp.done(); + _lastCommittedOp.append(builder, kLastCommittedOpFieldName); } Status ReplSetRequestVotesResponse::initialize(const BSONObj& argsObj) { diff --git a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp index c78b129ba39..215e6d96e0a 100644 --- a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp @@ -307,7 +307,7 @@ StatusWith<OpTime> ReplicationCoordinatorExternalStateImpl::loadLastOpTime(Opera << " entry to have type Timestamp, but found " << typeName(tsElement.type())); } - return OpTime::parseFromBSON(oplogEntry); + return OpTime::parseFromOplogEntry(oplogEntry); } catch (const DBException& ex) { return StatusWith<OpTime>(ex.toStatus()); } diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index a101e2b9aa1..291b591ab3f 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -1507,8 +1507,7 @@ bool ReplicationCoordinatorImpl::prepareReplSetUpdatePositionCommand(BSONObjBuil BSONObjBuilder entry(arrayBuilder.subobjStart()); entry.append("_id", itr->rid); if (isV1ElectionProtocol()) { - BSONObjBuilder opTimeBuilder(entry.subobjStart("optime")); - itr->opTime.append(&opTimeBuilder); + itr->opTime.append(&entry, "optime"); } else { entry.append("optime", itr->opTime.getTimestamp()); } diff --git a/src/mongo/db/repl/replication_coordinator_impl_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_test.cpp index 7f71262204f..ff49082a3e6 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp @@ -35,6 +35,7 @@ #include <set> #include <vector> +#include "mongo/bson/util/bson_extract.h" #include "mongo/db/operation_context_noop.h" #include "mongo/db/repl/handshake_args.h" #include "mongo/db/repl/is_master_response.h" @@ -2501,19 +2502,19 @@ TEST_F(ReplCoordTest, MetadataWrongConfigVersion) { // lower configVersion StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON( - rpc::kReplSetMetadataFieldName << BSON( - "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "term" << 2) << "lastOpVisible" - << BSON("ts" << Timestamp(10, 0) << "term" << 2) << "configVersion" - << 1 << "primaryIndex" << 2 << "term" << 2))); + rpc::kReplSetMetadataFieldName + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "lastOpVisible" + << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "configVersion" + << 1 << "primaryIndex" << 2 << "term" << 2))); getReplCoord()->processReplSetMetadata(metadata.getValue()); ASSERT_EQUALS(OpTime(Timestamp(0, 0), 0), getReplCoord()->getLastCommittedOpTime()); // higher configVersion StatusWith<rpc::ReplSetMetadata> metadata2 = rpc::ReplSetMetadata::readFromMetadata(BSON( - rpc::kReplSetMetadataFieldName << BSON( - "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "term" << 2) << "lastOpVisible" - << BSON("ts" << Timestamp(10, 0) << "term" << 2) << "configVersion" - << 100 << "primaryIndex" << 2 << "term" << 2))); + rpc::kReplSetMetadataFieldName + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "lastOpVisible" + << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "configVersion" + << 100 << "primaryIndex" << 2 << "term" << 2))); getReplCoord()->processReplSetMetadata(metadata2.getValue()); ASSERT_EQUALS(OpTime(Timestamp(0, 0), 0), getReplCoord()->getLastCommittedOpTime()); } @@ -2544,10 +2545,10 @@ TEST_F(ReplCoordTest, MetadataUpdatesLastCommittedOpTime) { // higher OpTime, should change StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON( - rpc::kReplSetMetadataFieldName << BSON( - "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "term" << 1) << "lastOpVisible" - << BSON("ts" << Timestamp(10, 0) << "term" << 1) << "configVersion" - << 2 << "primaryIndex" << 2 << "term" << 1))); + rpc::kReplSetMetadataFieldName + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 1) << "lastOpVisible" + << BSON("ts" << Timestamp(10, 0) << "t" << 1) << "configVersion" + << 2 << "primaryIndex" << 2 << "term" << 1))); getReplCoord()->processReplSetMetadata(metadata.getValue()); ASSERT_EQUALS(OpTime(Timestamp(10, 0), 1), getReplCoord()->getLastCommittedOpTime()); ASSERT_EQUALS(OpTime(Timestamp(10, 0), 1), getReplCoord()->getCurrentCommittedSnapshotOpTime()); @@ -2555,8 +2556,8 @@ TEST_F(ReplCoordTest, MetadataUpdatesLastCommittedOpTime) { // lower OpTime, should not change StatusWith<rpc::ReplSetMetadata> metadata2 = rpc::ReplSetMetadata::readFromMetadata(BSON( rpc::kReplSetMetadataFieldName - << BSON("lastOpCommitted" << BSON("ts" << Timestamp(9, 0) << "term" << 1) << "lastOpVisible" - << BSON("ts" << Timestamp(9, 0) << "term" << 1) << "configVersion" + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(9, 0) << "t" << 1) << "lastOpVisible" + << BSON("ts" << Timestamp(9, 0) << "t" << 1) << "configVersion" << 2 << "primaryIndex" << 2 << "term" << 1))); getReplCoord()->processReplSetMetadata(metadata2.getValue()); ASSERT_EQUALS(OpTime(Timestamp(10, 0), 1), getReplCoord()->getLastCommittedOpTime()); @@ -2584,10 +2585,10 @@ TEST_F(ReplCoordTest, MetadataUpdatesTermAndPrimaryId) { // higher term, should change StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON( - rpc::kReplSetMetadataFieldName << BSON( - "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "term" << 3) << "lastOpVisible" - << BSON("ts" << Timestamp(10, 0) << "term" << 3) << "configVersion" - << 2 << "primaryIndex" << 2 << "term" << 3))); + rpc::kReplSetMetadataFieldName + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "lastOpVisible" + << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "configVersion" + << 2 << "primaryIndex" << 2 << "term" << 3))); getReplCoord()->processReplSetMetadata(metadata.getValue()); ASSERT_EQUALS(OpTime(Timestamp(10, 0), 3), getReplCoord()->getLastCommittedOpTime()); ASSERT_EQUALS(3, getReplCoord()->getTerm()); @@ -2595,10 +2596,10 @@ TEST_F(ReplCoordTest, MetadataUpdatesTermAndPrimaryId) { // lower term, should not change StatusWith<rpc::ReplSetMetadata> metadata2 = rpc::ReplSetMetadata::readFromMetadata(BSON( - rpc::kReplSetMetadataFieldName << BSON( - "lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "term" << 3) << "lastOpVisible" - << BSON("ts" << Timestamp(11, 0) << "term" << 3) << "configVersion" - << 2 << "primaryIndex" << 1 << "term" << 2))); + rpc::kReplSetMetadataFieldName + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "lastOpVisible" + << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "configVersion" + << 2 << "primaryIndex" << 1 << "term" << 2))); getReplCoord()->processReplSetMetadata(metadata2.getValue()); ASSERT_EQUALS(OpTime(Timestamp(11, 0), 3), getReplCoord()->getLastCommittedOpTime()); ASSERT_EQUALS(3, getReplCoord()->getTerm()); @@ -2606,10 +2607,10 @@ TEST_F(ReplCoordTest, MetadataUpdatesTermAndPrimaryId) { // same term, should not change StatusWith<rpc::ReplSetMetadata> metadata3 = rpc::ReplSetMetadata::readFromMetadata(BSON( - rpc::kReplSetMetadataFieldName << BSON( - "lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "term" << 3) << "lastOpVisible" - << BSON("ts" << Timestamp(11, 0) << "term" << 3) << "configVersion" - << 2 << "primaryIndex" << 1 << "term" << 3))); + rpc::kReplSetMetadataFieldName + << BSON("lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "lastOpVisible" + << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "configVersion" + << 2 << "primaryIndex" << 1 << "term" << 3))); getReplCoord()->processReplSetMetadata(metadata3.getValue()); ASSERT_EQUALS(OpTime(Timestamp(11, 0), 3), getReplCoord()->getLastCommittedOpTime()); ASSERT_EQUALS(3, getReplCoord()->getTerm()); @@ -2954,7 +2955,8 @@ TEST_F(ReplCoordTest, LivenessForwardingForChainedMember) { BSONObj entry = entryElement.Obj(); long long memberId = entry["memberId"].Number(); memberIds.insert(memberId); - OpTime entryOpTime = OpTime::parseFromBSON(entry["optime"].Obj()).getValue(); + OpTime entryOpTime; + bsonExtractOpTimeField(entry, "optime", &entryOpTime); ASSERT_EQUALS(optime, entryOpTime); } ASSERT_EQUALS(2U, memberIds.size()); @@ -2980,7 +2982,8 @@ TEST_F(ReplCoordTest, LivenessForwardingForChainedMember) { BSONObj entry = entryElement.Obj(); long long memberId = entry["memberId"].Number(); memberIds2.insert(memberId); - OpTime entryOpTime = OpTime::parseFromBSON(entry["optime"].Obj()).getValue(); + OpTime entryOpTime; + bsonExtractOpTimeField(entry, "optime", &entryOpTime); ASSERT_EQUALS(optime, entryOpTime); } ASSERT_EQUALS(1U, memberIds2.size()); diff --git a/src/mongo/db/repl/rs_initialsync.cpp b/src/mongo/db/repl/rs_initialsync.cpp index d62b86f20e9..9ee2d8a65a3 100644 --- a/src/mongo/db/repl/rs_initialsync.cpp +++ b/src/mongo/db/repl/rs_initialsync.cpp @@ -253,7 +253,7 @@ bool _initialSyncApplyOplog(OperationContext* ctx, repl::SyncTail& syncer, Oplog return false; } - OpTime stopOpTime = fassertStatusOK(28777, OpTime::parseFromBSON(lastOp)); + OpTime stopOpTime = fassertStatusOK(28777, OpTime::parseFromOplogEntry(lastOp)); // If we already have what we need then return. if (stopOpTime == startOpTime) diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index a78c36c57e5..a88528a57d0 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -323,7 +323,7 @@ void syncFixUp(OperationContext* txn, // we have items we are writing that aren't from a point-in-time. thus best not to come // online until we get to that point in freshness. - OpTime minValid = fassertStatusOK(28774, OpTime::parseFromBSON(newMinValid)); + OpTime minValid = fassertStatusOK(28774, OpTime::parseFromOplogEntry(newMinValid)); log() << "minvalid=" << minValid; setMinValid(txn, minValid); @@ -426,7 +426,7 @@ void syncFixUp(OperationContext* txn, if (newMinValid.isEmpty()) { err = "can't get minvalid from sync source"; } else { - OpTime minValid = fassertStatusOK(28775, OpTime::parseFromBSON(newMinValid)); + OpTime minValid = fassertStatusOK(28775, OpTime::parseFromOplogEntry(newMinValid)); log() << "minvalid=" << minValid; setMinValid(txn, minValid); } diff --git a/src/mongo/db/repl/sync_tail.cpp b/src/mongo/db/repl/sync_tail.cpp index 76c8633bf31..5d8029c5124 100644 --- a/src/mongo/db/repl/sync_tail.cpp +++ b/src/mongo/db/repl/sync_tail.cpp @@ -431,7 +431,8 @@ void SyncTail::_applyOplogUntil(OperationContext* txn, const OpTime& endOpTime) // Check if we reached the end const BSONObj currentOp = ops.back(); - const OpTime currentOpTime = fassertStatusOK(28772, OpTime::parseFromBSON(currentOp)); + const OpTime currentOpTime = + fassertStatusOK(28772, OpTime::parseFromOplogEntry(currentOp)); // When we reach the end return this batch if (currentOpTime == endOpTime) { @@ -591,7 +592,7 @@ void SyncTail::oplogApplication() { // Set minValid to the last op to be applied in this next batch. // This will cause this node to go into RECOVERING state // if we should crash and restart before updating the oplog - setMinValid(&txn, fassertStatusOK(28773, OpTime::parseFromBSON(lastOp))); + setMinValid(&txn, fassertStatusOK(28773, OpTime::parseFromOplogEntry(lastOp))); multiApply(&txn, ops, &_prefetcherPool, diff --git a/src/mongo/db/repl/update_position_args.cpp b/src/mongo/db/repl/update_position_args.cpp index 5151fbfe1f6..6ccddfa96aa 100644 --- a/src/mongo/db/repl/update_position_args.cpp +++ b/src/mongo/db/repl/update_position_args.cpp @@ -94,10 +94,9 @@ Status UpdatePositionArgs::initialize(const BSONObj& argsObj) { OpTime opTime; if (entry[kOpTimeFieldName].isABSONObj()) { // In protocol version 1, { ts: <timestamp>, t: term } - StatusWith<OpTime> opTimeStatus = OpTime::parseFromBSON(entry[kOpTimeFieldName].Obj()); - if (!opTimeStatus.isOK()) - return opTimeStatus.getStatus(); - opTime = opTimeStatus.getValue(); + Status status = bsonExtractOpTimeField(entry, kOpTimeFieldName, &opTime); + if (!status.isOK()) + return status; } else { Timestamp ts; status = bsonExtractTimestampField(entry, kOpTimeFieldName, &ts); diff --git a/src/mongo/db/repl/vote_requester.cpp b/src/mongo/db/repl/vote_requester.cpp index 7bef97a148f..a8d24c3b496 100644 --- a/src/mongo/db/repl/vote_requester.cpp +++ b/src/mongo/db/repl/vote_requester.cpp @@ -75,7 +75,7 @@ std::vector<RemoteCommandRequest> VoteRequester::Algorithm::getRequests() const BSONObjBuilder lastCommittedOp(requestVotesCmdBuilder.subobjStart("lastCommittedOp")); lastCommittedOp.append("ts", _lastOplogEntry.getTimestamp()); - lastCommittedOp.append("term", _lastOplogEntry.getTerm()); + lastCommittedOp.append("t", _lastOplogEntry.getTerm()); lastCommittedOp.done(); const BSONObj requestVotesCmd = requestVotesCmdBuilder.obj(); diff --git a/src/mongo/rpc/metadata/repl_set_metadata.cpp b/src/mongo/rpc/metadata/repl_set_metadata.cpp index 8ea6f2fa867..aadd520a683 100644 --- a/src/mongo/rpc/metadata/repl_set_metadata.cpp +++ b/src/mongo/rpc/metadata/repl_set_metadata.cpp @@ -46,7 +46,6 @@ const char kLastOpCommittedFieldName[] = "lastOpCommitted"; const char kLastOpVisibleFieldName[] = "lastOpVisible"; const char kConfigVersionFieldName[] = "configVersion"; const char kPrimaryIndexFieldName[] = "primaryIndex"; -const char kTimestampFieldName[] = "ts"; const char kTermFieldName[] = "term"; } // unnamed namespace @@ -106,18 +105,8 @@ StatusWith<ReplSetMetadata> ReplSetMetadata::readFromMetadata(const BSONObj& met Status ReplSetMetadata::writeToMetadata(BSONObjBuilder* builder) const { BSONObjBuilder replMetadataBuilder(builder->subobjStart(kReplSetMetadataFieldName)); replMetadataBuilder.append(kTermFieldName, _currentTerm); - - BSONObjBuilder lastOpCommittedBuilder( - replMetadataBuilder.subobjStart(kLastOpCommittedFieldName)); - lastOpCommittedBuilder.append(kTimestampFieldName, _lastOpCommitted.getTimestamp()); - lastOpCommittedBuilder.append(kTermFieldName, _lastOpCommitted.getTerm()); - lastOpCommittedBuilder.doneFast(); - - BSONObjBuilder lastOpVisibleBuilder(replMetadataBuilder.subobjStart(kLastOpVisibleFieldName)); - lastOpVisibleBuilder.append(kTimestampFieldName, _lastOpVisible.getTimestamp()); - lastOpVisibleBuilder.append(kTermFieldName, _lastOpVisible.getTerm()); - lastOpVisibleBuilder.doneFast(); - + _lastOpCommitted.append(&replMetadataBuilder, kLastOpCommittedFieldName); + _lastOpVisible.append(&replMetadataBuilder, kLastOpVisibleFieldName); replMetadataBuilder.append(kConfigVersionFieldName, _configVersion); replMetadataBuilder.append(kPrimaryIndexFieldName, _currentPrimaryIndex); replMetadataBuilder.doneFast(); diff --git a/src/mongo/rpc/metadata/repl_set_metadata_test.cpp b/src/mongo/rpc/metadata/repl_set_metadata_test.cpp index 82bff1f0209..499bbeb0b23 100644 --- a/src/mongo/rpc/metadata/repl_set_metadata_test.cpp +++ b/src/mongo/rpc/metadata/repl_set_metadata_test.cpp @@ -50,9 +50,9 @@ TEST(ReplResponseMetadataTest, Roundtrip) { BSONObj expectedObj( BSON(kReplSetMetadataFieldName << BSON("term" << 3 << "lastOpCommitted" - << BSON("ts" << opTime.getTimestamp() << "term" << opTime.getTerm()) + << BSON("ts" << opTime.getTimestamp() << "t" << opTime.getTerm()) << "lastOpVisible" - << BSON("ts" << opTime2.getTimestamp() << "term" << opTime2.getTerm()) + << BSON("ts" << opTime2.getTimestamp() << "t" << opTime2.getTerm()) << "configVersion" << 6 << "primaryIndex" << 12))); BSONObj serializedObj = builder.obj(); diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp index f7bb0b02520..b316d57e55c 100644 --- a/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp +++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set_test_fixture.cpp @@ -429,15 +429,15 @@ void CatalogManagerReplSetTestFixture::checkReadConcern(const BSONObj& cmdObj, auto readConcernObj = readConcernElem.Obj(); ASSERT_EQ("majority", readConcernObj[repl::ReadConcernArgs::kLevelFieldName].str()); - auto afterElem = readConcernObj[repl::ReadConcernArgs::kOpTimeFieldName]; + auto afterElem = readConcernObj[repl::ReadConcernArgs::kAfterOpTimeFieldName]; ASSERT_EQ(Object, afterElem.type()); auto afterObj = afterElem.Obj(); - ASSERT_TRUE(afterObj.hasField(repl::ReadConcernArgs::kOpTimestampFieldName)); - ASSERT_EQ(expectedTS, afterObj[repl::ReadConcernArgs::kOpTimestampFieldName].timestamp()); - ASSERT_TRUE(afterObj.hasField(repl::ReadConcernArgs::kOpTermFieldName)); - ASSERT_EQ(expectedTerm, afterObj[repl::ReadConcernArgs::kOpTermFieldName].numberLong()); + ASSERT_TRUE(afterObj.hasField(repl::OpTime::kTimestampFieldName)); + ASSERT_EQ(expectedTS, afterObj[repl::OpTime::kTimestampFieldName].timestamp()); + ASSERT_TRUE(afterObj.hasField(repl::OpTime::kTermFieldName)); + ASSERT_EQ(expectedTerm, afterObj[repl::OpTime::kTermFieldName].numberLong()); } } // namespace mongo diff --git a/src/mongo/s/chunk_version.cpp b/src/mongo/s/chunk_version.cpp index 305875d4a6e..ff926d4db3e 100644 --- a/src/mongo/s/chunk_version.cpp +++ b/src/mongo/s/chunk_version.cpp @@ -111,7 +111,7 @@ StatusWith<ChunkVersionAndOpTime> ChunkVersionAndOpTime::parseFromBSONForCommand const ChunkVersion& chunkVersion = chunkVersionStatus.getValue(); - const auto opTimeStatus = repl::OpTime::parseFromBSON(obj); + const auto opTimeStatus = repl::OpTime::parseFromOplogEntry(obj); if (opTimeStatus.isOK()) { return ChunkVersionAndOpTime(chunkVersion, opTimeStatus.getValue()); } else if (opTimeStatus == ErrorCodes::NoSuchKey) { @@ -129,7 +129,7 @@ StatusWith<ChunkVersionAndOpTime> ChunkVersionAndOpTime::parseFromBSONForSetShar const ChunkVersion& chunkVersion = chunkVersionStatus.getValue(); - const auto opTimeStatus = repl::OpTime::parseFromBSON(obj); + const auto opTimeStatus = repl::OpTime::parseFromOplogEntry(obj); if (opTimeStatus.isOK()) { return ChunkVersionAndOpTime(chunkVersion, opTimeStatus.getValue()); } else if (opTimeStatus == ErrorCodes::NoSuchKey) { @@ -141,12 +141,14 @@ StatusWith<ChunkVersionAndOpTime> ChunkVersionAndOpTime::parseFromBSONForSetShar void ChunkVersionAndOpTime::appendForSetShardVersion(BSONObjBuilder* builder) const { _verAndOpT.value.addToBSON(*builder, kVersion); - _verAndOpT.opTime.append(builder); + builder->append("ts", _verAndOpT.opTime.getTimestamp()); + builder->append("t", _verAndOpT.opTime.getTerm()); } void ChunkVersionAndOpTime::appendForCommands(BSONObjBuilder* builder) const { builder->appendArray(kShardVersion, _verAndOpT.value.toBSON()); - _verAndOpT.opTime.append(builder); + builder->append("ts", _verAndOpT.opTime.getTimestamp()); + builder->append("t", _verAndOpT.opTime.getTerm()); } } // namespace mongo diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h index b14b50b3036..e21bed06561 100644 --- a/src/mongo/util/assert_util.h +++ b/src/mongo/util/assert_util.h @@ -270,6 +270,12 @@ inline T fassertStatusOK(int msgid, StatusWith<T> sw) { return std::move(sw.getValue()); } +inline void fassertStatusOK(int msgid, const Status& s) { + if (MONGO_unlikely(!s.isOK())) { + fassertFailedWithStatus(msgid, s); + } +} + /* warning only - keeps going */ #define MONGO_wassert(_Expression) \ do { \ |