summaryrefslogtreecommitdiff
path: root/src/mongo/db/exec/document_value
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
commit4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch)
tree1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/db/exec/document_value
parentaa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff)
parent8f0827553e09872941945a093b647a4211a9db7f (diff)
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0' with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/db/exec/document_value')
-rw-r--r--src/mongo/db/exec/document_value/document.cpp128
-rw-r--r--src/mongo/db/exec/document_value/document.h100
-rw-r--r--src/mongo/db/exec/document_value/document_internal.h62
-rw-r--r--src/mongo/db/exec/document_value/document_metadata_fields.cpp55
-rw-r--r--src/mongo/db/exec/document_value/document_metadata_fields.h152
-rw-r--r--src/mongo/db/exec/document_value/document_metadata_fields_test.cpp192
-rw-r--r--src/mongo/db/exec/document_value/document_value_test.cpp235
-rw-r--r--src/mongo/db/exec/document_value/document_value_test_util.h7
-rw-r--r--src/mongo/db/exec/document_value/value.cpp18
-rw-r--r--src/mongo/db/exec/document_value/value.h13
-rw-r--r--src/mongo/db/exec/document_value/value_comparator_test.cpp28
11 files changed, 178 insertions, 812 deletions
diff --git a/src/mongo/db/exec/document_value/document.cpp b/src/mongo/db/exec/document_value/document.cpp
index 7172370e4c3..dd833b3c28f 100644
--- a/src/mongo/db/exec/document_value/document.cpp
+++ b/src/mongo/db/exec/document_value/document.cpp
@@ -88,11 +88,8 @@ const StringDataSet Document::allMetadataFieldNames{Document::metaFieldTextScore
Document::metaFieldGeoNearPoint,
Document::metaFieldSearchScore,
Document::metaFieldSearchHighlights,
- Document::metaFieldSearchSortValues,
Document::metaFieldIndexKey,
- Document::metaFieldSearchScoreDetails,
- Document::metaFieldVectorSearchScore,
- Document::metaFieldSearchSequenceToken};
+ Document::metaFieldSearchScoreDetails};
DocumentStorageIterator::DocumentStorageIterator(DocumentStorage* storage, BSONObjIterator bsonIt)
: _bsonIt(std::move(bsonIt)),
@@ -133,7 +130,7 @@ bool DocumentStorageIterator::shouldSkipDeleted() {
// If we strip the metadata see if a field name matches the known list. All metadata fields
// start with '$' so optimize for a quick bailout.
- if (_storage->bsonHasMetadata() && !fieldName.empty() && fieldName[0] == '$' &&
+ if (_storage->stripMetadata() && fieldName[0] == '$' &&
Document::allMetadataFieldNames.contains(fieldName)) {
return true;
}
@@ -346,8 +343,8 @@ void DocumentStorage::reserveFields(size_t expectedFields) {
}
intrusive_ptr<DocumentStorage> DocumentStorage::clone() const {
- auto out = make_intrusive<DocumentStorage>(
- _bson, _bsonHasMetadata, _modified, _numBytesFromBSONInCache);
+ auto out =
+ make_intrusive<DocumentStorage>(_bson, _stripMetadata, _modified, _numBytesFromBSONInCache);
if (_cache) {
// Make a copy of the buffer with the fields.
@@ -376,7 +373,6 @@ intrusive_ptr<DocumentStorage> DocumentStorage::clone() const {
out->_haveLazyLoadedMetadata = _haveLazyLoadedMetadata;
out->_metadataFields = _metadataFields;
- out->_snapshottedSize = _snapshottedSize;
return out;
}
@@ -393,12 +389,11 @@ DocumentStorage::~DocumentStorage() {
}
}
-void DocumentStorage::reset(const BSONObj& bson, bool bsonHasMetadata) {
+void DocumentStorage::reset(const BSONObj& bson, bool stripMetadata) {
_bson = bson;
_numBytesFromBSONInCache = 0;
- _bsonHasMetadata = bsonHasMetadata;
+ _stripMetadata = stripMetadata;
_modified = false;
- _snapshottedSize = 0;
// Clean cache.
for (auto it = iteratorCacheOnly(); !it.atEnd(); it.advance()) {
@@ -414,22 +409,10 @@ void DocumentStorage::reset(const BSONObj& bson, bool bsonHasMetadata) {
_metadataFields = DocumentMetadataFields{};
}
-Document DocumentStorage::shred() const {
- MutableDocument md;
- // Iterate raw bson if possible. This avoids caching all of the values in a doc that might get
- // thrown away.
- if (!isModified() && !bsonHasMetadata()) {
- for (const auto& elem : _bson) {
- md[elem.fieldNameStringData()] = Value(elem).shred();
- }
- } else {
- for (DocumentStorageIterator it = iterator(); !it.atEnd(); it.advance()) {
- const auto& valueElem = it.get();
- md[it.fieldName()] = valueElem.val.shred();
- }
+void DocumentStorage::fillCache() const {
+ for (DocumentStorageIterator it = iterator(); !it.atEnd(); it.advance()) {
+ it->val.fillCache();
}
- md.setMetadata(DocumentMetadataFields(metadata()));
- return md.freeze();
}
void DocumentStorage::loadLazyMetadata() const {
@@ -437,13 +420,11 @@ void DocumentStorage::loadLazyMetadata() const {
return;
}
- bool oldModified = _metadataFields.isModified();
-
BSONObjIterator it(_bson);
while (it.more()) {
BSONElement elem(it.next());
auto fieldName = elem.fieldNameStringData();
- if (!fieldName.empty() && fieldName[0] == '$') {
+ if (fieldName[0] == '$') {
if (fieldName == Document::metaFieldTextScore) {
_metadataFields.setTextScore(elem.Double());
} else if (fieldName == Document::metaFieldSearchScore) {
@@ -479,17 +460,10 @@ void DocumentStorage::loadLazyMetadata() const {
_metadataFields.setIndexKey(elem.Obj());
} else if (fieldName == Document::metaFieldSearchScoreDetails) {
_metadataFields.setSearchScoreDetails(elem.Obj());
- } else if (fieldName == Document::metaFieldSearchSortValues) {
- _metadataFields.setSearchSortValues(elem.Obj());
- } else if (fieldName == Document::metaFieldVectorSearchScore) {
- _metadataFields.setVectorSearchScore(elem.Double());
- } else if (fieldName == Document::metaFieldSearchSequenceToken) {
- _metadataFields.setSearchSequenceToken(Value(elem));
}
}
}
- _metadataFields.setModified(oldModified);
_haveLazyLoadedMetadata = true;
}
@@ -539,11 +513,22 @@ void Document::toBson(BSONObjBuilder* builder, size_t recursionLevel) const {
}
}
+BSONObj Document::toBson() const {
+ if (!storage().isModified() && !storage().stripMetadata()) {
+ return storage().bsonObj();
+ }
+
+ BSONObjBuilder bb;
+ toBson(&bb);
+ return bb.obj();
+}
+
boost::optional<BSONObj> Document::toBsonIfTriviallyConvertible() const {
- if (isTriviallyConvertible()) {
+ if (!storage().isModified() && !storage().stripMetadata()) {
return storage().bsonObj();
+ } else {
+ return boost::none;
}
- return boost::none;
}
constexpr StringData Document::metaFieldTextScore;
@@ -554,44 +539,35 @@ constexpr StringData Document::metaFieldGeoNearPoint;
constexpr StringData Document::metaFieldSearchScore;
constexpr StringData Document::metaFieldSearchHighlights;
constexpr StringData Document::metaFieldSearchScoreDetails;
-constexpr StringData Document::metaFieldSearchSortValues;
-constexpr StringData Document::metaFieldVectorSearchScore;
-void Document::toBsonWithMetaData(BSONObjBuilder* builder) const {
- toBson(builder);
+BSONObj Document::toBsonWithMetaData() const {
+ BSONObjBuilder bb;
+ toBson(&bb);
if (!metadata()) {
- return;
+ return bb.obj();
}
if (metadata().hasTextScore())
- builder->append(metaFieldTextScore, metadata().getTextScore());
+ bb.append(metaFieldTextScore, metadata().getTextScore());
if (metadata().hasRandVal())
- builder->append(metaFieldRandVal, metadata().getRandVal());
+ bb.append(metaFieldRandVal, metadata().getRandVal());
if (metadata().hasSortKey())
- builder->append(metaFieldSortKey,
- DocumentMetadataFields::serializeSortKey(metadata().isSingleElementKey(),
- metadata().getSortKey()));
+ bb.append(metaFieldSortKey,
+ DocumentMetadataFields::serializeSortKey(metadata().isSingleElementKey(),
+ metadata().getSortKey()));
if (metadata().hasGeoNearDistance())
- builder->append(metaFieldGeoNearDistance, metadata().getGeoNearDistance());
+ bb.append(metaFieldGeoNearDistance, metadata().getGeoNearDistance());
if (metadata().hasGeoNearPoint())
- metadata().getGeoNearPoint().addToBsonObj(builder, metaFieldGeoNearPoint);
+ metadata().getGeoNearPoint().addToBsonObj(&bb, metaFieldGeoNearPoint);
if (metadata().hasSearchScore())
- builder->append(metaFieldSearchScore, metadata().getSearchScore());
+ bb.append(metaFieldSearchScore, metadata().getSearchScore());
if (metadata().hasSearchHighlights())
- metadata().getSearchHighlights().addToBsonObj(builder, metaFieldSearchHighlights);
+ metadata().getSearchHighlights().addToBsonObj(&bb, metaFieldSearchHighlights);
if (metadata().hasIndexKey())
- builder->append(metaFieldIndexKey, metadata().getIndexKey());
+ bb.append(metaFieldIndexKey, metadata().getIndexKey());
if (metadata().hasSearchScoreDetails())
- builder->append(metaFieldSearchScoreDetails, metadata().getSearchScoreDetails());
- if (metadata().hasSearchSortValues()) {
- builder->append(metaFieldSearchSortValues, metadata().getSearchSortValues());
- }
- if (metadata().hasSearchSequenceToken()) {
- metadata().getSearchSequenceToken().addToBsonObj(builder, metaFieldSearchSequenceToken);
- }
- if (metadata().hasVectorSearchScore()) {
- builder->append(metaFieldVectorSearchScore, metadata().getVectorSearchScore());
- }
+ bb.append(metaFieldSearchScoreDetails, metadata().getSearchScoreDetails());
+ return bb.obj();
}
Document Document::fromBsonWithMetaData(const BSONObj& bson) {
@@ -728,17 +704,31 @@ const Value Document::getNestedField(const FieldPath& path, vector<Position>* po
return getNestedFieldHelper(*this, path, positions, 0);
}
-size_t Document::getApproximateSize() const {
- return sizeof(Document) + storage().snapshottedApproximateSize();
+size_t Document::getApproximateSizeWithoutBackingBSON() const {
+ size_t size = sizeof(Document);
+ if (!_storage)
+ return size;
+
+ size += sizeof(DocumentStorage);
+ size += storage().allocatedBytes();
+
+ for (auto it = storage().iteratorCacheOnly(); !it.atEnd(); it.advance()) {
+ size += it->val.getApproximateSize();
+ size -= sizeof(Value); // already accounted for above
+ }
+
+ // The metadata also occupies space in the document storage that's pre-allocated.
+ size += storage().getMetadataApproximateSize();
+
+ return size;
}
-size_t Document::getCurrentApproximateSize() const {
- return sizeof(Document) + storage().currentApproximateSize();
+size_t Document::getApproximateSize() const {
+ return getApproximateSizeWithoutBackingBSON() + storage().bsonObjSize();
}
size_t Document::memUsageForSorter() const {
- return storage().currentApproximateSize() - storage().bsonObjSize() +
- storage().nonCachedBsonObjSize();
+ return getApproximateSizeWithoutBackingBSON() + storage().nonCachedBsonObjSize();
}
void Document::hash_combine(size_t& seed,
diff --git a/src/mongo/db/exec/document_value/document.h b/src/mongo/db/exec/document_value/document.h
index 6114aee792d..8fcfb28dd8b 100644
--- a/src/mongo/db/exec/document_value/document.h
+++ b/src/mongo/db/exec/document_value/document.h
@@ -100,10 +100,7 @@ public:
static constexpr StringData metaFieldSearchScore = "$searchScore"_sd;
static constexpr StringData metaFieldSearchHighlights = "$searchHighlights"_sd;
static constexpr StringData metaFieldSearchScoreDetails = "$searchScoreDetails"_sd;
- static constexpr StringData metaFieldSearchSortValues = "$searchSortValues"_sd;
static constexpr StringData metaFieldIndexKey = "$indexKey"_sd;
- static constexpr StringData metaFieldVectorSearchScore = "$vectorSearchScore"_sd;
- static constexpr StringData metaFieldSearchSequenceToken = "$searchSequenceToken"_sd;
static const StringDataSet allMetadataFieldNames;
@@ -194,8 +191,7 @@ public:
/**
* Get the approximate size of the Document, plus its underlying storage and sub-values. Returns
- * size in bytes. The return value of this function is snapshotted. All subsequent calls of this
- * method will return the same value.
+ * size in bytes.
*
* Note: Some memory may be shared with other Documents or between fields within a single
* Document so this can overestimate usage.
@@ -206,11 +202,6 @@ public:
size_t getApproximateSize() const;
/**
- * Same as 'getApproximateSize()', but this method re-computes the size on every call.
- */
- size_t getCurrentApproximateSize() const;
-
- /**
* Return the approximate amount of space used by metadata.
*/
size_t getMetadataApproximateSize() const {
@@ -248,10 +239,10 @@ public:
}
/**
- * Returns a cache-only copy of the document with no backing bson.
+ * Populates the internal cache by recursively walking the underlying BSON.
*/
- Document shred() const {
- return storage().shred();
+ void fillCache() const {
+ storage().fillCache();
}
/** Calculate a hash value.
@@ -262,38 +253,12 @@ public:
void hash_combine(size_t& seed, const StringData::ComparatorInterface* stringComparator) const;
/**
- * Returns true, if this document is trivially convertible to BSON, meaning the underlying
- * storage is already in BSON format and there are no damages.
- */
- bool isTriviallyConvertible() const {
- return !storage().isModified() && !storage().bsonHasMetadata();
- }
-
- /**
- * Returns true, if this document is trivially convertible to BSON with metadata, meaning the
- * underlying storage is already in BSON format and there are no damages.
- */
- bool isTriviallyConvertibleWithMetadata() const {
- return !storage().isModified() && !storage().isMetadataModified();
- }
-
- /**
* Serializes this document to the BSONObj under construction in 'builder'. Metadata is not
* included. Throws a AssertionException if 'recursionLevel' exceeds the maximum allowable
* depth.
*/
void toBson(BSONObjBuilder* builder, size_t recursionLevel = 1) const;
-
- template <typename BSONTraits = BSONObj::DefaultSizeTrait>
- BSONObj toBson() const {
- if (isTriviallyConvertible()) {
- return storage().bsonObj();
- }
-
- BSONObjBuilder bb;
- toBson(&bb);
- return bb.obj<BSONTraits>();
- }
+ BSONObj toBson() const;
/**
* Serializes this document iff the conversion is "trivial," meaning that the underlying storage
@@ -307,18 +272,7 @@ public:
/**
* Like the 'toBson()' method, but includes metadata as top-level fields.
*/
- void toBsonWithMetaData(BSONObjBuilder* builder) const;
-
- template <typename BSONTraits = BSONObj::DefaultSizeTrait>
- BSONObj toBsonWithMetaData() const {
- if (isTriviallyConvertibleWithMetadata()) {
- return storage().bsonObj();
- }
-
- BSONObjBuilder bb;
- toBsonWithMetaData(&bb);
- return bb.obj<BSONTraits>();
- }
+ BSONObj toBsonWithMetaData() const;
/**
* Like Document(BSONObj) but treats top-level fields with special names as metadata.
@@ -416,6 +370,12 @@ private:
getNestedFieldNonCachingHelper(const FieldPath& dottedField, size_t level) const;
boost::intrusive_ptr<const DocumentStorage> _storage;
+
+ /**
+ * Returns the approximate size of this `Document` instance without considering the size of its
+ * backing BSON object.
+ */
+ size_t getApproximateSizeWithoutBackingBSON() const;
};
//
@@ -551,11 +511,13 @@ public:
}
/**
- * Replace the current base Document with the BSON object. Setting 'bsonHasMetadata' to true
- * signals that the BSON object contains metadata fields.
+ * Replace the current base Document with bson.
+ *
+ * The paramater 'stripMetadata' controls whether we strip the metadata fields from the
+ * underlying bson when converting the document object back to bson.
*/
- void reset(const BSONObj& bson, bool bsonHasMetadata) {
- storage().reset(bson, bsonHasMetadata);
+ void reset(const BSONObj& bson, bool stripMetadata) {
+ storage().reset(bson, stripMetadata);
}
/** Add the given field to the Document.
@@ -692,7 +654,6 @@ public:
* TODO: there are some optimizations that may make sense at freeze time.
*/
Document freeze() {
- resetSnapshottedApproximateSize();
// This essentially moves _storage into a new Document by way of temp.
Document ret;
boost::intrusive_ptr<const DocumentStorage> temp(storagePtr(), /*inc_ref_count=*/false);
@@ -711,12 +672,8 @@ public:
* Note that unlike freeze(), this indicates intention to continue
* modifying this document. The returned Document will not observe
* future changes to this MutableDocument.
- *
- * Note that the computed snapshotted approximate size of the Document
- * is not preserved across calls.
*/
Document peek() {
- resetSnapshottedApproximateSize();
return Document(storagePtr());
}
@@ -738,13 +695,13 @@ public:
storage().makeOwned();
}
- /**
- * Creates a new document storage with the BSON object. Setting 'bsonHasMetadata' to true
- * signals that the BSON object contains metadata fields (the complete list is in
- * Document::allMetadataFieldNames).
+ /** Create a new document storage with the BSON object.
+ *
+ * The optional paramater 'stripMetadata' controls whether we strip the metadata fields (the
+ * complete list is in Document::allMetadataFieldNames).
*/
- DocumentStorage& newStorageWithBson(const BSONObj& bson, bool bsonHasMetadata) {
- reset(make_intrusive<DocumentStorage>(bson, bsonHasMetadata, false, 0));
+ DocumentStorage& newStorageWithBson(const BSONObj& bson, bool stripMetadata) {
+ reset(make_intrusive<DocumentStorage>(bson, stripMetadata, false, 0));
return const_cast<DocumentStorage&>(*storagePtr());
}
@@ -782,19 +739,12 @@ private:
MutableValue getNestedFieldHelper(const FieldPath& dottedField, size_t level);
MutableValue getNestedFieldHelper(const std::vector<Position>& positions, size_t level);
- // this should only be called by storage methods and peek/freeze/resetsnapshottedApproximateSize
+ // this should only be called by storage methods and peek/freeze
const DocumentStorage* storagePtr() const {
dassert(!_storage || typeid(*_storage) == typeid(const DocumentStorage));
return static_cast<const DocumentStorage*>(_storage);
}
- void resetSnapshottedApproximateSize() {
- auto mutableStorage = const_cast<DocumentStorage*>(storagePtr());
- if (mutableStorage) {
- mutableStorage->resetSnapshottedApproximateSize();
- }
- }
-
// These are both const to prevent modifications bypassing storage() method.
// They always point to NULL or an object with dynamic type DocumentStorage.
const RefCountable* _storageHolder; // Only used in constructors and destructor
diff --git a/src/mongo/db/exec/document_value/document_internal.h b/src/mongo/db/exec/document_value/document_internal.h
index d7fb3b337d6..1387ca908b4 100644
--- a/src/mongo/db/exec/document_value/document_internal.h
+++ b/src/mongo/db/exec/document_value/document_internal.h
@@ -359,11 +359,11 @@ public:
/**
* Construct a storage from the BSON. The BSON is lazily processed as fields are requested from
- * the document. If we know that the BSON contains metadata fields we can set the
- * 'bsonHasMetadata' flag to true.
+ * the document. If we know that the BSON does not contain any metadata fields we can set the
+ * 'stripMetadata' flag to false that will speed up the field iteration.
*/
DocumentStorage(const BSONObj& bson,
- bool bsonHasMetadata,
+ bool stripMetadata,
bool modified,
uint32_t numBytesFromBSONInCache)
: _cache(nullptr),
@@ -373,17 +373,17 @@ public:
_hashTabMask(0),
_bson(bson),
_numBytesFromBSONInCache(numBytesFromBSONInCache),
- _bsonHasMetadata(bsonHasMetadata),
+ _stripMetadata(stripMetadata),
_modified(modified) {}
~DocumentStorage();
- void reset(const BSONObj& bson, bool bsonHasMetadata);
+ void reset(const BSONObj& bson, bool stripMetadata);
/**
- * Returns a cache-only copy of the document with no backing bson.
+ * Populates the cache by recursively walking the underlying BSON.
*/
- Document shred() const;
+ void fillCache() const;
static const DocumentStorage& emptyDoc() {
return kEmptyDoc;
@@ -551,7 +551,7 @@ public:
* WorkingSetMember.
*/
const DocumentMetadataFields& metadata() const {
- if (_bsonHasMetadata) {
+ if (_stripMetadata) {
loadLazyMetadata();
}
return _metadataFields;
@@ -589,8 +589,8 @@ public:
return _firstElement ? _firstElement->plusBytes(_usedBytes) : nullptr;
}
- auto bsonHasMetadata() const {
- return _bsonHasMetadata;
+ auto stripMetadata() const {
+ return _stripMetadata;
}
Position constructInCache(const BSONElement& elem);
@@ -599,37 +599,10 @@ public:
return _modified;
}
- auto isMetadataModified() const {
- return _metadataFields.isModified();
- }
-
auto bsonObj() const {
return _bson;
}
- size_t currentApproximateSize() const {
- size_t size = sizeof(DocumentStorage) + allocatedBytes() + getMetadataApproximateSize() +
- bsonObjSize();
-
- for (auto it = iteratorCacheOnly(); !it.atEnd(); it.advance()) {
- size += it->val.getApproximateSize() - sizeof(Value);
- }
-
- return size;
- }
-
- size_t snapshottedApproximateSize() const {
- if (_snapshottedSize == 0) {
- const_cast<DocumentStorage*>(this)->_snapshottedSize = currentApproximateSize();
- }
-
- return _snapshottedSize;
- }
-
- void resetSnapshottedApproximateSize() {
- _snapshottedSize = 0;
- }
-
private:
/// Returns the position of the named field in the cache or Position()
template <typename T>
@@ -712,23 +685,22 @@ private:
// whole backing BSON, but only the portion of backing BSON that's not already in the cache.
uint32_t _numBytesFromBSONInCache = 0;
- // Tracks whether or not the metadata has been lazy-loaded from the backing '_bson' object. If
- // so, then no attempt will be made to load the metadata again, even if the metadata has been
- // released by a call to 'releaseMetadata()'.
+ // If '_stripMetadata' is true, tracks whether or not the metadata has been lazy-loaded from the
+ // backing '_bson' object. If so, then no attempt will be made to load the metadata again, even
+ // if the metadata has been released by a call to 'releaseMetadata()'.
mutable bool _haveLazyLoadedMetadata = false;
mutable DocumentMetadataFields _metadataFields;
- // True if this storage was constructed from BSON with metadata. Serializing this object using
- // the 'toBson()' method will omit (strip) the metadata fields.
- bool _bsonHasMetadata{false};
+ // The storage constructed from a BSON value may contain metadata. When we process the BSON we
+ // have to move the metadata to the MetadataFields object. If we know that the BSON does not
+ // have any metadata we can set _stripMetadata to false that will speed up the iteration.
+ bool _stripMetadata{false};
// This flag is set to true anytime the storage returns a mutable field. It is used to optimize
// a conversion to BSON; i.e. if there are not any modifications we can directly return _bson.
bool _modified{false};
- size_t _snapshottedSize{0};
-
// Defined in document.cpp
static const DocumentStorage kEmptyDoc;
diff --git a/src/mongo/db/exec/document_value/document_metadata_fields.cpp b/src/mongo/db/exec/document_value/document_metadata_fields.cpp
index 27f64ef7286..90e15ef5c2a 100644
--- a/src/mongo/db/exec/document_value/document_metadata_fields.cpp
+++ b/src/mongo/db/exec/document_value/document_metadata_fields.cpp
@@ -46,7 +46,6 @@ DocumentMetadataFields::DocumentMetadataFields(const DocumentMetadataFields& oth
DocumentMetadataFields& DocumentMetadataFields::operator=(const DocumentMetadataFields& other) {
_holder = other._holder ? std::make_unique<MetadataHolder>(*other._holder) : nullptr;
- _modified = true;
return *this;
}
@@ -55,7 +54,6 @@ DocumentMetadataFields::DocumentMetadataFields(DocumentMetadataFields&& other)
DocumentMetadataFields& DocumentMetadataFields::operator=(DocumentMetadataFields&& other) {
_holder = std::move(other._holder);
- _modified = true;
return *this;
}
@@ -87,21 +85,12 @@ void DocumentMetadataFields::mergeWith(const DocumentMetadataFields& other) {
if (!hasSearchScoreDetails() && other.hasSearchScoreDetails()) {
setSearchScoreDetails(other.getSearchScoreDetails());
}
- if (!hasSearchSequenceToken() && other.hasSearchSequenceToken()) {
- setSearchSequenceToken(other.getSearchSequenceToken());
- }
if (!hasTimeseriesBucketMinTime() && other.hasTimeseriesBucketMinTime()) {
setTimeseriesBucketMinTime(other.getTimeseriesBucketMinTime());
}
if (!hasTimeseriesBucketMaxTime() && other.hasTimeseriesBucketMaxTime()) {
setTimeseriesBucketMaxTime(other.getTimeseriesBucketMaxTime());
}
- if (!hasSearchSortValues() && other.hasSearchSortValues()) {
- setSearchSortValues(other.getSearchSortValues());
- }
- if (!hasVectorSearchScore() && other.hasVectorSearchScore()) {
- setVectorSearchScore(other.getVectorSearchScore());
- }
}
void DocumentMetadataFields::copyFrom(const DocumentMetadataFields& other) {
@@ -132,21 +121,12 @@ void DocumentMetadataFields::copyFrom(const DocumentMetadataFields& other) {
if (other.hasSearchScoreDetails()) {
setSearchScoreDetails(other.getSearchScoreDetails());
}
- if (other.hasSearchSequenceToken()) {
- setSearchSequenceToken(other.getSearchSequenceToken());
- }
if (other.hasTimeseriesBucketMinTime()) {
setTimeseriesBucketMinTime(other.getTimeseriesBucketMinTime());
}
if (other.hasTimeseriesBucketMaxTime()) {
setTimeseriesBucketMaxTime(other.getTimeseriesBucketMaxTime());
}
- if (other.hasSearchSortValues()) {
- setSearchSortValues(other.getSearchSortValues());
- }
- if (other.hasVectorSearchScore()) {
- setVectorSearchScore(other.getVectorSearchScore());
- }
}
size_t DocumentMetadataFields::getApproximateSize() const {
@@ -168,8 +148,7 @@ size_t DocumentMetadataFields::getApproximateSize() const {
size -= sizeof(_holder->searchHighlights);
size += _holder->indexKey.objsize();
size += _holder->searchScoreDetails.objsize();
- size += _holder->searchSortValues.objsize();
- size -= sizeof(_holder->searchSequenceToken);
+
return size;
}
@@ -217,10 +196,6 @@ void DocumentMetadataFields::serializeForSorter(BufBuilder& buf) const {
buf.appendNum(static_cast<char>(MetaType::kSearchScoreDetails + 1));
getSearchScoreDetails().appendSelfToBufBuilder(buf);
}
- if (hasSearchSequenceToken()) {
- buf.appendNum(static_cast<char>(MetaType::kSearchSequenceToken + 1));
- getSearchSequenceToken().serializeForSorter(buf);
- }
if (hasTimeseriesBucketMinTime()) {
buf.appendNum(static_cast<char>(MetaType::kTimeseriesBucketMinTime + 1));
buf.appendNum(getTimeseriesBucketMinTime().toMillisSinceEpoch());
@@ -229,14 +204,6 @@ void DocumentMetadataFields::serializeForSorter(BufBuilder& buf) const {
buf.appendNum(static_cast<char>(MetaType::kTimeseriesBucketMaxTime + 1));
buf.appendNum(getTimeseriesBucketMaxTime().toMillisSinceEpoch());
}
- if (hasSearchSortValues()) {
- buf.appendNum(static_cast<char>(MetaType::kSearchSortValues + 1));
- getSearchSortValues().appendSelfToBufBuilder(buf);
- }
- if (hasVectorSearchScore()) {
- buf.appendNum(static_cast<char>(MetaType::kVectorSearchScore + 1));
- buf.appendNum(getVectorSearchScore());
- }
buf.appendNum(static_cast<char>(0));
}
@@ -269,19 +236,9 @@ void DocumentMetadataFields::deserializeForSorter(BufReader& buf, DocumentMetada
out->setSearchScoreDetails(
BSONObj::deserializeForSorter(buf, BSONObj::SorterDeserializeSettings()));
} else if (marker == static_cast<char>(MetaType::kTimeseriesBucketMinTime) + 1) {
- out->setTimeseriesBucketMinTime(
- Date_t::fromMillisSinceEpoch(buf.read<LittleEndian<long long>>()));
+ out->setTimeseriesBucketMinTime(Date_t::fromMillisSinceEpoch(buf.read<long long>()));
} else if (marker == static_cast<char>(MetaType::kTimeseriesBucketMaxTime) + 1) {
- out->setTimeseriesBucketMaxTime(
- Date_t::fromMillisSinceEpoch(buf.read<LittleEndian<long long>>()));
- } else if (marker == static_cast<char>(MetaType::kSearchSortValues) + 1) {
- out->setSearchSortValues(
- BSONObj::deserializeForSorter(buf, BSONObj::SorterDeserializeSettings()));
- } else if (marker == static_cast<char>(MetaType::kVectorSearchScore) + 1) {
- out->setVectorSearchScore(buf.read<LittleEndian<double>>());
- } else if (marker == static_cast<char>(MetaType::kSearchSequenceToken) + 1) {
- out->setSearchSequenceToken(
- Value::deserializeForSorter(buf, Value::SorterDeserializeSettings()));
+ out->setTimeseriesBucketMaxTime(Date_t::fromMillisSinceEpoch(buf.read<long long>()));
} else {
uasserted(28744, "Unrecognized marker, unable to deserialize buffer");
}
@@ -341,12 +298,6 @@ const char* DocumentMetadataFields::typeNameToDebugString(DocumentMetadataFields
return "timeseries bucket min time";
case DocumentMetadataFields::kTimeseriesBucketMaxTime:
return "timeseries bucket max time";
- case DocumentMetadataFields::kSearchSortValues:
- return "$search sort values";
- case DocumentMetadataFields::kSearchSequenceToken:
- return "$search sequence token";
- case DocumentMetadataFields::kVectorSearchScore:
- return "$vectorSearch distance";
default:
MONGO_UNREACHABLE;
}
diff --git a/src/mongo/db/exec/document_value/document_metadata_fields.h b/src/mongo/db/exec/document_value/document_metadata_fields.h
index 6759675c7ea..12932c29686 100644
--- a/src/mongo/db/exec/document_value/document_metadata_fields.h
+++ b/src/mongo/db/exec/document_value/document_metadata_fields.h
@@ -67,9 +67,6 @@ public:
kSearchScoreDetails,
kTimeseriesBucketMinTime,
kTimeseriesBucketMaxTime,
- kSearchSortValues,
- kVectorSearchScore,
- kSearchSequenceToken,
// New fields must be added before the kNumFields sentinel.
kNumFields
@@ -151,7 +148,11 @@ public:
}
void setTextScore(double score) {
- _setCommon(MetaType::kTextScore);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kTextScore);
_holder->textScore = score;
}
@@ -165,7 +166,11 @@ public:
}
void setRandVal(double val) {
- _setCommon(MetaType::kRandVal);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kRandVal);
_holder->randVal = val;
}
@@ -179,7 +184,11 @@ public:
}
void setSortKey(Value sortKey, bool isSingleElementKey) {
- _setCommon(MetaType::kSortKey);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kSortKey);
_holder->isSingleElementKey = isSingleElementKey;
_holder->sortKey = std::move(sortKey);
}
@@ -198,7 +207,11 @@ public:
}
void setGeoNearDistance(double dist) {
- _setCommon(MetaType::kGeoNearDist);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kGeoNearDist);
_holder->geoNearDistance = dist;
}
@@ -212,7 +225,11 @@ public:
}
void setGeoNearPoint(Value point) {
- _setCommon(MetaType::kGeoNearPoint);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kGeoNearPoint);
_holder->geoNearPoint = std::move(point);
}
@@ -226,7 +243,11 @@ public:
}
void setSearchScore(double score) {
- _setCommon(MetaType::kSearchScore);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kSearchScore);
_holder->searchScore = score;
}
@@ -240,7 +261,11 @@ public:
}
void setSearchHighlights(Value highlights) {
- _setCommon(MetaType::kSearchHighlights);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kSearchHighlights);
_holder->searchHighlights = highlights;
}
@@ -254,7 +279,11 @@ public:
}
void setIndexKey(BSONObj indexKey) {
- _setCommon(MetaType::kIndexKey);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kIndexKey);
_holder->indexKey = indexKey.getOwned();
}
@@ -268,7 +297,11 @@ public:
}
void setRecordId(RecordId rid) {
- _setCommon(MetaType::kRecordId);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+
+ _holder->metaFields.set(MetaType::kRecordId);
_holder->recordId = rid;
}
@@ -282,7 +315,10 @@ public:
}
void setSearchScoreDetails(BSONObj details) {
- _setCommon(MetaType::kSearchScoreDetails);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+ _holder->metaFields.set(MetaType::kSearchScoreDetails);
_holder->searchScoreDetails = details.getOwned();
}
@@ -291,14 +327,15 @@ public:
}
Date_t getTimeseriesBucketMinTime() const {
- tassert(6850100,
- "Document must have timeseries bucket min time metadata field set",
- hasTimeseriesBucketMinTime());
+ invariant(hasTimeseriesBucketMinTime());
return _holder->timeseriesBucketMinTime;
}
void setTimeseriesBucketMinTime(Date_t time) {
- _setCommon(MetaType::kTimeseriesBucketMinTime);
+ if (!_holder) {
+ _holder = std::make_unique<MetadataHolder>();
+ }
+ _holder->metaFields.set(MetaType::kTimeseriesBucketMinTime);
_holder->timeseriesBucketMinTime = time;
}
@@ -307,83 +344,20 @@ public:
}
Date_t getTimeseriesBucketMaxTime() const {
- tassert(6850101,
- "Document must have timeseries bucket max time metadata field set",
- hasTimeseriesBucketMaxTime());
+ invariant(hasTimeseriesBucketMaxTime());
return _holder->timeseriesBucketMaxTime;
}
void setTimeseriesBucketMaxTime(Date_t time) {
- _setCommon(MetaType::kTimeseriesBucketMaxTime);
- _holder->timeseriesBucketMaxTime = time;
- }
-
- bool hasSearchSortValues() const {
- return _holder && _holder->metaFields.test(MetaType::kSearchSortValues);
- }
-
- BSONObj getSearchSortValues() const {
- tassert(7320401, "Document must have $searchSortValues set", hasSearchSortValues());
- return _holder->searchSortValues;
- }
-
- void setSearchSortValues(BSONObj vals) {
- _setCommon(MetaType::kSearchSortValues);
- _holder->searchSortValues = vals.getOwned();
- }
-
- bool hasVectorSearchScore() const {
- return _holder && _holder->metaFields.test(MetaType::kVectorSearchScore);
- }
-
- double getVectorSearchScore() const {
- tassert(7828400, "vectorSearchScore must be present in metadata", hasVectorSearchScore());
- return _holder->vectorSearchScore;
- }
-
- void setVectorSearchScore(double vectorSearchScore) {
- _setCommon(MetaType::kVectorSearchScore);
- _holder->vectorSearchScore = vectorSearchScore;
- }
-
- bool hasSearchSequenceToken() const {
- return _holder && _holder->metaFields.test(MetaType::kSearchSequenceToken);
- }
-
- Value getSearchSequenceToken() const {
- invariant(hasSearchSequenceToken());
- return _holder->searchSequenceToken;
- }
-
- void setSearchSequenceToken(Value details) {
- _setCommon(MetaType::kSearchSequenceToken);
- _holder->searchSequenceToken = details;
- }
-
- void serializeForSorter(BufBuilder& buf) const;
-
- bool isModified() const {
- return _modified;
- }
-
- /**
- * Sets the 'modified' flag to the given value. Necessary for implementing a lazy load
- * optimization for the contained mutable 'DocumentMetadataFields' instance inside the
- * 'Document' class.
- */
- void setModified(bool newValue) {
- _modified = newValue;
- }
-
-private:
- inline void _setCommon(MetaType mt) {
if (!_holder) {
_holder = std::make_unique<MetadataHolder>();
}
- _holder->metaFields.set(mt);
- _modified = true;
+ _holder->metaFields.set(MetaType::kTimeseriesBucketMaxTime);
+ _holder->timeseriesBucketMaxTime = time;
}
+ void serializeForSorter(BufBuilder& buf) const;
+private:
// A simple data struct housing all possible metadata fields.
struct MetadataHolder {
std::bitset<MetaType::kNumFields> metaFields;
@@ -405,18 +379,10 @@ private:
BSONObj searchScoreDetails;
Date_t timeseriesBucketMinTime;
Date_t timeseriesBucketMaxTime;
- BSONObj searchSortValues;
- double vectorSearchScore{0.0};
- Value searchSequenceToken;
};
// Null until the first setter is called, at which point a MetadataHolder struct is allocated.
std::unique_ptr<MetadataHolder> _holder;
-
- // This flag is set to true anytime a 'DocumentMetadataFields' instance is modified. It is used
- // to optimize document conversion to BSON with metadata; i.e. if there are no modifications we
- // can directly return the underlying BSON.
- bool _modified{false};
};
using QueryMetadataBitSet = std::bitset<DocumentMetadataFields::MetaType::kNumFields>;
diff --git a/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp b/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp
index 23ab2277c96..5515009b2bd 100644
--- a/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp
+++ b/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp
@@ -34,7 +34,6 @@
#include "mongo/db/exec/document_value/document_metadata_fields.h"
#include "mongo/db/exec/document_value/document_value_test_util.h"
#include "mongo/unittest/bson_test_util.h"
-#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -51,8 +50,6 @@ TEST(DocumentMetadataFieldsTest, AllMetadataRoundtripsThroughSerialization) {
metadata.setIndexKey(BSON("b" << 1));
metadata.setSearchScoreDetails(BSON("scoreDetails"
<< "foo"));
- metadata.setSearchSortValues(BSON("a" << 1));
- metadata.setVectorSearchScore(7.6);
BufBuilder builder;
metadata.serializeForSorter(builder);
@@ -72,8 +69,6 @@ TEST(DocumentMetadataFieldsTest, AllMetadataRoundtripsThroughSerialization) {
ASSERT_BSONOBJ_EQ(deserialized.getSearchScoreDetails(),
BSON("scoreDetails"
<< "foo"));
- ASSERT_BSONOBJ_EQ(deserialized.getSearchSortValues(), BSON("a" << 1));
- ASSERT_EQ(deserialized.getVectorSearchScore(), 7.6);
}
TEST(DocumentMetadataFieldsTest, HasMethodsReturnFalseForEmptyMetadata) {
@@ -88,8 +83,6 @@ TEST(DocumentMetadataFieldsTest, HasMethodsReturnFalseForEmptyMetadata) {
ASSERT_FALSE(metadata.hasSearchHighlights());
ASSERT_FALSE(metadata.hasIndexKey());
ASSERT_FALSE(metadata.hasSearchScoreDetails());
- ASSERT_FALSE(metadata.hasSearchSortValues());
- ASSERT_FALSE(metadata.hasVectorSearchScore());
}
TEST(DocumentMetadataFieldsTest, HasMethodsReturnTrueForInitializedMetadata) {
@@ -132,14 +125,6 @@ TEST(DocumentMetadataFieldsTest, HasMethodsReturnTrueForInitializedMetadata) {
metadata.setSearchScoreDetails(BSON("scoreDetails"
<< "foo"));
ASSERT_TRUE(metadata.hasSearchScoreDetails());
-
- ASSERT_FALSE(metadata.hasSearchSortValues());
- metadata.setSearchSortValues(BSON("a" << 1));
- ASSERT_TRUE(metadata.hasSearchSortValues());
-
- ASSERT_FALSE(metadata.hasVectorSearchScore());
- metadata.setVectorSearchScore(7.6);
- ASSERT_TRUE(metadata.hasVectorSearchScore());
}
TEST(DocumentMetadataFieldsTest, MoveConstructor) {
@@ -154,8 +139,6 @@ TEST(DocumentMetadataFieldsTest, MoveConstructor) {
metadata.setIndexKey(BSON("b" << 1));
metadata.setSearchScoreDetails(BSON("scoreDetails"
<< "foo"));
- metadata.setSearchSortValues(BSON("a" << 1));
- metadata.setVectorSearchScore(7.6);
DocumentMetadataFields moveConstructed(std::move(metadata));
ASSERT_TRUE(moveConstructed);
@@ -171,8 +154,6 @@ TEST(DocumentMetadataFieldsTest, MoveConstructor) {
ASSERT_BSONOBJ_EQ(moveConstructed.getSearchScoreDetails(),
BSON("scoreDetails"
<< "foo"));
- ASSERT_BSONOBJ_EQ(moveConstructed.getSearchSortValues(), BSON("a" << 1));
- ASSERT_EQ(moveConstructed.getVectorSearchScore(), 7.6);
ASSERT_FALSE(metadata); // NOLINT(bugprone-use-after-move)
}
@@ -189,8 +170,6 @@ TEST(DocumentMetadataFieldsTest, MoveAssignmentOperator) {
metadata.setIndexKey(BSON("b" << 1));
metadata.setSearchScoreDetails(BSON("scoreDetails"
<< "foo"));
- metadata.setSearchSortValues(BSON("a" << 1));
- metadata.setVectorSearchScore(7.6);
DocumentMetadataFields moveAssigned;
moveAssigned.setTextScore(12.3);
@@ -209,8 +188,6 @@ TEST(DocumentMetadataFieldsTest, MoveAssignmentOperator) {
ASSERT_BSONOBJ_EQ(moveAssigned.getSearchScoreDetails(),
BSON("scoreDetails"
<< "foo"));
- ASSERT_BSONOBJ_EQ(moveAssigned.getSearchSortValues(), BSON("a" << 1));
- ASSERT_EQ(moveAssigned.getVectorSearchScore(), 7.6);
ASSERT_FALSE(metadata); // NOLINT(bugprone-use-after-move)
}
@@ -264,8 +241,6 @@ TEST(DocumentMetadataFieldsTest, MergeWithOnlyCopiesMetadataThatDestinationDoesN
ASSERT_FALSE(destination.hasSearchHighlights());
ASSERT_FALSE(destination.hasIndexKey());
ASSERT_FALSE(destination.hasSearchScoreDetails());
- ASSERT_FALSE(destination.hasSearchSortValues());
- ASSERT_FALSE(destination.hasVectorSearchScore());
}
TEST(DocumentMetadataFieldsTest, CopyFromCopiesAllMetadataThatSourceHas) {
@@ -291,173 +266,6 @@ TEST(DocumentMetadataFieldsTest, CopyFromCopiesAllMetadataThatSourceHas) {
ASSERT_FALSE(destination.hasSearchHighlights());
ASSERT_FALSE(destination.hasIndexKey());
ASSERT_FALSE(destination.hasSearchScoreDetails());
- ASSERT_FALSE(destination.hasSearchSortValues());
- ASSERT_FALSE(destination.hasVectorSearchScore());
-}
-
-TEST(DocumentMetadataFieldsTest, GetTimeseriesBucketMinTimeExists) {
- DocumentMetadataFields source;
- Date_t time;
- source.setTimeseriesBucketMinTime(time);
- ASSERT_EQ(source.getTimeseriesBucketMinTime(), time);
-}
-
-TEST(DocumentMetadataFieldsTest, GetTimeseriesBucketMaxTimeExists) {
- DocumentMetadataFields source;
- Date_t time;
- source.setTimeseriesBucketMaxTime(time);
- ASSERT_EQ(source.getTimeseriesBucketMaxTime(), time);
-}
-
-TEST(DocumentMetadataFieldsTest, MetadataIsMarkedModifiedOnSetMetadataField) {
- // Test setting metadata fields directly.
-
- auto testFieldSetter = [](std::function<void(DocumentMetadataFields&)> invokeSetter) {
- DocumentMetadataFields metadata;
- ASSERT_FALSE(metadata.isModified());
- invokeSetter(metadata);
- ASSERT_TRUE(metadata.isModified());
- };
-
- testFieldSetter([](DocumentMetadataFields& md) { md.setTextScore(10.0); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setRandVal(20.0); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setSortKey(Value(30), true); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setGeoNearDistance(40.0); });
- testFieldSetter(
- [](DocumentMetadataFields& md) { md.setGeoNearPoint(Value{BSON_ARRAY(1 << 2)}); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setSearchScore(50.0); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setSearchHighlights(Value{"foo"_sd}); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setIndexKey(BSON("b" << 1)); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setRecordId(RecordId{6}); });
- testFieldSetter([](DocumentMetadataFields& md) {
- md.setSearchScoreDetails(BSON("scoreDetails"
- << "foo"));
- });
- testFieldSetter([](DocumentMetadataFields& md) { md.setTimeseriesBucketMinTime(Date_t()); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setTimeseriesBucketMaxTime(Date_t()); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setSearchSortValues(BSON("a" << 1)); });
- testFieldSetter([](DocumentMetadataFields& md) { md.setVectorSearchScore(60.0); });
-}
-
-TEST(DocumentMetadataFieldsTest, MetadataIsConstructedUnmodified) {
- // We consider new instances as unmodified for all constructors (default, copy, move) even when
- // the original metadata has the 'modified' flag set.
-
- // Testing the default constructor.
- DocumentMetadataFields metadata1;
- ASSERT_FALSE(metadata1.isModified());
- metadata1.setTextScore(10.0);
- ASSERT_TRUE(metadata1.isModified());
-
- // Testing the copy-constructor.
- DocumentMetadataFields metadata2(metadata1);
- ASSERT_FALSE(metadata2.isModified());
-
- // Testing the move-constructor.
- DocumentMetadataFields metadata3(std::move(metadata1));
- ASSERT_FALSE(metadata3.isModified());
-}
-
-TEST(DocumentMetadataFieldsTest, CopyAssignmentIsModification) {
- // We consider copy-assignment as modification even when the instances are equal and the copied
- // metadata does not have the 'modified' flag set.
-
- DocumentMetadataFields metadata1;
- ASSERT_FALSE(metadata1.isModified());
-
- DocumentMetadataFields metadata2;
- ASSERT_FALSE(metadata2.isModified());
-
- // Testing copy-assignment to empty object (metadata2 == metadata1).
- metadata2 = metadata1;
- ASSERT_TRUE(metadata2.isModified());
-
- // Testing copy-assignment in a more common case (metadata1 is empty, metadata2 is not empty).
- metadata2.setTextScore(10.0);
- metadata2.setModified(false);
- ASSERT_FALSE(metadata2.isModified());
- metadata1 = metadata2;
- ASSERT_TRUE(metadata1.isModified());
- ASSERT_EQ(metadata2.getTextScore(), metadata1.getTextScore());
-}
-
-TEST(DocumentMetadataFieldsTest, MoveAssignmentIsModification) {
- // We consider move-assignment as modification even when the instances are equal and the moved
- // metadata does not have the 'modified' flag set.
-
- DocumentMetadataFields metadata1;
- ASSERT_FALSE(metadata1.isModified());
-
- DocumentMetadataFields metadata2;
- ASSERT_FALSE(metadata2.isModified());
-
- // Testing move-assignment to empty object (metadata2 == metadata1).
- metadata2 = std::move(metadata1);
- ASSERT_TRUE(metadata2.isModified());
-
- // Testing move-assignment in a more common case (metadata3 is empty, metadata2 is not empty).
- metadata2.setTextScore(10.0);
- metadata2.setModified(false);
- ASSERT_FALSE(metadata2.isModified());
-
- DocumentMetadataFields metadata3;
- ASSERT_FALSE(metadata3.isModified());
-
- metadata3 = std::move(metadata2);
- ASSERT_TRUE(metadata3.isModified());
- ASSERT_EQ(10.0, metadata3.getTextScore());
-}
-
-TEST(DocumentMetadataFieldsTest, MetadataIsMarkedModifiedOnCopyFrom) {
- DocumentMetadataFields metadata1;
- metadata1.setRandVal(20.0);
- ASSERT_TRUE(metadata1.isModified());
-
- // Testing 'setModified(false)'.
- metadata1.setModified(false);
- ASSERT_FALSE(metadata1.isModified());
-
- // Calling 'copyFrom(metadata1)' modifies metadata2 even when metadata2 == metadata1 and
- // metadata1 is not marked as modified.
- DocumentMetadataFields metadata2(metadata1);
- ASSERT_FALSE(metadata2.isModified());
- metadata2.copyFrom(metadata1);
- ASSERT_TRUE(metadata2.isModified());
-}
-
-TEST(DocumentMetadataFieldsTest, MetadataIsMarkedModifiedOnMergeWith) {
- DocumentMetadataFields metadata1;
- metadata1.setRandVal(20.0);
- ASSERT_TRUE(metadata1.isModified());
-
- metadata1.setModified(false);
- ASSERT_FALSE(metadata1.isModified());
-
- // Calling 'mergeWith(metadata1)' modifies metadata2 only when metadata1 has fields not set in
- // metadata1.
- DocumentMetadataFields metadata2(metadata1);
- ASSERT_FALSE(metadata2.isModified());
- metadata2.mergeWith(metadata1);
- ASSERT_FALSE(metadata2.isModified());
-
- DocumentMetadataFields metadata3;
- ASSERT_FALSE(metadata3.isModified());
- metadata3.mergeWith(metadata2);
- ASSERT_TRUE(metadata3.isModified());
-}
-
-DEATH_TEST_REGEX(DocumentMetadataFieldsTest,
- GetTimeseriesBucketMinTimeDoesntExist,
- "Tripwire assertion.*6850100") {
- DocumentMetadataFields source;
- source.getTimeseriesBucketMinTime();
-}
-
-DEATH_TEST_REGEX(DocumentMetadataFieldsTest,
- GetTimeseriesBucketMaxTimeDoesntExist,
- "Tripwire assertion.*6850101") {
- DocumentMetadataFields source;
- source.getTimeseriesBucketMaxTime();
}
} // namespace mongo
diff --git a/src/mongo/db/exec/document_value/document_value_test.cpp b/src/mongo/db/exec/document_value/document_value_test.cpp
index ca1123a7555..421da707001 100644
--- a/src/mongo/db/exec/document_value/document_value_test.cpp
+++ b/src/mongo/db/exec/document_value/document_value_test.cpp
@@ -355,89 +355,6 @@ TEST(DocumentGetFieldNonCaching, TraverseArray) {
checkArrayTagIsReturned();
}
-TEST(DocumentSize, ApproximateSizeIsSnapshotted) {
- const auto rawBson = BSON("field"
- << "value");
- const Document document{rawBson};
- const auto noCacheSize = document.getApproximateSize();
-
- // Force the cache construction, making the total size of the 'Document' bigger.
- // 'getApproximateSize()' must still return the same value.
- document["field"];
- const auto fullCacheSizeSnapshot = document.getApproximateSize();
- const auto fullCacheSizeCurrent = document.getCurrentApproximateSize();
- ASSERT_EQ(noCacheSize, fullCacheSizeSnapshot);
- ASSERT_LT(noCacheSize, fullCacheSizeCurrent);
-}
-
-TEST(DocumentSize, ApproximateSizeDuringBuildIsUpdated) {
- MutableDocument builder;
- builder.addField("a1", Value(1));
- builder.addField("a2", mongo::Value(2));
- builder.addField("a3", mongo::Value(3));
- auto middleBuildSize = builder.getApproximateSize();
-
- builder.addField("a4", Value(4));
- builder.addField("a5", mongo::Value(5));
- builder.addField("a6", mongo::Value(6));
- auto peekSize = builder.peek().getApproximateSize();
-
- builder.addField("a7", Value(7));
- builder.addField("a8", mongo::Value(8));
- builder.addField("a9", mongo::Value(9));
- auto beforeFreezeSize = builder.getApproximateSize();
-
- Document result = builder.freeze();
- auto frozenSize = result.getApproximateSize();
-
- ASSERT_LT(middleBuildSize, peekSize);
- ASSERT_LT(peekSize, beforeFreezeSize);
- ASSERT_EQ(beforeFreezeSize, frozenSize);
-}
-
-TEST(ShredDocument, OutputHasNoBackingBSON) {
- BSONObj bson =
- BSON("a" << 1 << "subObj" << BSON("a" << 1) << "subArray" << BSON_ARRAY(BSON("a" << 1)));
- auto original = fromBson(bson);
- auto originalSize = original.getApproximateSize();
-
- auto shredded = original.shred();
- auto originalSizeAfterShredding = original.getApproximateSize();
- // Fields in the original doc shouldn't be cached since it was raw bson
- ASSERT_EQ(originalSize, originalSizeAfterShredding);
-
- // BSON is more compact than ValueElement
- auto shreddedSize = shredded.getApproximateSize();
- ASSERT_LT(originalSize, shreddedSize);
-
- // Accessing a field shouldn't change the size since all fields are already cached.
- shredded["a"];
- ASSERT_EQ(shredded.getCurrentApproximateSize(), shreddedSize);
-}
-
-TEST(ShredDocument, HandlesModifiedDocuments) {
- BSONObj bson = BSON("a" << 1 << "subObj" << BSON("a" << 1));
- Document original = fromBson(bson);
- MutableDocument md(original);
- md["b"] = Value(2);
- md["subObj"]["b"] = Value(2);
- Document shredded = md.freeze().shred();
-
- ASSERT(!shredded["b"].missing());
- ASSERT(!shredded["subObj"]["b"].missing());
-}
-
-TEST(ShredDocument, HandlesMetadata) {
- BSONObj bson = BSON("a" << 1 << "subObj" << BSON("a" << 1));
- Document original = fromBson(bson);
- MutableDocument md(original);
- DocumentMetadataFields meta;
- meta.setSearchScore(6);
- md.setMetadata(std::move(meta));
- Document shredded = md.freeze().shred();
- ASSERT_EQ(6, shredded.metadata().getSearchScore());
-}
-
/** Add Document fields. */
class AddField {
public:
@@ -788,22 +705,6 @@ public:
BSONObjBuilder objBuilder;
BSONArrayBuilder arrBuilder;
};
-
-TEST(DocumentTest, ToBsonSizeTraits) {
- constexpr size_t longStringLength = 9 * 1024 * 1024;
- static_assert(longStringLength <= BSONObjMaxInternalSize &&
- 2 * longStringLength > BSONObjMaxInternalSize &&
- 2 * longStringLength <= BufferMaxSize);
- std::string longString(longStringLength, 'A');
- MutableDocument md;
- md.addField("a", Value(longString));
- ASSERT_DOES_NOT_THROW(md.peek().toBson());
- md.addField("b", Value(longString));
- ASSERT_THROWS_CODE(md.peek().toBson(), DBException, ErrorCodes::BSONObjectTooLarge);
- ASSERT_THROWS_CODE(
- md.peek().toBson<BSONObj::DefaultSizeTrait>(), DBException, ErrorCodes::BSONObjectTooLarge);
- ASSERT_DOES_NOT_THROW(md.peek().toBson<BSONObj::LargeSizeTrait>());
-}
} // namespace Document
namespace MetaFields {
@@ -930,15 +831,6 @@ TEST(MetaFields, FromBsonWithMetadataAcceptsIndexKeyMetadata) {
ASSERT_BSONOBJ_EQ(bsonWithoutMetadata, BSON("a" << 1));
}
-TEST(MetaFields, FromBsonWithMetadataHandlesEmptyFieldName) {
- auto bson = BSON("" << 1 << "$indexKey" << BSON("b" << 1));
- auto doc = Document::fromBsonWithMetaData(bson);
- ASSERT_TRUE(doc.metadata().hasIndexKey());
- ASSERT_BSONOBJ_EQ(doc.metadata().getIndexKey(), BSON("b" << 1));
- auto bsonWithoutMetadata = doc.toBson();
- ASSERT_BSONOBJ_EQ(bsonWithoutMetadata, BSON("" << 1));
-}
-
TEST(MetaFields, CopyMetadataFromCopiesAllMetadata) {
Document source = Document::fromBsonWithMetaData(
BSON("a" << 1 << "$textScore" << 9.9 << "b" << 1 << "$randVal" << 42.0 << "c" << 1
@@ -948,8 +840,7 @@ TEST(MetaFields, CopyMetadataFromCopiesAllMetadata) {
<< "foo"
<< "h" << 1 << "$indexKey" << BSON("y" << 1) << "$searchScoreDetails"
<< BSON("scoreDetails"
- << "foo")
- << "$searchSortValues" << BSON("a" << 1) << "$vectorSearchScore" << 6.7));
+ << "foo")));
MutableDocument destination{};
destination.copyMetaDataFrom(source);
@@ -966,8 +857,6 @@ TEST(MetaFields, CopyMetadataFromCopiesAllMetadata) {
ASSERT_BSONOBJ_EQ(result.metadata().getSearchScoreDetails(),
BSON("scoreDetails"
<< "foo"));
- ASSERT_BSONOBJ_EQ(result.metadata().getSearchSortValues(), BSON("a" << 1));
- ASSERT_EQ(result.metadata().getVectorSearchScore(), 6.7);
}
class SerializationTest : public unittest::Test {
@@ -988,8 +877,6 @@ protected:
ASSERT_EQ(output.metadata().hasSearchScore(), input.metadata().hasSearchScore());
ASSERT_EQ(output.metadata().hasSearchHighlights(), input.metadata().hasSearchHighlights());
ASSERT_EQ(output.metadata().hasIndexKey(), input.metadata().hasIndexKey());
- ASSERT_EQ(output.metadata().hasVectorSearchScore(),
- input.metadata().hasVectorSearchScore());
if (input.metadata().hasTextScore()) {
ASSERT_EQ(output.metadata().getTextScore(), input.metadata().getTextScore());
}
@@ -1010,10 +897,6 @@ protected:
ASSERT_BSONOBJ_EQ(output.metadata().getSearchScoreDetails(),
input.metadata().getSearchScoreDetails());
}
- if (input.metadata().hasVectorSearchScore()) {
- ASSERT_EQ(output.metadata().getVectorSearchScore(),
- input.metadata().getVectorSearchScore());
- }
ASSERT(output.toBson().binaryEqual(input.toBson()));
}
@@ -1028,7 +911,6 @@ TEST_F(SerializationTest, MetaSerializationNoVals) {
<< "def"_sd));
docBuilder.metadata().setSearchScoreDetails(BSON("scoreDetails"
<< "foo"));
- docBuilder.metadata().setVectorSearchScore(40.0);
assertRoundTrips(docBuilder.freeze());
}
@@ -1043,7 +925,6 @@ TEST_F(SerializationTest, MetaSerializationWithVals) {
docBuilder.metadata().setIndexKey(BSON("key" << 42));
docBuilder.metadata().setSearchScoreDetails(BSON("scoreDetails"
<< "foo"));
- docBuilder.metadata().setVectorSearchScore(40.0);
assertRoundTrips(docBuilder.freeze());
}
@@ -1066,8 +947,6 @@ TEST(MetaFields, ToAndFromBson) {
<< "def"_sd));
docBuilder.metadata().setSearchScoreDetails(BSON("scoreDetails"
<< "foo"));
- docBuilder.metadata().setSearchSortValues(BSON("a" << 42));
- docBuilder.metadata().setVectorSearchScore(40.0);
Document doc = docBuilder.freeze();
BSONObj obj = doc.toBsonWithMetaData();
ASSERT_EQ(10.0, obj[Document::metaFieldTextScore].Double());
@@ -1079,8 +958,6 @@ TEST(MetaFields, ToAndFromBson) {
ASSERT_BSONOBJ_EQ(obj[Document::metaFieldSearchScoreDetails].Obj(),
BSON("scoreDetails"
<< "foo"));
- ASSERT_BSONOBJ_EQ(BSON("a" << 42), obj[Document::metaFieldSearchSortValues].Obj());
- ASSERT_EQ(40.0, obj[Document::metaFieldVectorSearchScore].Double());
Document fromBson = Document::fromBsonWithMetaData(obj);
ASSERT_TRUE(fromBson.metadata().hasTextScore());
ASSERT_TRUE(fromBson.metadata().hasRandVal());
@@ -1089,110 +966,6 @@ TEST(MetaFields, ToAndFromBson) {
ASSERT_BSONOBJ_EQ(BSON("scoreDetails"
<< "foo"),
fromBson.metadata().getSearchScoreDetails());
- ASSERT_BSONOBJ_EQ(BSON("a" << 42), fromBson.metadata().getSearchSortValues());
- ASSERT_EQ(40.0, fromBson.metadata().getVectorSearchScore());
-}
-
-TEST(MetaFields, ToAndFromBsonTrivialConvertibility) {
- Value sortKey{Document{{"token"_sd, "SOMENCODEDATA"_sd}}};
- // Create a document with a backing BSONObj and separate metadata.
- auto origObjNoMetadata = BSON("a" << 42);
- ASSERT_FALSE(origObjNoMetadata.hasField(Document::metaFieldSortKey));
-
- MutableDocument docBuilder;
- docBuilder.reset(origObjNoMetadata, false);
- docBuilder.metadata().setSortKey(sortKey, true);
- Document docWithSeparateBsonAndMetadata = docBuilder.freeze();
-
- BSONObj origObjWithMetadata = docWithSeparateBsonAndMetadata.toBsonWithMetaData();
- ASSERT_TRUE(origObjWithMetadata.hasField(Document::metaFieldSortKey));
- Document restoredDocWithMetadata = Document::fromBsonWithMetaData(origObjWithMetadata);
- ASSERT_DOCUMENT_EQ(docWithSeparateBsonAndMetadata, restoredDocWithMetadata);
-
- // Test the 'isTriviallyConvertible()' function.
- // The original document is trivially convertible without metadata because the metadata was
- // added to the document separately from the backing BSON object.
- ASSERT_TRUE(docWithSeparateBsonAndMetadata.isTriviallyConvertible());
- // The original document is NOT trivially convertible with metadata because the metadata was
- // added to the document and does not exist in the BSONObj.
- ASSERT_FALSE(docWithSeparateBsonAndMetadata.isTriviallyConvertibleWithMetadata());
- // The restored document is trivially convertible with metadata because the underlying BSONObj
- // contains the metadata serialized from the original document.
- ASSERT_TRUE(restoredDocWithMetadata.isTriviallyConvertibleWithMetadata());
- // The restored document is NOT trivially convertible without metadata because the metadata
- // fields need to be stripped from the underlying BSONObj.
- ASSERT_FALSE(restoredDocWithMetadata.isTriviallyConvertible());
-
- // Test that the conversion with metadata 'origObjWithMetadata' -> 'restoredDocWithMetadata' ->
- // 'restoredObjWithMetadata' is trivial because the backing BSON already contains metadata and
- // neither the metadata nor the non-metadata fields have been modified.
- BSONObj restoredObjWithMetadata = restoredDocWithMetadata.toBsonWithMetaData();
- ASSERT_TRUE(restoredObjWithMetadata.hasField(Document::metaFieldSortKey));
- // Test that 'restoredObjWithMetadata' is referring to the exact same memory location as
- // 'origObjWithMetadata', i.e. both objdata() and objsize() match.
- ASSERT_EQ(origObjWithMetadata.objdata(), restoredObjWithMetadata.objdata());
- ASSERT_EQ(origObjWithMetadata.objsize(), restoredObjWithMetadata.objsize());
-
- // Test that the conversion without metadata 'origObjWithMetadata' -> 'restoredDocWithMetadata'
- // -> 'strippedRestoredObj' is NOT trivial because the backing BSON has metadata that must be
- // omitted during serialization.
- BSONObj strippedRestoredObj = restoredDocWithMetadata.toBson();
- ASSERT_FALSE(strippedRestoredObj.hasField(Document::metaFieldSortKey));
- // 'restoredDocWithMetadata' is trivially convertible with metadata and converting it to BSON
- // without metadata will return a new BSON object.
- ASSERT_TRUE(origObjNoMetadata.binaryEqual(strippedRestoredObj));
- ASSERT_NE(origObjNoMetadata.objdata(), strippedRestoredObj.objdata());
-
- // Test that the conversion without metadata 'origObjNoMetadata' ->
- // 'docWithSeparateBsonAndMetadata' -> 'restoredObjNoMetadata' is trivial because
- // 'origObjNoMetadata' does not contain any metadata.
- BSONObj restoredObjNoMetadata = docWithSeparateBsonAndMetadata.toBson();
- ASSERT_FALSE(restoredObjNoMetadata.hasField(Document::metaFieldSortKey));
- // Test that 'restoredObjNoMetadata' is referring to the exact same memory location as
- // 'origObjNoMetadata', i.e. both objdata() and objsize() match.
- ASSERT_EQ(origObjNoMetadata.objdata(), restoredObjNoMetadata.objdata());
- ASSERT_EQ(origObjNoMetadata.objsize(), restoredObjNoMetadata.objsize());
-}
-
-TEST(MetaFields, TrivialConvertibilityBsonWithoutMetadata) {
- // Test that an unmodified document without metadata is trivially convertible to BSON with and
- // without metadata.
- auto bsonWithoutMetadata = BSON("a" << 42);
- Document doc(bsonWithoutMetadata);
- ASSERT_TRUE(doc.isTriviallyConvertible());
- ASSERT_TRUE(doc.isTriviallyConvertibleWithMetadata());
-}
-
-TEST(MetaFields, TrivialConvertibilityNoBson) {
- // A Document created with no backing BSON is not trivially convertible.
- auto docNoBson = Document{{"a", 42}};
- ASSERT_FALSE(docNoBson.isTriviallyConvertible());
- ASSERT_FALSE(docNoBson.isTriviallyConvertibleWithMetadata());
-
- // An empty Document is trivially convertible, since the default BSONObj is also empty.
- auto emptyDoc = Document{};
- ASSERT_TRUE(emptyDoc.isTriviallyConvertible());
- ASSERT_TRUE(emptyDoc.isTriviallyConvertibleWithMetadata());
-}
-
-TEST(MetaFields, TrivialConvertibilityModified) {
- // Modifying a document with a backing BSON renders it not trivially convertible.
- MutableDocument mutDocModified(Document(BSON("a" << 42)));
- mutDocModified.addField("b", Value(43));
- auto modifiedDoc = mutDocModified.freeze();
- ASSERT_FALSE(modifiedDoc.isTriviallyConvertible());
- ASSERT_FALSE(modifiedDoc.isTriviallyConvertibleWithMetadata());
-}
-
-TEST(MetaFields, TrivialConvertibilityMetadataModified) {
- // Modifying the metadata of a document with a backing BSON renders it not trivially convertible
- // with metadata.
- MutableDocument mutDocModifiedMd(
- Document::fromBsonWithMetaData(BSON(Document::metaFieldTextScore << 10.0)));
- mutDocModifiedMd.metadata().setRandVal(20.0);
- auto modifiedMdDoc = mutDocModifiedMd.freeze();
- ASSERT_FALSE(modifiedMdDoc.isTriviallyConvertible());
- ASSERT_FALSE(modifiedMdDoc.isTriviallyConvertibleWithMetadata());
}
TEST(MetaFields, MetaFieldsIncludedInDocumentApproximateSize) {
@@ -1210,10 +983,8 @@ TEST(MetaFields, MetaFieldsIncludedInDocumentApproximateSize) {
const size_t bigMetadataDocSize = doc2.getApproximateSize();
ASSERT_GT(bigMetadataDocSize, smallMetadataDocSize);
- // Do a sanity check on the amount of space taken by metadata in document 2. Note that the size
- // of certain data types may vary on different build variants, so we cannot assert on the exact
- // size.
- ASSERT_LT(doc2.getMetadataApproximateSize(), 400U);
+ // Do a sanity check on the amount of space taken by metadata in document 2.
+ ASSERT_LT(doc2.getMetadataApproximateSize(), 300U);
Document emptyDoc;
ASSERT_LT(emptyDoc.getMetadataApproximateSize(), 100U);
diff --git a/src/mongo/db/exec/document_value/document_value_test_util.h b/src/mongo/db/exec/document_value/document_value_test_util.h
index 7b88c9688fa..b6959a7d17f 100644
--- a/src/mongo/db/exec/document_value/document_value_test_util.h
+++ b/src/mongo/db/exec/document_value/document_value_test_util.h
@@ -59,13 +59,6 @@
#define _ASSERT_DOCVAL_COMPARISON(NAME, a, b) \
::mongo::unittest::assertComparison_##NAME(__FILE__, __LINE__, #a, #b, a, b)
-// TODO SERVER-87736 make these not say "AUTO".
-// These are backport-special macros, adapted from the "AUTO" version on more recent branches. The
-// automatic functionality doesn't exist on this branch. But the assertions should still pass.
-#define ASSERT_VALUE_EQ_AUTO(expected, val) ASSERT_EQ(expected, val.toString())
-#define ASSERT_DOCUMENT_EQ_AUTO(expected, actual) \
- ASSERT_BSONOBJ_EQ(fromjson(expected), actual.toBson())
-
namespace mongo {
namespace unittest {
diff --git a/src/mongo/db/exec/document_value/value.cpp b/src/mongo/db/exec/document_value/value.cpp
index 616efb2128a..248514180f0 100644
--- a/src/mongo/db/exec/document_value/value.cpp
+++ b/src/mongo/db/exec/document_value/value.cpp
@@ -45,7 +45,6 @@
#include "mongo/db/query/datetime/date_time_support.h"
#include "mongo/platform/decimal128.h"
#include "mongo/util/hex.h"
-#include "mongo/util/murmur3.h"
#include "mongo/util/represent_as.h"
#include "mongo/util/str.h"
@@ -936,7 +935,7 @@ void Value::hash_combine(size_t& seed,
case Code:
case Symbol: {
StringData sd = getRawData();
- seed = murmur3<sizeof(size_t)>(sd, seed);
+ MurmurHash3_x86_32(sd.rawData(), sd.size(), seed, &seed);
break;
}
@@ -945,7 +944,7 @@ void Value::hash_combine(size_t& seed,
if (stringComparator) {
stringComparator->hash_combine(seed, sd);
} else {
- seed = murmur3<sizeof(size_t)>(sd, seed);
+ MurmurHash3_x86_32(sd.rawData(), sd.size(), seed, &seed);
}
break;
}
@@ -969,14 +968,14 @@ void Value::hash_combine(size_t& seed,
case BinData: {
StringData sd = getRawData();
- seed = murmur3<sizeof(size_t)>(sd, seed);
+ MurmurHash3_x86_32(sd.rawData(), sd.size(), seed, &seed);
boost::hash_combine(seed, _storage.binDataType());
break;
}
case RegEx: {
StringData sd = getRawData();
- seed = murmur3<sizeof(size_t)>(sd, seed);
+ MurmurHash3_x86_32(sd.rawData(), sd.size(), seed, &seed);
break;
}
@@ -1254,17 +1253,14 @@ ostream& operator<<(ostream& out, const Value& val) {
verify(false);
}
-Value Value::shred() const {
+void Value::fillCache() const {
if (isObject()) {
- return Value(getDocument().shred());
+ getDocument().fillCache();
} else if (isArray()) {
- std::vector<Value> values;
for (auto&& val : getArray()) {
- values.push_back(val.shred());
+ val.fillCache();
}
- return Value(values);
}
- return Value(*this);
}
void Value::serializeForSorter(BufBuilder& buf) const {
diff --git a/src/mongo/db/exec/document_value/value.h b/src/mongo/db/exec/document_value/value.h
index 62a31f25727..bf54221326c 100644
--- a/src/mongo/db/exec/document_value/value.h
+++ b/src/mongo/db/exec/document_value/value.h
@@ -344,9 +344,9 @@ public:
friend std::ostream& operator<<(std::ostream& out, const Value& v);
/**
- * Returns a cache-only copy of the value with no backing bson.
+ * Populates the internal cache by recursively walking the underlying BSON.
*/
- Value shred() const;
+ void fillCache() const;
void swap(Value& rhs) {
_storage.swap(rhs._storage);
@@ -430,16 +430,13 @@ public:
ImplicitValue(T&& arg) : Value(std::forward<T>(arg)) {}
ImplicitValue(std::initializer_list<ImplicitValue> values) : Value(convertToValues(values)) {}
- ImplicitValue(std::vector<ImplicitValue> values) : Value(convertToValues(values)) {}
- template <typename T>
- ImplicitValue(std::vector<T> values) : Value(convertToValues(values)) {}
+ ImplicitValue(std::vector<int> values) : Value(convertToValues(values)) {}
- template <typename T>
- static std::vector<Value> convertToValues(const std::vector<T>& vec) {
+ static std::vector<Value> convertToValues(const std::vector<int>& vec) {
std::vector<Value> values;
values.reserve(vec.size());
- for_each(vec.begin(), vec.end(), ([&](const T& val) { values.emplace_back(val); }));
+ for_each(vec.begin(), vec.end(), ([&](const int& val) { values.emplace_back(val); }));
return values;
}
diff --git a/src/mongo/db/exec/document_value/value_comparator_test.cpp b/src/mongo/db/exec/document_value/value_comparator_test.cpp
index ac854fdadbe..963a29bc11a 100644
--- a/src/mongo/db/exec/document_value/value_comparator_test.cpp
+++ b/src/mongo/db/exec/document_value/value_comparator_test.cpp
@@ -312,33 +312,5 @@ TEST(ValueComparatorTest, HashingCodeShouldNotRespectCollation) {
ASSERT_NE(comparator.hash(val1), comparator.hash(val2));
}
-// This test was originally designed to reproduce SERVER-78126.
-TEST(ValueComparatorTest, ArraysDifferingByOneStringShouldHaveDifferentHashes) {
- const ValueComparator comparator{};
- const Value val1{std::vector<Value>{Value{std::string{"a"}}, Value{std::string{"x"}}}};
- const Value val2{std::vector<Value>{Value{std::string{"b"}}, Value{std::string{"x"}}}};
- ASSERT_NE(comparator.compare(val1, val2), 0);
- ASSERT_NE(comparator.hash(val1), comparator.hash(val2));
-}
-
-TEST(ValueComparatorTest, ArraysDifferingByOneStringShouldHaveDifferentHashesWithCollation) {
- CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
- const ValueComparator comparator{&collator};
- const Value val1{std::vector<Value>{Value{std::string{"abc"}}, Value{std::string{"xyz"}}}};
- const Value val2{std::vector<Value>{Value{std::string{"bcd"}}, Value{std::string{"xyz"}}}};
- ASSERT_NE(comparator.compare(val1, val2), 0);
- ASSERT_NE(comparator.hash(val1), comparator.hash(val2));
-}
-
-TEST(ValueComparatorTest, ObjectsDifferingByOneStringShouldHaveDifferentHashes) {
- const ValueComparator comparator{};
- const Value val1(
- Document({{"foo"_sd, Value{std::string{"abc"}}}, {"bar"_sd, Value{std::string{"xyz"}}}}));
- const Value val2(
- Document({{"foo"_sd, Value{std::string{"def"}}}, {"bar"_sd, Value{std::string{"xyz"}}}}));
- ASSERT_NE(comparator.compare(val1, val2), 0);
- ASSERT_NE(comparator.hash(val1), comparator.hash(val2));
-}
-
} // namespace
} // namespace mongo