summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/bson/bsonobj.cpp19
-rw-r--r--src/mongo/bson/bsonobj.h4
-rw-r--r--src/mongo/db/catalog/index_catalog_impl.cpp38
-rw-r--r--src/mongo/db/catalog/index_catalog_impl.h6
-rw-r--r--src/mongo/db/catalog/record_store_validate_adaptor.cpp35
-rw-r--r--src/mongo/db/exec/stagedebug_cmd.cpp17
-rw-r--r--src/mongo/db/exec/working_set_common.cpp22
-rw-r--r--src/mongo/db/fts/fts_index_format.cpp13
-rw-r--r--src/mongo/db/fts/fts_index_format.h9
-rw-r--r--src/mongo/db/fts/fts_index_format_test.cpp128
-rw-r--r--src/mongo/db/index/2d_access_method.cpp14
-rw-r--r--src/mongo/db/index/2d_access_method.h7
-rw-r--r--src/mongo/db/index/2d_key_generator_test.cpp44
-rw-r--r--src/mongo/db/index/SConscript1
-rw-r--r--src/mongo/db/index/btree_access_method.cpp18
-rw-r--r--src/mongo/db/index/btree_access_method.h7
-rw-r--r--src/mongo/db/index/btree_key_generator.cpp82
-rw-r--r--src/mongo/db/index/btree_key_generator.h34
-rw-r--r--src/mongo/db/index/btree_key_generator_test.cpp692
-rw-r--r--src/mongo/db/index/expression_keys_private.cpp74
-rw-r--r--src/mongo/db/index/expression_keys_private.h32
-rw-r--r--src/mongo/db/index/fts_access_method.cpp14
-rw-r--r--src/mongo/db/index/fts_access_method.h7
-rw-r--r--src/mongo/db/index/hash_access_method.cpp19
-rw-r--r--src/mongo/db/index/hash_access_method.h7
-rw-r--r--src/mongo/db/index/hash_key_generator_test.cpp87
-rw-r--r--src/mongo/db/index/haystack_access_method.cpp16
-rw-r--r--src/mongo/db/index/haystack_access_method.h7
-rw-r--r--src/mongo/db/index/index_access_method.cpp143
-rw-r--r--src/mongo/db/index/index_access_method.h67
-rw-r--r--src/mongo/db/index/index_build_interceptor.cpp18
-rw-r--r--src/mongo/db/index/index_build_interceptor.h4
-rw-r--r--src/mongo/db/index/s2_access_method.cpp16
-rw-r--r--src/mongo/db/index/s2_access_method.h7
-rw-r--r--src/mongo/db/index/s2_key_generator_test.cpp410
-rw-r--r--src/mongo/db/index/sort_key_generator.cpp14
-rw-r--r--src/mongo/db/index/wildcard_access_method.cpp20
-rw-r--r--src/mongo/db/index/wildcard_access_method.h11
-rw-r--r--src/mongo/db/index/wildcard_key_generator.cpp60
-rw-r--r--src/mongo/db/index/wildcard_key_generator.h35
-rw-r--r--src/mongo/db/index/wildcard_key_generator_test.cpp373
-rw-r--r--src/mongo/db/storage/biggie/biggie_sorted_impl.cpp47
-rw-r--r--src/mongo/db/storage/biggie/biggie_sorted_impl.h6
-rw-r--r--src/mongo/db/storage/devnull/devnull_kv_engine.cpp6
-rw-r--r--src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp47
-rw-r--r--src/mongo/db/storage/key_string.cpp93
-rw-r--r--src/mongo/db/storage/key_string.h139
-rw-r--r--src/mongo/db/storage/mobile/mobile_index.cpp80
-rw-r--r--src/mongo/db/storage/mobile/mobile_index.h16
-rw-r--r--src/mongo/db/storage/sorted_data_interface.h6
-rw-r--r--src/mongo/db/storage/sorted_data_interface_test_bulkbuilder.cpp17
-rw-r--r--src/mongo/db/storage/sorted_data_interface_test_insert.cpp14
-rw-r--r--src/mongo/db/storage/sorted_data_interface_test_unindex.cpp20
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp92
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_index.h24
-rw-r--r--src/mongo/dbtests/index_access_method_test.cpp144
-rw-r--r--src/mongo/dbtests/validate_tests.cpp10
57 files changed, 2120 insertions, 1272 deletions
diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp
index 5985ec18976..0e44b7d398d 100644
--- a/src/mongo/bson/bsonobj.cpp
+++ b/src/mongo/bson/bsonobj.cpp
@@ -378,6 +378,25 @@ BSONObj BSONObj::replaceFieldNames(const BSONObj& names) const {
return b.obj();
}
+BSONObj BSONObj::stripFieldNames(const BSONObj& obj) {
+ if (!obj.hasFieldNames())
+ return obj;
+
+ BSONObjBuilder bb;
+ for (auto e : obj) {
+ bb.appendAs(e, StringData());
+ }
+ return bb.obj();
+}
+
+bool BSONObj::hasFieldNames() const {
+ for (auto e : *this) {
+ if (e.fieldName()[0])
+ return true;
+ }
+ return false;
+}
+
Status BSONObj::storageValidEmbedded() const {
BSONObjIterator i(*this);
diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h
index 82efac98902..bf8559f7dbd 100644
--- a/src/mongo/bson/bsonobj.h
+++ b/src/mongo/bson/bsonobj.h
@@ -532,6 +532,10 @@ public:
passed object. */
BSONObj replaceFieldNames(const BSONObj& obj) const;
+ static BSONObj stripFieldNames(const BSONObj& obj);
+
+ bool hasFieldNames() const;
+
/**
* Returns true if this object is valid according to the specified BSON version, and returns
* false otherwise.
diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp
index f5181ffe234..786bafdb68e 100644
--- a/src/mongo/db/catalog/index_catalog_impl.cpp
+++ b/src/mongo/db/catalog/index_catalog_impl.cpp
@@ -1228,8 +1228,8 @@ const IndexDescriptor* IndexCatalogImpl::refreshEntry(OperationContext* opCtx,
Status IndexCatalogImpl::_indexKeys(OperationContext* opCtx,
IndexCatalogEntry* index,
- const std::vector<BSONObj>& keys,
- const BSONObjSet& multikeyMetadataKeys,
+ const std::vector<KeyString::Value>& keys,
+ const KeyStringSet& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths,
const BSONObj& obj,
RecordId loc,
@@ -1292,12 +1292,16 @@ Status IndexCatalogImpl::_indexFilteredRecords(OperationContext* opCtx,
return status;
}
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- BSONObjSet multikeyMetadataKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
+ KeyStringSet multikeyMetadataKeys;
MultikeyPaths multikeyPaths;
- index->accessMethod()->getKeys(
- *bsonRecord.docPtr, options.getKeysMode, &keys, &multikeyMetadataKeys, &multikeyPaths);
+ index->accessMethod()->getKeys(*bsonRecord.docPtr,
+ options.getKeysMode,
+ &keys,
+ &multikeyMetadataKeys,
+ &multikeyPaths,
+ bsonRecord.id);
Status status = _indexKeys(opCtx,
index,
@@ -1381,7 +1385,7 @@ Status IndexCatalogImpl::_updateRecord(OperationContext* const opCtx,
void IndexCatalogImpl::_unindexKeys(OperationContext* opCtx,
IndexCatalogEntry* index,
- const std::vector<BSONObj>& keys,
+ const std::vector<KeyString::Value>& keys,
const BSONObj& obj,
RecordId loc,
bool logIfError,
@@ -1404,13 +1408,7 @@ void IndexCatalogImpl::_unindexKeys(OperationContext* opCtx,
int64_t removed;
fassert(31155,
index->indexBuildInterceptor()->sideWrite(
- opCtx,
- keys,
- SimpleBSONObjComparator::kInstance.makeBSONObjSet(),
- {},
- loc,
- IndexBuildInterceptor::Op::kDelete,
- &removed));
+ opCtx, keys, {}, {}, loc, IndexBuildInterceptor::Op::kDelete, &removed));
if (keysDeletedOut) {
*keysDeletedOut += removed;
}
@@ -1449,10 +1447,14 @@ void IndexCatalogImpl::_unindexRecord(OperationContext* opCtx,
// There's no need to compute the prefixes of the indexed fields that cause the index to be
// multikey when removing a document since the index metadata isn't updated when keys are
// deleted.
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
-
- entry->accessMethod()->getKeys(
- obj, IndexAccessMethod::GetKeysMode::kRelaxConstraintsUnfiltered, &keys, nullptr, nullptr);
+ KeyStringSet keys;
+
+ entry->accessMethod()->getKeys(obj,
+ IndexAccessMethod::GetKeysMode::kRelaxConstraintsUnfiltered,
+ &keys,
+ nullptr,
+ nullptr,
+ loc);
_unindexKeys(opCtx, entry, {keys.begin(), keys.end()}, obj, loc, logIfError, keysDeletedOut);
}
diff --git a/src/mongo/db/catalog/index_catalog_impl.h b/src/mongo/db/catalog/index_catalog_impl.h
index 9eecee90e52..6746fab533d 100644
--- a/src/mongo/db/catalog/index_catalog_impl.h
+++ b/src/mongo/db/catalog/index_catalog_impl.h
@@ -313,8 +313,8 @@ private:
Status _indexKeys(OperationContext* opCtx,
IndexCatalogEntry* index,
- const std::vector<BSONObj>& keys,
- const BSONObjSet& multikeyMetadataKeys,
+ const std::vector<KeyString::Value>& keys,
+ const KeyStringSet& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths,
const BSONObj& obj,
RecordId loc,
@@ -341,7 +341,7 @@ private:
void _unindexKeys(OperationContext* opCtx,
IndexCatalogEntry* index,
- const std::vector<BSONObj>& keys,
+ const std::vector<KeyString::Value>& keys,
const BSONObj& obj,
RecordId loc,
bool logIfError,
diff --git a/src/mongo/db/catalog/record_store_validate_adaptor.cpp b/src/mongo/db/catalog/record_store_validate_adaptor.cpp
index f86fa1e0bd5..674576f9057 100644
--- a/src/mongo/db/catalog/record_store_validate_adaptor.cpp
+++ b/src/mongo/db/catalog/record_store_validate_adaptor.cpp
@@ -93,14 +93,15 @@ Status RecordStoreValidateAdaptor::validate(const RecordId& recordId,
}
}
- BSONObjSet documentKeySet = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- BSONObjSet multikeyMetadataKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet documentKeySet;
+ KeyStringSet multikeyMetadataKeys;
MultikeyPaths multikeyPaths;
iam->getKeys(recordBson,
IndexAccessMethod::GetKeysMode::kEnforceConstraints,
&documentKeySet,
&multikeyMetadataKeys,
- &multikeyPaths);
+ &multikeyPaths,
+ recordId);
if (!descriptor->isMultikey(_opCtx) &&
iam->shouldMarkIndexAsMultikey(
@@ -115,14 +116,30 @@ Status RecordStoreValidateAdaptor::validate(const RecordId& recordId,
curRecordResults.valid = false;
}
- for (const auto& key : multikeyMetadataKeys) {
- _indexConsistency->addMultikeyMetadataPath(makeWildCardMultikeyMetadataKeyString(key),
- &indexInfo);
+ for (const auto& keyString : multikeyMetadataKeys) {
+ try {
+ auto key = KeyString::toBsonSafe(keyString.getBuffer(),
+ keyString.getSize(),
+ indexInfo.ord,
+ keyString.getTypeBits());
+ _indexConsistency->addMultikeyMetadataPath(
+ makeWildCardMultikeyMetadataKeyString(key), &indexInfo);
+ } catch (...) {
+ return exceptionToStatus();
+ }
}
- for (const auto& key : documentKeySet) {
- indexInfo.ks->resetToKey(key, indexInfo.ord, recordId);
- _indexConsistency->addDocKey(*indexInfo.ks, &indexInfo, recordId, key);
+ for (const auto& keyString : documentKeySet) {
+ try {
+ auto key = KeyString::toBsonSafe(keyString.getBuffer(),
+ keyString.getSize(),
+ indexInfo.ord,
+ keyString.getTypeBits());
+ indexInfo.ks->resetToKey(key, indexInfo.ord, recordId);
+ _indexConsistency->addDocKey(*indexInfo.ks, &indexInfo, recordId, key);
+ } catch (...) {
+ return exceptionToStatus();
+ }
}
}
return status;
diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp
index 73701afe43b..ecca17e1287 100644
--- a/src/mongo/db/exec/stagedebug_cmd.cpp
+++ b/src/mongo/db/exec/stagedebug_cmd.cpp
@@ -70,19 +70,6 @@ using std::string;
using std::unique_ptr;
using std::vector;
-namespace {
-
-BSONObj stripFieldNames(const BSONObj& obj) {
- BSONObjIterator it(obj);
- BSONObjBuilder bob;
- while (it.more()) {
- bob.appendAs(it.next(), "");
- }
- return bob.obj();
-}
-
-} // namespace
-
/**
* A command for manually constructing a query tree and running it.
*
@@ -300,8 +287,8 @@ public:
IndexScanParams params(opCtx, desc);
params.bounds.isSimpleRange = true;
- params.bounds.startKey = stripFieldNames(nodeArgs["startKey"].Obj());
- params.bounds.endKey = stripFieldNames(nodeArgs["endKey"].Obj());
+ params.bounds.startKey = BSONObj::stripFieldNames(nodeArgs["startKey"].Obj());
+ params.bounds.endKey = BSONObj::stripFieldNames(nodeArgs["endKey"].Obj());
params.bounds.boundInclusion = IndexBounds::makeBoundInclusionFromBoundBools(
nodeArgs["startKeyInclusive"].Bool(), nodeArgs["endKeyInclusive"].Bool());
params.direction = nodeArgs["direction"].numberInt();
diff --git a/src/mongo/db/exec/working_set_common.cpp b/src/mongo/db/exec/working_set_common.cpp
index c3d65fa448b..39f08c153bb 100644
--- a/src/mongo/db/exec/working_set_common.cpp
+++ b/src/mongo/db/exec/working_set_common.cpp
@@ -80,17 +80,23 @@ bool WorkingSetCommon::fetch(OperationContext* opCtx,
// unneeded due to the structure of the plan.
invariant(!member->keyData.empty());
for (size_t i = 0; i < member->keyData.size(); i++) {
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
// There's no need to compute the prefixes of the indexed fields that cause the index to
// be multikey when ensuring the keyData is still valid.
- BSONObjSet* multikeyMetadataKeys = nullptr;
+ KeyStringSet* multikeyMetadataKeys = nullptr;
MultikeyPaths* multikeyPaths = nullptr;
- member->keyData[i].index->getKeys(member->obj.value(),
- IndexAccessMethod::GetKeysMode::kEnforceConstraints,
- &keys,
- multikeyMetadataKeys,
- multikeyPaths);
- if (!keys.count(member->keyData[i].keyData)) {
+ auto* iam = member->keyData[i].index;
+ iam->getKeys(member->obj.value(),
+ IndexAccessMethod::GetKeysMode::kEnforceConstraints,
+ &keys,
+ multikeyMetadataKeys,
+ multikeyPaths,
+ member->recordId);
+ KeyString::HeapBuilder keyString(iam->getSortedDataInterface()->getKeyStringVersion(),
+ member->keyData[i].keyData,
+ iam->getSortedDataInterface()->getOrdering(),
+ member->recordId);
+ if (!keys.count(keyString.release())) {
// document would no longer be at this position in the index.
return false;
}
diff --git a/src/mongo/db/fts/fts_index_format.cpp b/src/mongo/db/fts/fts_index_format.cpp
index ab9950635fb..b514a67a6dd 100644
--- a/src/mongo/db/fts/fts_index_format.cpp
+++ b/src/mongo/db/fts/fts_index_format.cpp
@@ -135,7 +135,12 @@ MONGO_INITIALIZER(FTSIndexFormat)(InitializerContext* context) {
return Status::OK();
}
-void FTSIndexFormat::getKeys(const FTSSpec& spec, const BSONObj& obj, BSONObjSet* keys) {
+void FTSIndexFormat::getKeys(const FTSSpec& spec,
+ const BSONObj& obj,
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id) {
int extraSize = 0;
vector<BSONElement> extrasBefore;
vector<BSONElement> extrasAfter;
@@ -182,7 +187,11 @@ void FTSIndexFormat::getKeys(const FTSSpec& spec, const BSONObj& obj, BSONObjSet
verify(guess >= res.objsize());
- keys->insert(res);
+ KeyString::HeapBuilder keyString(keyStringVersion, res, ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.release());
keyBSONSize += res.objsize();
}
}
diff --git a/src/mongo/db/fts/fts_index_format.h b/src/mongo/db/fts/fts_index_format.h
index dd83e8603a8..5ac0823c0c0 100644
--- a/src/mongo/db/fts/fts_index_format.h
+++ b/src/mongo/db/fts/fts_index_format.h
@@ -34,6 +34,8 @@
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobj_comparator_interface.h"
#include "mongo/db/fts/fts_util.h"
+#include "mongo/db/storage/key_string.h"
+#include "mongo/db/storage/sorted_data_interface.h"
namespace mongo {
@@ -43,7 +45,12 @@ class FTSSpec;
class FTSIndexFormat {
public:
- static void getKeys(const FTSSpec& spec, const BSONObj& document, BSONObjSet* keys);
+ static void getKeys(const FTSSpec& spec,
+ const BSONObj& document,
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id = boost::none);
/**
* Helper method to get return entry from the FTSIndex as a BSONObj
diff --git a/src/mongo/db/fts/fts_index_format_test.cpp b/src/mongo/db/fts/fts_index_format_test.cpp
index c9d6779e639..46b10c81228 100644
--- a/src/mongo/db/fts/fts_index_format_test.cpp
+++ b/src/mongo/db/fts/fts_index_format_test.cpp
@@ -51,15 +51,17 @@ using unittest::assertGet;
TEST(FTSIndexFormat, Simple1) {
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << BSON("data"
<< "text")))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
FTSIndexFormat::getKeys(spec,
BSON("data"
<< "cat sat"),
- &keys);
+ &keys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
ASSERT_EQUALS(2U, keys.size());
- for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) {
- BSONObj key = *i;
+ for (auto& keyString : keys) {
+ auto key = KeyString::toBson(keyString, Ordering::make(BSONObj()));
ASSERT_EQUALS(2, key.nFields());
ASSERT_EQUALS(String, key.firstElement().type());
}
@@ -69,15 +71,17 @@ TEST(FTSIndexFormat, ExtraBack1) {
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << BSON("data"
<< "text"
<< "x" << 1)))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
FTSIndexFormat::getKeys(spec,
BSON("data"
<< "cat"
<< "x" << 5),
- &keys);
+ &keys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
ASSERT_EQUALS(1U, keys.size());
- BSONObj key = *(keys.begin());
+ auto key = KeyString::toBson(*keys.begin(), Ordering::make(BSONObj()));
ASSERT_EQUALS(3, key.nFields());
BSONObjIterator i(key);
ASSERT_EQUALS(StringData("cat"), i.next().valuestr());
@@ -88,15 +92,17 @@ TEST(FTSIndexFormat, ExtraBack1) {
TEST(FTSIndexFormat, ExtraFront1) {
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << BSON("x" << 1 << "data"
<< "text")))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
FTSIndexFormat::getKeys(spec,
BSON("data"
<< "cat"
<< "x" << 5),
- &keys);
+ &keys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
ASSERT_EQUALS(1U, keys.size());
- BSONObj key = *(keys.begin());
+ auto key = KeyString::toBson(*keys.begin(), Ordering::make(BSONObj()));
ASSERT_EQUALS(3, key.nFields());
BSONObjIterator i(key);
ASSERT_EQUALS(5, i.next().numberInt());
@@ -108,18 +114,22 @@ TEST(FTSIndexFormat, StopWords1) {
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << BSON("data"
<< "text")))));
- BSONObjSet keys1 = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys1;
FTSIndexFormat::getKeys(spec,
BSON("data"
<< "computer"),
- &keys1);
+ &keys1,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
ASSERT_EQUALS(1U, keys1.size());
- BSONObjSet keys2 = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys2;
FTSIndexFormat::getKeys(spec,
BSON("data"
<< "any computer"),
- &keys2);
+ &keys2,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
ASSERT_EQUALS(1U, keys2.size());
}
@@ -127,10 +137,10 @@ TEST(FTSIndexFormat, StopWords1) {
* Helper function to compare keys returned in getKeys() result
* with expected values.
*/
-void assertEqualsIndexKeys(std::set<std::string>& expectedKeys, const BSONObjSet& keys) {
+void assertEqualsIndexKeys(std::set<std::string>& expectedKeys, const KeyStringSet& keys) {
ASSERT_EQUALS(expectedKeys.size(), keys.size());
- for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) {
- BSONObj key = *i;
+ for (auto& keyString : keys) {
+ auto key = KeyString::toBson(keyString, Ordering::make(BSONObj()));
ASSERT_EQUALS(2, key.nFields());
ASSERT_EQUALS(String, key.firstElement().type());
string s = key.firstElement().String();
@@ -156,14 +166,18 @@ TEST(FTSIndexFormat, LongWordsTextIndexVersion1) {
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << BSON("data"
<< "text")
<< "textIndexVersion" << 1))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
string longPrefix(1024U, 'a');
// "aaa...aaacat"
string longWordCat = longPrefix + "cat";
// "aaa...aaasat"
string longWordSat = longPrefix + "sat";
string text = str::stream() << longWordCat << " " << longWordSat;
- FTSIndexFormat::getKeys(spec, BSON("data" << text), &keys);
+ FTSIndexFormat::getKeys(spec,
+ BSON("data" << text),
+ &keys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
// Hard-coded expected computed keys for future-proofing.
std::set<string> expectedKeys;
@@ -185,7 +199,7 @@ TEST(FTSIndexFormat, LongWordTextIndexVersion2) {
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << BSON("data"
<< "text")
<< "textIndexVersion" << 2))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
string longPrefix(1024U, 'a');
// "aaa...aaacat"
string longWordCat = longPrefix + "cat";
@@ -194,7 +208,11 @@ TEST(FTSIndexFormat, LongWordTextIndexVersion2) {
// "aaa...aaamongodbfts"
string longWordMongoDBFts = longPrefix + "mongodbfts";
string text = str::stream() << longWordCat << " " << longWordSat << " " << longWordMongoDBFts;
- FTSIndexFormat::getKeys(spec, BSON("data" << text), &keys);
+ FTSIndexFormat::getKeys(spec,
+ BSON("data" << text),
+ &keys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
// Hard-coded expected computed keys for future-proofing.
std::set<string> expectedKeys;
@@ -218,14 +236,18 @@ TEST(FTSIndexFormat, LongWordTextIndexVersion3) {
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << BSON("data"
<< "text")
<< "textIndexVersion" << 3))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
string longPrefix(1024U, 'a');
// "aaa...aaacat"
string longWordCat = longPrefix + "cat";
// "aaa...aaasat"
string longWordSat = longPrefix + "sat";
string text = str::stream() << longWordCat << " " << longWordSat;
- FTSIndexFormat::getKeys(spec, BSON("data" << text), &keys);
+ FTSIndexFormat::getKeys(spec,
+ BSON("data" << text),
+ &keys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
// Hard-coded expected computed keys for future-proofing.
std::set<string> expectedKeys;
@@ -246,63 +268,74 @@ TEST(FTSIndexFormat, LongWordTextIndexVersion3) {
TEST(FTSIndexFormat, GetKeysWithLeadingEmptyArrayThrows) {
BSONObj keyPattern = fromjson("{'a.b': 1, data: 'text'}");
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << keyPattern << "textIndexVersion" << 3))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
BSONObj objToIndex = fromjson("{a: {b: []}, data: 'foo'}");
- ASSERT_THROWS_CODE(FTSIndexFormat::getKeys(spec, objToIndex, &keys),
- AssertionException,
- ErrorCodes::CannotBuildIndexKeys);
+ ASSERT_THROWS_CODE(
+ FTSIndexFormat::getKeys(
+ spec, objToIndex, &keys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj())),
+ AssertionException,
+ ErrorCodes::CannotBuildIndexKeys);
}
TEST(FTSIndexFormat, GetKeysWithTrailingEmptyArrayThrows) {
BSONObj keyPattern = fromjson("{data: 'text', 'a.b': 1}");
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << keyPattern << "textIndexVersion" << 3))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
BSONObj objToIndex = fromjson("{a: {b: []}, data: 'foo'}");
- ASSERT_THROWS_CODE(FTSIndexFormat::getKeys(spec, objToIndex, &keys),
- AssertionException,
- ErrorCodes::CannotBuildIndexKeys);
+ ASSERT_THROWS_CODE(
+ FTSIndexFormat::getKeys(
+ spec, objToIndex, &keys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj())),
+ AssertionException,
+ ErrorCodes::CannotBuildIndexKeys);
}
TEST(FTSIndexFormat, GetKeysWithLeadingSingleElementArrayThrows) {
BSONObj keyPattern = fromjson("{'a.b': 1, data: 'text'}");
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << keyPattern << "textIndexVersion" << 3))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
BSONObj objToIndex = fromjson("{a: [{b: 9}], data: 'foo'}");
- ASSERT_THROWS_CODE(FTSIndexFormat::getKeys(spec, objToIndex, &keys),
- AssertionException,
- ErrorCodes::CannotBuildIndexKeys);
+ ASSERT_THROWS_CODE(
+ FTSIndexFormat::getKeys(
+ spec, objToIndex, &keys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj())),
+ AssertionException,
+ ErrorCodes::CannotBuildIndexKeys);
}
TEST(FTSIndexFormat, GetKeysWithTrailingSingleElementArrayThrows) {
BSONObj keyPattern = fromjson("{data: 'text', 'a.b': 1}");
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << keyPattern << "textIndexVersion" << 3))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
BSONObj objToIndex = fromjson("{a: [{b: 9}], data: 'foo'}");
- ASSERT_THROWS_CODE(FTSIndexFormat::getKeys(spec, objToIndex, &keys),
- AssertionException,
- ErrorCodes::CannotBuildIndexKeys);
+ ASSERT_THROWS_CODE(
+ FTSIndexFormat::getKeys(
+ spec, objToIndex, &keys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj())),
+ AssertionException,
+ ErrorCodes::CannotBuildIndexKeys);
}
TEST(FTSIndexFormat, GetKeysWithMultiElementArrayThrows) {
BSONObj keyPattern = fromjson("{'a.b': 1, 'a.c': 'text'}");
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << keyPattern << "textIndexVersion" << 3))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
BSONObj objToIndex = fromjson("{a: [{b: 9, c: 'foo'}, {b: 10, c: 'bar'}]}");
- ASSERT_THROWS_CODE(FTSIndexFormat::getKeys(spec, objToIndex, &keys),
- AssertionException,
- ErrorCodes::CannotBuildIndexKeys);
+ ASSERT_THROWS_CODE(
+ FTSIndexFormat::getKeys(
+ spec, objToIndex, &keys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj())),
+ AssertionException,
+ ErrorCodes::CannotBuildIndexKeys);
}
TEST(FTSIndexFormat, GetKeysWithPositionalPathAllowed) {
BSONObj keyPattern = fromjson("{'a.0': 1, 'a.b': 'text'}");
FTSSpec spec(assertGet(FTSSpec::fixSpec(BSON("key" << keyPattern << "textIndexVersion" << 3))));
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
BSONObj objToIndex = fromjson("{a: [{b: 'foo'}, {b: 'bar'}]}");
- FTSIndexFormat::getKeys(spec, objToIndex, &keys);
+ FTSIndexFormat::getKeys(
+ spec, objToIndex, &keys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj()));
ASSERT_EQ(2U, keys.size());
{
- BSONObj key = *(keys.begin());
+ auto key = KeyString::toBson(*keys.begin(), Ordering::make(BSONObj()));
ASSERT_EQ(3, key.nFields());
BSONObjIterator it{key};
ASSERT_BSONELT_EQ(it.next(), fromjson("{'': {b: 'foo'}}").firstElement());
@@ -310,7 +343,8 @@ TEST(FTSIndexFormat, GetKeysWithPositionalPathAllowed) {
}
{
- BSONObj key = *(++keys.begin());
+ auto next = ++keys.begin();
+ auto key = KeyString::toBson(*next, Ordering::make(BSONObj()));
ASSERT_EQ(3, key.nFields());
BSONObjIterator it{key};
ASSERT_BSONELT_EQ(it.next(), fromjson("{'': {b: 'foo'}}").firstElement());
diff --git a/src/mongo/db/index/2d_access_method.cpp b/src/mongo/db/index/2d_access_method.cpp
index efd9c56b4f6..3aca45956ee 100644
--- a/src/mongo/db/index/2d_access_method.cpp
+++ b/src/mongo/db/index/2d_access_method.cpp
@@ -51,10 +51,16 @@ TwoDAccessMethod::TwoDAccessMethod(IndexCatalogEntry* btreeState,
/** Finds the key objects to put in an index */
void TwoDAccessMethod::doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
- ExpressionKeysPrivate::get2DKeys(obj, _params, keys);
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
+ ExpressionKeysPrivate::get2DKeys(obj,
+ _params,
+ keys,
+ getSortedDataInterface()->getKeyStringVersion(),
+ getSortedDataInterface()->getOrdering(),
+ id);
}
} // namespace mongo
diff --git a/src/mongo/db/index/2d_access_method.h b/src/mongo/db/index/2d_access_method.h
index 9e40c7aa2fc..5a8b426fb12 100644
--- a/src/mongo/db/index/2d_access_method.h
+++ b/src/mongo/db/index/2d_access_method.h
@@ -59,9 +59,10 @@ private:
* indexes don't support tracking path-level multikey information.
*/
void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const final;
TwoDIndexingParams _params;
};
diff --git a/src/mongo/db/index/2d_key_generator_test.cpp b/src/mongo/db/index/2d_key_generator_test.cpp
index b7f5d77c56c..2745eb06b8a 100644
--- a/src/mongo/db/index/2d_key_generator_test.cpp
+++ b/src/mongo/db/index/2d_key_generator_test.cpp
@@ -47,28 +47,26 @@ using namespace mongo;
namespace {
-std::string dumpKeyset(const BSONObjSet& objs) {
+std::string dumpKeyset(const KeyStringSet& keyStrings) {
std::stringstream ss;
ss << "[ ";
- for (BSONObjSet::iterator i = objs.begin(); i != objs.end(); ++i) {
- ss << i->toString() << " ";
+ for (auto& keyString : keyStrings) {
+ auto key = KeyString::toBson(keyString, Ordering::make(BSONObj()));
+ ss << key.toString() << " ";
}
ss << "]";
return ss.str();
}
-bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actualKeys) {
+bool assertKeysetsEqual(const KeyStringSet& expectedKeys, const KeyStringSet& actualKeys) {
if (expectedKeys.size() != actualKeys.size()) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
}
- if (!std::equal(expectedKeys.begin(),
- expectedKeys.end(),
- actualKeys.begin(),
- SimpleBSONObjComparator::kInstance.makeEqualTo())) {
+ if (!std::equal(expectedKeys.begin(), expectedKeys.end(), actualKeys.begin())) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
@@ -77,12 +75,17 @@ bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actual
return true;
}
-BSONObj make2DKey(const TwoDIndexingParams& params, int x, int y, BSONElement trailingFields) {
+KeyString::Value make2DKey(const TwoDIndexingParams& params,
+ int x,
+ int y,
+ BSONElement trailingFields) {
BSONObjBuilder bob;
BSONObj locObj = BSON_ARRAY(x << y);
params.geoHashConverter->hash(locObj, nullptr).appendHashMin(&bob, "");
bob.append(trailingFields);
- return bob.obj();
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, bob.obj(), Ordering::make(BSONObj()));
+ return keyString.release();
}
TEST(2dKeyGeneratorTest, TrailingField) {
@@ -90,10 +93,11 @@ TEST(2dKeyGeneratorTest, TrailingField) {
BSONObj infoObj = fromjson("{key: {a: '2d', b: 1}}");
TwoDIndexingParams params;
ExpressionParams::parseTwoDParams(infoObj, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- ExpressionKeysPrivate::get2DKeys(obj, params, &actualKeys);
+ KeyStringSet actualKeys;
+ ExpressionKeysPrivate::get2DKeys(
+ obj, params, &actualKeys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj()));
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
BSONObj trailingFields = BSON("" << 5);
expectedKeys.insert(make2DKey(params, 0, 0, trailingFields.firstElement()));
@@ -105,10 +109,11 @@ TEST(2dKeyGeneratorTest, ArrayTrailingField) {
BSONObj infoObj = fromjson("{key: {a: '2d', b: 1}}");
TwoDIndexingParams params;
ExpressionParams::parseTwoDParams(infoObj, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- ExpressionKeysPrivate::get2DKeys(obj, params, &actualKeys);
+ KeyStringSet actualKeys;
+ ExpressionKeysPrivate::get2DKeys(
+ obj, params, &actualKeys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj()));
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
BSONObj trailingFields = BSON("" << BSON_ARRAY(5 << 6));
expectedKeys.insert(make2DKey(params, 0, 0, trailingFields.firstElement()));
@@ -120,10 +125,11 @@ TEST(2dKeyGeneratorTest, ArrayOfObjectsTrailingField) {
BSONObj infoObj = fromjson("{key: {a: '2d', 'b.c': 1}}");
TwoDIndexingParams params;
ExpressionParams::parseTwoDParams(infoObj, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- ExpressionKeysPrivate::get2DKeys(obj, params, &actualKeys);
+ KeyStringSet actualKeys;
+ ExpressionKeysPrivate::get2DKeys(
+ obj, params, &actualKeys, KeyString::Version::kLatestVersion, Ordering::make(BSONObj()));
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
BSONObj trailingFields = BSON("" << BSON_ARRAY(5 << 6));
expectedKeys.insert(make2DKey(params, 0, 0, trailingFields.firstElement()));
diff --git a/src/mongo/db/index/SConscript b/src/mongo/db/index/SConscript
index 3d7f912bd6f..3d70ec06eb6 100644
--- a/src/mongo/db/index/SConscript
+++ b/src/mongo/db/index/SConscript
@@ -102,6 +102,7 @@ serveronlyEnv.Library(
'$BUILD_DIR/mongo/db/repl/repl_coordinator_interface',
'$BUILD_DIR/mongo/db/storage/encryption_hooks',
'$BUILD_DIR/mongo/db/storage/index_entry_comparison',
+ '$BUILD_DIR/mongo/db/storage/key_string',
'$BUILD_DIR/mongo/db/storage/storage_options',
'$BUILD_DIR/third_party/shim_snappy',
'index_descriptor',
diff --git a/src/mongo/db/index/btree_access_method.cpp b/src/mongo/db/index/btree_access_method.cpp
index 51d4ba3acbe..da13aa00f50 100644
--- a/src/mongo/db/index/btree_access_method.cpp
+++ b/src/mongo/db/index/btree_access_method.cpp
@@ -56,15 +56,21 @@ BtreeAccessMethod::BtreeAccessMethod(IndexCatalogEntry* btreeState,
fixed.push_back(BSONElement());
}
- _keyGenerator = std::make_unique<BtreeKeyGenerator>(
- fieldNames, fixed, _descriptor->isSparse(), btreeState->getCollator());
+ _keyGenerator =
+ std::make_unique<BtreeKeyGenerator>(fieldNames,
+ fixed,
+ _descriptor->isSparse(),
+ btreeState->getCollator(),
+ getSortedDataInterface()->getKeyStringVersion(),
+ getSortedDataInterface()->getOrdering());
}
void BtreeAccessMethod::doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
- _keyGenerator->getKeys(obj, keys, multikeyPaths);
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
+ _keyGenerator->getKeys(obj, keys, multikeyPaths, id);
}
} // namespace mongo
diff --git a/src/mongo/db/index/btree_access_method.h b/src/mongo/db/index/btree_access_method.h
index 3af203d1f78..ca9db80f4c3 100644
--- a/src/mongo/db/index/btree_access_method.h
+++ b/src/mongo/db/index/btree_access_method.h
@@ -49,9 +49,10 @@ public:
private:
void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const final;
// Our keys differ for V0 and V1.
std::unique_ptr<BtreeKeyGenerator> _keyGenerator;
diff --git a/src/mongo/db/index/btree_key_generator.cpp b/src/mongo/db/index/btree_key_generator.cpp
index 7f337879d9d..71b557cb4c9 100644
--- a/src/mongo/db/index/btree_key_generator.cpp
+++ b/src/mongo/db/index/btree_key_generator.cpp
@@ -58,19 +58,19 @@ const BSONElement undefinedElt = undefinedObj.firstElement();
BtreeKeyGenerator::BtreeKeyGenerator(std::vector<const char*> fieldNames,
std::vector<BSONElement> fixed,
bool isSparse,
- const CollatorInterface* collator)
- : _fieldNames(fieldNames),
+ const CollatorInterface* collator,
+ KeyString::Version keyStringVersion,
+ Ordering ordering)
+ : _keyStringVersion(keyStringVersion),
+ _ordering(ordering),
+ _fieldNames(fieldNames),
+ _isIdIndex(fieldNames.size() == 1 && std::string("_id") == fieldNames[0]),
_isSparse(isSparse),
+ _nullKeyString(_buildNullKeyString()),
_fixed(fixed),
_emptyPositionalInfo(fieldNames.size()),
_collator(collator) {
- BSONObjBuilder nullKeyBuilder;
- for (size_t i = 0; i < fieldNames.size(); ++i) {
- nullKeyBuilder.appendNull("");
- }
- _nullKey = nullKeyBuilder.obj();
- _isIdIndex = fieldNames.size() == 1 && std::string("_id") == fieldNames[0];
for (const char* fieldName : fieldNames) {
size_t pathLength = FieldRef{fieldName}.numParts();
invariant(pathLength > 0);
@@ -117,13 +117,14 @@ BSONElement BtreeKeyGenerator::_extractNextElement(const BSONObj& obj,
void BtreeKeyGenerator::_getKeysArrEltFixed(std::vector<const char*>* fieldNames,
std::vector<BSONElement>* fixed,
const BSONElement& arrEntry,
- BSONObjSet* keys,
+ KeyStringSet* keys,
unsigned numNotFound,
const BSONElement& arrObjElt,
const std::set<size_t>& arrIdxs,
bool mayExpandArrayUnembedded,
const std::vector<PositionalPathInfo>& positionalInfo,
- MultikeyPaths* multikeyPaths) const {
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
// Set up any terminal array values.
for (const auto idx : arrIdxs) {
if (*(*fieldNames)[idx] == '\0') {
@@ -138,29 +139,43 @@ void BtreeKeyGenerator::_getKeysArrEltFixed(std::vector<const char*>* fieldNames
keys,
numNotFound,
positionalInfo,
- multikeyPaths);
+ multikeyPaths,
+ id);
}
void BtreeKeyGenerator::getKeys(const BSONObj& obj,
- BSONObjSet* keys,
- MultikeyPaths* multikeyPaths) const {
+ KeyStringSet* keys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
if (_isIdIndex) {
// we special case for speed
BSONElement e = obj["_id"];
if (e.eoo()) {
- keys->insert(_nullKey);
+ keys->insert(_nullKeyString);
} else if (_collator) {
BSONObjBuilder b;
CollationIndexKey::collationAwareIndexKeyAppend(e, _collator, &b);
- // Insert a copy so its buffer size fits the object size.
- keys->insert(b.obj().copy());
+ KeyString::Builder keyString(_keyStringVersion, b.obj(), _ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ /*
+ * Insert a copy so its buffer size fits the key size.
+ */
+ keys->insert(keyString.getValueCopy());
} else {
int size = e.size() + 5 /* bson over head*/ - 3 /* remove _id string */;
BSONObjBuilder b(size);
b.appendAs(e, "");
- keys->insert(b.obj());
- invariant(keys->begin()->objsize() == size);
+ KeyString::Builder keyString(_keyStringVersion, b.obj(), _ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ /*
+ * Insert a copy so its buffer size fits the key size.
+ */
+ keys->insert(keyString.getValueCopy());
}
// The {_id: 1} index can never be multikey because the _id field isn't allowed to be an
@@ -175,20 +190,22 @@ void BtreeKeyGenerator::getKeys(const BSONObj& obj,
}
// '_fieldNames' and '_fixed' are passed by value so that their copies can be mutated as
// part of the _getKeysWithArray method.
- _getKeysWithArray(_fieldNames, _fixed, obj, keys, 0, _emptyPositionalInfo, multikeyPaths);
+ _getKeysWithArray(
+ _fieldNames, _fixed, obj, keys, 0, _emptyPositionalInfo, multikeyPaths, id);
}
if (keys->empty() && !_isSparse) {
- keys->insert(_nullKey);
+ keys->insert(_nullKeyString);
}
}
void BtreeKeyGenerator::_getKeysWithArray(std::vector<const char*> fieldNames,
std::vector<BSONElement> fixed,
const BSONObj& obj,
- BSONObjSet* keys,
+ KeyStringSet* keys,
unsigned numNotFound,
const std::vector<PositionalPathInfo>& positionalInfo,
- MultikeyPaths* multikeyPaths) const {
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
BSONElement arrElt;
// A set containing the position of any indexed fields in the key pattern that traverse through
@@ -261,7 +278,11 @@ void BtreeKeyGenerator::_getKeysWithArray(std::vector<const char*> fieldNames,
for (std::vector<BSONElement>::iterator i = fixed.begin(); i != fixed.end(); ++i) {
CollationIndexKey::collationAwareIndexKeyAppend(*i, _collator, &b);
}
- keys->insert(b.obj());
+ KeyString::HeapBuilder keyString(_keyStringVersion, b.obj(), _ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.release());
} else if (arrElt.embeddedObject().firstElement().eoo()) {
// We've encountered an empty array.
if (multikeyPaths && mayExpandArrayUnembedded) {
@@ -289,7 +310,8 @@ void BtreeKeyGenerator::_getKeysWithArray(std::vector<const char*> fieldNames,
arrIdxs,
true,
_emptyPositionalInfo,
- multikeyPaths);
+ multikeyPaths,
+ id);
} else {
BSONObj arrObj = arrElt.embeddedObject();
@@ -371,7 +393,8 @@ void BtreeKeyGenerator::_getKeysWithArray(std::vector<const char*> fieldNames,
arrIdxs,
mayExpandArrayUnembedded,
subPositionalInfo,
- multikeyPaths);
+ multikeyPaths,
+ id);
}
}
@@ -385,4 +408,13 @@ void BtreeKeyGenerator::_getKeysWithArray(std::vector<const char*> fieldNames,
}
}
+KeyString::Value BtreeKeyGenerator::_buildNullKeyString() const {
+ BSONObjBuilder nullKeyBuilder;
+ for (size_t i = 0; i < _fieldNames.size(); ++i) {
+ nullKeyBuilder.appendNull("");
+ }
+ KeyString::HeapBuilder nullKeyString(_keyStringVersion, nullKeyBuilder.obj(), _ordering);
+ return nullKeyString.release();
+}
+
} // namespace mongo
diff --git a/src/mongo/db/index/btree_key_generator.h b/src/mongo/db/index/btree_key_generator.h
index a8b529ea4e0..08b960acfc9 100644
--- a/src/mongo/db/index/btree_key_generator.h
+++ b/src/mongo/db/index/btree_key_generator.h
@@ -37,6 +37,7 @@
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index/multikey_paths.h"
#include "mongo/db/jsobj.h"
+#include "mongo/db/storage/key_string.h"
namespace mongo {
@@ -55,7 +56,9 @@ public:
BtreeKeyGenerator(std::vector<const char*> fieldNames,
std::vector<BSONElement> fixed,
bool isSparse,
- const CollatorInterface* collator);
+ const CollatorInterface* collator,
+ KeyString::Version keyStringVersion,
+ Ordering ordering);
/**
* Generates the index keys for the document 'obj', and stores them in the set 'keys'.
@@ -66,15 +69,20 @@ public:
* element with the prefixes of the indexed field that would cause this index to be multikey as
* a result of inserting 'keys'.
*/
- void getKeys(const BSONObj& obj, BSONObjSet* keys, MultikeyPaths* multikeyPaths) const;
+ void getKeys(const BSONObj& obj,
+ KeyStringSet* keys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id = boost::none) const;
private:
+ const KeyString::Version _keyStringVersion;
+ const Ordering _ordering;
// These are used by getKeys below.
- std::vector<const char*> _fieldNames;
- bool _isIdIndex;
- bool _isSparse;
- BSONObj _nullKey; // A full key with all fields null.
- BSONSizeTracker _sizeTracker;
+ const std::vector<const char*> _fieldNames;
+ const bool _isIdIndex;
+ const bool _isSparse;
+ const KeyString::Value _nullKeyString; // A full key with all fields null.
+ const BSONSizeTracker _sizeTracker;
std::vector<BSONElement> _fixed;
/**
@@ -136,10 +144,11 @@ private:
void _getKeysWithArray(std::vector<const char*> fieldNames,
std::vector<BSONElement> fixed,
const BSONObj& obj,
- BSONObjSet* keys,
+ KeyStringSet* keys,
unsigned numNotFound,
const std::vector<PositionalPathInfo>& positionalInfo,
- MultikeyPaths* multikeyPaths) const;
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const;
/**
* A call to _getKeysWithArray() begins by calling this for each field in the key pattern. It
@@ -187,13 +196,16 @@ private:
void _getKeysArrEltFixed(std::vector<const char*>* fieldNames,
std::vector<BSONElement>* fixed,
const BSONElement& arrEntry,
- BSONObjSet* keys,
+ KeyStringSet* keys,
unsigned numNotFound,
const BSONElement& arrObjElt,
const std::set<size_t>& arrIdxs,
bool mayExpandArrayUnembedded,
const std::vector<PositionalPathInfo>& positionalInfo,
- MultikeyPaths* multikeyPaths) const;
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const;
+
+ KeyString::Value _buildNullKeyString() const;
const std::vector<PositionalPathInfo> _emptyPositionalInfo;
diff --git a/src/mongo/db/index/btree_key_generator_test.cpp b/src/mongo/db/index/btree_key_generator_test.cpp
index da569fdb203..811c5d41bab 100644
--- a/src/mongo/db/index/btree_key_generator_test.cpp
+++ b/src/mongo/db/index/btree_key_generator_test.cpp
@@ -54,11 +54,12 @@ namespace {
// Helper functions
//
-std::string dumpKeyset(const BSONObjSet& objs) {
+std::string dumpKeyset(const KeyStringSet& keyStrings) {
std::stringstream ss;
ss << "[ ";
- for (BSONObjSet::iterator i = objs.begin(); i != objs.end(); ++i) {
- ss << i->toString() << " ";
+ for (auto& keyString : keyStrings) {
+ auto key = KeyString::toBson(keyString, Ordering::make(BSONObj()));
+ ss << key.toString() << " ";
}
ss << "]";
@@ -81,15 +82,12 @@ std::string dumpMultikeyPaths(const MultikeyPaths& multikeyPaths) {
return ss.str();
}
-bool keysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actualKeys) {
+bool keysetsEqual(const KeyStringSet& expectedKeys, const KeyStringSet& actualKeys) {
if (expectedKeys.size() != actualKeys.size()) {
return false;
}
- if (!std::equal(expectedKeys.begin(),
- expectedKeys.end(),
- actualKeys.begin(),
- SimpleBSONObjComparator::kInstance.makeEqualTo())) {
+ if (!std::equal(expectedKeys.begin(), expectedKeys.end(), actualKeys.begin())) {
return false;
}
@@ -98,7 +96,7 @@ bool keysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actualKeys)
bool testKeygen(const BSONObj& kp,
const BSONObj& obj,
- const BSONObjSet& expectedKeys,
+ const KeyStringSet& expectedKeys,
const MultikeyPaths& expectedMultikeyPaths,
bool sparse = false,
const CollatorInterface* collator = nullptr) {
@@ -118,14 +116,19 @@ bool testKeygen(const BSONObj& kp,
fixed.push_back(BSONElement());
}
- auto keyGen = std::make_unique<BtreeKeyGenerator>(fieldNames, fixed, sparse, collator);
+ auto keyGen = std::make_unique<BtreeKeyGenerator>(fieldNames,
+ fixed,
+ sparse,
+ collator,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
//
// Step 2: ask 'keyGen' to generate index keys for the object 'obj' and report any prefixes of
// the indexed fields that would cause the index to be multikey as a result of inserting
// 'actualKeys'.
//
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
keyGen->getKeys(obj, &actualKeys, &actualMultikeyPaths);
@@ -156,8 +159,9 @@ bool testKeygen(const BSONObj& kp,
TEST(BtreeKeyGeneratorTest, GetIdKeyFromObject) {
BSONObj keyPattern = fromjson("{_id: 1}");
BSONObj genKeysFrom = fromjson("{_id: 'foo', b: 4}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 'foo'}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 'foo'}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -165,8 +169,9 @@ TEST(BtreeKeyGeneratorTest, GetIdKeyFromObject) {
TEST(BtreeKeyGeneratorTest, GetKeysFromObjectSimple) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{b: 4, a: 5}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 5}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -174,8 +179,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromObjectSimple) {
TEST(BtreeKeyGeneratorTest, GetKeysFromObjectDotted) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: {b: 4}, c: 'foo'}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 4}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 4}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -183,10 +189,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromObjectDotted) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArraySimple) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{a: [1, 2, 3]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -194,8 +203,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArraySimple) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArrayWithIdenticalValues) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{a: [0, 0, 0]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 0}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 0}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -203,8 +213,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArrayWithIdenticalValues) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArrayWithEquivalentValues) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{a: [0, NumberInt(0), NumberLong(0)]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 0}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 0}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -212,10 +223,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArrayWithEquivalentValues) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArrayFirstElement) {
BSONObj keyPattern = fromjson("{a: 1, b: 1}");
BSONObj genKeysFrom = fromjson("{a: [1, 2, 3], b: 2}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1, '': 2}"));
- expectedKeys.insert(fromjson("{'': 2, '': 2}"));
- expectedKeys.insert(fromjson("{'': 3, '': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1, '': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2, '': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3, '': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -223,10 +237,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArrayFirstElement) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArraySecondElement) {
BSONObj keyPattern = fromjson("{first: 1, a: 1}");
BSONObj genKeysFrom = fromjson("{first: 5, a: [1, 2, 3]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 5, '': 1}"));
- expectedKeys.insert(fromjson("{'': 5, '': 2}"));
- expectedKeys.insert(fromjson("{'': 5, '': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5, '': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5, '': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5, '': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -234,10 +251,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArraySecondElement) {
TEST(BtreeKeyGeneratorTest, GetKeysFromSecondLevelArray) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: {b: [1, 2, 3]}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -245,7 +265,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromSecondLevelArray) {
TEST(BtreeKeyGeneratorTest, GetKeysFromParallelArraysBasic) {
BSONObj keyPattern = fromjson("{'a': 1, 'b': 1}");
BSONObj genKeysFrom = fromjson("{a: [1, 2, 3], b: [1, 2, 3]}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -254,10 +274,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromParallelArraysBasic) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArraySubobjectBasic) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b:1,c:4}, {b:2,c:4}, {b:3,c:4}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -265,9 +288,11 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArraySubobjectBasic) {
TEST(BtreeKeyGeneratorTest, GetKeysFromSubobjectWithArrayOfSubobjects) {
BSONObj keyPattern = fromjson("{'a.b.c': 1}");
BSONObj genKeysFrom = fromjson("{a: {b: [{c: 1}, {c: 2}]}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{{1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -275,10 +300,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromSubobjectWithArrayOfSubobjects) {
TEST(BtreeKeyGeneratorTest, GetKeysArraySubobjectCompoundIndex) {
BSONObj keyPattern = fromjson("{'a.b': 1, d: 99}");
BSONObj genKeysFrom = fromjson("{a: [{b:1,c:4}, {b:2,c:4}, {b:3,c:4}], d: 99}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1, '': 99}"));
- expectedKeys.insert(fromjson("{'': 2, '': 99}"));
- expectedKeys.insert(fromjson("{'': 3, '': 99}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1, '': 99}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2, '': 99}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3, '': 99}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -286,11 +314,16 @@ TEST(BtreeKeyGeneratorTest, GetKeysArraySubobjectCompoundIndex) {
TEST(BtreeKeyGeneratorTest, GetKeysArraySubobjectSingleMissing) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [{foo: 41}, {b:1,c:4}, {b:2,c:4}, {b:3,c:4}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{
+ keyString1.release(), keyString2.release(), keyString3.release(), keyString4.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -298,8 +331,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysArraySubobjectSingleMissing) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArraySubobjectMissing) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [{foo: 41}, {foo: 41}, {foo: 41}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -307,8 +341,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArraySubobjectMissing) {
TEST(BtreeKeyGeneratorTest, GetKeysMissingField) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{b: 1}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -316,8 +351,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysMissingField) {
TEST(BtreeKeyGeneratorTest, GetKeysSubobjectMissing) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [1, 2]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -325,8 +361,10 @@ TEST(BtreeKeyGeneratorTest, GetKeysSubobjectMissing) {
TEST(BtreeKeyGeneratorTest, GetKeysFromCompound) {
BSONObj keyPattern = fromjson("{x: 1, y: 1}");
BSONObj genKeysFrom = fromjson("{x: 'a', y: 'b'}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 'a', '': 'b'}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': 'a', '': 'b'}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}, std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -334,8 +372,10 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromCompound) {
TEST(BtreeKeyGeneratorTest, GetKeysFromCompoundMissing) {
BSONObj keyPattern = fromjson("{x: 1, y: 1}");
BSONObj genKeysFrom = fromjson("{x: 'a'}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 'a', '': null}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': 'a', '': null}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}, std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -343,8 +383,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromCompoundMissing) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArraySubelementComplex) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a:[{b:[2]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
// Both the 'a' and 'a.b' arrays contain a single element, so they are considered multikey.
MultikeyPaths expectedMultikeyPaths{{0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
@@ -353,7 +394,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArraySubelementComplex) {
TEST(BtreeKeyGeneratorTest, GetKeysFromParallelArraysComplex) {
BSONObj keyPattern = fromjson("{'a.b': 1, 'a.c': 1}");
BSONObj genKeysFrom = fromjson("{a:[{b:[1],c:[2]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -362,9 +403,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromParallelArraysComplex) {
TEST(BtreeKeyGeneratorTest, GetKeysAlternateMissing) {
BSONObj keyPattern = fromjson("{'a.b': 1, 'a.c': 1}");
BSONObj genKeysFrom = fromjson("{a:[{b:1},{c:2}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null, '': 2}"));
- expectedKeys.insert(fromjson("{'': 1, '': null}"));
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ fromjson("{'': null, '': 2}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ fromjson("{'': 1, '': null}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -372,10 +417,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysAlternateMissing) {
TEST(BtreeKeyGeneratorTest, GetKeysFromMultiComplex) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a:[{b:1},{b:[1,2,3]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -383,10 +431,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromMultiComplex) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArrayOfSubobjectsWithArrayValues) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b: [1, 2]}, {b: [2, 3]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -394,10 +445,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArrayOfSubobjectsWithArrayValues) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArrayOfSubobjectsWithNonDistinctArrayValues) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b: [1, 2, 3]}, {b: [2]}, {b: [3, 1]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -405,25 +459,31 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArrayOfSubobjectsWithNonDistinctArrayValu
TEST(BtreeKeyGeneratorTest, GetKeysArrayEmpty) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{a:[1,2]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': undefined}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.getValueCopy(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a: [1]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1}"));
+ expectedKeys.insert(keyString1.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a: []}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': undefined}"));
+ expectedKeys.insert(keyString3.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a: null}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': null}"));
+ expectedKeys.insert(keyString4.release());
expectedMultikeyPaths[0].clear();
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -431,9 +491,11 @@ TEST(BtreeKeyGeneratorTest, GetKeysArrayEmpty) {
TEST(BtreeKeyGeneratorTest, GetKeysFromDoubleArray) {
BSONObj keyPattern = fromjson("{a: 1, a: 1}");
BSONObj genKeysFrom = fromjson("{a:[1,2]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1, '': 1}"));
- expectedKeys.insert(fromjson("{'': 2, '': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1, '': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2, '': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -441,8 +503,10 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromDoubleArray) {
TEST(BtreeKeyGeneratorTest, GetKeysFromDoubleEmptyArray) {
BSONObj keyPattern = fromjson("{a: 1, a: 1}");
BSONObj genKeysFrom = fromjson("{a:[]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': undefined, '': undefined}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': undefined, '': undefined}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -450,28 +514,34 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromDoubleEmptyArray) {
TEST(BtreeKeyGeneratorTest, GetKeysFromMultiEmptyArray) {
BSONObj keyPattern = fromjson("{a: 1, b: 1}");
BSONObj genKeysFrom = fromjson("{a: 1, b: [1, 2]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1, '': 1}"));
- expectedKeys.insert(fromjson("{'': 1, '': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1, '': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1, '': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ fromjson("{'': 1, '': undefined}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.getValueCopy(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a: 1, b: [1]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1, '': 1}"));
+ expectedKeys.insert(keyString1.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a: 1, b: []}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1, '': undefined}"));
+ expectedKeys.insert(keyString3.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
TEST(BtreeKeyGeneratorTest, GetKeysFromNestedEmptyArray) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a:[]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -479,8 +549,10 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromNestedEmptyArray) {
TEST(BtreeKeyGeneratorTest, GetKeysFromMultiNestedEmptyArray) {
BSONObj keyPattern = fromjson("{'a.b': 1, 'a.c': 1}");
BSONObj genKeysFrom = fromjson("{a:[]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null, '': null}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': null, '': null}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -488,19 +560,27 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromMultiNestedEmptyArray) {
TEST(BtreeKeyGeneratorTest, GetKeysFromUnevenNestedEmptyArray) {
BSONObj keyPattern = fromjson("{'a': 1, 'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a:[]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': undefined, '': null}"));
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ fromjson("{'': undefined, '': null}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:1}, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[]}, '': undefined}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[{b: 1}]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': {b:1}, '': 1}"));
+ expectedKeys.insert(keyString2.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[{b: []}]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': {b:[]}, '': undefined}"));
+ expectedKeys.insert(keyString3.release());
expectedMultikeyPaths[1].insert(1U);
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -508,8 +588,10 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromUnevenNestedEmptyArray) {
TEST(BtreeKeyGeneratorTest, GetKeysFromReverseUnevenNestedEmptyArray) {
BSONObj keyPattern = fromjson("{'a.b': 1, 'a': 1}");
BSONObj genKeysFrom = fromjson("{a:[]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null, '': undefined}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': null, '': undefined}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -518,8 +600,10 @@ TEST(BtreeKeyGeneratorTest, SparseReverseUnevenNestedEmptyArray) {
const bool sparse = true;
BSONObj keyPattern = fromjson("{'a.b': 1, 'a': 1}");
BSONObj genKeysFrom = fromjson("{a:[]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null, '': undefined}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': null, '': undefined}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths, sparse));
}
@@ -528,7 +612,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromSparseEmptyArray) {
const bool sparse = true;
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a:1}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths, sparse));
@@ -544,7 +628,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromSparseEmptyArraySecond) {
const bool sparse = true;
BSONObj keyPattern = fromjson("{z: 1, 'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a:1}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}, std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths, sparse));
@@ -560,7 +644,9 @@ TEST(BtreeKeyGeneratorTest, SparseNonObjectMissingNestedField) {
const bool sparse = true;
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a:[]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths, sparse));
@@ -569,36 +655,41 @@ TEST(BtreeKeyGeneratorTest, SparseNonObjectMissingNestedField) {
genKeysFrom = fromjson("{a:[1,{b:1}]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1}"));
+ expectedKeys.insert(keyString.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths, sparse));
}
TEST(BtreeKeyGeneratorTest, GetKeysFromIndexedArrayIndex) {
BSONObj keyPattern = fromjson("{'a.0': 1}");
BSONObj genKeysFrom = fromjson("{a:[1]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': [1]}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': undefined}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.getValueCopy()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[1]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': [1]}"));
+ expectedKeys.insert(keyString2.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': undefined}"));
+ expectedKeys.insert(keyString3.getValueCopy());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': undefined}"));
+ expectedKeys.insert(keyString3.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:{'0':1}}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1}"));
+ expectedKeys.insert(keyString1.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[{'0':1}]}");
@@ -614,19 +705,24 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromIndexedArrayIndex) {
TEST(BtreeKeyGeneratorTest, GetKeysFromDoubleIndexedArrayIndex) {
BSONObj keyPattern = fromjson("{'a.0.0': 1}");
BSONObj genKeysFrom = fromjson("{a:[[1]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': undefined}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': null}"));
+ expectedKeys.insert(keyString2.getValueCopy());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': null}"));
+ expectedKeys.insert(keyString2.release());
// Here the first "0" path component acts like a regular field name rather than a positional
// path element, since the 0th array index does not exist. Therefore, path component "a" is
// considered multikey.
@@ -635,7 +731,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromDoubleIndexedArrayIndex) {
genKeysFrom = fromjson("{a:[[[]]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': undefined}"));
+ expectedKeys.insert(keyString3.release());
expectedMultikeyPaths = {std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -643,46 +739,47 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromDoubleIndexedArrayIndex) {
TEST(BtreeKeyGeneratorTest, GetKeysFromObjectWithinArray) {
BSONObj keyPattern = fromjson("{'a.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a:[{b:1}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': [1]}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': undefined}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.getValueCopy()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[{b:[1]}]}");
- expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1}"));
expectedMultikeyPaths = {{2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[{b:[[1]]}]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': [1]}"));
+ expectedKeys.insert(keyString2.getValueCopy());
expectedMultikeyPaths = {{2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[{b:1}]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1}"));
+ expectedKeys.insert(keyString1.release());
// Path component "0" refers to an array which is subsequently expanded, so it is considered
// multikey.
expectedMultikeyPaths = {{1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[{b:[1]}]]}");
- expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': 1}"));
expectedMultikeyPaths = {{1U, 2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[{b:[[1]]}]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': [1]}"));
+ expectedKeys.insert(keyString2.release());
expectedMultikeyPaths = {{1U, 2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a:[[{b:[]}]]}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': undefined}"));
+ expectedKeys.insert(keyString3.release());
expectedMultikeyPaths = {{1U, 2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -690,9 +787,11 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromObjectWithinArray) {
TEST(BtreeKeyGeneratorTest, GetKeysPositionalElementIsExpandedArray) {
BSONObj keyPattern = fromjson("{'a.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a:[[{b:1}, {b:2}]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{{1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -700,8 +799,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysPositionalElementIsExpandedArray) {
TEST(BtreeKeyGeneratorTest, GetKeysTrailingPositionalElementIsSingletonArray) {
BSONObj keyPattern = fromjson("{'a.b.c.3': 1}");
BSONObj genKeysFrom = fromjson("{a:{b:{c:[0,1,2,[3]]}}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': [3]}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': [3]}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -709,8 +809,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysTrailingPositionalElementIsSingletonArray) {
TEST(BtreeKeyGeneratorTest, GetKeysTrailingPositionalElementIsEmptyArray) {
BSONObj keyPattern = fromjson("{'a.b.c.3': 1}");
BSONObj genKeysFrom = fromjson("{a:{b:{c:[0,1,2,[]]}}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': undefined}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': undefined}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -718,8 +819,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysTrailingPositionalElementIsEmptyArray) {
TEST(BtreeKeyGeneratorTest, GetKeysManyPositionalElementsComplex) {
BSONObj keyPattern = fromjson("{'a.0.1.2.b.0': 1}");
BSONObj genKeysFrom = fromjson("{a:[[1, [1, 2, [{b: [[], 2]}]]], 1]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': undefined}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': undefined}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{3U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -727,8 +829,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysManyPositionalElementsComplex) {
TEST(BtreeKeyGeneratorTest, GetKeysFromArrayWithinObjectWithinArray) {
BSONObj keyPattern = fromjson("{'a.0.b.0': 1}");
BSONObj genKeysFrom = fromjson("{a:[{b:[1]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -736,7 +839,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysFromArrayWithinObjectWithinArray) {
TEST(BtreeKeyGeneratorTest, ParallelArraysInNestedObjects) {
BSONObj keyPattern = fromjson("{'a.a': 1, 'b.a': 1}");
BSONObj genKeysFrom = fromjson("{a:{a:[1]}, b:{a:[1]}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -745,7 +848,7 @@ TEST(BtreeKeyGeneratorTest, ParallelArraysInNestedObjects) {
TEST(BtreeKeyGeneratorTest, ParallelArraysUneven) {
BSONObj keyPattern = fromjson("{'b.a': 1, 'a': 1}");
BSONObj genKeysFrom = fromjson("{b:{a:[1]}, a:[1,2]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -754,10 +857,13 @@ TEST(BtreeKeyGeneratorTest, ParallelArraysUneven) {
TEST(BtreeKeyGeneratorTest, MultipleArraysNotParallel) {
BSONObj keyPattern = fromjson("{'a.b.c': 1}");
BSONObj genKeysFrom = fromjson("{a: [1, 2, {b: {c: [3, 4]}}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
- expectedKeys.insert(fromjson("{'': 3}"));
- expectedKeys.insert(fromjson("{'': 4}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 4}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -765,10 +871,14 @@ TEST(BtreeKeyGeneratorTest, MultipleArraysNotParallel) {
TEST(BtreeKeyGeneratorTest, MultipleArraysNotParallelCompound) {
BSONObj keyPattern = fromjson("{'a.b.c': 1, 'a.b.d': 1}");
BSONObj genKeysFrom = fromjson("{a: [1, 2, {b: {c: [3, 4], d: 5}}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null, '': null}"));
- expectedKeys.insert(fromjson("{'': 3, '': 5}"));
- expectedKeys.insert(fromjson("{'': 4, '': 5}"));
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ fromjson("{'': null, '': null}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3, '': 5}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 4, '': 5}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 2U}, {0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -776,12 +886,26 @@ TEST(BtreeKeyGeneratorTest, MultipleArraysNotParallelCompound) {
TEST(BtreeKeyGeneratorTest, GetKeysComplexNestedArrays) {
BSONObj keyPattern = fromjson("{'a.b.c.d': 1, 'a.g': 1, 'a.b.f': 1, 'a.b.c': 1, 'a.b.e': 1}");
BSONObj genKeysFrom = fromjson("{a: [1, {b: [2, {c: [3, {d: 1}], e: 4}, 5, {f: 6}], g: 7}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'':null, '':null, '':null, '':null, '':null}"));
- expectedKeys.insert(fromjson("{'':null, '':7, '':null, '':null, '':null}"));
- expectedKeys.insert(fromjson("{'':null, '':7, '':null, '':3, '':4}"));
- expectedKeys.insert(fromjson("{'':null, '':7, '':6, '':null, '':null}"));
- expectedKeys.insert(fromjson("{'':1, '':7, '':null, '':{d: 1}, '':4}"));
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ fromjson("{'':null, '':null, '':null, '':null, '':null}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ fromjson("{'':null, '':7, '':null, '':null, '':null}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ fromjson("{'':null, '':7, '':null, '':3, '':4}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(KeyString::Version::kLatestVersion,
+ fromjson("{'':null, '':7, '':6, '':null, '':null}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString5(KeyString::Version::kLatestVersion,
+ fromjson("{'':1, '':7, '':null, '':{d: 1}, '':4}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(),
+ keyString2.release(),
+ keyString3.release(),
+ keyString4.release(),
+ keyString5.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 1U, 2U}, {0U}, {0U, 1U}, {0U, 1U, 2U}, {0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -790,8 +914,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysComplexNestedArrays) {
TEST(BtreeKeyGeneratorTest, GetKeys2DArray) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{a: [[2]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': [2]}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': [2]}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -801,7 +926,7 @@ TEST(BtreeKeyGeneratorTest, GetKeys2DArray) {
TEST(BtreeKeyGeneratorTest, GetKeysParallelEmptyArrays) {
BSONObj keyPattern = fromjson("{a: 1, b: 1}");
BSONObj genKeysFrom = fromjson("{a: [], b: []}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -810,7 +935,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysParallelEmptyArrays) {
TEST(BtreeKeyGeneratorTest, GetKeysParallelArraysOneArrayEmpty) {
BSONObj keyPattern = fromjson("{a: 1, b: 1}");
BSONObj genKeysFrom = fromjson("{a: [], b: [1, 2, 3]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -819,7 +944,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysParallelArraysOneArrayEmpty) {
TEST(BtreeKeyGeneratorTest, GetKeysParallelArraysOneArrayEmptyNested) {
BSONObj keyPattern = fromjson("{'a.b.c': 1, 'a.b.d': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b: [{c: [1, 2, 3], d: []}]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -829,8 +954,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysParallelArraysOneArrayEmptyNested) {
TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternMissingElement) {
BSONObj keyPattern = fromjson("{'a.2': 1}");
BSONObj genKeysFrom = fromjson("{a: [{'2': 5}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 5}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -839,8 +965,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternMissingElement) {
TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray) {
BSONObj keyPattern = fromjson("{'a.2': 1}");
BSONObj genKeysFrom = fromjson("{a: [[1, 2, 5]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -849,8 +976,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray) {
TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray2) {
BSONObj keyPattern = fromjson("{'a.2': 1}");
BSONObj genKeysFrom = fromjson("{a: [[1, 2, 5], [3, 4, 6], [0, 1, 2]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': [0, 1, 2]}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': [0, 1, 2]}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -859,8 +987,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray2) {
TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray3) {
BSONObj keyPattern = fromjson("{'a.2': 1}");
BSONObj genKeysFrom = fromjson("{a: [{'0': 1, '1': 2, '2': 5}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 5}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -869,8 +998,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray3) {
TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray4) {
BSONObj keyPattern = fromjson("{'a.b.2': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b: [[1, 2, 5]]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -879,9 +1009,11 @@ TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray4) {
TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray5) {
BSONObj keyPattern = fromjson("{'a.2': 1}");
BSONObj genKeysFrom = fromjson("{a: [[1, 2, 5], {'2': 6}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
- expectedKeys.insert(fromjson("{'': 6}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 6}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -889,8 +1021,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysPositionalKeyPatternNestedArray5) {
TEST(BtreeKeyGeneratorTest, GetNullKeyNestedArray) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [[1, 2, 5]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -898,11 +1031,20 @@ TEST(BtreeKeyGeneratorTest, GetNullKeyNestedArray) {
TEST(BtreeKeyGeneratorTest, GetKeysUnevenNestedArrays) {
BSONObj keyPattern = fromjson("{a: 1, 'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [1, {b: [2, 3, 4]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1, '': null}"));
- expectedKeys.insert(fromjson("{'': {b:[2,3,4]}, '': 2}"));
- expectedKeys.insert(fromjson("{'': {b:[2,3,4]}, '': 3}"));
- expectedKeys.insert(fromjson("{'': {b:[2,3,4]}, '': 4}"));
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ fromjson("{'': 1, '': null}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[2,3,4]}, '': 2}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[2,3,4]}, '': 3}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[2,3,4]}, '': 4}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{
+ keyString1.release(), keyString2.release(), keyString3.release(), keyString4.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -912,8 +1054,9 @@ TEST(BtreeKeyGeneratorTest, GetKeysUnevenNestedArrays) {
TEST(BtreeKeyGeneratorTest, GetKeysRepeatedFieldName) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{a: 2, a: 3}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -923,9 +1066,11 @@ TEST(BtreeKeyGeneratorTest, GetKeysRepeatedFieldName) {
TEST(BtreeKeyGeneratorTest, GetKeysEmptyPathPiece) {
BSONObj keyPattern = fromjson("{'a..c': 1}");
BSONObj genKeysFrom = fromjson("{a: {'': [{c: 1}, {c: 2}]}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release()};
MultikeyPaths expectedMultikeyPaths{{1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -934,24 +1079,27 @@ TEST(BtreeKeyGeneratorTest, GetKeysEmptyPathPiece) {
// handling of empty path components.
TEST(BtreeKeyGeneratorTest, GetKeysLastPathPieceEmpty) {
BSONObj keyPattern = fromjson("{'a.': 1}");
-
BSONObj genKeysFrom = fromjson("{a: 2}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': {'': 2}}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
genKeysFrom = fromjson("{a: {'': 2}}");
expectedKeys.clear();
- expectedKeys.insert(fromjson("{'': {'': 2}}"));
+ expectedKeys.insert(keyString2.release());
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
TEST(BtreeKeyGeneratorTest, GetKeysFirstPathPieceEmpty) {
BSONObj keyPattern = fromjson("{'.a': 1}");
BSONObj genKeysFrom = fromjson("{a: 2}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -959,10 +1107,13 @@ TEST(BtreeKeyGeneratorTest, GetKeysFirstPathPieceEmpty) {
TEST(BtreeKeyGeneratorTest, GetKeysFirstPathPieceEmpty2) {
BSONObj keyPattern = fromjson("{'.a': 1}");
BSONObj genKeysFrom = fromjson("{'': [{a: [1, 2, 3]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{0U, 1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -970,7 +1121,7 @@ TEST(BtreeKeyGeneratorTest, GetKeysFirstPathPieceEmpty2) {
TEST(BtreeKeyGeneratorTest, PositionalKeyPatternParallelArrays) {
BSONObj keyPattern = fromjson("{a: 1, 'b.0': 1}");
BSONObj genKeysFrom = fromjson("{a: [1], b: [2]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
MultikeyPaths expectedMultikeyPaths(keyPattern.nFields());
ASSERT_THROWS(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths),
AssertionException);
@@ -979,8 +1130,9 @@ TEST(BtreeKeyGeneratorTest, PositionalKeyPatternParallelArrays) {
TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_b_Extracts_b_ElementInsideSingleton2DArray) {
BSONObj keyPattern = fromjson("{'a.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [[{b: 1}]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{1U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -988,8 +1140,9 @@ TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_b_Extracts_b_ElementInsideSingleton2D
TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_0_b_Extracts_b_ElementInsideSingleton2DArray) {
BSONObj keyPattern = fromjson("{'a.0.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [[{b: 1}]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -998,10 +1151,13 @@ TEST(BtreeKeyGeneratorTest,
KeyPattern_a_0_0_b_ExtractsEachValueFrom_b_ArrayInsideSingleton2DArray) {
BSONObj keyPattern = fromjson("{'a.0.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [[{b: [1, 2, 3]}]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{3U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -1009,8 +1165,9 @@ TEST(BtreeKeyGeneratorTest,
TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_0_b_Extracts_b_ElementInsideSingleton3DArray) {
BSONObj keyPattern = fromjson("{'a.0.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [[[ {b: 1} ]]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -1018,10 +1175,13 @@ TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_0_b_Extracts_b_ElementInsideSingleton
TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_0_b_ExtractsEach_b_ElementInside3DArray) {
BSONObj keyPattern = fromjson("{'a.0.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [[[{b: 1}, {b: 2}, {b: 3}]]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 1}"));
- expectedKeys.insert(fromjson("{'': 2}"));
- expectedKeys.insert(fromjson("{'': 3}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 1}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 3}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
MultikeyPaths expectedMultikeyPaths{{2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -1029,8 +1189,9 @@ TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_0_b_ExtractsEach_b_ElementInside3DArr
TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_0_b_ExtractsNullFrom4DArray) {
BSONObj keyPattern = fromjson("{'a.0.0.b': 1}");
BSONObj genKeysFrom = fromjson("{a: [[[[ {b: 1} ]]]]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': null}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': null}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{2U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -1038,8 +1199,9 @@ TEST(BtreeKeyGeneratorTest, KeyPattern_a_0_0_b_ExtractsNullFrom4DArray) {
TEST(BtreeKeyGeneratorTest, PositionalKeyPatternNestedArrays5) {
BSONObj keyPattern = fromjson("{'a.b.1': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b: [1, 2]}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 2}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 2}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -1048,11 +1210,20 @@ TEST(BtreeKeyGeneratorTest, PositionalKeyPatternNestedArrays5) {
TEST(BtreeKeyGeneratorTest, PositionalKeyPatternNestedArrays6) {
BSONObj keyPattern = fromjson("{'a': 1, 'a.b': 1, 'a.0.b':1, 'a.b.0': 1, 'a.0.b.0': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b: [1,2]}, {b: 3}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': {b:3}, '': 3, '': 1, '': null, '': 1}"));
- expectedKeys.insert(fromjson("{'': {b:3}, '': 3, '': 2, '': null, '': 1}"));
- expectedKeys.insert(fromjson("{'': {b:[1,2]}, '': 1, '': 1, '': 1, '': 1}"));
- expectedKeys.insert(fromjson("{'': {b:[1,2]}, '': 2, '': 2, '': 1, '': 1}"));
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:3}, '': 3, '': 1, '': null, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:3}, '': 3, '': 2, '': null, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[1,2]}, '': 1, '': 1, '': 1, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[1,2]}, '': 2, '': 2, '': 1, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{
+ keyString1.release(), keyString2.release(), keyString3.release(), keyString4.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U, 1U}, {2U}, {0U}, std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -1061,11 +1232,22 @@ TEST(BtreeKeyGeneratorTest, PositionalKeyPatternNestedArrays6) {
TEST(BtreeKeyGeneratorTest, PositionalKeyPatternNestedArrays7) {
BSONObj keyPattern = fromjson("{'a': 1, 'a.b': 1, 'a.0.b':1, 'a.b.0': 1, 'a.0.b.0': 1}");
BSONObj genKeysFrom = fromjson("{a: [{b: [1,2]}, {b: {'0': 3}}]}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': {b:{'0':3}}, '': {'0':3}, '': 1, '': 3, '': 1}"));
- expectedKeys.insert(fromjson("{'': {b:{'0':3}}, '': {'0':3}, '': 2, '': 3, '': 1}"));
- expectedKeys.insert(fromjson("{'': {b:[1,2]}, '': 1, '': 1, '': 1, '': 1}"));
- expectedKeys.insert(fromjson("{'': {b:[1,2]}, '': 2, '': 2, '': 1, '': 1}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:{'0':3}}, '': {'0':3}, '': 1, '': 3, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:{'0':3}}, '': {'0':3}, '': 2, '': 3, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[1,2]}, '': 1, '': 1, '': 1, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(KeyString::Version::kLatestVersion,
+ fromjson("{'': {b:[1,2]}, '': 2, '': 2, '': 1, '': 1}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{
+ keyString1.release(), keyString2.release(), keyString3.release(), keyString4.release()};
MultikeyPaths expectedMultikeyPaths{{0U}, {0U, 1U}, {2U}, {0U}, std::set<size_t>{}};
ASSERT(testKeygen(keyPattern, genKeysFrom, expectedKeys, expectedMultikeyPaths));
}
@@ -1073,8 +1255,9 @@ TEST(BtreeKeyGeneratorTest, PositionalKeyPatternNestedArrays7) {
TEST(BtreeKeyGeneratorTest, GetCollationAwareIdKeyFromObject) {
BSONObj keyPattern = fromjson("{_id: 1}");
BSONObj genKeysFrom = fromjson("{_id: 'foo', b: 4}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 'oof'}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 'oof'}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(
@@ -1084,8 +1267,9 @@ TEST(BtreeKeyGeneratorTest, GetCollationAwareIdKeyFromObject) {
TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromObjectSimple) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{b: 4, a: 'foo'}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 'oof'}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 'oof'}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(
@@ -1095,8 +1279,9 @@ TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromObjectSimple) {
TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromObjectDotted) {
BSONObj keyPattern = fromjson("{'a.b': 1}");
BSONObj genKeysFrom = fromjson("{a: {b: 'foo'}, c: 4}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 'oof'}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 'oof'}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(
@@ -1106,10 +1291,13 @@ TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromObjectDotted) {
TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromArraySimple) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{a: ['foo', 'bar', 'baz']}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 'oof'}"));
- expectedKeys.insert(fromjson("{'': 'rab'}"));
- expectedKeys.insert(fromjson("{'': 'zab'}"));
+ KeyString::HeapBuilder keyString1(
+ KeyString::Version::kLatestVersion, fromjson("{'': 'oof'}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(
+ KeyString::Version::kLatestVersion, fromjson("{'': 'rab'}"), Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(
+ KeyString::Version::kLatestVersion, fromjson("{'': 'zab'}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{{0U}};
ASSERT(
@@ -1119,8 +1307,9 @@ TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromArraySimple) {
TEST(BtreeKeyGeneratorTest, CollatorDoesNotAffectNonStringIdKey) {
BSONObj keyPattern = fromjson("{_id: 1}");
BSONObj genKeysFrom = fromjson("{_id: 5, b: 4}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 5}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(
@@ -1130,8 +1319,9 @@ TEST(BtreeKeyGeneratorTest, CollatorDoesNotAffectNonStringIdKey) {
TEST(BtreeKeyGeneratorTest, CollatorDoesNotAffectNonStringKeys) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{b: 4, a: 5}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': 5}"));
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, fromjson("{'': 5}"), Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(
@@ -1141,8 +1331,10 @@ TEST(BtreeKeyGeneratorTest, CollatorDoesNotAffectNonStringKeys) {
TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromNestedObject) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{b: 4, a: {c: 'foo'}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': {c: 'oof'}}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': {c: 'oof'}}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(
@@ -1152,8 +1344,10 @@ TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromNestedObject) {
TEST(BtreeKeyGeneratorTest, GetCollationAwareKeysFromNestedArray) {
BSONObj keyPattern = fromjson("{a: 1}");
BSONObj genKeysFrom = fromjson("{b: 4, a: {c: ['foo', 'bar', 'baz']}}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(fromjson("{'': {c: ['oof', 'rab', 'zab']}}"));
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ fromjson("{'': {c: ['oof', 'rab', 'zab']}}"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
MultikeyPaths expectedMultikeyPaths{std::set<size_t>{}};
ASSERT(
diff --git a/src/mongo/db/index/expression_keys_private.cpp b/src/mongo/db/index/expression_keys_private.cpp
index 11ed573f27f..c7b67beef8a 100644
--- a/src/mongo/db/index/expression_keys_private.cpp
+++ b/src/mongo/db/index/expression_keys_private.cpp
@@ -67,7 +67,12 @@ namespace dps = ::mongo::dotted_path_support;
* Insert the BSONObj into keys.
* Used by getHaystackKeys.
*/
-void addKey(const string& root, const BSONElement& e, BSONObjSet* keys) {
+void addKey(const string& root,
+ const BSONElement& e,
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id) {
BSONObjBuilder buf;
buf.append("", root);
@@ -76,7 +81,11 @@ void addKey(const string& root, const BSONElement& e, BSONObjSet* keys) {
else
buf.appendAs(e, "");
- keys->insert(buf.obj());
+ KeyString::HeapBuilder keyString(keyStringVersion, buf.obj(), ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.release());
}
//
@@ -236,7 +245,10 @@ using std::vector;
// static
void ExpressionKeysPrivate::get2DKeys(const BSONObj& obj,
const TwoDIndexingParams& params,
- BSONObjSet* keys) {
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id) {
BSONElementMultiSet bSet;
// Get all the nested location fields, but don't return individual elements from
@@ -323,7 +335,11 @@ void ExpressionKeysPrivate::get2DKeys(const BSONObj& obj,
b.append("", aBuilder.arr());
}
}
- keys->insert(b.obj());
+ KeyString::Builder keyString(keyStringVersion, b.obj(), ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.getValueCopy());
if (singleElement)
break;
}
@@ -333,8 +349,11 @@ void ExpressionKeysPrivate::get2DKeys(const BSONObj& obj,
// static
void ExpressionKeysPrivate::getFTSKeys(const BSONObj& obj,
const fts::FTSSpec& ftsSpec,
- BSONObjSet* keys) {
- fts::FTSIndexFormat::getKeys(ftsSpec, obj, keys);
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id) {
+ fts::FTSIndexFormat::getKeys(ftsSpec, obj, keys, keyStringVersion, ordering, id);
}
// static
@@ -344,7 +363,10 @@ void ExpressionKeysPrivate::getHashKeys(const BSONObj& obj,
int hashVersion,
bool isSparse,
const CollatorInterface* collator,
- BSONObjSet* keys) {
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id) {
const char* cstr = hashedField.c_str();
BSONElement fieldVal = dps::extractElementAtPath(obj, cstr);
@@ -363,10 +385,19 @@ void ExpressionKeysPrivate::getHashKeys(const BSONObj& obj,
if (!fieldVal.eoo()) {
BSONObj key = BSON("" << makeSingleHashKey(fieldVal, seed, hashVersion));
- keys->insert(key);
+ KeyString::HeapBuilder keyString(keyStringVersion, key, ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.release());
} else if (!isSparse) {
BSONObj nullObj = BSON("" << BSONNULL);
- keys->insert(BSON("" << makeSingleHashKey(nullObj.firstElement(), seed, hashVersion)));
+ BSONObj key = BSON("" << makeSingleHashKey(nullObj.firstElement(), seed, hashVersion));
+ KeyString::HeapBuilder keyString(keyStringVersion, key, ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.release());
}
}
@@ -381,7 +412,10 @@ void ExpressionKeysPrivate::getHaystackKeys(const BSONObj& obj,
const std::string& geoField,
const std::vector<std::string>& otherFields,
double bucketSize,
- BSONObjSet* keys) {
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id) {
BSONElement loc = dps::extractElementAtPath(obj, geoField);
if (loc.eoo()) {
@@ -414,14 +448,14 @@ void ExpressionKeysPrivate::getHaystackKeys(const BSONObj& obj,
// We're indexing a document that doesn't have the secondary non-geo field present.
// XXX: do we want to add this even if all.size() > 0? result:empty search terms
// match everything instead of only things w/empty search terms)
- addKey(root, BSONElement(), keys);
+ addKey(root, BSONElement(), keys, keyStringVersion, ordering, id);
} else {
// Ex:If our secondary field is type: "foo" or type: {a:"foo", b:"bar"},
// all.size()==1. We can query on the complete field.
// Ex: If our secondary field is type: ["A", "B"] all.size()==2 and all has values
// "A" and "B". The query looks for any of the fields in the array.
for (BSONElementSet::iterator i = all.begin(); i != all.end(); ++i) {
- addKey(root, *i, keys);
+ addKey(root, *i, keys, keyStringVersion, ordering, id);
}
}
}
@@ -445,8 +479,11 @@ std::string ExpressionKeysPrivate::makeHaystackString(int hashedX, int hashedY)
void ExpressionKeysPrivate::getS2Keys(const BSONObj& obj,
const BSONObj& keyPattern,
const S2IndexingParams& params,
- BSONObjSet* keys,
- MultikeyPaths* multikeyPaths) {
+ KeyStringSet* keys,
+ MultikeyPaths* multikeyPaths,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id) {
BSONObjSet keysToAdd = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
// Does one of our documents have a geo field?
@@ -560,7 +597,14 @@ void ExpressionKeysPrivate::getS2Keys(const BSONObj& obj,
<< " num keys: " << keysToAdd.size() << " obj inserted: " << redact(obj);
}
- *keys = std::move(keysToAdd);
+ invariant(keys->empty());
+ for (const auto& key : keysToAdd) {
+ KeyString::HeapBuilder keyString(keyStringVersion, key, ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.release());
+ }
}
} // namespace mongo
diff --git a/src/mongo/db/index/expression_keys_private.h b/src/mongo/db/index/expression_keys_private.h
index b5fbed56e70..17e24f98bf7 100644
--- a/src/mongo/db/index/expression_keys_private.h
+++ b/src/mongo/db/index/expression_keys_private.h
@@ -35,6 +35,7 @@
#include "mongo/bson/bsonobj_comparator_interface.h"
#include "mongo/db/hasher.h"
#include "mongo/db/index/multikey_paths.h"
+#include "mongo/db/storage/key_string.h"
namespace mongo {
@@ -59,13 +60,23 @@ public:
// 2d
//
- static void get2DKeys(const BSONObj& obj, const TwoDIndexingParams& params, BSONObjSet* keys);
+ static void get2DKeys(const BSONObj& obj,
+ const TwoDIndexingParams& params,
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id = boost::none);
//
// FTS
//
- static void getFTSKeys(const BSONObj& obj, const fts::FTSSpec& ftsSpec, BSONObjSet* keys);
+ static void getFTSKeys(const BSONObj& obj,
+ const fts::FTSSpec& ftsSpec,
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id = boost::none);
//
// Hash
@@ -80,7 +91,10 @@ public:
int hashVersion,
bool isSparse,
const CollatorInterface* collator,
- BSONObjSet* keys);
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id = boost::none);
/**
* Hashing function used by both getHashKeys and the cursors we create.
@@ -100,7 +114,10 @@ public:
const std::string& geoField,
const std::vector<std::string>& otherFields,
double bucketSize,
- BSONObjSet* keys);
+ KeyStringSet* keys,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id = boost::none);
/**
* Returns a hash of a BSON element.
@@ -124,8 +141,11 @@ public:
static void getS2Keys(const BSONObj& obj,
const BSONObj& keyPattern,
const S2IndexingParams& params,
- BSONObjSet* keys,
- MultikeyPaths* multikeyPaths);
+ KeyStringSet* keys,
+ MultikeyPaths* multikeyPaths,
+ KeyString::Version keyStringVersion,
+ Ordering ordering,
+ boost::optional<RecordId> id = boost::none);
};
} // namespace mongo
diff --git a/src/mongo/db/index/fts_access_method.cpp b/src/mongo/db/index/fts_access_method.cpp
index 46f20b77b78..0734d5fa5fd 100644
--- a/src/mongo/db/index/fts_access_method.cpp
+++ b/src/mongo/db/index/fts_access_method.cpp
@@ -40,10 +40,16 @@ FTSAccessMethod::FTSAccessMethod(IndexCatalogEntry* btreeState,
_ftsSpec(btreeState->descriptor()->infoObj()) {}
void FTSAccessMethod::doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
- ExpressionKeysPrivate::getFTSKeys(obj, _ftsSpec, keys);
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
+ ExpressionKeysPrivate::getFTSKeys(obj,
+ _ftsSpec,
+ keys,
+ getSortedDataInterface()->getKeyStringVersion(),
+ getSortedDataInterface()->getOrdering(),
+ id);
}
} // namespace mongo
diff --git a/src/mongo/db/index/fts_access_method.h b/src/mongo/db/index/fts_access_method.h
index f4ec0c14468..016246b0208 100644
--- a/src/mongo/db/index/fts_access_method.h
+++ b/src/mongo/db/index/fts_access_method.h
@@ -53,9 +53,10 @@ private:
* indexes don't support tracking path-level multikey information.
*/
void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const final;
fts::FTSSpec _ftsSpec;
};
diff --git a/src/mongo/db/index/hash_access_method.cpp b/src/mongo/db/index/hash_access_method.cpp
index 3aae1930d40..f8a58929e87 100644
--- a/src/mongo/db/index/hash_access_method.cpp
+++ b/src/mongo/db/index/hash_access_method.cpp
@@ -56,11 +56,20 @@ HashAccessMethod::HashAccessMethod(IndexCatalogEntry* btreeState,
}
void HashAccessMethod::doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
- ExpressionKeysPrivate::getHashKeys(
- obj, _hashedField, _seed, _hashVersion, _descriptor->isSparse(), _collator, keys);
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
+ ExpressionKeysPrivate::getHashKeys(obj,
+ _hashedField,
+ _seed,
+ _hashVersion,
+ _descriptor->isSparse(),
+ _collator,
+ keys,
+ getSortedDataInterface()->getKeyStringVersion(),
+ getSortedDataInterface()->getOrdering(),
+ id);
}
} // namespace mongo
diff --git a/src/mongo/db/index/hash_access_method.h b/src/mongo/db/index/hash_access_method.h
index e96ce878625..7dd6536de75 100644
--- a/src/mongo/db/index/hash_access_method.h
+++ b/src/mongo/db/index/hash_access_method.h
@@ -56,9 +56,10 @@ private:
* indexes don't support tracking path-level multikey information.
*/
void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const final;
// Only one of our fields is hashed. This is the field name for it.
std::string _hashedField;
diff --git a/src/mongo/db/index/hash_key_generator_test.cpp b/src/mongo/db/index/hash_key_generator_test.cpp
index e66e2bef5f6..fb84de9f5d1 100644
--- a/src/mongo/db/index/hash_key_generator_test.cpp
+++ b/src/mongo/db/index/hash_key_generator_test.cpp
@@ -50,28 +50,26 @@ namespace {
const HashSeed kHashSeed = 0;
const int kHashVersion = 0;
-std::string dumpKeyset(const BSONObjSet& objs) {
+std::string dumpKeyset(const KeyStringSet& keyStrings) {
std::stringstream ss;
ss << "[ ";
- for (BSONObjSet::iterator i = objs.begin(); i != objs.end(); ++i) {
- ss << i->toString() << " ";
+ for (auto& keyString : keyStrings) {
+ auto key = KeyString::toBson(keyString, Ordering::make(BSONObj()));
+ ss << key.toString() << " ";
}
ss << "]";
return ss.str();
}
-bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actualKeys) {
+bool assertKeysetsEqual(const KeyStringSet& expectedKeys, const KeyStringSet& actualKeys) {
if (expectedKeys.size() != actualKeys.size()) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
}
- if (!std::equal(expectedKeys.begin(),
- expectedKeys.end(),
- actualKeys.begin(),
- SimpleBSONObjComparator::kInstance.makeEqualTo())) {
+ if (!std::equal(expectedKeys.begin(), expectedKeys.end(), actualKeys.begin())) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
@@ -80,19 +78,29 @@ bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actual
return true;
}
-BSONObj makeHashKey(BSONElement elt) {
- return BSON("" << BSONElementHasher::hash64(elt, kHashSeed));
+KeyString::Value makeHashKey(BSONElement elt) {
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << BSONElementHasher::hash64(elt, kHashSeed)),
+ Ordering::make(BSONObj()));
+ return keyString.release();
}
TEST(HashKeyGeneratorTest, CollationAppliedBeforeHashing) {
BSONObj obj = fromjson("{a: 'string'}");
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
- ExpressionKeysPrivate::getHashKeys(
- obj, "a", kHashSeed, kHashVersion, false, &collator, &actualKeys);
+ ExpressionKeysPrivate::getHashKeys(obj,
+ "a",
+ kHashSeed,
+ kHashVersion,
+ false,
+ &collator,
+ &actualKeys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
BSONObj backwardsObj = fromjson("{a: 'gnirts'}");
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet expectedKeys;
expectedKeys.insert(makeHashKey(backwardsObj["a"]));
ASSERT(assertKeysetsEqual(expectedKeys, actualKeys));
@@ -100,12 +108,19 @@ TEST(HashKeyGeneratorTest, CollationAppliedBeforeHashing) {
TEST(HashKeyGeneratorTest, CollationDoesNotAffectNonStringFields) {
BSONObj obj = fromjson("{a: 5}");
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
- ExpressionKeysPrivate::getHashKeys(
- obj, "a", kHashSeed, kHashVersion, false, &collator, &actualKeys);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ ExpressionKeysPrivate::getHashKeys(obj,
+ "a",
+ kHashSeed,
+ kHashVersion,
+ false,
+ &collator,
+ &actualKeys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyStringSet expectedKeys;
expectedKeys.insert(makeHashKey(obj["a"]));
ASSERT(assertKeysetsEqual(expectedKeys, actualKeys));
@@ -114,12 +129,19 @@ TEST(HashKeyGeneratorTest, CollationDoesNotAffectNonStringFields) {
TEST(HashKeyGeneratorTest, CollatorAppliedBeforeHashingNestedObject) {
BSONObj obj = fromjson("{a: {b: 'string'}}");
BSONObj backwardsObj = fromjson("{a: {b: 'gnirts'}}");
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
- ExpressionKeysPrivate::getHashKeys(
- obj, "a", kHashSeed, kHashVersion, false, &collator, &actualKeys);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ ExpressionKeysPrivate::getHashKeys(obj,
+ "a",
+ kHashSeed,
+ kHashVersion,
+ false,
+ &collator,
+ &actualKeys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyStringSet expectedKeys;
expectedKeys.insert(makeHashKey(backwardsObj["a"]));
ASSERT(assertKeysetsEqual(expectedKeys, actualKeys));
@@ -127,11 +149,18 @@ TEST(HashKeyGeneratorTest, CollatorAppliedBeforeHashingNestedObject) {
TEST(HashKeyGeneratorTest, NoCollation) {
BSONObj obj = fromjson("{a: 'string'}");
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- ExpressionKeysPrivate::getHashKeys(
- obj, "a", kHashSeed, kHashVersion, false, nullptr, &actualKeys);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
+ ExpressionKeysPrivate::getHashKeys(obj,
+ "a",
+ kHashSeed,
+ kHashVersion,
+ false,
+ nullptr,
+ &actualKeys,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyStringSet expectedKeys;
expectedKeys.insert(makeHashKey(obj["a"]));
ASSERT(assertKeysetsEqual(expectedKeys, actualKeys));
diff --git a/src/mongo/db/index/haystack_access_method.cpp b/src/mongo/db/index/haystack_access_method.cpp
index 93be4804030..bd4993ff3e5 100644
--- a/src/mongo/db/index/haystack_access_method.cpp
+++ b/src/mongo/db/index/haystack_access_method.cpp
@@ -65,10 +65,18 @@ HaystackAccessMethod::HaystackAccessMethod(IndexCatalogEntry* btreeState,
}
void HaystackAccessMethod::doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
- ExpressionKeysPrivate::getHaystackKeys(obj, _geoField, _otherFields, _bucketSize, keys);
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
+ ExpressionKeysPrivate::getHaystackKeys(obj,
+ _geoField,
+ _otherFields,
+ _bucketSize,
+ keys,
+ getSortedDataInterface()->getKeyStringVersion(),
+ getSortedDataInterface()->getOrdering(),
+ id);
}
void HaystackAccessMethod::searchCommand(OperationContext* opCtx,
diff --git a/src/mongo/db/index/haystack_access_method.h b/src/mongo/db/index/haystack_access_method.h
index 6c609e04cde..d434fd9ca38 100644
--- a/src/mongo/db/index/haystack_access_method.h
+++ b/src/mongo/db/index/haystack_access_method.h
@@ -77,9 +77,10 @@ private:
* geoHaystack indexes don't support tracking path-level multikey information.
*/
void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const final;
std::string _geoField;
std::vector<std::string> _otherFields;
diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp
index 46971923f03..852460066dd 100644
--- a/src/mongo/db/index/index_access_method.cpp
+++ b/src/mongo/db/index/index_access_method.cpp
@@ -81,8 +81,8 @@ bool isMultikeyFromPaths(const MultikeyPaths& multikeyPaths) {
[](const std::set<std::size_t>& components) { return !components.empty(); });
}
-std::vector<BSONObj> asVector(const BSONObjSet& objSet) {
- return {objSet.begin(), objSet.end()};
+std::vector<KeyString::Value> asVector(const KeyStringSet& keySet) {
+ return {keySet.begin(), keySet.end()};
}
} // namespace
@@ -114,7 +114,9 @@ AbstractIndexAccessMethod::AbstractIndexAccessMethod(IndexCatalogEntry* btreeSta
verify(IndexDescriptor::isIndexVersionSupported(_descriptor->version()));
}
-bool AbstractIndexAccessMethod::isFatalError(OperationContext* opCtx, Status status, BSONObj key) {
+bool AbstractIndexAccessMethod::isFatalError(OperationContext* opCtx,
+ Status status,
+ KeyString::Value key) {
// If the status is Status::OK() return false immediately.
if (status.isOK()) {
return false;
@@ -123,7 +125,7 @@ bool AbstractIndexAccessMethod::isFatalError(OperationContext* opCtx, Status sta
// A document might be indexed multiple times during a background index build if it moves ahead
// of the cursor (e.g. via an update). We test this scenario and swallow the error accordingly.
if (status == ErrorCodes::DuplicateKeyValue && !_btreeState->isReady(opCtx)) {
- LOG(3) << "key " << key << " already in index during background indexing (ok)";
+ LOG(3) << "KeyString " << key << " already in index during background indexing (ok)";
return false;
}
return true;
@@ -137,12 +139,12 @@ Status AbstractIndexAccessMethod::insert(OperationContext* opCtx,
InsertResult* result) {
invariant(options.fromIndexBuilder || !_btreeState->isHybridBuilding());
- BSONObjSet multikeyMetadataKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet multikeyMetadataKeys;
+ KeyStringSet keys;
MultikeyPaths multikeyPaths;
// Delegate to the subclass.
- getKeys(obj, options.getKeysMode, &keys, &multikeyMetadataKeys, &multikeyPaths);
+ getKeys(obj, options.getKeysMode, &keys, &multikeyMetadataKeys, &multikeyPaths, loc);
return insertKeys(opCtx,
{keys.begin(), keys.end()},
@@ -154,8 +156,8 @@ Status AbstractIndexAccessMethod::insert(OperationContext* opCtx,
}
Status AbstractIndexAccessMethod::insertKeys(OperationContext* opCtx,
- const vector<BSONObj>& keys,
- const vector<BSONObj>& multikeyMetadataKeys,
+ const vector<KeyString::Value>& keys,
+ const vector<KeyString::Value>& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths,
const RecordId& loc,
const InsertDeleteOptions& options,
@@ -165,25 +167,24 @@ Status AbstractIndexAccessMethod::insertKeys(OperationContext* opCtx,
// the multikey metadata keys, they should point to the reserved 'kMultikeyMetadataKeyId'.
for (const auto keyVec : {&keys, &multikeyMetadataKeys}) {
const auto& recordId = (keyVec == &keys ? loc : kMultikeyMetadataKeyId);
- for (const auto& key : *keyVec) {
+ for (const auto& keyString : *keyVec) {
bool unique = _descriptor->unique();
- Status status = _newInterface->insert(opCtx, key, recordId, !unique /* dupsAllowed */);
+ Status status =
+ _newInterface->insert(opCtx, keyString, recordId, !unique /* dupsAllowed */);
// When duplicates are encountered and allowed, retry with dupsAllowed. Add the
// key to the output vector so callers know which duplicate keys were inserted.
if (ErrorCodes::DuplicateKey == status.code() && options.dupsAllowed) {
invariant(unique);
- status = _newInterface->insert(opCtx, key, recordId, true /* dupsAllowed */);
+ status = _newInterface->insert(opCtx, keyString, recordId, true /* dupsAllowed */);
- // This is speculative in that the 'dupsInserted' vector is not used by any code
- // today. It is currently in place to test detecting duplicate key errors during
- // hybrid index builds. Duplicate detection in the future will likely not take
- // place in this insert() method.
if (status.isOK() && result) {
+ auto key =
+ KeyString::toBson(keyString, getSortedDataInterface()->getOrdering());
result->dupsInserted.push_back(key);
}
}
- if (isFatalError(opCtx, status, key)) {
+ if (isFatalError(opCtx, status, keyString)) {
return status;
}
}
@@ -200,16 +201,16 @@ Status AbstractIndexAccessMethod::insertKeys(OperationContext* opCtx,
}
void AbstractIndexAccessMethod::removeOneKey(OperationContext* opCtx,
- const BSONObj& key,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) {
try {
- _newInterface->unindex(opCtx, key, loc, dupsAllowed);
+ _newInterface->unindex(opCtx, keyString, loc, dupsAllowed);
} catch (AssertionException& e) {
log() << "Assertion failure: _unindex failed on: " << _descriptor->parentNS()
<< " for index: " << _descriptor->indexName();
- log() << "Assertion failure: _unindex failed: " << redact(e) << " key:" << key.toString()
+ log() << "Assertion failure: _unindex failed: " << redact(e) << " KeyString:" << keyString
<< " dl:" << loc;
logContext();
}
@@ -226,7 +227,7 @@ std::unique_ptr<SortedDataInterface::Cursor> AbstractIndexAccessMethod::newCurso
}
Status AbstractIndexAccessMethod::removeKeys(OperationContext* opCtx,
- const std::vector<BSONObj>& keys,
+ const std::vector<KeyString::Value>& keys,
const RecordId& loc,
const InsertDeleteOptions& options,
int64_t* numDeleted) {
@@ -244,15 +245,19 @@ Status AbstractIndexAccessMethod::initializeAsEmpty(OperationContext* opCtx) {
}
Status AbstractIndexAccessMethod::touch(OperationContext* opCtx, const BSONObj& obj) {
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
// There's no need to compute the prefixes of the indexed fields that cause the index to be
// multikey when paging a document's index entries into memory.
- BSONObjSet* multikeyMetadataKeys = nullptr;
+ KeyStringSet* multikeyMetadataKeys = nullptr;
MultikeyPaths* multikeyPaths = nullptr;
getKeys(obj, GetKeysMode::kEnforceConstraints, &keys, multikeyMetadataKeys, multikeyPaths);
std::unique_ptr<SortedDataInterface::Cursor> cursor(_newInterface->newCursor(opCtx));
- for (const auto& key : keys) {
+ for (const auto& keyString : keys) {
+ auto key = KeyString::toBson(keyString.getBuffer(),
+ keyString.getSize(),
+ getSortedDataInterface()->getOrdering(),
+ keyString.getTypeBits());
cursor->seekExact(key);
}
@@ -267,11 +272,11 @@ Status AbstractIndexAccessMethod::touch(OperationContext* opCtx) const {
RecordId AbstractIndexAccessMethod::findSingle(OperationContext* opCtx,
const BSONObj& requestedKey) const {
// Generate the key for this index.
- BSONObj actualKey;
+ boost::optional<KeyString::Value> actualKey;
if (_btreeState->getCollator()) {
// For performance, call get keys only if there is a non-simple collation.
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- BSONObjSet* multikeyMetadataKeys = nullptr;
+ KeyStringSet keys;
+ KeyStringSet* multikeyMetadataKeys = nullptr;
MultikeyPaths* multikeyPaths = nullptr;
getKeys(requestedKey,
GetKeysMode::kEnforceConstraints,
@@ -279,19 +284,25 @@ RecordId AbstractIndexAccessMethod::findSingle(OperationContext* opCtx,
multikeyMetadataKeys,
multikeyPaths);
invariant(keys.size() == 1);
- actualKey = *keys.begin();
+ actualKey.emplace(std::move(*keys.begin()));
} else {
- actualKey = requestedKey;
+ KeyString::HeapBuilder requestedKeyString(getSortedDataInterface()->getKeyStringVersion(),
+ BSONObj::stripFieldNames(requestedKey),
+ getSortedDataInterface()->getOrdering());
+ actualKey.emplace(requestedKeyString.release());
}
std::unique_ptr<SortedDataInterface::Cursor> cursor(_newInterface->newCursor(opCtx));
const auto requestedInfo = kDebugBuild ? SortedDataInterface::Cursor::kKeyAndLoc
: SortedDataInterface::Cursor::kWantLoc;
- if (auto kv = cursor->seekExact(actualKey, requestedInfo)) {
+ auto key = KeyString::toBson(actualKey->getBuffer(),
+ actualKey->getSize(),
+ getSortedDataInterface()->getOrdering(),
+ actualKey->getTypeBits());
+ if (auto kv = cursor->seekExact(key, requestedInfo)) {
// StorageEngine should guarantee these.
dassert(!kv->loc.isNull());
- dassert(kv->key.woCompare(actualKey, /*order*/ BSONObj(), /*considerFieldNames*/ false) ==
- 0);
+ dassert(kv->key.woCompare(key, /*order*/ BSONObj(), /*considerFieldNames*/ false) == 0);
return kv->loc;
}
@@ -317,20 +328,26 @@ long long AbstractIndexAccessMethod::getSpaceUsedBytes(OperationContext* opCtx)
return _newInterface->getSpaceUsedBytes(opCtx);
}
-pair<vector<BSONObj>, vector<BSONObj>> AbstractIndexAccessMethod::setDifference(
- const BSONObjSet& left, const BSONObjSet& right) {
+pair<vector<KeyString::Value>, vector<KeyString::Value>> AbstractIndexAccessMethod::setDifference(
+ const KeyStringSet& left, const KeyStringSet& right, Ordering ordering) {
// Two iterators to traverse the two sets in sorted order.
auto leftIt = left.begin();
auto rightIt = right.begin();
- vector<BSONObj> onlyLeft;
- vector<BSONObj> onlyRight;
+ vector<KeyString::Value> onlyLeft;
+ vector<KeyString::Value> onlyRight;
while (leftIt != left.end() && rightIt != right.end()) {
- const int cmp = leftIt->woCompare(*rightIt);
+ const int cmp = leftIt->compare(*rightIt);
if (cmp == 0) {
- // 'leftIt' and 'rightIt' compare equal using woCompare(), but may not be identical,
- // which should result in an index change.
- if (!leftIt->binaryEqual(*rightIt)) {
+ /*
+ * 'leftIt' and 'rightIt' compare equal using compare(), but may not be identical, which
+ * should result in an index change.
+ */
+ auto leftKey = KeyString::toBson(
+ leftIt->getBuffer(), leftIt->getSize(), ordering, leftIt->getTypeBits());
+ auto rightKey = KeyString::toBson(
+ rightIt->getBuffer(), rightIt->getSize(), ordering, rightIt->getTypeBits());
+ if (!leftKey.binaryEqual(rightKey)) {
onlyLeft.push_back(*leftIt);
onlyRight.push_back(*rightIt);
}
@@ -371,7 +388,7 @@ void AbstractIndexAccessMethod::prepareUpdate(OperationContext* opCtx,
// There's no need to compute the prefixes of the indexed fields that possibly caused the
// index to be multikey when the old version of the document was written since the index
// metadata isn't updated when keys are deleted.
- getKeys(from, getKeysMode, &ticket->oldKeys, nullptr, nullptr);
+ getKeys(from, getKeysMode, &ticket->oldKeys, nullptr, nullptr, record);
}
if (!indexFilter || indexFilter->matchesBSON(to)) {
@@ -379,13 +396,15 @@ void AbstractIndexAccessMethod::prepareUpdate(OperationContext* opCtx,
options.getKeysMode,
&ticket->newKeys,
&ticket->newMultikeyMetadataKeys,
- &ticket->newMultikeyPaths);
+ &ticket->newMultikeyPaths,
+ record);
}
ticket->loc = record;
ticket->dupsAllowed = options.dupsAllowed;
- std::tie(ticket->removed, ticket->added) = setDifference(ticket->oldKeys, ticket->newKeys);
+ std::tie(ticket->removed, ticket->added) =
+ setDifference(ticket->oldKeys, ticket->newKeys, getSortedDataInterface()->getOrdering());
ticket->_isValid = true;
}
@@ -417,9 +436,9 @@ Status AbstractIndexAccessMethod::update(OperationContext* opCtx,
const auto newMultikeyMetadataKeys = asVector(ticket.newMultikeyMetadataKeys);
for (const auto keySet : {&ticket.added, &newMultikeyMetadataKeys}) {
const auto& recordId = (keySet == &ticket.added ? ticket.loc : kMultikeyMetadataKeyId);
- for (const auto& key : *keySet) {
- Status status = _newInterface->insert(opCtx, key, recordId, ticket.dupsAllowed);
- if (isFatalError(opCtx, status, key)) {
+ for (const auto& keyString : *keySet) {
+ Status status = _newInterface->insert(opCtx, keyString, recordId, ticket.dupsAllowed);
+ if (isFatalError(opCtx, status, keyString)) {
return status;
}
}
@@ -480,7 +499,7 @@ private:
// Caches the set of all multikey metadata keys generated during the bulk build process.
// These are inserted into the sorter after all normal data keys have been added, just
// before the bulk build is committed.
- BSONObjSet _multikeyMetadataKeys{SimpleBSONObjComparator::kInstance.makeBSONObjSet()};
+ KeyStringSet _multikeyMetadataKeys;
};
std::unique_ptr<IndexAccessMethod::BulkBuilder> AbstractIndexAccessMethod::initiateBulk(
@@ -503,11 +522,12 @@ Status AbstractIndexAccessMethod::BulkBuilderImpl::insert(OperationContext* opCt
const BSONObj& obj,
const RecordId& loc,
const InsertDeleteOptions& options) {
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
MultikeyPaths multikeyPaths;
try {
- _real->getKeys(obj, options.getKeysMode, &keys, &_multikeyMetadataKeys, &multikeyPaths);
+ _real->getKeys(
+ obj, options.getKeysMode, &keys, &_multikeyMetadataKeys, &multikeyPaths, loc);
} catch (...) {
return exceptionToStatus();
}
@@ -523,7 +543,11 @@ Status AbstractIndexAccessMethod::BulkBuilderImpl::insert(OperationContext* opCt
}
}
- for (const auto& key : keys) {
+ for (const auto& keyString : keys) {
+ auto key = KeyString::toBson(keyString.getBuffer(),
+ keyString.getSize(),
+ _real->getSortedDataInterface()->getOrdering(),
+ keyString.getTypeBits());
_sorter->add(key, loc);
++_keysInserted;
}
@@ -547,7 +571,11 @@ bool AbstractIndexAccessMethod::BulkBuilderImpl::isMultikey() const {
IndexAccessMethod::BulkBuilder::Sorter::Iterator*
AbstractIndexAccessMethod::BulkBuilderImpl::done() {
- for (const auto& key : _multikeyMetadataKeys) {
+ for (const auto& keyString : _multikeyMetadataKeys) {
+ auto key = KeyString::toBson(keyString.getBuffer(),
+ keyString.getSize(),
+ _real->getSortedDataInterface()->getOrdering(),
+ keyString.getTypeBits());
_sorter->add(key, kMultikeyMetadataKeyId);
++_keysInserted;
}
@@ -655,9 +683,10 @@ void AbstractIndexAccessMethod::setIndexIsMultikey(OperationContext* opCtx, Mult
void AbstractIndexAccessMethod::getKeys(const BSONObj& obj,
GetKeysMode mode,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
static stdx::unordered_set<int> whiteList{ErrorCodes::CannotBuildIndexKeys,
// Btree
ErrorCodes::CannotIndexParallelArrays,
@@ -682,7 +711,7 @@ void AbstractIndexAccessMethod::getKeys(const BSONObj& obj,
13026,
13027};
try {
- doGetKeys(obj, keys, multikeyMetadataKeys, multikeyPaths);
+ doGetKeys(obj, keys, multikeyMetadataKeys, multikeyPaths, id);
} catch (const AssertionException& ex) {
// Suppress all indexing errors when mode is kRelaxConstraints.
if (mode == GetKeysMode::kEnforceConstraints) {
@@ -712,8 +741,8 @@ void AbstractIndexAccessMethod::getKeys(const BSONObj& obj,
}
bool AbstractIndexAccessMethod::shouldMarkIndexAsMultikey(
- const vector<BSONObj>& keys,
- const vector<BSONObj>& multikeyMetadataKeys,
+ const vector<KeyString::Value>& keys,
+ const vector<KeyString::Value>& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths) const {
return (keys.size() > 1 || isMultikeyFromPaths(multikeyPaths));
}
diff --git a/src/mongo/db/index/index_access_method.h b/src/mongo/db/index/index_access_method.h
index 0014b11afe4..fa6cb4e0dcf 100644
--- a/src/mongo/db/index/index_access_method.h
+++ b/src/mongo/db/index/index_access_method.h
@@ -91,8 +91,8 @@ public:
InsertResult* result) = 0;
virtual Status insertKeys(OperationContext* opCtx,
- const std::vector<BSONObj>& keys,
- const std::vector<BSONObj>& multikeyMetadataKeys,
+ const std::vector<KeyString::Value>& keys,
+ const std::vector<KeyString::Value>& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths,
const RecordId& loc,
const InsertDeleteOptions& options,
@@ -103,7 +103,7 @@ public:
* 'numDeleted' will be set to the number of keys removed from the index for the provided keys.
*/
virtual Status removeKeys(OperationContext* opCtx,
- const std::vector<BSONObj>& keys,
+ const std::vector<KeyString::Value>& keys,
const RecordId& loc,
const InsertDeleteOptions& options,
int64_t* numDeleted) = 0;
@@ -307,17 +307,19 @@ public:
*/
virtual void getKeys(const BSONObj& obj,
GetKeysMode mode,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const = 0;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const = 0;
/**
* Given the set of keys, multikeyMetadataKeys and multikeyPaths generated by a particular
* document, return 'true' if the index should be marked as multikey and 'false' otherwise.
*/
- virtual bool shouldMarkIndexAsMultikey(const std::vector<BSONObj>& keys,
- const std::vector<BSONObj>& multikeyMetadataKeys,
- const MultikeyPaths& multikeyPaths) const = 0;
+ virtual bool shouldMarkIndexAsMultikey(
+ const std::vector<KeyString::Value>& keys,
+ const std::vector<KeyString::Value>& multikeyMetadataKeys,
+ const MultikeyPaths& multikeyPaths) const = 0;
/**
* Returns the intersection of 'fields' and the set of multikey metadata paths stored in the
@@ -380,20 +382,15 @@ public:
* prepareUpdate fills out the UpdateStatus and update actually applies it.
*/
struct UpdateTicket {
- UpdateTicket()
- : oldKeys(SimpleBSONObjComparator::kInstance.makeBSONObjSet()),
- newKeys(oldKeys),
- newMultikeyMetadataKeys(newKeys) {}
-
bool _isValid{false};
- BSONObjSet oldKeys;
- BSONObjSet newKeys;
+ KeyStringSet oldKeys;
+ KeyStringSet newKeys;
- BSONObjSet newMultikeyMetadataKeys;
+ KeyStringSet newMultikeyMetadataKeys;
- std::vector<BSONObj> removed;
- std::vector<BSONObj> added;
+ std::vector<KeyString::Value> removed;
+ std::vector<KeyString::Value> added;
RecordId loc;
bool dupsAllowed;
@@ -444,8 +441,8 @@ public:
* setDifference({BSON("a" << 0.0)}, {BSON("a" << 0LL)}) would result in the pair
* ( {BSON("a" << 0.0)}, {BSON("a" << 0LL)} ).
*/
- static std::pair<std::vector<BSONObj>, std::vector<BSONObj>> setDifference(
- const BSONObjSet& left, const BSONObjSet& right);
+ static std::pair<std::vector<KeyString::Value>, std::vector<KeyString::Value>> setDifference(
+ const KeyStringSet& left, const KeyStringSet& right, Ordering ordering);
AbstractIndexAccessMethod(IndexCatalogEntry* btreeState,
std::unique_ptr<SortedDataInterface> btree);
@@ -457,15 +454,15 @@ public:
InsertResult* result) final;
Status insertKeys(OperationContext* opCtx,
- const std::vector<BSONObj>& keys,
- const std::vector<BSONObj>& multikeyMetadataKeys,
+ const std::vector<KeyString::Value>& keys,
+ const std::vector<KeyString::Value>& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths,
const RecordId& loc,
const InsertDeleteOptions& options,
InsertResult* result) final;
Status removeKeys(OperationContext* opCtx,
- const std::vector<BSONObj>& keys,
+ const std::vector<KeyString::Value>& keys,
const RecordId& loc,
const InsertDeleteOptions& options,
int64_t* numDeleted) final;
@@ -519,12 +516,13 @@ public:
void getKeys(const BSONObj& obj,
GetKeysMode mode,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id = boost::none) const final;
- bool shouldMarkIndexAsMultikey(const std::vector<BSONObj>& keys,
- const std::vector<BSONObj>& multikeyMetadataKeys,
+ bool shouldMarkIndexAsMultikey(const std::vector<KeyString::Value>& keys,
+ const std::vector<KeyString::Value>& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths) const override;
SortedDataInterface* getSortedDataInterface() const override final;
@@ -545,9 +543,10 @@ protected:
* information that must be stored in a reserved keyspace within the index.
*/
virtual void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const = 0;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const = 0;
IndexCatalogEntry* const _btreeState; // owned by IndexCatalogEntry
const IndexDescriptor* const _descriptor;
@@ -561,7 +560,7 @@ private:
* in the event that a non-fatal 'ErrorCodes::DuplicateKeyValue' is encountered during a
* background index build.
*/
- bool isFatalError(OperationContext* opCtx, Status status, BSONObj key);
+ bool isFatalError(OperationContext* opCtx, Status status, KeyString::Value key);
/**
* Removes a single key from the index.
@@ -569,7 +568,7 @@ private:
* Used by remove() only.
*/
void removeOneKey(OperationContext* opCtx,
- const BSONObj& key,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed);
diff --git a/src/mongo/db/index/index_build_interceptor.cpp b/src/mongo/db/index/index_build_interceptor.cpp
index fc6f6067484..04b80266722 100644
--- a/src/mongo/db/index/index_build_interceptor.cpp
+++ b/src/mongo/db/index/index_build_interceptor.cpp
@@ -250,7 +250,13 @@ Status IndexBuildInterceptor::_applyWrite(OperationContext* opCtx,
const RecordId opRecordId = RecordId(operation["recordId"].Long());
const Op opType =
(strcmp(operation.getStringField("op"), "i") == 0) ? Op::kInsert : Op::kDelete;
- const BSONObjSet keySet = SimpleBSONObjComparator::kInstance.makeBSONObjSet({key});
+
+ KeyString::HeapBuilder keyString(
+ _indexCatalogEntry->accessMethod()->getSortedDataInterface()->getKeyStringVersion(),
+ key,
+ _indexCatalogEntry->ordering(),
+ opRecordId);
+ const KeyStringSet keySet{std::move(keyString.release())};
auto accessMethod = _indexCatalogEntry->accessMethod();
if (opType == Op::kInsert) {
@@ -360,8 +366,8 @@ boost::optional<MultikeyPaths> IndexBuildInterceptor::getMultikeyPaths() const {
}
Status IndexBuildInterceptor::sideWrite(OperationContext* opCtx,
- const std::vector<BSONObj>& keys,
- const BSONObjSet& multikeyMetadataKeys,
+ const std::vector<KeyString::Value>& keys,
+ const KeyStringSet& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths,
RecordId loc,
Op op,
@@ -391,12 +397,13 @@ Status IndexBuildInterceptor::sideWrite(OperationContext* opCtx,
}
std::vector<BSONObj> toInsert;
- for (const auto& key : keys) {
+ for (const auto& keyString : keys) {
// Documents inserted into this table must be consumed in insert-order.
// Additionally, these writes should be timestamped with the same timestamps that the
// other writes making up this operation are given. When index builds can cope with
// replication rollbacks, side table writes associated with a CUD operation should
// remain/rollback along with the corresponding oplog entry.
+ auto key = KeyString::toBson(keyString, _indexCatalogEntry->ordering());
toInsert.emplace_back(BSON("op" << (op == Op::kInsert ? "i" : "d") << "key" << key
<< "recordId" << loc.repr()));
}
@@ -405,7 +412,8 @@ Status IndexBuildInterceptor::sideWrite(OperationContext* opCtx,
// Wildcard indexes write multikey path information, typically part of the catalog
// document, to the index itself. Multikey information is never deleted, so we only need
// to add this data on the insert path.
- for (const auto& key : multikeyMetadataKeys) {
+ for (const auto& keyString : multikeyMetadataKeys) {
+ auto key = KeyString::toBson(keyString, _indexCatalogEntry->ordering());
toInsert.emplace_back(BSON("op"
<< "i"
<< "key" << key << "recordId"
diff --git a/src/mongo/db/index/index_build_interceptor.h b/src/mongo/db/index/index_build_interceptor.h
index f8afcd4f56a..a9b36131ed5 100644
--- a/src/mongo/db/index/index_build_interceptor.h
+++ b/src/mongo/db/index/index_build_interceptor.h
@@ -69,8 +69,8 @@ public:
* On success, `numKeysOut` if non-null will contain the number of keys added or removed.
*/
Status sideWrite(OperationContext* opCtx,
- const std::vector<BSONObj>& keys,
- const BSONObjSet& multikeyMetadataKeys,
+ const std::vector<KeyString::Value>& keys,
+ const KeyStringSet& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths,
RecordId loc,
Op op,
diff --git a/src/mongo/db/index/s2_access_method.cpp b/src/mongo/db/index/s2_access_method.cpp
index 6881641b23b..777415dc1a5 100644
--- a/src/mongo/db/index/s2_access_method.cpp
+++ b/src/mongo/db/index/s2_access_method.cpp
@@ -125,10 +125,18 @@ StatusWith<BSONObj> S2AccessMethod::fixSpec(const BSONObj& specObj) {
}
void S2AccessMethod::doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
- ExpressionKeysPrivate::getS2Keys(obj, _descriptor->keyPattern(), _params, keys, multikeyPaths);
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
+ ExpressionKeysPrivate::getS2Keys(obj,
+ _descriptor->keyPattern(),
+ _params,
+ keys,
+ multikeyPaths,
+ getSortedDataInterface()->getKeyStringVersion(),
+ getSortedDataInterface()->getOrdering(),
+ id);
}
} // namespace mongo
diff --git a/src/mongo/db/index/s2_access_method.h b/src/mongo/db/index/s2_access_method.h
index 4851f6fbc7d..e8ff0bd2cb1 100644
--- a/src/mongo/db/index/s2_access_method.h
+++ b/src/mongo/db/index/s2_access_method.h
@@ -65,9 +65,10 @@ private:
* be multikey as a result of inserting 'keys'.
*/
void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const final;
S2IndexingParams _params;
diff --git a/src/mongo/db/index/s2_key_generator_test.cpp b/src/mongo/db/index/s2_key_generator_test.cpp
index 93fc8ac545d..9e158f4cb87 100644
--- a/src/mongo/db/index/s2_key_generator_test.cpp
+++ b/src/mongo/db/index/s2_key_generator_test.cpp
@@ -49,11 +49,12 @@ using namespace mongo;
namespace {
-std::string dumpKeyset(const BSONObjSet& objs) {
+std::string dumpKeyset(const KeyStringSet& keyStrings) {
std::stringstream ss;
ss << "[ ";
- for (BSONObjSet::iterator i = objs.begin(); i != objs.end(); ++i) {
- ss << i->toString() << " ";
+ for (auto& keyString : keyStrings) {
+ auto key = KeyString::toBson(keyString, Ordering::make(BSONObj()));
+ ss << key.toString() << " ";
}
ss << "]";
@@ -76,17 +77,14 @@ std::string dumpMultikeyPaths(const MultikeyPaths& multikeyPaths) {
return ss.str();
}
-bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actualKeys) {
+bool assertKeysetsEqual(const KeyStringSet& expectedKeys, const KeyStringSet& actualKeys) {
if (expectedKeys.size() != actualKeys.size()) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
}
- if (!std::equal(expectedKeys.begin(),
- expectedKeys.end(),
- actualKeys.begin(),
- SimpleBSONObjComparator::kInstance.makeEqualTo())) {
+ if (!std::equal(expectedKeys.begin(), expectedKeys.end(), actualKeys.begin())) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
@@ -120,14 +118,21 @@ long long getCellID(int x, int y, bool multiPoint = false) {
const CollatorInterface* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
// There's no need to compute the prefixes of the indexed fields that cause the index to be
// multikey when computing the cell id of the geo field.
MultikeyPaths* multikeyPaths = nullptr;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &keys, multikeyPaths);
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &keys,
+ multikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
ASSERT_EQUALS(1U, keys.size());
- return (*keys.begin()).firstElement().Long();
+ auto key = KeyString::toBson(*keys.begin(), Ordering::make(BSONObj()));
+ return key.firstElement().Long();
}
TEST(S2KeyGeneratorTest, GetS2KeysFromSubobjectWithArrayOfGeoAndNonGeoSubobjects) {
@@ -141,16 +146,30 @@ TEST(S2KeyGeneratorTest, GetS2KeysFromSubobjectWithArrayOfGeoAndNonGeoSubobjects
CollatorInterfaceMock* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(
- genKeysFrom, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << 1 << "" << getCellID(0, 0)));
- expectedKeys.insert(BSON("" << 1 << "" << getCellID(3, 3)));
- expectedKeys.insert(BSON("" << 2 << "" << getCellID(0, 0)));
- expectedKeys.insert(BSON("" << 2 << "" << getCellID(3, 3)));
+ ExpressionKeysPrivate::getS2Keys(genKeysFrom,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ BSON("" << 1 << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ BSON("" << 1 << "" << getCellID(3, 3)),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ BSON("" << 2 << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(KeyString::Version::kLatestVersion,
+ BSON("" << 2 << "" << getCellID(3, 3)),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{
+ keyString1.release(), keyString2.release(), keyString3.release(), keyString4.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{{1U}, {1U}}, actualMultikeyPaths);
@@ -167,15 +186,26 @@ TEST(S2KeyGeneratorTest, GetS2KeysFromArrayOfNonGeoSubobjectsWithArrayValues) {
CollatorInterfaceMock* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(
- genKeysFrom, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << 1 << "" << getCellID(0, 0)));
- expectedKeys.insert(BSON("" << 2 << "" << getCellID(0, 0)));
- expectedKeys.insert(BSON("" << 3 << "" << getCellID(0, 0)));
+ ExpressionKeysPrivate::getS2Keys(genKeysFrom,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ BSON("" << 1 << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ BSON("" << 2 << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ BSON("" << 3 << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{{0U, 1U}, std::set<size_t>{}}, actualMultikeyPaths);
@@ -190,16 +220,27 @@ TEST(S2KeyGeneratorTest, GetS2KeysFromMultiPointInGeoField) {
CollatorInterfaceMock* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(
- genKeysFrom, keyPattern, params, &actualKeys, &actualMultikeyPaths);
+ ExpressionKeysPrivate::getS2Keys(genKeysFrom,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
const bool multiPoint = true;
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << 1 << "" << getCellID(0, 0, multiPoint)));
- expectedKeys.insert(BSON("" << 1 << "" << getCellID(1, 0, multiPoint)));
- expectedKeys.insert(BSON("" << 1 << "" << getCellID(1, 1, multiPoint)));
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ BSON("" << 1 << "" << getCellID(0, 0, multiPoint)),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ BSON("" << 1 << "" << getCellID(1, 0, multiPoint)),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ BSON("" << 1 << "" << getCellID(1, 1, multiPoint)),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release(), keyString3.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, {0U}}, actualMultikeyPaths);
@@ -213,13 +254,21 @@ TEST(S2KeyGeneratorTest, CollationAppliedToNonGeoStringFieldAfterGeoField) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "gnirts"));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "gnirts"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, std::set<size_t>{}},
@@ -234,14 +283,22 @@ TEST(S2KeyGeneratorTest, CollationAppliedToNonGeoStringFieldBeforeGeoField) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON(""
- << "gnirts"
- << "" << getCellID(0, 0)));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON(""
+ << "gnirts"
+ << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, std::set<size_t>{}},
@@ -256,15 +313,23 @@ TEST(S2KeyGeneratorTest, CollationAppliedToAllNonGeoStringFields) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON(""
- << "gnirts"
- << "" << getCellID(0, 0) << ""
- << "2gnirts"));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON(""
+ << "gnirts"
+ << "" << getCellID(0, 0) << ""
+ << "2gnirts"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(
@@ -280,13 +345,21 @@ TEST(S2KeyGeneratorTest, CollationAppliedToNonGeoStringFieldWithMultiplePathComp
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "gnirts"));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "gnirts"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, std::set<size_t>{}},
@@ -301,15 +374,25 @@ TEST(S2KeyGeneratorTest, CollationAppliedToStringsInArray) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "gnirts"));
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "2gnirts"));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "gnirts"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "2gnirts"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString1.release(), keyString2.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, {0U}}, actualMultikeyPaths);
@@ -324,27 +407,42 @@ TEST(S2KeyGeneratorTest, CollationAppliedToStringsInAllArrays) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "gnirts"
- << ""
- << "cba"));
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "gnirts"
- << ""
- << "fed"));
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "2gnirts"
- << ""
- << "cba"));
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "2gnirts"
- << ""
- << "fed"));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString1(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "gnirts"
+ << ""
+ << "cba"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString2(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "gnirts"
+ << ""
+ << "fed"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString3(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "2gnirts"
+ << ""
+ << "cba"),
+ Ordering::make(BSONObj()));
+ KeyString::HeapBuilder keyString4(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "2gnirts"
+ << ""
+ << "fed"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{
+ keyString1.release(), keyString2.release(), keyString3.release(), keyString4.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, {0U}, {0U}}, actualMultikeyPaths);
@@ -358,12 +456,20 @@ TEST(S2KeyGeneratorTest, CollationDoesNotAffectNonStringFields) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << "" << 5));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << "" << 5),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, std::set<size_t>{}},
@@ -378,14 +484,22 @@ TEST(S2KeyGeneratorTest, CollationAppliedToStringsInNestedObjects) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
ExpressionParams::initialize2dsphereParams(infoObj, &collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << BSON("c"
- << "gnirts")));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << BSON("c"
+ << "gnirts")),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, std::set<size_t>{}},
@@ -400,13 +514,21 @@ TEST(S2KeyGeneratorTest, NoCollation) {
const CollatorInterface* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << ""
- << "string"));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << ""
+ << "string"),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, std::set<size_t>{}},
@@ -421,12 +543,20 @@ TEST(S2KeyGeneratorTest, EmptyArrayForLeadingFieldIsConsideredMultikey) {
const CollatorInterface* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << BSONUndefined << "" << getCellID(0, 0)));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << BSONUndefined << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{{0U}, std::set<size_t>{}}, actualMultikeyPaths);
@@ -440,12 +570,20 @@ TEST(S2KeyGeneratorTest, EmptyArrayForTrailingFieldIsConsideredMultikey) {
const CollatorInterface* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << getCellID(0, 0) << "" << BSONUndefined));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << getCellID(0, 0) << "" << BSONUndefined),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{std::set<size_t>{}, {0U}}, actualMultikeyPaths);
@@ -459,12 +597,20 @@ TEST(S2KeyGeneratorTest, SingleElementTrailingArrayIsConsideredMultikey) {
const CollatorInterface* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << 99 << "" << getCellID(0, 0)));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << 99 << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{{1U}, std::set<size_t>{}}, actualMultikeyPaths);
@@ -478,12 +624,20 @@ TEST(S2KeyGeneratorTest, MidPathSingleElementArrayIsConsideredMultikey) {
const CollatorInterface* collator = nullptr;
ExpressionParams::initialize2dsphereParams(infoObj, collator, &params);
- BSONObjSet actualKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet actualKeys;
MultikeyPaths actualMultikeyPaths;
- ExpressionKeysPrivate::getS2Keys(obj, keyPattern, params, &actualKeys, &actualMultikeyPaths);
-
- BSONObjSet expectedKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- expectedKeys.insert(BSON("" << 99 << "" << getCellID(0, 0)));
+ ExpressionKeysPrivate::getS2Keys(obj,
+ keyPattern,
+ params,
+ &actualKeys,
+ &actualMultikeyPaths,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj()));
+
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion,
+ BSON("" << 99 << "" << getCellID(0, 0)),
+ Ordering::make(BSONObj()));
+ KeyStringSet expectedKeys{keyString.release()};
assertKeysetsEqual(expectedKeys, actualKeys);
assertMultikeyPathsEqual(MultikeyPaths{{0U}, std::set<size_t>{}}, actualMultikeyPaths);
diff --git a/src/mongo/db/index/sort_key_generator.cpp b/src/mongo/db/index/sort_key_generator.cpp
index 82122a65448..d47308c5e62 100644
--- a/src/mongo/db/index/sort_key_generator.cpp
+++ b/src/mongo/db/index/sort_key_generator.cpp
@@ -68,7 +68,12 @@ SortKeyGenerator::SortKeyGenerator(SortPattern sortPattern, const CollatorInterf
}
constexpr bool isSparse = false;
- _indexKeyGen = std::make_unique<BtreeKeyGenerator>(fieldNames, fixed, isSparse, _collator);
+ _indexKeyGen = std::make_unique<BtreeKeyGenerator>(fieldNames,
+ fixed,
+ isSparse,
+ _collator,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(_sortSpecWithoutMeta));
}
StatusWith<BSONObj> SortKeyGenerator::getSortKey(const WorkingSetMember& wsm) const {
@@ -162,10 +167,7 @@ StatusWith<BSONObj> SortKeyGenerator::getSortKeyFromDocumentWithoutMetadata(
// The keys themselves will incorporate the collation, with strings translated to their
// corresponding collation keys. Therefore, we use the simple string comparator when comparing
// the keys themselves.
- const StringData::ComparatorInterface* stringComparator = nullptr;
- BSONObjComparator patternCmp(
- _sortSpecWithoutMeta, BSONObjComparator::FieldNamesMode::kConsider, stringComparator);
- BSONObjSet keys = patternCmp.makeBSONObjSet();
+ KeyStringSet keys;
try {
// There's no need to compute the prefixes of the indexed fields that cause the index to be
@@ -187,7 +189,7 @@ StatusWith<BSONObj> SortKeyGenerator::getSortKeyFromDocumentWithoutMetadata(
invariant(!keys.empty());
// The sort key is the first index key, ordered according to the pattern '_sortSpecWithoutMeta'.
- return *keys.begin();
+ return KeyString::toBson(*keys.begin(), Ordering::make(_sortSpecWithoutMeta));
}
} // namespace mongo
diff --git a/src/mongo/db/index/wildcard_access_method.cpp b/src/mongo/db/index/wildcard_access_method.cpp
index 4269d3dcab2..8a6a5564e0a 100644
--- a/src/mongo/db/index/wildcard_access_method.cpp
+++ b/src/mongo/db/index/wildcard_access_method.cpp
@@ -40,21 +40,25 @@ namespace mongo {
WildcardAccessMethod::WildcardAccessMethod(IndexCatalogEntry* wildcardState,
std::unique_ptr<SortedDataInterface> btree)
: AbstractIndexAccessMethod(wildcardState, std::move(btree)),
- _keyGen(
- _descriptor->keyPattern(), _descriptor->pathProjection(), _btreeState->getCollator()) {}
+ _keyGen(_descriptor->keyPattern(),
+ _descriptor->pathProjection(),
+ _btreeState->getCollator(),
+ getSortedDataInterface()->getKeyStringVersion(),
+ getSortedDataInterface()->getOrdering()) {}
bool WildcardAccessMethod::shouldMarkIndexAsMultikey(
- const std::vector<BSONObj>& keys,
- const std::vector<BSONObj>& multikeyMetadataKeys,
+ const std::vector<KeyString::Value>& keys,
+ const std::vector<KeyString::Value>& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths) const {
return !multikeyMetadataKeys.empty();
}
void WildcardAccessMethod::doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const {
- _keyGen.generateKeys(obj, keys, multikeyMetadataKeys);
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const {
+ _keyGen.generateKeys(obj, keys, multikeyMetadataKeys, id);
}
FieldRef WildcardAccessMethod::extractMultikeyPathFromIndexKey(const IndexKeyEntry& entry) {
diff --git a/src/mongo/db/index/wildcard_access_method.h b/src/mongo/db/index/wildcard_access_method.h
index 7fde78eb256..3390261a0f8 100644
--- a/src/mongo/db/index/wildcard_access_method.h
+++ b/src/mongo/db/index/wildcard_access_method.h
@@ -66,8 +66,8 @@ public:
* more multikey metadata keys have been generated; that is, if the 'multikeyMetadataKeys'
* vector is non-empty.
*/
- bool shouldMarkIndexAsMultikey(const std::vector<BSONObj>& keys,
- const std::vector<BSONObj>& multikeyMetadataKeys,
+ bool shouldMarkIndexAsMultikey(const std::vector<KeyString::Value>& keys,
+ const std::vector<KeyString::Value>& multikeyMetadataKeys,
const MultikeyPaths& multikeyPaths) const final;
/**
@@ -94,9 +94,10 @@ public:
private:
void doGetKeys(const BSONObj& obj,
- BSONObjSet* keys,
- BSONObjSet* multikeyMetadataKeys,
- MultikeyPaths* multikeyPaths) const final;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyMetadataKeys,
+ MultikeyPaths* multikeyPaths,
+ boost::optional<RecordId> id) const final;
std::set<FieldRef> _getMultikeyPathSet(OperationContext* opCtx,
const IndexBounds& indexBounds,
diff --git a/src/mongo/db/index/wildcard_key_generator.cpp b/src/mongo/db/index/wildcard_key_generator.cpp
index f8a6ff57da4..6056c41d278 100644
--- a/src/mongo/db/index/wildcard_key_generator.cpp
+++ b/src/mongo/db/index/wildcard_key_generator.cpp
@@ -93,23 +93,31 @@ std::unique_ptr<ProjectionExecAgg> WildcardKeyGenerator::createProjectionExec(
WildcardKeyGenerator::WildcardKeyGenerator(BSONObj keyPattern,
BSONObj pathProjection,
- const CollatorInterface* collator)
- : _collator(collator), _keyPattern(keyPattern) {
+ const CollatorInterface* collator,
+ KeyString::Version keyStringVersion,
+ Ordering ordering)
+ : _collator(collator),
+ _keyPattern(keyPattern),
+ _keyStringVersion(keyStringVersion),
+ _ordering(ordering) {
_projExec = createProjectionExec(keyPattern, pathProjection);
}
void WildcardKeyGenerator::generateKeys(BSONObj inputDoc,
- BSONObjSet* keys,
- BSONObjSet* multikeyPaths) const {
+ KeyStringSet* keys,
+ KeyStringSet* multikeyPaths,
+ boost::optional<RecordId> id) const {
FieldRef rootPath;
- _traverseWildcard(_projExec->applyProjection(inputDoc), false, &rootPath, keys, multikeyPaths);
+ _traverseWildcard(
+ _projExec->applyProjection(inputDoc), false, &rootPath, keys, multikeyPaths, id);
}
void WildcardKeyGenerator::_traverseWildcard(BSONObj obj,
bool objIsArray,
FieldRef* path,
- BSONObjSet* keys,
- BSONObjSet* multikeyPaths) const {
+ KeyStringSet* keys,
+ KeyStringSet* multikeyPaths,
+ boost::optional<RecordId> id) const {
for (const auto elem : obj) {
// If the element's fieldName contains a ".", fast-path skip it because it's not queryable.
if (elem.fieldNameStringData().find('.', 0) != std::string::npos)
@@ -121,22 +129,22 @@ void WildcardKeyGenerator::_traverseWildcard(BSONObj obj,
switch (elem.type()) {
case BSONType::Array:
// If this is a nested array, we don't descend it but instead index it as a value.
- if (_addKeyForNestedArray(elem, *path, objIsArray, keys))
+ if (_addKeyForNestedArray(elem, *path, objIsArray, keys, id))
break;
// Add an entry for the multi-key path, and then fall through to BSONType::Object.
_addMultiKey(*path, multikeyPaths);
case BSONType::Object:
- if (_addKeyForEmptyLeaf(elem, *path, keys))
+ if (_addKeyForEmptyLeaf(elem, *path, keys, id))
break;
_traverseWildcard(
- elem.Obj(), elem.type() == BSONType::Array, path, keys, multikeyPaths);
+ elem.Obj(), elem.type() == BSONType::Array, path, keys, multikeyPaths, id);
break;
default:
- _addKey(elem, *path, keys);
+ _addKey(elem, *path, keys, id);
}
// Remove the element's fieldname from the path, if it was pushed onto it earlier.
@@ -147,10 +155,11 @@ void WildcardKeyGenerator::_traverseWildcard(BSONObj obj,
bool WildcardKeyGenerator::_addKeyForNestedArray(BSONElement elem,
const FieldRef& fullPath,
bool enclosingObjIsArray,
- BSONObjSet* keys) const {
+ KeyStringSet* keys,
+ boost::optional<RecordId> id) const {
// If this element is an array whose parent is also an array, index it as a value.
if (enclosingObjIsArray && elem.type() == BSONType::Array) {
- _addKey(elem, fullPath, keys);
+ _addKey(elem, fullPath, keys, id);
return true;
}
return false;
@@ -158,12 +167,13 @@ bool WildcardKeyGenerator::_addKeyForNestedArray(BSONElement elem,
bool WildcardKeyGenerator::_addKeyForEmptyLeaf(BSONElement elem,
const FieldRef& fullPath,
- BSONObjSet* keys) const {
+ KeyStringSet* keys,
+ boost::optional<RecordId> id) const {
invariant(elem.isABSONObj());
if (elem.embeddedObject().isEmpty()) {
// In keeping with the behaviour of regular indexes, an empty object is indexed as-is while
// empty arrays are indexed as 'undefined'.
- _addKey(elem.type() == BSONType::Array ? BSONElement{} : elem, fullPath, keys);
+ _addKey(elem.type() == BSONType::Array ? BSONElement{} : elem, fullPath, keys, id);
return true;
}
return false;
@@ -171,7 +181,8 @@ bool WildcardKeyGenerator::_addKeyForEmptyLeaf(BSONElement elem,
void WildcardKeyGenerator::_addKey(BSONElement elem,
const FieldRef& fullPath,
- BSONObjSet* keys) const {
+ KeyStringSet* keys,
+ boost::optional<RecordId> id) const {
// Wildcard keys are of the form { "": "path.to.field", "": <collation-aware value> }.
BSONObjBuilder bob;
bob.append("", fullPath.dottedField());
@@ -180,15 +191,26 @@ void WildcardKeyGenerator::_addKey(BSONElement elem,
} else {
bob.appendUndefined("");
}
- keys->insert(bob.obj());
+ KeyString::HeapBuilder keyString(_keyStringVersion, bob.obj(), _ordering);
+ if (id) {
+ keyString.appendRecordId(*id);
+ }
+ keys->insert(keyString.release());
}
-void WildcardKeyGenerator::_addMultiKey(const FieldRef& fullPath, BSONObjSet* multikeyPaths) const {
+void WildcardKeyGenerator::_addMultiKey(const FieldRef& fullPath,
+ KeyStringSet* multikeyPaths) const {
// Multikey paths are denoted by a key of the form { "": 1, "": "path.to.array" }. The argument
// 'multikeyPaths' may be nullptr if the access method is being used in an operation which does
// not require multikey path generation.
if (multikeyPaths) {
- multikeyPaths->insert(BSON("" << 1 << "" << fullPath.dottedField()));
+ auto key = BSON("" << 1 << "" << fullPath.dottedField());
+ KeyString::HeapBuilder keyString(
+ _keyStringVersion,
+ key,
+ _ordering,
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
+ multikeyPaths->insert(keyString.release());
}
}
diff --git a/src/mongo/db/index/wildcard_key_generator.h b/src/mongo/db/index/wildcard_key_generator.h
index ea76bd1a0af..f5c8524c751 100644
--- a/src/mongo/db/index/wildcard_key_generator.h
+++ b/src/mongo/db/index/wildcard_key_generator.h
@@ -32,6 +32,8 @@
#include "mongo/db/exec/projection_exec_agg.h"
#include "mongo/db/field_ref.h"
#include "mongo/db/query/collation/collator_interface.h"
+#include "mongo/db/storage/key_string.h"
+#include "mongo/db/storage/sorted_data_interface.h"
namespace mongo {
@@ -54,7 +56,9 @@ public:
WildcardKeyGenerator(BSONObj keyPattern,
BSONObj pathProjection,
- const CollatorInterface* collator);
+ const CollatorInterface* collator,
+ KeyString::Version keyStringVersion,
+ Ordering ordering);
/**
* Returns a pointer to the key generator's underlying ProjectionExecAgg.
@@ -65,35 +69,48 @@ public:
/**
* Applies the appropriate Wildcard projection to the input doc, and then adds one key-value
- * pair to the BSONObjSet 'keys' for each leaf node in the post-projection document:
+ * pair to the set 'keys' for each leaf node in the post-projection document:
* { '': 'path.to.field', '': <collation-aware-field-value> }
* Also adds one entry to 'multikeyPaths' for each array encountered in the post-projection
* document, in the following format:
* { '': 1, '': 'path.to.array' }
*/
- void generateKeys(BSONObj inputDoc, BSONObjSet* keys, BSONObjSet* multikeyPaths) const;
+ void generateKeys(BSONObj inputDoc,
+ KeyStringSet* keys,
+ KeyStringSet* multikeyPaths,
+ boost::optional<RecordId> id = boost::none) const;
private:
// Traverses every path of the post-projection document, adding keys to the set as it goes.
void _traverseWildcard(BSONObj obj,
bool objIsArray,
FieldRef* path,
- BSONObjSet* keys,
- BSONObjSet* multikeyPaths) const;
+ KeyStringSet* keys,
+ KeyStringSet* multikeyPaths,
+ boost::optional<RecordId> id) const;
// Helper functions to format the entry appropriately before adding it to the key/path tracker.
- void _addMultiKey(const FieldRef& fullPath, BSONObjSet* multikeyPaths) const;
- void _addKey(BSONElement elem, const FieldRef& fullPath, BSONObjSet* keys) const;
+ void _addMultiKey(const FieldRef& fullPath, KeyStringSet* multikeyPaths) const;
+ void _addKey(BSONElement elem,
+ const FieldRef& fullPath,
+ KeyStringSet* keys,
+ boost::optional<RecordId> id) const;
// Helper to check whether the element is a nested array, and conditionally add it to 'keys'.
bool _addKeyForNestedArray(BSONElement elem,
const FieldRef& fullPath,
bool enclosingObjIsArray,
- BSONObjSet* keys) const;
- bool _addKeyForEmptyLeaf(BSONElement elem, const FieldRef& fullPath, BSONObjSet* keys) const;
+ KeyStringSet* keys,
+ boost::optional<RecordId> id) const;
+ bool _addKeyForEmptyLeaf(BSONElement elem,
+ const FieldRef& fullPath,
+ KeyStringSet* keys,
+ boost::optional<RecordId> id) const;
std::unique_ptr<ProjectionExecAgg> _projExec;
const CollatorInterface* _collator;
const BSONObj _keyPattern;
+ const KeyString::Version _keyStringVersion;
+ const Ordering _ordering;
};
} // namespace mongo
diff --git a/src/mongo/db/index/wildcard_key_generator_test.cpp b/src/mongo/db/index/wildcard_key_generator_test.cpp
index aeb0383c7ee..4d5d7f9f3c1 100644
--- a/src/mongo/db/index/wildcard_key_generator_test.cpp
+++ b/src/mongo/db/index/wildcard_key_generator_test.cpp
@@ -40,32 +40,39 @@
namespace mongo {
namespace {
-BSONObjSet makeKeySet(std::initializer_list<BSONObj> init = {}) {
- return SimpleBSONObjComparator::kInstance.makeBSONObjSet(std::move(init));
+KeyStringSet makeKeySet(std::initializer_list<BSONObj> init = {}, RecordId id = RecordId()) {
+ KeyStringSet keys;
+ Ordering ordering = Ordering::make(BSONObj());
+ for (const auto& key : init) {
+ KeyString::HeapBuilder keyString(KeyString::Version::kLatestVersion, key, ordering);
+ if (!id.isNull()) {
+ keyString.appendRecordId(id);
+ }
+ keys.insert(keyString.release());
+ }
+ return keys;
}
-std::string dumpKeyset(const BSONObjSet& objs) {
+std::string dumpKeyset(const KeyStringSet& keyStrings) {
std::stringstream ss;
ss << "[ ";
- for (BSONObjSet::iterator i = objs.begin(); i != objs.end(); ++i) {
- ss << i->toString() << " ";
+ for (auto& keyString : keyStrings) {
+ auto key = KeyString::toBson(keyString, Ordering::make(BSONObj()));
+ ss << key.toString() << " ";
}
ss << "]";
return ss.str();
}
-bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actualKeys) {
+bool assertKeysetsEqual(const KeyStringSet& expectedKeys, const KeyStringSet& actualKeys) {
if (expectedKeys.size() != actualKeys.size()) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
}
- if (!std::equal(expectedKeys.begin(),
- expectedKeys.end(),
- actualKeys.begin(),
- SimpleBSONObjComparator::kInstance.makeEqualTo())) {
+ if (!std::equal(expectedKeys.begin(), expectedKeys.end(), actualKeys.begin())) {
log() << "Expected: " << dumpKeyset(expectedKeys) << ", "
<< "Actual: " << dumpKeyset(actualKeys);
return false;
@@ -77,7 +84,11 @@ bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actual
// Full-document tests with no projection.
TEST(WildcardKeyGeneratorFullDocumentTest, ExtractTopLevelKey) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{a: 1}");
auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}")});
@@ -92,7 +103,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractTopLevelKey) {
}
TEST(WildcardKeyGeneratorFullDocumentTest, ExtractKeysFromNestedObject) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{a: {b: 'one', c: 2}}");
auto expectedKeys =
@@ -100,8 +115,8 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractKeysFromNestedObject) {
auto expectedMultikeyPaths = makeKeySet();
- auto outputKeys = makeKeySet();
- auto multikeyMetadataKeys = makeKeySet();
+ KeyStringSet outputKeys;
+ KeyStringSet multikeyMetadataKeys;
keyGen.generateKeys(inputDoc, &outputKeys, &multikeyMetadataKeys);
ASSERT(assertKeysetsEqual(expectedKeys, outputKeys));
@@ -109,7 +124,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractKeysFromNestedObject) {
}
TEST(WildcardKeyGeneratorFullDocumentTest, ShouldIndexEmptyObject) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{a: 1, b: {}}");
auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"), fromjson("{'': 'b', '': {}}")});
@@ -124,17 +143,23 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ShouldIndexEmptyObject) {
}
TEST(WildcardKeyGeneratorFullDocumentTest, ShouldIndexNonNestedEmptyArrayAsUndefined) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{ a: [], b: {c: []}, d: [[], {e: []}]}");
auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': undefined}"),
fromjson("{'': 'b.c', '': undefined}"),
fromjson("{'': 'd', '': []}"),
fromjson("{'': 'd.e', '': undefined}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'a'}"),
- fromjson("{'': 1, '': 'b.c'}"),
- fromjson("{'': 1, '': 'd'}"),
- fromjson("{'': 1, '': 'd.e'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'a'}"),
+ fromjson("{'': 1, '': 'b.c'}"),
+ fromjson("{'': 1, '': 'd'}"),
+ fromjson("{'': 1, '': 'd.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -145,7 +170,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ShouldIndexNonNestedEmptyArrayAsUndef
}
TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPath) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{a: [1, 2, {b: 'one', c: 2}, {d: 3}]}");
auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"),
@@ -154,7 +183,9 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPath) {
fromjson("{'': 'a.c', '': 2}"),
fromjson("{'': 'a.d', '': 3}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'a'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'a'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -165,7 +196,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPath) {
}
TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPathAndDedupKeys) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {d: 3}]}");
auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"),
@@ -174,7 +209,9 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPathAndDedupKeys) {
fromjson("{'': 'a.c', '': 2}"),
fromjson("{'': 'a.d', '': 3}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'a'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'a'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -185,7 +222,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPathAndDedupKeys) {
}
TEST(WildcardKeyGeneratorFullDocumentTest, ExtractZeroElementMultikeyPath) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {d: 3}], e: []}");
auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"),
@@ -196,7 +237,8 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractZeroElementMultikeyPath) {
fromjson("{'': 'e', '': undefined}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -207,7 +249,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractZeroElementMultikeyPath) {
}
TEST(WildcardKeyGeneratorFullDocumentTest, ExtractNestedMultikeyPaths) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
// Note: the 'e' array is nested within a subdocument in the enclosing 'a' array; it will
// generate a separate multikey entry 'a.e' and index keys for each of its elements. The raw
@@ -227,7 +273,8 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractNestedMultikeyPaths) {
fromjson("{'': 'a.e', '': 5}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -238,7 +285,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractNestedMultikeyPaths) {
}
TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMixedPathTypesAndAllSubpaths) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
// Tests a mix of multikey paths, various duplicate-key scenarios, and deeply-nested paths.
auto inputDoc = fromjson(
@@ -261,10 +312,12 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMixedPathTypesAndAllSubpaths)
fromjson("{'': 'g.h.k', '': 12.0}"),
fromjson("{'': 'l', '': 'string'}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'a'}"),
- fromjson("{'': 1, '': 'a.e'}"),
- fromjson("{'': 1, '': 'g.h.j'}"),
- fromjson("{'': 1, '': 'g.h.j.k'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'a'}"),
+ fromjson("{'': 1, '': 'a.e'}"),
+ fromjson("{'': 1, '': 'g.h.j'}"),
+ fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -277,7 +330,11 @@ TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMixedPathTypesAndAllSubpaths)
// Single-subtree implicit projection.
TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithSinglePathComponent) {
- WildcardKeyGenerator keyGen{fromjson("{'g.$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'g.$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -290,7 +347,8 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithSinglePathComponen
fromjson("{'': 'g.h.k', '': 12.0}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")});
+ makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -301,7 +359,11 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithSinglePathComponen
}
TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithMultiplePathComponents) {
- WildcardKeyGenerator keyGen{fromjson("{'g.h.$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'g.h.$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -314,7 +376,8 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithMultiplePathCompon
fromjson("{'': 'g.h.k', '': 12.0}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")});
+ makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -325,7 +388,11 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithMultiplePathCompon
}
TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractMultikeySubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'g.h.j.$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'g.h.j.$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -336,7 +403,8 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractMultikeySubtree) {
fromjson("{'': 'g.h.j.k', '': 11.5}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")});
+ makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -347,7 +415,11 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractMultikeySubtree) {
}
TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractNestedMultikeySubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'a.e.$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'a.e.$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -360,7 +432,8 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractNestedMultikeySubtree) {
fromjson("{'': 'a.e', '': 5}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -373,7 +446,11 @@ TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractNestedMultikeySubtree) {
// Explicit inclusion tests.
TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionSingleSubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{g: 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{g: 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -386,7 +463,8 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionSingleSubtree) {
fromjson("{'': 'g.h.k', '': 12.0}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")});
+ makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -397,7 +475,11 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionSingleSubtree) {
}
TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedSubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h': 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'g.h': 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -410,7 +492,8 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedSubtree) {
fromjson("{'': 'g.h.k', '': 12.0}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")});
+ makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -421,7 +504,11 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedSubtree) {
}
TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultikeySubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h.j': 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'g.h.j': 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -432,7 +519,8 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultikeySubtree) {
fromjson("{'': 'g.h.j.k', '': 11.5}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")});
+ makeKeySet({fromjson("{'': 1, '': 'g.h.j'}"), fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -443,7 +531,11 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultikeySubtree) {
}
TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedMultikeySubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'a.e': 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'a.e': 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -454,7 +546,8 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedMultikeySubtree
fromjson("{'': 'a.e', '': 5}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -465,8 +558,11 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedMultikeySubtree
}
TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultipleSubtrees) {
- WildcardKeyGenerator keyGen{
- fromjson("{'$**': 1}"), fromjson("{'a.b': 1, 'a.c': 1, 'a.e': 1, 'g.h.i': 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'a.b': 1, 'a.c': 1, 'a.e': 1, 'g.h.i': 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -480,7 +576,8 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultipleSubtrees) {
fromjson("{'': 'g.h.i', '': 9}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -493,7 +590,11 @@ TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultipleSubtrees) {
// Explicit exclusion tests.
TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionSingleSubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{g: 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{g: 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -511,7 +612,8 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionSingleSubtree) {
fromjson("{'': 'l', '': 'string'}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -522,7 +624,11 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionSingleSubtree) {
}
TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedSubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h': 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'g.h': 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -541,7 +647,8 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedSubtree) {
fromjson("{'': 'l', '': 'string'}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -552,7 +659,11 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedSubtree) {
}
TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultikeySubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h.j': 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'g.h.j': 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -572,7 +683,8 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultikeySubtree) {
fromjson("{'': 'l', '': 'string'}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -583,7 +695,11 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultikeySubtree) {
}
TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedMultikeySubtree) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'a.e': 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'a.e': 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -603,9 +719,11 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedMultikeySubtree
fromjson("{'': 'g.h.k', '': 12}"),
fromjson("{'': 'l', '': 'string'}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'a'}"),
- fromjson("{'': 1, '': 'g.h.j'}"),
- fromjson("{'': 1, '': 'g.h.j.k'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'a'}"),
+ fromjson("{'': 1, '': 'g.h.j'}"),
+ fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -616,8 +734,11 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedMultikeySubtree
}
TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultipleSubtrees) {
- WildcardKeyGenerator keyGen{
- fromjson("{'$**': 1}"), fromjson("{'a.b': 0, 'a.c': 0, 'a.e': 0, 'g.h.i': 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'a.b': 0, 'a.c': 0, 'a.e': 0, 'g.h.i': 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], "
@@ -634,9 +755,11 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultipleSubtrees) {
fromjson("{'': 'g.h.k', '': 12.0}"),
fromjson("{'': 'l', '': 'string'}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'a'}"),
- fromjson("{'': 1, '': 'g.h.j'}"),
- fromjson("{'': 1, '': 'g.h.j.k'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'a'}"),
+ fromjson("{'': 1, '': 'g.h.j'}"),
+ fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -649,7 +772,11 @@ TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultipleSubtrees) {
// Test _id inclusion and exclusion behaviour.
TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfProjectionIsEmpty) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -662,7 +789,8 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfProjectionIsEmpty) {
fromjson("{'': 'g.h.k', '': 12.0}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -673,7 +801,11 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfProjectionIsEmpty) {
}
TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldForSingleSubtreeKeyPattern) {
- WildcardKeyGenerator keyGen{fromjson("{'a.$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'a.$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -684,7 +816,8 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldForSingleSubtreeKeyPattern) {
fromjson("{'': 'a.e', '': 4}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -695,7 +828,11 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldForSingleSubtreeKeyPattern) {
}
TEST(WildcardKeyGeneratorIdTest, PermitIdFieldAsSingleSubtreeKeyPattern) {
- WildcardKeyGenerator keyGen{fromjson("{'_id.$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'_id.$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -714,7 +851,11 @@ TEST(WildcardKeyGeneratorIdTest, PermitIdFieldAsSingleSubtreeKeyPattern) {
}
TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldAsSingleSubtreeKeyPattern) {
- WildcardKeyGenerator keyGen{fromjson("{'_id.id1.$**': 1}"), {}, nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'_id.id1.$**': 1}"),
+ {},
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -732,7 +873,11 @@ TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldAsSingleSubtreeKeyPattern) {
}
TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldByDefaultForInclusionProjection) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{a: 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{a: 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -743,7 +888,8 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldByDefaultForInclusionProjection)
fromjson("{'': 'a.e', '': 4}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -754,7 +900,11 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldByDefaultForInclusionProjection)
}
TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldInclusionInExplicitProjection) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'_id.id1': 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'_id.id1': 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -772,7 +922,11 @@ TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldInclusionInExplicitProjection)
}
TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldByDefaultForExclusionProjection) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{a: 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{a: 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -791,7 +945,11 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldByDefaultForExclusionProjection)
}
TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldExclusionInExplicitProjection) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'_id.id1': 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{'_id.id1': 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -805,7 +963,8 @@ TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldExclusionInExplicitProjection)
fromjson("{'': 'g.h.k', '': 12.0}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -816,7 +975,11 @@ TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldExclusionInExplicitProjection)
}
TEST(WildcardKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInProjection) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 1, a: 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{_id: 1, a: 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -829,7 +992,8 @@ TEST(WildcardKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInProjection
fromjson("{'': 'a.e', '': 4}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -840,7 +1004,11 @@ TEST(WildcardKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInProjection
}
TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfExplicitlySpecifiedInProjection) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 0, a: 1}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{_id: 0, a: 1}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -851,7 +1019,8 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfExplicitlySpecifiedInProjection
fromjson("{'': 'a.e', '': 4}")});
auto expectedMultikeyPaths =
- makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")});
+ makeKeySet({fromjson("{'': 1, '': 'a'}"), fromjson("{'': 1, '': 'a.e'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -862,7 +1031,11 @@ TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfExplicitlySpecifiedInProjection
}
TEST(WildcardKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInExclusionProjection) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 1, a: 0}"), nullptr};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ fromjson("{_id: 1, a: 0}"),
+ nullptr,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}");
@@ -886,7 +1059,11 @@ TEST(WildcardKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInExclusionP
TEST(WildcardKeyGeneratorCollationTest, CollationMixedPathAndKeyTypes) {
CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, &collator};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ &collator,
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
// Verify that the collation is only applied to String values, but all types are indexed.
auto dateVal = "{'$date': 1529453450288}"_sd;
@@ -916,10 +1093,12 @@ TEST(WildcardKeyGeneratorCollationTest, CollationMixedPathAndKeyTypes) {
fromjson("{'': 'g.h.k', '': 12.0}"),
fromjson("{'': 'l', '': 'gnirts'}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'a'}"),
- fromjson("{'': 1, '': 'a.e'}"),
- fromjson("{'': 1, '': 'g.h.j'}"),
- fromjson("{'': 1, '': 'g.h.j.k'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'a'}"),
+ fromjson("{'': 1, '': 'a.e'}"),
+ fromjson("{'': 1, '': 'g.h.j'}"),
+ fromjson("{'': 1, '': 'g.h.j.k'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -930,7 +1109,11 @@ TEST(WildcardKeyGeneratorCollationTest, CollationMixedPathAndKeyTypes) {
}
TEST(WildcardKeyGeneratorDottedFieldsTest, DoNotIndexDottedFields) {
- WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, {}};
+ WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"),
+ {},
+ {},
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson(
"{'a.b': 0, '.b': 1, 'b.': 2, a: {'.b': 3, 'b.': 4, 'b.c': 5, 'q': 6}, b: [{'d.e': 7}, {r: "
@@ -941,7 +1124,9 @@ TEST(WildcardKeyGeneratorDottedFieldsTest, DoNotIndexDottedFields) {
fromjson("{'': 'b', '': [{'a.b': 9}]}"),
fromjson("{'': 'c', '': 10}")});
- auto expectedMultikeyPaths = makeKeySet({fromjson("{'': 1, '': 'b'}")});
+ auto expectedMultikeyPaths =
+ makeKeySet({fromjson("{'': 1, '': 'b'}")},
+ RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId});
auto outputKeys = makeKeySet();
auto multikeyMetadataKeys = makeKeySet();
@@ -952,7 +1137,11 @@ TEST(WildcardKeyGeneratorDottedFieldsTest, DoNotIndexDottedFields) {
}
TEST(WildcardKeyGeneratorDottedFieldsTest, DoNotIndexDottedFieldsWithSimilarSubpathInKey) {
- WildcardKeyGenerator keyGen{fromjson("{'a.b.$**': 1}"), {}, {}};
+ WildcardKeyGenerator keyGen{fromjson("{'a.b.$**': 1}"),
+ {},
+ {},
+ KeyString::Version::kLatestVersion,
+ Ordering::make(BSONObj())};
auto inputDoc = fromjson("{'a.b': 0}");
diff --git a/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp b/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp
index 15d604fe069..f6a5003edde 100644
--- a/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp
+++ b/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp
@@ -65,16 +65,6 @@ bool hasFieldNames(const BSONObj& obj) {
return false;
}
-// This just makes all the fields in a BSON object equal to "".
-BSONObj stripFieldNames(const BSONObj& obj) {
- BSONObjIterator it(obj);
- BSONObjBuilder bob;
- while (it.more()) {
- bob.appendAs(it.next(), "");
- }
- return bob.obj();
-}
-
// This function converts a key and an ordering to a KeyString::Builder.
std::unique_ptr<KeyString::Builder> keyToKeyStringBuilder(const BSONObj& key, Ordering order) {
KeyString::Version version = KeyString::Version::V1;
@@ -109,7 +99,7 @@ std::string createKeyString(const BSONObj& key,
return std::string(ks.getBuffer(), ks.getSize());
}
-std::string createKeyString(const KeyString::Builder& keyString,
+std::string createKeyString(const KeyString::Value& keyString,
const RecordId& loc,
std::string prefixToUse,
bool isUnique) {
@@ -210,13 +200,12 @@ Status SortedDataBuilderInterface::addKey(const BSONObj& key, const RecordId& lo
invariant(loc.isNormal() || loc.isReserved());
invariant(!hasFieldNames(key));
- KeyString::Builder keyString(KeyString::Version::V1, key, _order, loc);
+ KeyString::HeapBuilder keyString(KeyString::Version::V1, key, _order, loc);
- return addKey(keyString, loc);
+ return addKey(std::move(keyString.release()), loc);
}
-Status SortedDataBuilderInterface::addKey(const KeyString::Builder& keyString,
- const RecordId& loc) {
+Status SortedDataBuilderInterface::addKey(const KeyString::Value& keyString, const RecordId& loc) {
dassert(loc == KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
StringStore* workingCopy(RecoveryUnit::get(_opCtx)->getHead());
@@ -242,8 +231,7 @@ Status SortedDataBuilderInterface::addKey(const KeyString::Builder& keyString,
if (twoKeyCmp == 0 && twoRIDCmp != 0) {
if (!_dupsAllowed) {
- auto key = KeyString::toBson(
- keyString.getBuffer(), keyString.getSize(), _order, keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _order);
return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern);
}
// Duplicate index entries are allowed on this unique index, so we put the RecordId in the
@@ -324,13 +312,13 @@ Status SortedDataInterface::insert(OperationContext* opCtx,
const RecordId& loc,
bool dupsAllowed) {
// The KeyString representation of the key.
- KeyString::Builder keyString(_keyStringVersion, key, _ordering, loc);
+ KeyString::HeapBuilder keyString(_keyStringVersion, key, _ordering, loc);
- return insert(opCtx, keyString, loc, dupsAllowed);
+ return insert(opCtx, std::move(keyString.release()), loc, dupsAllowed);
}
Status SortedDataInterface::insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) {
dassert(loc == KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
@@ -360,10 +348,7 @@ Status SortedDataInterface::insert(OperationContext* opCtx,
} else {
// There was an attempt to create an index entry with a different RecordId while
// dups were not allowed.
- auto key = KeyString::toBson(keyString.getBuffer(),
- keyString.getSize(),
- _ordering,
- keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _ordering);
return buildDupKeyErrorStatus(
key, _collectionNamespace, _indexName, _keyPattern);
}
@@ -398,13 +383,13 @@ void SortedDataInterface::unindex(OperationContext* opCtx,
const BSONObj& key,
const RecordId& loc,
bool dupsAllowed) {
- KeyString::Builder keyString(_keyStringVersion, key, _ordering, loc);
+ KeyString::HeapBuilder keyString(_keyStringVersion, key, _ordering, loc);
- unindex(opCtx, keyString, loc, dupsAllowed);
+ unindex(opCtx, std::move(keyString.release()), loc, dupsAllowed);
}
void SortedDataInterface::unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) {
dassert(loc == KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
@@ -630,7 +615,7 @@ bool SortedDataInterface::Cursor::checkCursorValid() {
// RecordId in the KeyString and use a "<" comparison instead of "<=" since we know
// that no RecordId will ever reach RecordId::max() so we don't need to check the
// equal side of things. This assumption doesn't hold for unique index KeyStrings.
- BSONObj strippedBSON = stripFieldNames(*_endPosKey);
+ BSONObj strippedBSON = BSONObj::stripFieldNames(*_endPosKey);
std::string endPosKeyString =
createKeyString(strippedBSON, RecordId::max(), _prefix, _order, _isUnique);
@@ -653,7 +638,7 @@ bool SortedDataInterface::Cursor::checkCursorValid() {
if (*_endPosReverse == _workingCopy->rend())
return true;
- BSONObj strippedBSON = stripFieldNames(*_endPosKey);
+ BSONObj strippedBSON = BSONObj::stripFieldNames(*_endPosKey);
std::string endPosKeyString =
createKeyString(strippedBSON, RecordId::min(), _prefix, _order, _isUnique);
@@ -670,7 +655,7 @@ bool SortedDataInterface::Cursor::checkCursorValid() {
}
void SortedDataInterface::Cursor::setEndPosition(const BSONObj& key, bool inclusive) {
- auto finalKey = stripFieldNames(key);
+ auto finalKey = BSONObj::stripFieldNames(key);
StringStore* workingCopy(RecoveryUnit::get(_opCtx)->getHead());
if (finalKey.isEmpty()) {
_endPos = boost::none;
@@ -808,7 +793,7 @@ boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seekAfterProcessing(
boost::optional<IndexKeyEntry> SortedDataInterface::Cursor::seek(const BSONObj& key,
bool inclusive,
RequestedInfo parts) {
- BSONObj finalKey = stripFieldNames(key);
+ BSONObj finalKey = BSONObj::stripFieldNames(key);
_lastMoveWasRestore = false;
_atEOF = false;
diff --git a/src/mongo/db/storage/biggie/biggie_sorted_impl.h b/src/mongo/db/storage/biggie/biggie_sorted_impl.h
index 6c7e9aacb21..d5183bf530c 100644
--- a/src/mongo/db/storage/biggie/biggie_sorted_impl.h
+++ b/src/mongo/db/storage/biggie/biggie_sorted_impl.h
@@ -49,7 +49,7 @@ public:
const BSONObj& keyPattern);
void commit(bool mayInterrupt) override;
virtual Status addKey(const BSONObj& key, const RecordId& loc);
- virtual Status addKey(const KeyString::Builder& keyString, const RecordId& loc);
+ virtual Status addKey(const KeyString::Value& keyString, const RecordId& loc);
private:
OperationContext* _opCtx;
@@ -86,7 +86,7 @@ public:
const RecordId& loc,
bool dupsAllowed) override;
virtual Status insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) override;
virtual void unindex(OperationContext* opCtx,
@@ -94,7 +94,7 @@ public:
const RecordId& loc,
bool dupsAllowed) override;
virtual void unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) override;
virtual Status dupKeyCheck(OperationContext* opCtx, const BSONObj& key) override;
diff --git a/src/mongo/db/storage/devnull/devnull_kv_engine.cpp b/src/mongo/db/storage/devnull/devnull_kv_engine.cpp
index a661666c19d..b1ea7aeee94 100644
--- a/src/mongo/db/storage/devnull/devnull_kv_engine.cpp
+++ b/src/mongo/db/storage/devnull/devnull_kv_engine.cpp
@@ -173,7 +173,7 @@ public:
return Status::OK();
}
- virtual Status addKey(const KeyString::Builder& keyString, const RecordId& loc) {
+ virtual Status addKey(const KeyString::Value& keyString, const RecordId& loc) {
return Status::OK();
}
};
@@ -197,7 +197,7 @@ public:
}
virtual Status insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) {
return Status::OK();
@@ -209,7 +209,7 @@ public:
bool dupsAllowed) {}
virtual void unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) {}
diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp
index 3e9476642bd..73de310adf0 100644
--- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp
+++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp
@@ -48,26 +48,6 @@ using std::vector;
namespace {
-
-bool hasFieldNames(const BSONObj& obj) {
- BSONForEach(e, obj) {
- if (e.fieldName()[0])
- return true;
- }
- return false;
-}
-
-BSONObj stripFieldNames(const BSONObj& query) {
- if (!hasFieldNames(query))
- return query;
-
- BSONObjBuilder bb;
- BSONForEach(e, query) {
- bb.appendAs(e, StringData());
- }
- return bb.obj();
-}
-
typedef std::set<IndexKeyEntry, IndexEntryComparison> IndexSet;
bool keyExists(const IndexSet& data, const BSONObj& key) {
@@ -111,7 +91,7 @@ public:
// inserts should be in ascending (key, RecordId) order.
invariant(loc.isValid());
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
if (!_data->empty()) {
// Compare specified key with last inserted key, ignoring its RecordId
@@ -131,11 +111,10 @@ public:
return Status::OK();
}
- Status addKey(const KeyString::Builder& keyString, const RecordId& loc) {
+ Status addKey(const KeyString::Value& keyString, const RecordId& loc) {
dassert(loc == KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
- auto key = KeyString::toBson(
- keyString.getBuffer(), keyString.getSize(), _ordering, keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _ordering);
return addKey(key, loc);
}
@@ -186,7 +165,7 @@ public:
const RecordId& loc,
bool dupsAllowed) {
invariant(loc.isValid());
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
// TODO optimization: save the iterator from the dup-check to speed up insert
@@ -202,13 +181,12 @@ public:
}
virtual Status insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) {
dassert(loc == KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
- auto key = KeyString::toBson(
- keyString.getBuffer(), keyString.getSize(), _ordering, keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _ordering);
return insert(opCtx, key, loc, dupsAllowed);
}
@@ -218,7 +196,7 @@ public:
const RecordId& loc,
bool dupsAllowed) {
invariant(loc.isValid());
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
IndexKeyEntry entry(key.getOwned(), loc);
const size_t numDeleted = _data->erase(entry);
@@ -230,13 +208,12 @@ public:
}
virtual void unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) {
dassert(loc == KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
- auto key = KeyString::toBson(
- keyString.getBuffer(), keyString.getSize(), _ordering, keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _ordering);
return unindex(opCtx, key, loc, dupsAllowed);
}
@@ -259,7 +236,7 @@ public:
}
virtual Status dupKeyCheck(OperationContext* opCtx, const BSONObj& key) {
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
if (isDup(*_data, key))
return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern);
return Status::OK();
@@ -307,7 +284,7 @@ public:
// NOTE: this uses the opposite min/max rules as a normal seek because a forward
// scan should land after the key if inclusive and before if exclusive.
- _endState = EndState(stripFieldNames(key),
+ _endState = EndState(BSONObj::stripFieldNames(key),
_forward == inclusive ? RecordId::max() : RecordId::min());
seekEndCursor();
}
@@ -322,7 +299,7 @@ public:
return {};
}
} else {
- const BSONObj query = stripFieldNames(key);
+ const BSONObj query = BSONObj::stripFieldNames(key);
locate(query, _forward == inclusive ? RecordId::min() : RecordId::max());
_lastMoveWasRestore = false;
if (_isEOF)
diff --git a/src/mongo/db/storage/key_string.cpp b/src/mongo/db/storage/key_string.cpp
index a1f23adba73..de20dc242c6 100644
--- a/src/mongo/db/storage/key_string.cpp
+++ b/src/mongo/db/storage/key_string.cpp
@@ -2099,72 +2099,36 @@ std::string BuilderBase<BufferT>::toString() const {
return toHex(getBuffer(), getSize());
}
-template <class BufferT>
-int BuilderBase<BufferT>::compare(const BuilderBase<BufferT>& other) const {
- int a = getSize();
- int b = other.getSize();
-
- int min = std::min(a, b);
-
- int cmp = memcmp(getBuffer(), other.getBuffer(), min);
-
- if (cmp) {
- if (cmp < 0)
- return -1;
- return 1;
- }
-
- // keys match
-
- if (a == b)
- return 0;
-
- return a < b ? -1 : 1;
+std::string Value::toString() const {
+ return toHex(getBuffer(), getSize());
}
-template <class BufferT>
-int BuilderBase<BufferT>::compareWithoutRecordId(const BuilderBase<BufferT>& other) const {
- int a = !isEmpty() ? sizeWithoutRecordIdAtEnd(getBuffer(), getSize()) : 0;
- int b = !other.isEmpty() ? sizeWithoutRecordIdAtEnd(other.getBuffer(), other.getSize()) : 0;
-
- int min = std::min(a, b);
-
- int cmp = memcmp(getBuffer(), other.getBuffer(), min);
-
- if (cmp) {
- if (cmp < 0)
- return -1;
- return 1;
+TypeBits& TypeBits::operator=(const TypeBits& tb) {
+ if (&tb == this) {
+ return *this;
}
- // keys match
+ version = tb.version;
+ _curBit = tb._curBit;
+ _isAllZeros = tb._isAllZeros;
- if (a == b)
- return 0;
+ _buf.reset();
+ _buf.appendBuf(tb._buf.buf(), tb._buf.len());
- return a < b ? -1 : 1;
+ return *this;
}
-int Value::compare(const Value& other) const {
- int a = getSize();
- int b = other.getSize();
-
- int min = std::min(a, b);
-
- int cmp = memcmp(getBuffer(), other.getBuffer(), min);
-
- if (cmp) {
- if (cmp < 0)
- return -1;
- return 1;
+Value& Value::operator=(const Value& other) {
+ if (&other == this) {
+ return *this;
}
- // keys match
-
- if (a == b)
- return 0;
+ _version = other._version;
+ _typeBits = other._typeBits;
+ _size = other._size;
+ _buffer = other._buffer;
- return a < b ? -1 : 1;
+ return *this;
}
uint32_t TypeBits::readSizeFromBuffer(BufReader* reader) {
@@ -2417,6 +2381,25 @@ RecordId decodeRecordId(BufReader* reader) {
return RecordId(repr);
}
+int compare(const char* leftBuf, const char* rightBuf, size_t leftSize, size_t rightSize) {
+ int min = std::min(leftSize, rightSize);
+
+ int cmp = memcmp(leftBuf, rightBuf, min);
+
+ if (cmp) {
+ if (cmp < 0)
+ return -1;
+ return 1;
+ }
+
+ // keys match
+
+ if (leftSize == rightSize)
+ return 0;
+
+ return leftSize < rightSize ? -1 : 1;
+}
+
template class BuilderBase<BufBuilder>;
template class BuilderBase<StackBufBuilder>;
diff --git a/src/mongo/db/storage/key_string.h b/src/mongo/db/storage/key_string.h
index df992e1009d..2727162d15d 100644
--- a/src/mongo/db/storage/key_string.h
+++ b/src/mongo/db/storage/key_string.h
@@ -76,7 +76,7 @@ public:
_buf.appendBuf(tb._buf.buf(), tb._buf.len());
}
- TypeBits& operator=(const TypeBits& tb) = delete;
+ TypeBits& operator=(const TypeBits& tb);
TypeBits(TypeBits&&) = default;
TypeBits& operator=(TypeBits&&) = default;
@@ -293,12 +293,22 @@ public:
Value(Version version, TypeBits typeBits, size_t size, ConstSharedBuffer buffer)
: _version(version), _typeBits(typeBits), _size(size), _buffer(std::move(buffer)) {}
- int compare(const Value& other) const;
+ Value& operator=(const Value& other);
+
+ template <class T>
+ int compare(const T& other) const;
+
+ template <class T>
+ int compareWithoutRecordId(const T& other) const;
size_t getSize() const {
return _size;
}
+ bool isEmpty() const {
+ return _size == 0;
+ }
+
const char* getBuffer() const {
return _buffer.get();
}
@@ -307,37 +317,18 @@ public:
return _typeBits;
}
+ /**
+ * Returns a hex encoding of this key.
+ */
+ std::string toString() const;
+
private:
- const Version _version;
+ Version _version;
TypeBits _typeBits;
size_t _size;
ConstSharedBuffer _buffer;
};
-inline bool operator<(const Value& lhs, const Value& rhs) {
- return lhs.compare(rhs) < 0;
-}
-
-inline bool operator<=(const Value& lhs, const Value& rhs) {
- return lhs.compare(rhs) <= 0;
-}
-
-inline bool operator==(const Value& lhs, const Value& rhs) {
- return lhs.compare(rhs) == 0;
-}
-
-inline bool operator>(const Value& lhs, const Value& rhs) {
- return lhs.compare(rhs) > 0;
-}
-
-inline bool operator>=(const Value& lhs, const Value& rhs) {
- return lhs.compare(rhs) >= 0;
-}
-
-inline bool operator!=(const Value& lhs, const Value& rhs) {
- return !(lhs == rhs);
-}
-
enum class Discriminator {
kInclusive, // Anything to be stored in an index must use this.
kExclusiveBefore,
@@ -420,7 +411,7 @@ public:
_prepareForRelease();
invariant(_state == BuildState::kEndAdded || _state == BuildState::kAppendedRecordID ||
_state == BuildState::kAppendedTypeBits);
- BufBuilder newBuf;
+ BufBuilder newBuf(_buffer.len());
newBuf.appendBuf(_buffer.buf(), _buffer.len());
return {version, _typeBits, static_cast<size_t>(newBuf.len()), newBuf.release()};
}
@@ -478,8 +469,11 @@ public:
return _typeBits;
}
- int compare(const BuilderBase& other) const;
- int compareWithoutRecordId(const BuilderBase& other) const;
+ template <class T>
+ int compare(const T& other) const;
+
+ template <class T>
+ int compareWithoutRecordId(const T& other) const;
/**
* @return a hex encoding of this key
@@ -598,38 +592,58 @@ private:
using Builder = BuilderBase<StackBufBuilder>;
using HeapBuilder = BuilderBase<BufBuilder>;
+/*
+ * The isKeyString struct allows the operators below to only be enabled if the types being operated
+ * on are KeyStrings.
+ */
+template <class T>
+struct isKeyString : public std::false_type {};
+
template <class BufferT>
-inline bool operator<(const BuilderBase<BufferT>& lhs, const BuilderBase<BufferT>& rhs) {
+struct isKeyString<BuilderBase<BufferT>> : public std::true_type {};
+
+template <>
+struct isKeyString<Value> : public std::true_type {};
+
+template <class T>
+inline typename std::enable_if<isKeyString<T>::value, bool>::type operator<(const T& lhs,
+ const T& rhs) {
return lhs.compare(rhs) < 0;
}
-template <class BufferT>
-inline bool operator<=(const BuilderBase<BufferT>& lhs, const BuilderBase<BufferT>& rhs) {
+template <class T>
+inline typename std::enable_if<isKeyString<T>::value, bool>::type operator<=(const T& lhs,
+ const T& rhs) {
return lhs.compare(rhs) <= 0;
}
-template <class BufferT>
-inline bool operator==(const BuilderBase<BufferT>& lhs, const BuilderBase<BufferT>& rhs) {
+template <class T>
+inline typename std::enable_if<isKeyString<T>::value, bool>::type operator==(const T& lhs,
+ const T& rhs) {
return lhs.compare(rhs) == 0;
}
-template <class BufferT>
-inline bool operator>(const BuilderBase<BufferT>& lhs, const BuilderBase<BufferT>& rhs) {
+template <class T>
+inline typename std::enable_if<isKeyString<T>::value, bool>::type operator>(const T& lhs,
+ const T& rhs) {
return lhs.compare(rhs) > 0;
}
-template <class BufferT>
-inline bool operator>=(const BuilderBase<BufferT>& lhs, const BuilderBase<BufferT>& rhs) {
+template <class T>
+inline typename std::enable_if<isKeyString<T>::value, bool>::type operator>=(const T& lhs,
+ const T& rhs) {
return lhs.compare(rhs) >= 0;
}
-template <class BufferT>
-inline bool operator!=(const BuilderBase<BufferT>& lhs, const BuilderBase<BufferT>& rhs) {
+template <class T>
+inline typename std::enable_if<isKeyString<T>::value, bool>::type operator!=(const T& lhs,
+ const T& rhs) {
return !(lhs == rhs);
}
-template <class BufferT>
-inline std::ostream& operator<<(std::ostream& stream, const BuilderBase<BufferT>& value) {
+template <class T>
+inline typename std::enable_if<isKeyString<T>::value, std::ostream&>::type operator<<(
+ std::ostream& stream, const T& value) {
return stream << value.toString();
}
@@ -646,6 +660,11 @@ BSONObj toBson(StringData data, Ordering ord, const TypeBits& types);
BSONObj toBson(const char* buffer, size_t len, Ordering ord, const TypeBits& types) noexcept;
BSONObj toBsonSafe(const char* buffer, size_t len, Ordering ord, const TypeBits& types);
+template <class T>
+BSONObj toBson(const T& keyString, Ordering ord) noexcept {
+ return toBson(keyString.getBuffer(), keyString.getSize(), ord, keyString.getTypeBits());
+}
+
/**
* Decodes a RecordId from the end of a buffer.
*/
@@ -661,6 +680,40 @@ size_t sizeWithoutRecordIdAtEnd(const void* bufferRaw, size_t bufSize);
*/
RecordId decodeRecordId(BufReader* reader);
+int compare(const char* leftBuf, const char* rightBuf, size_t leftSize, size_t rightSize);
+
+template <class BufferT>
+template <class T>
+int BuilderBase<BufferT>::compare(const T& other) const {
+ return KeyString::compare(getBuffer(), other.getBuffer(), getSize(), other.getSize());
+}
+
+template <class BufferT>
+template <class T>
+int BuilderBase<BufferT>::compareWithoutRecordId(const T& other) const {
+ return KeyString::compare(
+ getBuffer(),
+ other.getBuffer(),
+ !isEmpty() ? sizeWithoutRecordIdAtEnd(getBuffer(), getSize()) : 0,
+ !other.isEmpty() ? sizeWithoutRecordIdAtEnd(other.getBuffer(), other.getSize()) : 0);
+}
+
+template <class T>
+int Value::compare(const T& other) const {
+ return KeyString::compare(getBuffer(), other.getBuffer(), getSize(), other.getSize());
+}
+
+template <class T>
+int Value::compareWithoutRecordId(const T& other) const {
+ return KeyString::compare(
+ getBuffer(),
+ other.getBuffer(),
+ !isEmpty() ? sizeWithoutRecordIdAtEnd(getBuffer(), getSize()) : 0,
+ !other.isEmpty() ? sizeWithoutRecordIdAtEnd(other.getBuffer(), other.getSize()) : 0);
+}
+
} // namespace KeyString
+using KeyStringSet = std::set<KeyString::Value>;
+
} // namespace mongo
diff --git a/src/mongo/db/storage/mobile/mobile_index.cpp b/src/mongo/db/storage/mobile/mobile_index.cpp
index d5e794c6507..96dd6b690e0 100644
--- a/src/mongo/db/storage/mobile/mobile_index.cpp
+++ b/src/mongo/db/storage/mobile/mobile_index.cpp
@@ -46,28 +46,6 @@ namespace {
using std::shared_ptr;
using std::string;
using std::vector;
-
-// BTree stuff
-
-bool hasFieldNames(const BSONObj& obj) {
- BSONForEach(e, obj) {
- if (e.fieldName()[0])
- return true;
- }
- return false;
-}
-
-BSONObj stripFieldNames(const BSONObj& query) {
- if (!hasFieldNames(query))
- return query;
-
- BSONObjBuilder bb;
- BSONForEach(e, query) {
- bb.appendAs(e, StringData());
- }
- return bb.obj();
-}
-
} // namespace
MobileIndex::MobileIndex(OperationContext* opCtx,
@@ -86,15 +64,15 @@ Status MobileIndex::insert(OperationContext* opCtx,
const RecordId& recId,
bool dupsAllowed) {
invariant(recId.isValid());
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
- KeyString::Builder keyString(_keyStringVersion, key, _ordering, recId);
+ KeyString::HeapBuilder keyString(_keyStringVersion, key, _ordering, recId);
- return insert(opCtx, keyString, recId, dupsAllowed);
+ return insert(opCtx, std::move(keyString.release()), recId, dupsAllowed);
}
Status MobileIndex::insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) {
return _insert(opCtx, keyString, recId, dupsAllowed);
@@ -144,18 +122,18 @@ void MobileIndex::unindex(OperationContext* opCtx,
const RecordId& recId,
bool dupsAllowed) {
invariant(recId.isValid());
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
- KeyString::Builder keyString(_keyStringVersion, key, _ordering, recId);
+ KeyString::HeapBuilder keyString(_keyStringVersion, key, _ordering, recId);
- return unindex(opCtx, keyString, recId, dupsAllowed);
+ unindex(opCtx, std::move(keyString.release()), recId, dupsAllowed);
}
void MobileIndex::unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) {
- return _unindex(opCtx, keyString, recId, dupsAllowed);
+ _unindex(opCtx, keyString, recId, dupsAllowed);
}
void MobileIndex::_doDelete(OperationContext* opCtx,
@@ -254,7 +232,7 @@ Status MobileIndex::create(OperationContext* opCtx, const std::string& ident) {
}
Status MobileIndex::dupKeyCheck(OperationContext* opCtx, const BSONObj& key) {
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
invariant(_isUnique);
if (_isDup(opCtx, key))
@@ -295,14 +273,14 @@ public:
Status addKey(const BSONObj& key, const RecordId& recId) override {
invariant(recId.isValid());
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
- KeyString::Builder keyString(
+ KeyString::HeapBuilder keyString(
_index->getKeyStringVersion(), key, _index->getOrdering(), recId);
- return addKey(keyString, recId);
+ return addKey(std::move(keyString.release()), recId);
}
- Status addKey(const KeyString::Builder& keyString, const RecordId& recId) override {
+ Status addKey(const KeyString::Value& keyString, const RecordId& recId) override {
Status status = _checkNextKey(keyString);
if (!status.isOK()) {
return status;
@@ -320,21 +298,18 @@ protected:
* Checks whether the new key to be inserted is > or >= the previous one depending
* on _dupsAllowed.
*/
- Status _checkNextKey(const KeyString::Builder& keyString) {
- const int cmp = keyString.compare(_lastKeyString);
+ Status _checkNextKey(const KeyString::Value& keyString) {
+ const int cmp = _lastKeyString.compare(keyString);
if (!_dupsAllowed && cmp == 0) {
- auto key = KeyString::toBson(keyString.getBuffer(),
- keyString.getSize(),
- _index->getOrdering(),
- keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _index->getOrdering());
return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern);
- } else if (cmp < 0) {
+ } else if (cmp > 0) {
return Status(ErrorCodes::InternalError, "expected higher RecordId in bulk builder");
}
return Status::OK();
}
- virtual Status _addKey(const KeyString::Builder& keyString, const RecordId& recId) = 0;
+ virtual Status _addKey(const KeyString::Value& keyString, const RecordId& recId) = 0;
MobileIndex* _index;
OperationContext* const _opCtx;
@@ -359,7 +334,7 @@ public:
: BulkBuilderBase(index, opCtx, dupsAllowed, collectionNamespace, indexName, keyPattern) {}
protected:
- Status _addKey(const KeyString::Builder& keyString, const RecordId&) override {
+ Status _addKey(const KeyString::Value& keyString, const RecordId&) override {
KeyString::TypeBits typeBits = keyString.getTypeBits();
return _index->doInsert(
_opCtx, keyString.getBuffer(), keyString.getSize(), typeBits, typeBits, false);
@@ -383,7 +358,7 @@ public:
}
protected:
- Status _addKey(const KeyString::Builder& keyString, const RecordId& recId) override {
+ Status _addKey(const KeyString::Value& keyString, const RecordId& recId) override {
dassert(recId ==
KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
@@ -457,13 +432,14 @@ public:
? KeyString::Discriminator::kExclusiveAfter
: KeyString::Discriminator::kExclusiveBefore;
_endPosition = std::make_unique<KeyString::Builder>(_index.getKeyStringVersion());
- _endPosition->resetToKey(stripFieldNames(key), _index.getOrdering(), discriminator);
+ _endPosition->resetToKey(
+ BSONObj::stripFieldNames(key), _index.getOrdering(), discriminator);
}
boost::optional<IndexKeyEntry> seek(const BSONObj& key,
bool inclusive,
RequestedInfo parts) override {
- const BSONObj startKey = stripFieldNames(key);
+ const BSONObj startKey = BSONObj::stripFieldNames(key);
// By using a discriminator other than kInclusive, there is no need to distinguish
// unique vs non-unique key formats since both start with the key.
const auto discriminator = _isForward == inclusive
@@ -701,7 +677,7 @@ std::unique_ptr<SortedDataInterface::Cursor> MobileIndexStandard::newCursor(Oper
}
Status MobileIndexStandard::_insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) {
invariant(dupsAllowed);
@@ -712,7 +688,7 @@ Status MobileIndexStandard::_insert(OperationContext* opCtx,
}
void MobileIndexStandard::_unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId&,
bool dupsAllowed) {
invariant(dupsAllowed);
@@ -739,7 +715,7 @@ std::unique_ptr<SortedDataInterface::Cursor> MobileIndexUnique::newCursor(Operat
}
Status MobileIndexUnique::_insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) {
// Replication is not supported so dups are not allowed.
@@ -761,7 +737,7 @@ Status MobileIndexUnique::_insert(OperationContext* opCtx,
}
void MobileIndexUnique::_unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) {
// Replication is not supported so dups are not allowed.
diff --git a/src/mongo/db/storage/mobile/mobile_index.h b/src/mongo/db/storage/mobile/mobile_index.h
index eee3befe307..8855f0c7e1f 100644
--- a/src/mongo/db/storage/mobile/mobile_index.h
+++ b/src/mongo/db/storage/mobile/mobile_index.h
@@ -58,7 +58,7 @@ public:
bool dupsAllowed) override;
Status insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) override;
@@ -68,7 +68,7 @@ public:
bool dupsAllowed) override;
void unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) override;
@@ -128,12 +128,12 @@ protected:
KeyString::Builder* value = nullptr);
virtual Status _insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) = 0;
virtual void _unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) = 0;
@@ -162,12 +162,12 @@ public:
protected:
Status _insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) override;
void _unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) override;
};
@@ -185,12 +185,12 @@ public:
protected:
Status _insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) override;
void _unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& recId,
bool dupsAllowed) override;
diff --git a/src/mongo/db/storage/sorted_data_interface.h b/src/mongo/db/storage/sorted_data_interface.h
index d2c3608a073..1f0408d688a 100644
--- a/src/mongo/db/storage/sorted_data_interface.h
+++ b/src/mongo/db/storage/sorted_data_interface.h
@@ -107,7 +107,7 @@ public:
* at a RecordId other than 'loc' and duplicates were not allowed
*/
virtual Status insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) = 0;
@@ -131,7 +131,7 @@ public:
* otherwise
*/
virtual void unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& loc,
bool dupsAllowed) = 0;
@@ -421,7 +421,7 @@ public:
* this is violated an error Status (ErrorCodes::InternalError) will be returned.
*/
virtual Status addKey(const BSONObj& key, const RecordId& loc) = 0;
- virtual Status addKey(const KeyString::Builder& keyString, const RecordId& loc) = 0;
+ virtual Status addKey(const KeyString::Value& keyString, const RecordId& loc) = 0;
/**
* Do any necessary work to finish building the tree.
diff --git a/src/mongo/db/storage/sorted_data_interface_test_bulkbuilder.cpp b/src/mongo/db/storage/sorted_data_interface_test_bulkbuilder.cpp
index e2cf3ff4757..76bba035b5f 100644
--- a/src/mongo/db/storage/sorted_data_interface_test_bulkbuilder.cpp
+++ b/src/mongo/db/storage/sorted_data_interface_test_bulkbuilder.cpp
@@ -83,7 +83,7 @@ TEST(SortedDataInterface, BuilderAddKeyString) {
const std::unique_ptr<SortedDataBuilderInterface> builder(
sorted->getBulkBuilder(opCtx.get(), true));
- ASSERT_OK(builder->addKey(keyString1, loc1));
+ ASSERT_OK(builder->addKey(keyString1.getValueCopy(), loc1));
builder->commit(false);
}
@@ -200,8 +200,9 @@ TEST(SortedDataInterface, BuilderAddSameKeyString) {
const std::unique_ptr<SortedDataBuilderInterface> builder(
sorted->getBulkBuilder(opCtx.get(), false));
- ASSERT_OK(builder->addKey(keyStringLoc1, loc1));
- ASSERT_EQUALS(ErrorCodes::DuplicateKey, builder->addKey(keyStringLoc2, loc2));
+ ASSERT_OK(builder->addKey(keyStringLoc1.getValueCopy(), loc1));
+ ASSERT_EQUALS(ErrorCodes::DuplicateKey,
+ builder->addKey(keyStringLoc2.getValueCopy(), loc2));
builder->commit(false);
}
@@ -263,8 +264,8 @@ TEST(SortedDataInterface, BuilderAddSameKeyStringWithDupsAllowed) {
const std::unique_ptr<SortedDataBuilderInterface> builder(
sorted->getBulkBuilder(opCtx.get(), true /* allow duplicates */));
- ASSERT_OK(builder->addKey(keyStringLoc1, loc1));
- ASSERT_OK(builder->addKey(keyStringLoc2, loc2));
+ ASSERT_OK(builder->addKey(keyStringLoc1.getValueCopy(), loc1));
+ ASSERT_OK(builder->addKey(keyStringLoc2.getValueCopy(), loc2));
builder->commit(false);
}
@@ -324,9 +325,9 @@ TEST(SortedDataInterface, BuilderAddMultipleKeyStrings) {
const std::unique_ptr<SortedDataBuilderInterface> builder(
sorted->getBulkBuilder(opCtx.get(), true));
- ASSERT_OK(builder->addKey(keyString1, loc1));
- ASSERT_OK(builder->addKey(keyString2, loc2));
- ASSERT_OK(builder->addKey(keyString3, loc3));
+ ASSERT_OK(builder->addKey(keyString1.getValueCopy(), loc1));
+ ASSERT_OK(builder->addKey(keyString2.getValueCopy(), loc2));
+ ASSERT_OK(builder->addKey(keyString3.getValueCopy(), loc3));
builder->commit(false);
}
diff --git a/src/mongo/db/storage/sorted_data_interface_test_insert.cpp b/src/mongo/db/storage/sorted_data_interface_test_insert.cpp
index ebb604cb943..5b5ac187b55 100644
--- a/src/mongo/db/storage/sorted_data_interface_test_insert.cpp
+++ b/src/mongo/db/storage/sorted_data_interface_test_insert.cpp
@@ -84,7 +84,7 @@ TEST(SortedDataInterface, InsertKeyString) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_OK(sorted->insert(opCtx.get(), keyString1, loc1, true));
+ ASSERT_OK(sorted->insert(opCtx.get(), keyString1.getValueCopy(), loc1, true));
uow.commit();
}
}
@@ -281,8 +281,8 @@ TEST(SortedDataInterface, InsertSameKeyString) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_OK(sorted->insert(opCtx.get(), keyStringLoc1, loc1, false));
- ASSERT_NOT_OK(sorted->insert(opCtx.get(), keyStringLoc2, loc2, false));
+ ASSERT_OK(sorted->insert(opCtx.get(), keyStringLoc1.getValueCopy(), loc1, false));
+ ASSERT_NOT_OK(sorted->insert(opCtx.get(), keyStringLoc2.getValueCopy(), loc2, false));
uow.commit();
}
}
@@ -299,7 +299,7 @@ TEST(SortedDataInterface, InsertSameKeyString) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_NOT_OK(sorted->insert(opCtx.get(), keyStringLoc2, loc2, false));
+ ASSERT_NOT_OK(sorted->insert(opCtx.get(), keyStringLoc2.getValueCopy(), loc2, false));
uow.commit();
}
}
@@ -454,8 +454,8 @@ TEST(SortedDataInterface, InsertMultipleKeyStrings) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_OK(sorted->insert(opCtx.get(), keyString1, loc1, false));
- ASSERT_OK(sorted->insert(opCtx.get(), keyString2, loc2, false));
+ ASSERT_OK(sorted->insert(opCtx.get(), keyString1.getValueCopy(), loc1, false));
+ ASSERT_OK(sorted->insert(opCtx.get(), keyString2.getValueCopy(), loc2, false));
uow.commit();
}
}
@@ -473,7 +473,7 @@ TEST(SortedDataInterface, InsertMultipleKeyStrings) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_OK(sorted->insert(opCtx.get(), keyString3, loc3, false));
+ ASSERT_OK(sorted->insert(opCtx.get(), keyString3.getValueCopy(), loc3, false));
uow.commit();
}
}
diff --git a/src/mongo/db/storage/sorted_data_interface_test_unindex.cpp b/src/mongo/db/storage/sorted_data_interface_test_unindex.cpp
index 4281dc9010d..ff1956110ca 100644
--- a/src/mongo/db/storage/sorted_data_interface_test_unindex.cpp
+++ b/src/mongo/db/storage/sorted_data_interface_test_unindex.cpp
@@ -105,7 +105,7 @@ void unindexKeyString(bool partial) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_OK(sorted->insert(opCtx.get(), keyString1, loc1, true));
+ ASSERT_OK(sorted->insert(opCtx.get(), keyString1.getValueCopy(), loc1, true));
uow.commit();
}
}
@@ -119,7 +119,7 @@ void unindexKeyString(bool partial) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- sorted->unindex(opCtx.get(), keyString1, loc1, true);
+ sorted->unindex(opCtx.get(), keyString1.getValueCopy(), loc1, true);
ASSERT(sorted->isEmpty(opCtx.get()));
uow.commit();
}
@@ -375,9 +375,9 @@ void unindexMultipleSameKeyString(bool partial) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_OK(sorted->insert(opCtx.get(), keyStringLoc1, loc1, true));
- ASSERT_OK(
- sorted->insert(opCtx.get(), keyStringLoc2, loc2, true /* allow duplicates */));
+ ASSERT_OK(sorted->insert(opCtx.get(), keyStringLoc1.getValueCopy(), loc1, true));
+ ASSERT_OK(sorted->insert(
+ opCtx.get(), keyStringLoc2.getValueCopy(), loc2, true /* allow duplicates */));
uow.commit();
}
}
@@ -391,7 +391,7 @@ void unindexMultipleSameKeyString(bool partial) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- sorted->unindex(opCtx.get(), keyStringLoc2, loc2, true);
+ sorted->unindex(opCtx.get(), keyStringLoc2.getValueCopy(), loc2, true);
ASSERT_EQUALS(1, sorted->numEntries(opCtx.get()));
uow.commit();
}
@@ -406,8 +406,8 @@ void unindexMultipleSameKeyString(bool partial) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- ASSERT_OK(
- sorted->insert(opCtx.get(), keyStringLoc3, loc3, true /* allow duplicates */));
+ ASSERT_OK(sorted->insert(
+ opCtx.get(), keyStringLoc3.getValueCopy(), loc3, true /* allow duplicates */));
uow.commit();
}
}
@@ -421,9 +421,9 @@ void unindexMultipleSameKeyString(bool partial) {
const ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext());
{
WriteUnitOfWork uow(opCtx.get());
- sorted->unindex(opCtx.get(), keyStringLoc1, loc1, true);
+ sorted->unindex(opCtx.get(), keyStringLoc1.getValueCopy(), loc1, true);
ASSERT_EQUALS(1, sorted->numEntries(opCtx.get()));
- sorted->unindex(opCtx.get(), keyStringLoc3, loc3, true);
+ sorted->unindex(opCtx.get(), keyStringLoc3.getValueCopy(), loc3, true);
ASSERT(sorted->isEmpty(opCtx.get()));
uow.commit();
}
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
index edba35d6869..94cbf637f95 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp
@@ -79,26 +79,6 @@ using std::string;
using std::vector;
static const WiredTigerItem emptyItem(nullptr, 0);
-
-
-bool hasFieldNames(const BSONObj& obj) {
- BSONForEach(e, obj) {
- if (e.fieldName()[0])
- return true;
- }
- return false;
-}
-
-BSONObj stripFieldNames(const BSONObj& query) {
- if (!hasFieldNames(query))
- return query;
-
- BSONObjBuilder bb;
- BSONForEach(e, query) {
- bb.appendAs(e, StringData());
- }
- return bb.obj();
-}
} // namespace
@@ -270,17 +250,17 @@ Status WiredTigerIndex::insert(OperationContext* opCtx,
bool dupsAllowed) {
dassert(opCtx->lockState()->isWriteLocked());
invariant(id.isValid());
- dassert(!hasFieldNames(key));
+ dassert(!key.hasFieldNames());
TRACE_INDEX << " key: " << key << " id: " << id;
- KeyString::Builder keyString(getKeyStringVersion(), key, _ordering, id);
+ KeyString::HeapBuilder keyString(getKeyStringVersion(), key, _ordering, id);
- return insert(opCtx, keyString, id, dupsAllowed);
+ return insert(opCtx, std::move(keyString.release()), id, dupsAllowed);
}
Status WiredTigerIndex::insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) {
dassert(opCtx->lockState()->isWriteLocked());
@@ -300,14 +280,14 @@ void WiredTigerIndex::unindex(OperationContext* opCtx,
const RecordId& id,
bool dupsAllowed) {
invariant(id.isValid());
- dassert(!hasFieldNames(key));
- KeyString::Builder keyString(getKeyStringVersion(), key, _ordering, id);
+ dassert(!key.hasFieldNames());
+ KeyString::HeapBuilder keyString(getKeyStringVersion(), key, _ordering, id);
- unindex(opCtx, keyString, id, dupsAllowed);
+ unindex(opCtx, std::move(keyString.release()), id, dupsAllowed);
}
void WiredTigerIndex::unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) {
dassert(opCtx->lockState()->isWriteLocked());
@@ -402,7 +382,7 @@ bool WiredTigerIndex::appendCustomStats(OperationContext* opCtx,
}
Status WiredTigerIndex::dupKeyCheck(OperationContext* opCtx, const BSONObj& key) {
- invariant(!hasFieldNames(key));
+ invariant(!key.hasFieldNames());
invariant(unique());
WiredTigerCursor curwrap(_uri, _tableId, false, opCtx);
@@ -648,12 +628,12 @@ public:
: BulkBuilder(idx, opCtx, prefix), _idx(idx) {}
Status addKey(const BSONObj& key, const RecordId& id) override {
- KeyString::Builder keyString(_idx->getKeyStringVersion(), key, _idx->_ordering, id);
+ KeyString::HeapBuilder keyString(_idx->getKeyStringVersion(), key, _idx->_ordering, id);
- return addKey(keyString, id);
+ return addKey(std::move(keyString.release()), id);
}
- Status addKey(const KeyString::Builder& keyString, const RecordId& id) override {
+ Status addKey(const KeyString::Value& keyString, const RecordId& id) override {
dassert(id == KeyString::decodeRecordIdAtEnd(keyString.getBuffer(), keyString.getSize()));
// Can't use WiredTigerCursor since we aren't using the cache.
@@ -703,12 +683,12 @@ public:
_previousKeyString(idx->getKeyStringVersion()) {}
Status addKey(const BSONObj& newKey, const RecordId& id) override {
- KeyString::Builder newKeyString(
+ KeyString::HeapBuilder newKeyString(
_idx->getKeyStringVersion(), newKey, _idx->getOrdering(), id);
- return addKey(newKeyString, id);
+ return addKey(std::move(newKeyString.release()), id);
}
- Status addKey(const KeyString::Builder& newKeyString, const RecordId& id) override {
+ Status addKey(const KeyString::Value& newKeyString, const RecordId& id) override {
dassert(id ==
KeyString::decodeRecordIdAtEnd(newKeyString.getBuffer(), newKeyString.getSize()));
@@ -728,16 +708,13 @@ public:
}
private:
- Status addKeyTimestampSafe(const KeyString::Builder& newKeyString) {
+ Status addKeyTimestampSafe(const KeyString::Value& newKeyString) {
// Do a duplicate check, but only if dups aren't allowed.
if (!_dupsAllowed) {
const int cmp = newKeyString.compareWithoutRecordId(_previousKeyString);
if (cmp == 0) {
// Duplicate found!
- auto newKey = KeyString::toBson(newKeyString.getBuffer(),
- newKeyString.getSize(),
- _idx->_ordering,
- newKeyString.getTypeBits());
+ auto newKey = KeyString::toBson(newKeyString, _idx->_ordering);
return buildDupKeyErrorStatus(
newKey, _idx->collectionNamespace(), _idx->indexName(), _idx->keyPattern());
} else {
@@ -769,12 +746,12 @@ private:
return Status::OK();
}
- Status addKeyTimestampUnsafe(const KeyString::Builder& newKeyString, const RecordId& id) {
+ Status addKeyTimestampUnsafe(const KeyString::Value& newKeyString, const RecordId& id) {
const int cmp = newKeyString.compareWithoutRecordId(_previousKeyString);
if (cmp != 0) {
if (!_previousKeyString.isEmpty()) {
// _previousKeyString.isEmpty() is only true on the first call to addKey().
- invariant(cmp > 0); // newKey must be > the last key
+ invariant(cmp > 0); // newKey must be > the last key.
// We are done with dups of the last key so we can insert it now.
doInsert();
}
@@ -782,10 +759,7 @@ private:
} else {
// Dup found!
if (!_dupsAllowed) {
- auto newKey = KeyString::toBson(newKeyString.getBuffer(),
- newKeyString.getSize(),
- _idx->_ordering,
- newKeyString.getTypeBits());
+ auto newKey = KeyString::toBson(newKeyString, _idx->_ordering);
return buildDupKeyErrorStatus(
newKey, _idx->collectionNamespace(), _idx->indexName(), _idx->keyPattern());
}
@@ -879,14 +853,14 @@ public:
? KeyString::Discriminator::kExclusiveAfter
: KeyString::Discriminator::kExclusiveBefore;
_endPosition = std::make_unique<KeyString::Builder>(_idx.getKeyStringVersion());
- _endPosition->resetToKey(stripFieldNames(key), _idx.getOrdering(), discriminator);
+ _endPosition->resetToKey(BSONObj::stripFieldNames(key), _idx.getOrdering(), discriminator);
}
boost::optional<IndexKeyEntry> seek(const BSONObj& key,
bool inclusive,
RequestedInfo parts) override {
dassert(_opCtx->lockState()->isReadLocked());
- const BSONObj finalKey = stripFieldNames(key);
+ const BSONObj finalKey = BSONObj::stripFieldNames(key);
const auto discriminator = _forward == inclusive
? KeyString::Discriminator::kExclusiveBefore
: KeyString::Discriminator::kExclusiveAfter;
@@ -1394,7 +1368,7 @@ bool WiredTigerIndexUnique::isDup(OperationContext* opCtx, WT_CURSOR* c, const B
Status WiredTigerIndexUnique::_insert(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) {
if (isTimestampSafeUniqueIdx()) {
@@ -1405,7 +1379,7 @@ Status WiredTigerIndexUnique::_insert(OperationContext* opCtx,
Status WiredTigerIndexUnique::_insertTimestampUnsafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) {
invariant(id.isValid());
@@ -1462,8 +1436,7 @@ Status WiredTigerIndexUnique::_insertTimestampUnsafe(OperationContext* opCtx,
}
if (!dupsAllowed) {
- auto key = KeyString::toBson(
- keyString.getBuffer(), keyString.getSize(), _ordering, keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _ordering);
return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern);
}
@@ -1485,7 +1458,7 @@ Status WiredTigerIndexUnique::_insertTimestampUnsafe(OperationContext* opCtx,
Status WiredTigerIndexUnique::_insertTimestampSafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
bool dupsAllowed) {
TRACE_INDEX << "Timestamp safe unique idx KeyString: " << keyString;
@@ -1547,7 +1520,7 @@ Status WiredTigerIndexUnique::_insertTimestampSafe(OperationContext* opCtx,
void WiredTigerIndexUnique::_unindex(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) {
if (isTimestampSafeUniqueIdx()) {
@@ -1558,7 +1531,7 @@ void WiredTigerIndexUnique::_unindex(OperationContext* opCtx,
void WiredTigerIndexUnique::_unindexTimestampUnsafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) {
invariant(id.isValid());
@@ -1645,8 +1618,7 @@ void WiredTigerIndexUnique::_unindexTimestampUnsafe(OperationContext* opCtx,
}
if (!foundId) {
- auto key = KeyString::toBson(
- keyString.getBuffer(), keyString.getSize(), _ordering, keyString.getTypeBits());
+ auto key = KeyString::toBson(keyString, _ordering);
warning().stream() << id << " not found in the index for key " << redact(key);
return; // nothing to do
}
@@ -1670,7 +1642,7 @@ void WiredTigerIndexUnique::_unindexTimestampUnsafe(OperationContext* opCtx,
void WiredTigerIndexUnique::_unindexTimestampSafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
bool dupsAllowed) {
WiredTigerItem item(keyString.getBuffer(), keyString.getSize());
setKey(c, item.Get());
@@ -1726,7 +1698,7 @@ SortedDataBuilderInterface* WiredTigerIndexStandard::getBulkBuilder(OperationCon
Status WiredTigerIndexStandard::_insert(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) {
invariant(dupsAllowed);
@@ -1752,7 +1724,7 @@ Status WiredTigerIndexStandard::_insert(OperationContext* opCtx,
void WiredTigerIndexStandard::_unindex(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId&,
bool dupsAllowed) {
invariant(dupsAllowed);
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h
index df17969fc5a..6f614f40f57 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h
@@ -97,7 +97,7 @@ public:
bool dupsAllowed);
virtual Status insert(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed);
@@ -107,7 +107,7 @@ public:
bool dupsAllowed);
virtual void unindex(OperationContext* opCtx,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed);
@@ -163,13 +163,13 @@ public:
protected:
virtual Status _insert(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) = 0;
virtual void _unindex(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) = 0;
@@ -226,36 +226,36 @@ public:
Status _insert(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) override;
Status _insertTimestampUnsafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed);
Status _insertTimestampSafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
bool dupsAllowed);
void _unindex(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) override;
void _unindexTimestampUnsafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed);
void _unindexTimestampSafe(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
bool dupsAllowed);
private:
@@ -290,13 +290,13 @@ public:
Status _insert(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) override;
void _unindex(OperationContext* opCtx,
WT_CURSOR* c,
- const KeyString::Builder& keyString,
+ const KeyString::Value& keyString,
const RecordId& id,
bool dupsAllowed) override;
};
diff --git a/src/mongo/dbtests/index_access_method_test.cpp b/src/mongo/dbtests/index_access_method_test.cpp
index 3327ea73cbb..79690c28874 100644
--- a/src/mongo/dbtests/index_access_method_test.cpp
+++ b/src/mongo/dbtests/index_access_method_test.cpp
@@ -40,44 +40,53 @@ namespace mongo {
namespace {
using std::vector;
+KeyStringSet makeKeyStringSet(std::initializer_list<BSONObj> objs) {
+ KeyStringSet keyStrings;
+ for (auto& obj : objs) {
+ KeyString::HeapBuilder keyString(
+ KeyString::Version::kLatestVersion, obj, Ordering::make(BSONObj()));
+ keyStrings.insert(keyString.release());
+ }
+ return keyStrings;
+}
+
TEST(IndexAccessMethodSetDifference, EmptyInputsShouldHaveNoDifference) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet();
- BSONObjSet right = bsonCmp.makeBSONObjSet();
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ KeyStringSet left;
+ KeyStringSet right;
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQ(0UL, diff.first.size());
ASSERT_EQ(0UL, diff.second.size());
}
TEST(IndexAccessMethodSetDifference, EmptyLeftShouldHaveNoDifference) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet();
- BSONObjSet right = bsonCmp.makeBSONObjSet({BSON("" << 0)});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ KeyStringSet left;
+ auto right = makeKeyStringSet({BSON("" << 0)});
+
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQ(0UL, diff.first.size());
ASSERT_EQ(1UL, diff.second.size());
}
TEST(IndexAccessMethodSetDifference, EmptyRightShouldReturnAllOfLeft) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet({BSON("" << 0), BSON("" << 1)});
- BSONObjSet right = bsonCmp.makeBSONObjSet();
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto left = makeKeyStringSet({BSON("" << 0), BSON("" << 1)});
+ KeyStringSet right;
+
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQ(2UL, diff.first.size());
ASSERT_EQ(0UL, diff.second.size());
}
TEST(IndexAccessMethodSetDifference, IdenticalSetsShouldHaveNoDifference) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet({BSON("" << 0),
- BSON(""
- << "string"),
- BSON("" << BSONNULL)});
- BSONObjSet right = bsonCmp.makeBSONObjSet({BSON("" << 0),
- BSON(""
- << "string"),
- BSON("" << BSONNULL)});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto left = makeKeyStringSet({BSON("" << 0),
+ BSON(""
+ << "string"),
+ BSON("" << BSONNULL)});
+ auto right = makeKeyStringSet({BSON("" << 0),
+ BSON(""
+ << "string"),
+ BSON("" << BSONNULL)});
+
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQ(0UL, diff.first.size());
ASSERT_EQ(0UL, diff.second.size());
}
@@ -87,10 +96,10 @@ TEST(IndexAccessMethodSetDifference, IdenticalSetsShouldHaveNoDifference) {
//
void assertDistinct(BSONObj left, BSONObj right) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet leftSet = bsonCmp.makeBSONObjSet({left});
- BSONObjSet rightSet = bsonCmp.makeBSONObjSet({right});
- auto diff = AbstractIndexAccessMethod::setDifference(leftSet, rightSet);
+ auto leftSet = makeKeyStringSet({left});
+ auto rightSet = makeKeyStringSet({right});
+ auto diff =
+ AbstractIndexAccessMethod::setDifference(leftSet, rightSet, Ordering::make(BSONObj()));
ASSERT_EQ(1UL, diff.first.size());
ASSERT_EQ(1UL, diff.second.size());
}
@@ -127,53 +136,47 @@ TEST(IndexAccessMethodSetDifference, ZerosOfDifferentTypesAreNotEquivalent) {
}
TEST(IndexAccessMethodSetDifference, ShouldDetectOneDifferenceAmongManySimilarities) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left =
- bsonCmp.makeBSONObjSet({BSON("" << 0),
- BSON(""
- << "string"),
- BSON("" << BSONNULL),
- BSON("" << static_cast<long long>(1)), // This is different.
- BSON("" << BSON("sub"
- << "document")),
- BSON("" << BSON_ARRAY(1 << "hi" << 42))});
- BSONObjSet right =
- bsonCmp.makeBSONObjSet({BSON("" << 0),
- BSON(""
- << "string"),
- BSON("" << BSONNULL),
- BSON("" << static_cast<double>(1.0)), // This is different.
- BSON("" << BSON("sub"
- << "document")),
- BSON("" << BSON_ARRAY(1 << "hi" << 42))});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto left = makeKeyStringSet({BSON("" << 0),
+ BSON(""
+ << "string"),
+ BSON("" << BSONNULL),
+ BSON("" << static_cast<long long>(1)), // This is different.
+ BSON("" << BSON("sub"
+ << "document")),
+ BSON("" << BSON_ARRAY(1 << "hi" << 42))});
+ auto right = makeKeyStringSet({BSON("" << 0),
+ BSON(""
+ << "string"),
+ BSON("" << BSONNULL),
+ BSON("" << static_cast<double>(1.0)), // This is different.
+ BSON("" << BSON("sub"
+ << "document")),
+ BSON("" << BSON_ARRAY(1 << "hi" << 42))});
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQUALS(1UL, diff.first.size());
ASSERT_EQUALS(1UL, diff.second.size());
}
TEST(IndexAccessMethodSetDifference, SingleObjInLeftShouldFindCorrespondingObjInRight) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet({BSON("" << 2)});
- BSONObjSet right = bsonCmp.makeBSONObjSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto left = makeKeyStringSet({BSON("" << 2)});
+ auto right = makeKeyStringSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQUALS(0UL, diff.first.size());
ASSERT_EQUALS(2UL, diff.second.size());
}
TEST(IndexAccessMethodSetDifference, SingleObjInRightShouldFindCorrespondingObjInLeft) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
- BSONObjSet right = bsonCmp.makeBSONObjSet({BSON("" << 2)});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto left = makeKeyStringSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
+ auto right = makeKeyStringSet({BSON("" << 2)});
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQUALS(2UL, diff.first.size());
ASSERT_EQUALS(0UL, diff.second.size());
}
TEST(IndexAccessMethodSetDifference, LeftSetAllSmallerThanRightShouldBeDisjoint) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
- BSONObjSet right = bsonCmp.makeBSONObjSet({BSON("" << 4), BSON("" << 5), BSON("" << 6)});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto left = makeKeyStringSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
+ auto right = makeKeyStringSet({BSON("" << 4), BSON("" << 5), BSON("" << 6)});
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQUALS(3UL, diff.first.size());
ASSERT_EQUALS(3UL, diff.second.size());
for (auto&& obj : diff.first) {
@@ -185,10 +188,9 @@ TEST(IndexAccessMethodSetDifference, LeftSetAllSmallerThanRightShouldBeDisjoint)
}
TEST(IndexAccessMethodSetDifference, LeftSetAllLargerThanRightShouldBeDisjoint) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left = bsonCmp.makeBSONObjSet({BSON("" << 4), BSON("" << 5), BSON("" << 6)});
- BSONObjSet right = bsonCmp.makeBSONObjSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto left = makeKeyStringSet({BSON("" << 4), BSON("" << 5), BSON("" << 6)});
+ auto right = makeKeyStringSet({BSON("" << 1), BSON("" << 2), BSON("" << 3)});
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQUALS(3UL, diff.first.size());
ASSERT_EQUALS(3UL, diff.second.size());
for (auto&& obj : diff.first) {
@@ -200,23 +202,23 @@ TEST(IndexAccessMethodSetDifference, LeftSetAllLargerThanRightShouldBeDisjoint)
}
TEST(IndexAccessMethodSetDifference, ShouldNotReportOverlapsFromNonDisjointSets) {
- SimpleBSONObjComparator bsonCmp;
- BSONObjSet left =
- bsonCmp.makeBSONObjSet({BSON("" << 0), BSON("" << 1), BSON("" << 4), BSON("" << 6)});
- BSONObjSet right = bsonCmp.makeBSONObjSet(
+ auto left = makeKeyStringSet({BSON("" << 0), BSON("" << 1), BSON("" << 4), BSON("" << 6)});
+ auto right = makeKeyStringSet(
{BSON("" << -1), BSON("" << 1), BSON("" << 3), BSON("" << 4), BSON("" << 7)});
- auto diff = AbstractIndexAccessMethod::setDifference(left, right);
+ auto diff = AbstractIndexAccessMethod::setDifference(left, right, Ordering::make(BSONObj()));
ASSERT_EQUALS(2UL, diff.first.size()); // 0, 6.
ASSERT_EQUALS(3UL, diff.second.size()); // -1, 3, 7.
- for (auto&& obj : diff.first) {
- ASSERT(left.find(obj) != left.end());
+ for (auto&& keyString : diff.first) {
+ ASSERT(left.find(keyString) != left.end());
// Make sure it's not in the intersection.
+ auto obj = KeyString::toBson(keyString, Ordering::make(BSONObj()));
ASSERT_BSONOBJ_NE(obj, BSON("" << 1));
ASSERT_BSONOBJ_NE(obj, BSON("" << 4));
}
- for (auto&& obj : diff.second) {
- ASSERT(right.find(obj) != right.end());
+ for (auto&& keyString : diff.second) {
+ ASSERT(right.find(keyString) != right.end());
// Make sure it's not in the intersection.
+ auto obj = KeyString::toBson(keyString, Ordering::make(BSONObj()));
ASSERT_BSONOBJ_NE(obj, BSON("" << 1));
ASSERT_BSONOBJ_NE(obj, BSON("" << 4));
}
diff --git a/src/mongo/dbtests/validate_tests.cpp b/src/mongo/dbtests/validate_tests.cpp
index ed805c905f7..e813b21cef2 100644
--- a/src/mongo/dbtests/validate_tests.cpp
+++ b/src/mongo/dbtests/validate_tests.cpp
@@ -825,12 +825,13 @@ public:
options.dupsAllowed = true;
options.logIfError = true;
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
iam->getKeys(actualKey,
IndexAccessMethod::GetKeysMode::kRelaxConstraintsUnfiltered,
&keys,
nullptr,
- nullptr);
+ nullptr,
+ id1);
auto removeStatus =
iam->removeKeys(&_opCtx, {keys.begin(), keys.end()}, id1, options, &numDeleted);
auto insertStatus = iam->insert(&_opCtx, badKey, id1, options, &insertResult);
@@ -1255,12 +1256,13 @@ public:
options.logIfError = true;
options.dupsAllowed = true;
- BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ KeyStringSet keys;
iam->getKeys(actualKey,
IndexAccessMethod::GetKeysMode::kRelaxConstraintsUnfiltered,
&keys,
nullptr,
- nullptr);
+ nullptr,
+ rid);
auto removeStatus =
iam->removeKeys(&_opCtx, {keys.begin(), keys.end()}, rid, options, &numDeleted);