summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Neupauer <martin.neupauer@mongodb.com>2022-01-14 19:17:03 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-01-14 20:50:30 +0000
commit5a86a7dfff7743a7ac2dc9484fc854351c253f69 (patch)
tree101c6c32d2c2e9d2749b3b08727ca76a765a6f01 /src
parent94d5eb0aba620a65439f0252377d74dd7683f485 (diff)
downloadmongo-5a86a7dfff7743a7ac2dc9484fc854351c253f69.tar.gz
SERVER-61630 support a string form of RecordId
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/exec/sbe/sbe_hash_agg_test.cpp74
-rw-r--r--src/mongo/db/exec/sbe/stages/ix_scan.cpp5
-rw-r--r--src/mongo/db/exec/sbe/stages/scan.cpp14
-rw-r--r--src/mongo/db/exec/sbe/stages/scan.h4
-rw-r--r--src/mongo/db/exec/sbe/values/bson.cpp2
-rw-r--r--src/mongo/db/exec/sbe/values/slot.cpp11
-rw-r--r--src/mongo/db/exec/sbe/values/value.cpp27
-rw-r--r--src/mongo/db/exec/sbe/values/value.h14
-rw-r--r--src/mongo/db/exec/sbe/values/value_builder.h4
-rw-r--r--src/mongo/db/exec/sbe/values/value_serialization_test.cpp9
-rw-r--r--src/mongo/db/query/plan_executor_sbe.cpp6
-rw-r--r--src/mongo/db/query/sbe_stage_builder_coll_scan.cpp14
-rw-r--r--src/mongo/db/record_id.h33
-rw-r--r--src/mongo/db/record_id_test.cpp42
14 files changed, 202 insertions, 57 deletions
diff --git a/src/mongo/db/exec/sbe/sbe_hash_agg_test.cpp b/src/mongo/db/exec/sbe/sbe_hash_agg_test.cpp
index 58ecd40b98e..7037bd1e86d 100644
--- a/src/mongo/db/exec/sbe/sbe_hash_agg_test.cpp
+++ b/src/mongo/db/exec/sbe/sbe_hash_agg_test.cpp
@@ -770,18 +770,50 @@ TEST_F(HashAggStageTest, HashAggBasicCountWithRecordIds) {
// Build a scan of record ids [1,10,999,10,1,999,8589869056,999,10,8589869056] input array.
auto [inputTag, inputVal] = sbe::value::makeNewArray();
auto testData = sbe::value::getArrayView(inputVal);
-
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(1));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(10));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(999));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(10));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(999));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(1));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(999));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(8589869056));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(999));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(10));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(8589869056));
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(1);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(10);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(999);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(10);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(999);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(1);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(999);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(8589869056);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(999);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(10);
+ testData->push_back(ridTag, ridVal);
+ }
+ {
+ auto [ridTag, ridVal] = sbe::value::makeNewRecordId(8589869056);
+ testData->push_back(ridTag, ridVal);
+ }
auto [scanSlot, scanStage] = generateVirtualScan(inputTag, inputVal);
@@ -807,8 +839,8 @@ TEST_F(HashAggStageTest, HashAggBasicCountWithRecordIds) {
auto [res1ScanTag, res1ScanVal] = resultAccessors[0]->getViewOfValue();
auto [res1Tag, res1Val] = resultAccessors[1]->getViewOfValue();
// There are '2' occurences of '1' in the input.
- assertValuesEqual(
- res1ScanTag, res1ScanVal, value::TypeTags::RecordId, value::bitcastFrom<int64_t>(1));
+ ASSERT_TRUE(res1ScanTag == value::TypeTags::RecordId);
+ ASSERT_TRUE(sbe::value::getRecordIdView(res1ScanVal)->getLong() == 1);
assertValuesEqual(
res1Tag, res1Val, value::TypeTags::NumberInt64, value::bitcastFrom<int64_t>(2));
@@ -816,10 +848,8 @@ TEST_F(HashAggStageTest, HashAggBasicCountWithRecordIds) {
auto [res2ScanTag, res2ScanVal] = resultAccessors[0]->getViewOfValue();
auto [res2Tag, res2Val] = resultAccessors[1]->getViewOfValue();
// There are '2' occurences of '8589869056' in the input.
- assertValuesEqual(res2ScanTag,
- res2ScanVal,
- value::TypeTags::RecordId,
- value::bitcastFrom<int64_t>(8589869056));
+ ASSERT_TRUE(res2ScanTag == value::TypeTags::RecordId);
+ ASSERT_TRUE(sbe::value::getRecordIdView(res2ScanVal)->getLong() == 8589869056);
assertValuesEqual(
res2Tag, res2Val, value::TypeTags::NumberInt64, value::bitcastFrom<int64_t>(2));
@@ -827,8 +857,8 @@ TEST_F(HashAggStageTest, HashAggBasicCountWithRecordIds) {
auto [res3ScanTag, res3ScanVal] = resultAccessors[0]->getViewOfValue();
auto [res3Tag, res3Val] = resultAccessors[1]->getViewOfValue();
// There are '3' occurences of '10' in the input.
- assertValuesEqual(
- res3ScanTag, res3ScanVal, value::TypeTags::RecordId, value::bitcastFrom<int64_t>(10));
+ ASSERT_TRUE(res3ScanTag == value::TypeTags::RecordId);
+ ASSERT_TRUE(sbe::value::getRecordIdView(res3ScanVal)->getLong() == 10);
assertValuesEqual(
res3Tag, res3Val, value::TypeTags::NumberInt64, value::bitcastFrom<int64_t>(3));
@@ -836,8 +866,8 @@ TEST_F(HashAggStageTest, HashAggBasicCountWithRecordIds) {
auto [res4ScanTag, res4ScanVal] = resultAccessors[0]->getViewOfValue();
auto [res4Tag, res4Val] = resultAccessors[1]->getViewOfValue();
// There are '4' occurences of '999' in the input.
- assertValuesEqual(
- res4ScanTag, res4ScanVal, value::TypeTags::RecordId, value::bitcastFrom<int64_t>(999));
+ ASSERT_TRUE(res4ScanTag == value::TypeTags::RecordId);
+ ASSERT_TRUE(sbe::value::getRecordIdView(res4ScanVal)->getLong() == 999);
assertValuesEqual(
res4Tag, res4Val, value::TypeTags::NumberInt64, value::bitcastFrom<int64_t>(4));
ASSERT_TRUE(stage->getNext() == PlanState::IS_EOF);
diff --git a/src/mongo/db/exec/sbe/stages/ix_scan.cpp b/src/mongo/db/exec/sbe/stages/ix_scan.cpp
index dc8244b047b..ebd2efcc5d6 100644
--- a/src/mongo/db/exec/sbe/stages/ix_scan.cpp
+++ b/src/mongo/db/exec/sbe/stages/ix_scan.cpp
@@ -381,9 +381,8 @@ PlanState IndexScanStage::getNext() {
}
if (_recordIdAccessor) {
- _recordIdAccessor->reset(false,
- value::TypeTags::RecordId,
- value::bitcastFrom<int64_t>(_nextRecord->loc.getLong()));
+ _recordIdAccessor->reset(
+ false, value::TypeTags::RecordId, value::bitcastFrom<RecordId*>(&_nextRecord->loc));
}
if (_accessors.size()) {
diff --git a/src/mongo/db/exec/sbe/stages/scan.cpp b/src/mongo/db/exec/sbe/stages/scan.cpp
index 03f8a9271ca..ad3d1b7e06b 100644
--- a/src/mongo/db/exec/sbe/stages/scan.cpp
+++ b/src/mongo/db/exec/sbe/stages/scan.cpp
@@ -317,7 +317,7 @@ void ScanStage::open(bool reOpen) {
str::stream() << "seek key is wrong type: " << msgTag,
tag == value::TypeTags::RecordId);
- _key = RecordId{value::bitcastTo<int64_t>(val)};
+ _key = *value::getRecordIdView(val);
}
if (!_cursor || !_seekKeyAccessor) {
@@ -391,9 +391,9 @@ PlanState ScanStage::getNext() {
}
if (_recordIdAccessor) {
- _recordIdAccessor->reset(false,
- value::TypeTags::RecordId,
- value::bitcastFrom<int64_t>(nextRecord->id.getLong()));
+ _recordId = nextRecord->id;
+ _recordIdAccessor->reset(
+ false, value::TypeTags::RecordId, value::bitcastFrom<RecordId*>(&_recordId));
}
if (!_fieldAccessors.empty()) {
@@ -899,9 +899,9 @@ PlanState ParallelScanStage::getNext() {
}
if (_recordIdAccessor) {
- _recordIdAccessor->reset(false,
- value::TypeTags::RecordId,
- value::bitcastFrom<int64_t>(nextRecord->id.getLong()));
+ _recordId = nextRecord->id;
+ _recordIdAccessor->reset(
+ false, value::TypeTags::RecordId, value::bitcastFrom<RecordId*>(&_recordId));
}
diff --git a/src/mongo/db/exec/sbe/stages/scan.h b/src/mongo/db/exec/sbe/stages/scan.h
index c7f10b35acd..95982e6eb0c 100644
--- a/src/mongo/db/exec/sbe/stages/scan.h
+++ b/src/mongo/db/exec/sbe/stages/scan.h
@@ -172,6 +172,8 @@ private:
value::SlotAccessorMap _varAccessors;
value::SlotAccessor* _seekKeyAccessor{nullptr};
+ RecordId _recordId;
+
bool _open{false};
std::unique_ptr<SeekableRecordCursor> _cursor;
@@ -292,6 +294,8 @@ private:
size_t _currentRange{std::numeric_limits<std::size_t>::max()};
Range _range;
+ RecordId _recordId;
+
bool _open{false};
std::unique_ptr<SeekableRecordCursor> _cursor;
diff --git a/src/mongo/db/exec/sbe/values/bson.cpp b/src/mongo/db/exec/sbe/values/bson.cpp
index d8ebe574b46..446a71b2301 100644
--- a/src/mongo/db/exec/sbe/values/bson.cpp
+++ b/src/mongo/db/exec/sbe/values/bson.cpp
@@ -287,7 +287,6 @@ void convertToBsonObj(ArrayBuilder& builder, value::ArrayEnumerator arr) {
case value::TypeTags::NumberInt32:
builder.append(value::bitcastTo<int32_t>(val));
break;
- case value::TypeTags::RecordId:
case value::TypeTags::NumberInt64:
builder.append(value::bitcastTo<int64_t>(val));
break;
@@ -426,7 +425,6 @@ void appendValueToBsonObj(ObjBuilder& builder,
case value::TypeTags::NumberInt32:
builder.append(name, value::bitcastTo<int32_t>(val));
break;
- case value::TypeTags::RecordId:
case value::TypeTags::NumberInt64:
builder.append(name, value::bitcastTo<int64_t>(val));
break;
diff --git a/src/mongo/db/exec/sbe/values/slot.cpp b/src/mongo/db/exec/sbe/values/slot.cpp
index 607e4dadb59..2a2af526aee 100644
--- a/src/mongo/db/exec/sbe/values/slot.cpp
+++ b/src/mongo/db/exec/sbe/values/slot.cpp
@@ -52,6 +52,8 @@ static std::pair<TypeTags, Value> deserializeValue(BufReader& buf) {
val = bitcastFrom<int32_t>(buf.read<LittleEndian<int32_t>>());
break;
case TypeTags::RecordId:
+ std::tie(tag, val) = makeCopyRecordId(RecordId::deserializeToken(buf));
+ break;
case TypeTags::NumberInt64:
val = bitcastFrom<int64_t>(buf.read<LittleEndian<int64_t>>());
break;
@@ -232,6 +234,8 @@ static void serializeValue(BufBuilder& buf, TypeTags tag, Value val) {
buf.appendNum(bitcastTo<int32_t>(val));
break;
case TypeTags::RecordId:
+ getRecordIdView(val)->serializeToken(buf);
+ break;
case TypeTags::NumberInt64:
buf.appendNum(bitcastTo<int64_t>(val));
break;
@@ -530,10 +534,9 @@ static void serializeValueIntoKeyString(KeyString::Builder& buf, TypeTags tag, V
break;
}
case TypeTags::RecordId: {
- // TODO SERVER-61630: Support RecordId strings when sbe also supports this.
BufBuilder innerBinDataBuf;
innerBinDataBuf.appendUChar(static_cast<uint8_t>(tag));
- innerBinDataBuf.appendNum(bitcastTo<int64_t>(val));
+ getRecordIdView(val)->serializeToken(innerBinDataBuf);
buf.appendBool(true);
buf.appendBinData(BSONBinData(
innerBinDataBuf.buf(), innerBinDataBuf.len(), BinDataType::BinDataGeneral));
@@ -592,13 +595,15 @@ int getApproximateSize(TypeTags tag, Value val) {
case TypeTags::Timestamp:
case TypeTags::Boolean:
case TypeTags::StringSmall:
- case TypeTags::RecordId:
case TypeTags::MinKey:
case TypeTags::MaxKey:
case TypeTags::bsonUndefined:
case TypeTags::LocalLambda:
break;
// There are deep types.
+ case TypeTags::RecordId:
+ result += getRecordIdView(val)->memUsage();
+ break;
case TypeTags::NumberDecimal:
result += sizeof(Decimal128);
break;
diff --git a/src/mongo/db/exec/sbe/values/value.cpp b/src/mongo/db/exec/sbe/values/value.cpp
index 84fd7eebc60..0e2e19d08a5 100644
--- a/src/mongo/db/exec/sbe/values/value.cpp
+++ b/src/mongo/db/exec/sbe/values/value.cpp
@@ -243,8 +243,27 @@ std::pair<TypeTags, Value> makeCopySortSpec(const SortSpec& ss) {
return {TypeTags::sortSpec, ssCopy};
}
+std::pair<TypeTags, Value> makeNewRecordId(int64_t rid) {
+ auto val = bitcastFrom<RecordId*>(new RecordId(rid));
+ return {TypeTags::RecordId, val};
+}
+
+std::pair<TypeTags, Value> makeNewRecordId(const char* str, int32_t size) {
+ auto val = bitcastFrom<RecordId*>(new RecordId(str, size));
+ return {TypeTags::RecordId, val};
+}
+
+std::pair<TypeTags, Value> makeCopyRecordId(const RecordId& rid) {
+ auto copy = bitcastFrom<RecordId*>(new RecordId(rid));
+ return {TypeTags::RecordId, copy};
+}
+
+
void releaseValue(TypeTags tag, Value val) noexcept {
switch (tag) {
+ case TypeTags::RecordId:
+ delete getRecordIdView(val);
+ break;
case TypeTags::NumberDecimal:
delete[] getRawPointerView(val);
break;
@@ -644,7 +663,7 @@ void writeValueToStream(T& stream, TypeTags tag, Value val, size_t depth = 1) {
break;
}
case TypeTags::RecordId:
- stream << "RecordId(" << bitcastTo<int64_t>(val) << ")";
+ stream << "RecordId(" << getRecordIdView(val)->toString() << ")";
break;
case TypeTags::jsFunction:
// TODO: Also include code.
@@ -728,6 +747,7 @@ BSONType tagToType(TypeTags tag) noexcept {
case TypeTags::NumberInt32:
return BSONType::NumberInt;
case TypeTags::RecordId:
+ return BSONType::EOO;
case TypeTags::NumberInt64:
return BSONType::NumberLong;
case TypeTags::NumberDouble:
@@ -799,12 +819,12 @@ bool isShallowType(TypeTags tag) noexcept {
case TypeTags::Timestamp:
case TypeTags::Boolean:
case TypeTags::StringSmall:
- case TypeTags::RecordId:
case TypeTags::MinKey:
case TypeTags::MaxKey:
case TypeTags::bsonUndefined:
case TypeTags::LocalLambda:
return true;
+ case TypeTags::RecordId:
case TypeTags::NumberDecimal:
case TypeTags::StringBig:
case TypeTags::bsonString:
@@ -838,6 +858,7 @@ std::size_t hashValue(TypeTags tag, Value val, const CollatorInterface* collator
case TypeTags::NumberInt32:
return abslHash(bitcastTo<int32_t>(val));
case TypeTags::RecordId:
+ return getRecordIdView(val)->hash();
case TypeTags::NumberInt64:
return abslHash(bitcastTo<int64_t>(val));
case TypeTags::NumberDouble: {
@@ -1154,7 +1175,7 @@ std::pair<TypeTags, Value> compareValue(TypeTags lhsTag,
// Special case for Nothing in a hash table (group) and sort comparison.
return {TypeTags::NumberInt32, bitcastFrom<int32_t>(0)};
} else if (lhsTag == TypeTags::RecordId && rhsTag == TypeTags::RecordId) {
- auto result = compareHelper(bitcastTo<int64_t>(lhsValue), bitcastTo<int64_t>(rhsValue));
+ int32_t result = getRecordIdView(lhsValue)->compare(*getRecordIdView(rhsValue));
return {TypeTags::NumberInt32, bitcastFrom<int32_t>(result)};
} else if (lhsTag == TypeTags::bsonRegex && rhsTag == TypeTags::bsonRegex) {
auto lhsRegex = getBsonRegexView(lhsValue);
diff --git a/src/mongo/db/exec/sbe/values/value.h b/src/mongo/db/exec/sbe/values/value.h
index c571773b655..b5947391347 100644
--- a/src/mongo/db/exec/sbe/values/value.h
+++ b/src/mongo/db/exec/sbe/values/value.h
@@ -56,8 +56,10 @@
namespace mongo {
/**
- * Forward declaration.
+ * Forward declarations.
*/
+class RecordId;
+
namespace KeyString {
class Value;
}
@@ -1084,6 +1086,14 @@ inline uint8_t* getBSONBinDataCompat(TypeTags tag, Value val) {
}
}
+inline RecordId* getRecordIdView(Value val) noexcept {
+ return reinterpret_cast<RecordId*>(val);
+}
+
+std::pair<TypeTags, Value> makeNewRecordId(int64_t rid);
+std::pair<TypeTags, Value> makeNewRecordId(const char* str, int32_t size);
+std::pair<TypeTags, Value> makeCopyRecordId(const RecordId&);
+
inline bool canUseSmallString(StringData input) {
auto length = input.size();
auto ptr = input.rawData();
@@ -1360,6 +1370,8 @@ void releaseValue(TypeTags tag, Value val) noexcept;
inline std::pair<TypeTags, Value> copyValue(TypeTags tag, Value val) {
switch (tag) {
+ case TypeTags::RecordId:
+ return makeCopyRecordId(*getRecordIdView(val));
case TypeTags::NumberDecimal:
return makeCopyDecimal(bitcastTo<Decimal128>(val));
case TypeTags::Array:
diff --git a/src/mongo/db/exec/sbe/values/value_builder.h b/src/mongo/db/exec/sbe/values/value_builder.h
index c3937a1d221..9ad2b511242 100644
--- a/src/mongo/db/exec/sbe/values/value_builder.h
+++ b/src/mongo/db/exec/sbe/values/value_builder.h
@@ -357,8 +357,8 @@ private:
return {true, ksTag, ksVal};
}
case TypeTags::RecordId: {
- int64_t ridValue = buf.read<LittleEndian<int64_t>>();
- return {false, TypeTags::RecordId, bitcastFrom<int64_t>(ridValue)};
+ auto [tag, val] = makeCopyRecordId(RecordId::deserializeToken(buf));
+ return {true, tag, val};
}
default:
MONGO_UNREACHABLE;
diff --git a/src/mongo/db/exec/sbe/values/value_serialization_test.cpp b/src/mongo/db/exec/sbe/values/value_serialization_test.cpp
index 9373750fcfd..5b44bef6549 100644
--- a/src/mongo/db/exec/sbe/values/value_serialization_test.cpp
+++ b/src/mongo/db/exec/sbe/values/value_serialization_test.cpp
@@ -45,7 +45,8 @@ TEST(ValueSerializeForSorter, Serialize) {
testData->push_back(value::TypeTags::Nothing, 0);
testData->push_back(value::TypeTags::NumberInt32, value::bitcastFrom<int32_t>(33550336));
- testData->push_back(value::TypeTags::RecordId, value::bitcastFrom<int64_t>(8589869056));
+ auto [ridTag, ridVal] = value::makeNewRecordId(8589869056);
+ testData->push_back(ridTag, ridVal);
testData->push_back(value::TypeTags::NumberInt64, value::bitcastFrom<int64_t>(137438691328));
testData->push_back(value::TypeTags::NumberDouble, value::bitcastFrom<double>(2.305e18));
@@ -228,9 +229,9 @@ TEST_F(ValueSerializeForKeyString, Numerics) {
}
TEST_F(ValueSerializeForKeyString, RecordIdMinKeyMaxKey) {
- runTest({{value::TypeTags::MinKey, 0},
- {value::TypeTags::MaxKey, 0},
- {value::TypeTags::RecordId, value::bitcastFrom<int64_t>(8589869056)}});
+ auto [ridTag, ridVal] = value::makeNewRecordId(8589869056);
+ sbe::value::ValueGuard guard{ridTag, ridVal};
+ runTest({{value::TypeTags::MinKey, 0}, {value::TypeTags::MaxKey, 0}, {ridTag, ridVal}});
}
TEST_F(ValueSerializeForKeyString, BoolNullAndNothing) {
diff --git a/src/mongo/db/query/plan_executor_sbe.cpp b/src/mongo/db/query/plan_executor_sbe.cpp
index acd7a746988..d15daede90e 100644
--- a/src/mongo/db/query/plan_executor_sbe.cpp
+++ b/src/mongo/db/query/plan_executor_sbe.cpp
@@ -329,7 +329,9 @@ BSONObj PlanExecutorSBE::getPostBatchResumeToken() const {
"but found a result without a valid RecordId: "
<< msgTag,
tag == sbe::value::TypeTags::RecordId);
- return BSON("$recordId" << sbe::value::bitcastTo<int64_t>(val));
+ BSONObjBuilder builder;
+ sbe::value::getRecordIdView(val)->serializeToken("$recordId", &builder);
+ return builder.obj();
}
}
@@ -383,7 +385,7 @@ sbe::PlanState fetchNext(sbe::PlanStage* root,
invariant(recordIdSlot);
auto [tag, val] = recordIdSlot->getViewOfValue();
if (tag == sbe::value::TypeTags::RecordId) {
- *dlOut = RecordId{sbe::value::bitcastTo<int64_t>(val)};
+ *dlOut = *sbe::value::getRecordIdView(val);
}
}
return state;
diff --git a/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp b/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp
index 1ae5d110a24..d2102cea044 100644
--- a/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp
+++ b/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp
@@ -268,16 +268,15 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateOptimizedOplo
auto resumeRecordIdSlot = state.env->getSlot("resumeRecordId"_sd);
return {resumeRecordIdSlot, makeVariable(resumeRecordIdSlot)};
} else if (csn->resumeAfterRecordId) {
- return {
- state.slotId(),
- makeConstant(sbe::value::TypeTags::RecordId, csn->resumeAfterRecordId->getLong())};
+ auto [tag, val] = sbe::value::makeCopyRecordId(*csn->resumeAfterRecordId);
+ return {state.slotId(), makeConstant(tag, val)};
} else if (csn->minRecord) {
auto cursor = collection->getRecordStore()->getCursor(state.opCtx);
auto startRec = cursor->seekNear(*csn->minRecord);
if (startRec) {
LOGV2_DEBUG(205841, 3, "Using direct oplog seek");
- return {state.slotId(),
- makeConstant(sbe::value::TypeTags::RecordId, startRec->id.getLong())};
+ auto [tag, val] = sbe::value::makeCopyRecordId(startRec->id);
+ return {state.slotId(), makeConstant(tag, val)};
}
}
return {};
@@ -550,9 +549,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateGenericCollSc
auto [seekRecordIdSlot, seekRecordIdExpression] =
[&]() -> std::pair<boost::optional<sbe::value::SlotId>, std::unique_ptr<sbe::EExpression>> {
if (csn->resumeAfterRecordId) {
- return {
- state.slotId(),
- makeConstant(sbe::value::TypeTags::RecordId, csn->resumeAfterRecordId->getLong())};
+ auto [tag, val] = sbe::value::makeCopyRecordId(*csn->resumeAfterRecordId);
+ return {state.slotId(), makeConstant(tag, val)};
} else if (isTailableResumeBranch) {
auto resumeRecordIdSlot = state.env->getSlot("resumeRecordId"_sd);
return {resumeRecordIdSlot, makeVariable(resumeRecordIdSlot)};
diff --git a/src/mongo/db/record_id.h b/src/mongo/db/record_id.h
index c94e93d5a28..66a58a37a04 100644
--- a/src/mongo/db/record_id.h
+++ b/src/mongo/db/record_id.h
@@ -287,6 +287,19 @@ public:
}
/**
+ * Same as above but in a binary.
+ */
+ void serializeToken(BufBuilder& buf) const {
+ buf.appendChar(static_cast<char>(_format));
+ withFormat([&](Null) {},
+ [&](int64_t rid) { buf.appendNum(rid); },
+ [&](const char* str, int size) {
+ buf.appendNum(size);
+ buf.appendBuf(str, size);
+ });
+ }
+
+ /**
* Decode a token created by serializeToken().
*/
static RecordId deserializeToken(const BSONElement& elem) {
@@ -310,6 +323,26 @@ public:
}
/**
+ * Decode a token created by serializeToken().
+ */
+ static RecordId deserializeToken(BufReader& buf) {
+ auto format = buf.read<Format>();
+ if (format == Format::kNull) {
+ return RecordId();
+ } else if (format == Format::kLong) {
+ return RecordId(buf.read<LittleEndian<int64_t>>());
+ } else if (format == Format::kSmallStr || format == Format::kBigStr) {
+ const int size = buf.read<LittleEndian<int>>();
+ const char* str = static_cast<const char*>(buf.skip(size));
+ return RecordId(str, size);
+ } else {
+ uasserted(ErrorCodes::BadValue,
+ fmt::format("Could not deserialize RecordId with type {}",
+ static_cast<int8_t>(format)));
+ }
+ }
+
+ /**
* This maximum size for 'small' strings was chosen as a good tradeoff between keeping the
* RecordId struct lightweight to copy by value (32 bytes), but also making the struct large
* enough to hold a wider variety of strings. Larger strings must be stored in the
diff --git a/src/mongo/db/record_id_test.cpp b/src/mongo/db/record_id_test.cpp
index e7f0795b6fb..2a0e4360caf 100644
--- a/src/mongo/db/record_id_test.cpp
+++ b/src/mongo/db/record_id_test.cpp
@@ -248,6 +248,48 @@ TEST(RecordId, RoundTripSerialize) {
}
}
+TEST(RecordId, RoundTripSerializeBinary) {
+ {
+ RecordId id(1);
+ BufBuilder builder;
+ id.serializeToken(builder);
+ BufReader reader(builder.buf(), builder.len());
+ ASSERT_EQ(id, RecordId::deserializeToken(reader));
+ }
+
+ {
+ RecordId id(4611686018427387904);
+ BufBuilder builder;
+ id.serializeToken(builder);
+ BufReader reader(builder.buf(), builder.len());
+ ASSERT_EQ(id, RecordId::deserializeToken(reader));
+ }
+
+ {
+ RecordId id;
+ BufBuilder builder;
+ id.serializeToken(builder);
+ BufReader reader(builder.buf(), builder.len());
+ ASSERT_EQ(id, RecordId::deserializeToken(reader));
+ }
+
+ {
+ RecordId id(record_id_helpers::keyForOID(OID::gen()));
+ BufBuilder builder;
+ id.serializeToken(builder);
+ BufReader reader(builder.buf(), builder.len());
+ ASSERT_EQ(id, RecordId::deserializeToken(reader));
+ }
+
+ {
+ char buf[1024] = {'x'};
+ RecordId id(buf, sizeof(buf));
+ BufBuilder builder;
+ id.serializeToken(builder);
+ BufReader reader(builder.buf(), builder.len());
+ ASSERT_EQ(id, RecordId::deserializeToken(reader));
+ }
+}
TEST(RecordId, RecordIdBigStr) {
char buf[1024] = {'x'};