summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Noma <gregory.noma@gmail.com>2020-07-21 16:52:17 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-21 21:18:08 +0000
commit98a7db0a562b818426c19203e8d16cc93980b279 (patch)
tree85421e21ff3d43e46cbb0db1b7bce1ab2a889480
parentf200a0b9dc462acad59dabead90ae35fe309e205 (diff)
downloadmongo-98a7db0a562b818426c19203e8d16cc93980b279.tar.gz
SERVER-48067 Reduce memory consumption for unique index builds with large numbers of non-unique keys
(cherry picked from commit 3c2951938d65667d675c48511d9d1046655809a5)
-rw-r--r--src/mongo/db/catalog/index_catalog_impl.cpp7
-rw-r--r--src/mongo/db/catalog/multi_index_block.cpp42
-rw-r--r--src/mongo/db/index/duplicate_key_tracker.cpp48
-rw-r--r--src/mongo/db/index/duplicate_key_tracker.h4
-rw-r--r--src/mongo/db/index/index_access_method.cpp40
-rw-r--r--src/mongo/db/index/index_access_method.h42
-rw-r--r--src/mongo/db/index/index_build_interceptor.cpp36
-rw-r--r--src/mongo/db/index/index_build_interceptor.h4
-rw-r--r--src/mongo/dbtests/validate_tests.cpp88
9 files changed, 145 insertions, 166 deletions
diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp
index 13c194b6c98..266fac5b46b 100644
--- a/src/mongo/db/catalog/index_catalog_impl.cpp
+++ b/src/mongo/db/catalog/index_catalog_impl.cpp
@@ -1312,7 +1312,7 @@ Status IndexCatalogImpl::_indexKeys(OperationContext* opCtx,
*keysInsertedOut += inserted;
}
} else {
- InsertResult result;
+ int64_t numInserted;
status = index->accessMethod()->insertKeys(
opCtx,
keys,
@@ -1320,9 +1320,10 @@ Status IndexCatalogImpl::_indexKeys(OperationContext* opCtx,
multikeyPaths,
loc,
options,
- &result);
+ nullptr,
+ &numInserted);
if (keysInsertedOut) {
- *keysInsertedOut += result.numInserted;
+ *keysInsertedOut += numInserted;
}
}
diff --git a/src/mongo/db/catalog/multi_index_block.cpp b/src/mongo/db/catalog/multi_index_block.cpp
index 158dd471849..cb902dec15b 100644
--- a/src/mongo/db/catalog/multi_index_block.cpp
+++ b/src/mongo/db/catalog/multi_index_block.cpp
@@ -648,7 +648,6 @@ Status MultiIndexBlock::insert(OperationContext* opCtx, const BSONObj& doc, cons
continue;
}
- InsertResult result;
Status idxStatus(ErrorCodes::InternalError, "");
if (_indexes[i].bulk) {
// When calling insert, BulkBuilderImpl's Sorter performs file I/O that may result in an
@@ -659,7 +658,8 @@ Status MultiIndexBlock::insert(OperationContext* opCtx, const BSONObj& doc, cons
return exceptionToStatus();
}
} else {
- idxStatus = _indexes[i].real->insert(opCtx, doc, loc, _indexes[i].options, &result);
+ idxStatus =
+ _indexes[i].real->insert(opCtx, doc, loc, _indexes[i].options, nullptr, nullptr);
}
if (!idxStatus.isOK())
@@ -684,11 +684,6 @@ Status MultiIndexBlock::dumpInsertsFromBulk(OperationContext* opCtx,
if (_indexes[i].bulk == NULL)
continue;
- // If 'dupRecords' is provided, it will be used to store all records that would result in
- // duplicate key errors. Only pass 'dupKeysInserted', which stores inserted duplicate keys,
- // when 'dupRecords' is not used because these two vectors are mutually incompatible.
- std::vector<BSONObj> dupKeysInserted;
-
// When dupRecords is passed, 'dupsAllowed' should be passed to reflect whether or not the
// index is unique.
bool dupsAllowed = (dupRecords) ? !_indexes[i].block->getEntry()->descriptor()->unique()
@@ -701,30 +696,23 @@ Status MultiIndexBlock::dumpInsertsFromBulk(OperationContext* opCtx,
// SERVER-41918 This call to commitBulk() results in file I/O that may result in an
// exception.
try {
- Status status = _indexes[i].real->commitBulk(opCtx,
- _indexes[i].bulk.get(),
- dupsAllowed,
- dupRecords,
- (dupRecords) ? nullptr : &dupKeysInserted);
+ Status status = _indexes[i].real->commitBulk(
+ opCtx,
+ _indexes[i].bulk.get(),
+ dupsAllowed,
+ [=](const BSONObj& duplicateKey) {
+ // Do not record duplicates when explicitly ignored. This may be the case on
+ // secondaries.
+ return dupsAllowed && !dupRecords && !_ignoreUnique &&
+ entry->indexBuildInterceptor()
+ ? entry->indexBuildInterceptor()->recordDuplicateKey(opCtx, duplicateKey)
+ : Status::OK();
+ },
+ dupRecords);
if (!status.isOK()) {
return status;
}
-
- // Do not record duplicates when explicitly ignored. This may be the case on
- // secondaries.
- auto interceptor = entry->indexBuildInterceptor();
- if (!interceptor || _ignoreUnique) {
- continue;
- }
-
- // Record duplicate key insertions for later verification.
- if (dupKeysInserted.size()) {
- status = interceptor->recordDuplicateKeys(opCtx, dupKeysInserted);
- if (!status.isOK()) {
- return status;
- }
- }
} catch (...) {
return exceptionToStatus();
}
diff --git a/src/mongo/db/index/duplicate_key_tracker.cpp b/src/mongo/db/index/duplicate_key_tracker.cpp
index ac06389c2d3..71311c05899 100644
--- a/src/mongo/db/index/duplicate_key_tracker.cpp
+++ b/src/mongo/db/index/duplicate_key_tracker.cpp
@@ -58,39 +58,25 @@ void DuplicateKeyTracker::deleteTemporaryTable(OperationContext* opCtx) {
_keyConstraintsTable->deleteTemporaryTable(opCtx);
}
-Status DuplicateKeyTracker::recordKeys(OperationContext* opCtx, const std::vector<BSONObj>& keys) {
- if (keys.size() == 0)
- return Status::OK();
+Status DuplicateKeyTracker::recordKey(OperationContext* opCtx, const BSONObj& key) {
+ invariant(opCtx->lockState()->inAWriteUnitOfWork());
- std::vector<BSONObj> toInsert;
- toInsert.reserve(keys.size());
- for (auto&& key : keys) {
- BSONObjBuilder builder;
- builder.append(kKeyField, key);
-
- BSONObj obj = builder.obj();
-
- toInsert.emplace_back(std::move(obj));
- }
-
- std::vector<Record> records;
- records.reserve(keys.size());
- for (auto&& obj : toInsert) {
- records.emplace_back(Record{RecordId(), RecordData(obj.objdata(), obj.objsize())});
- }
-
- LOG(1) << "recording " << records.size() << " duplicate key conflicts on unique index: "
+ LOG(1) << "Index build: recording duplicate key conflict on unique index: "
<< _indexCatalogEntry->descriptor()->indexName();
- WriteUnitOfWork wuow(opCtx);
- std::vector<Timestamp> timestamps(records.size());
- Status s = _keyConstraintsTable->rs()->insertRecords(opCtx, &records, timestamps);
- if (!s.isOK())
- return s;
+ auto status =
+ _keyConstraintsTable->rs()->insertRecord(opCtx, key.objdata(), key.objsize(), Timestamp());
+ if (!status.isOK())
+ return status.getStatus();
- wuow.commit();
+ auto numDuplicates = _duplicateCounter.addAndFetch(1);
+ opCtx->recoveryUnit()->onRollback([this]() { _duplicateCounter.fetchAndAdd(-1); });
- _duplicateCounter.fetchAndAdd(records.size());
+ if (numDuplicates % 1000 == 0) {
+ log() << "Index build: high number (" << numDuplicates
+ << ") of duplicate keys on unique index: "
+ << _indexCatalogEntry->descriptor()->indexName();
+ }
return Status::OK();
}
@@ -111,14 +97,12 @@ Status DuplicateKeyTracker::checkConstraints(OperationContext* opCtx) const {
CurOp::get(opCtx)->setProgress_inlock(curopMessage, _duplicateCounter.load(), 1));
}
-
int resolved = 0;
while (record) {
resolved++;
- BSONObj conflict = record->data.toBson();
- BSONObj keyObj = conflict[kKeyField].Obj();
+ auto key = record->data.toBson();
- auto status = index->dupKeyCheck(opCtx, keyObj);
+ auto status = index->dupKeyCheck(opCtx, key);
if (!status.isOK())
return status;
diff --git a/src/mongo/db/index/duplicate_key_tracker.h b/src/mongo/db/index/duplicate_key_tracker.h
index c5399620984..61d93a5871a 100644
--- a/src/mongo/db/index/duplicate_key_tracker.h
+++ b/src/mongo/db/index/duplicate_key_tracker.h
@@ -63,9 +63,9 @@ public:
void deleteTemporaryTable(OperationContext* opCtx);
/**
- * Given a set of duplicate keys, insert them into the key constraint table.
+ * Given a duplicate key, insert it into the key constraint table.
*/
- Status recordKeys(OperationContext* opCtx, const std::vector<BSONObj>& keys);
+ Status recordKey(OperationContext* opCtx, const BSONObj& key);
/**
* Returns Status::OK if all previously recorded duplicate key constraint violations have been
diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp
index 5f4a6d7dd92..cc050e63dd8 100644
--- a/src/mongo/db/index/index_access_method.cpp
+++ b/src/mongo/db/index/index_access_method.cpp
@@ -184,7 +184,8 @@ Status AbstractIndexAccessMethod::insert(OperationContext* opCtx,
const BSONObj& obj,
const RecordId& loc,
const InsertDeleteOptions& options,
- InsertResult* result) {
+ KeyHandlerFn&& onDuplicateKey,
+ int64_t* numInserted) {
invariant(options.fromIndexBuilder || !_btreeState->isHybridBuilding());
BSONObjSet multikeyMetadataKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
@@ -205,7 +206,8 @@ Status AbstractIndexAccessMethod::insert(OperationContext* opCtx,
multikeyPaths,
loc,
options,
- result);
+ std::move(onDuplicateKey),
+ numInserted);
}
Status AbstractIndexAccessMethod::insertKeys(OperationContext* opCtx,
@@ -214,7 +216,8 @@ Status AbstractIndexAccessMethod::insertKeys(OperationContext* opCtx,
const MultikeyPaths& multikeyPaths,
const RecordId& loc,
const InsertDeleteOptions& options,
- InsertResult* result) {
+ KeyHandlerFn&& onDuplicateKey,
+ int64_t* numInserted) {
bool checkIndexKeySize = shouldCheckIndexKeySize(opCtx);
// Add all new data keys, and all new multikey metadata keys, into the index. When iterating
@@ -230,20 +233,15 @@ Status AbstractIndexAccessMethod::insertKeys(OperationContext* opCtx,
_newInterface->insert(opCtx, key, recordId, !unique /* dupsAllowed */);
status = ret.getStatus();
- // When duplicates are encountered and allowed, retry with dupsAllowed. Add the
- // key to the output vector so callers know which duplicate keys were inserted.
+ // When duplicates are encountered and allowed, retry with dupsAllowed. Call
+ // onDuplicateKey() with the inserted duplicate key.
if (ErrorCodes::DuplicateKey == status.code() && options.dupsAllowed) {
invariant(unique);
ret = _newInterface->insert(opCtx, key, recordId, true /* dupsAllowed */);
status = ret.getStatus();
- // 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) {
- result->dupsInserted.push_back(key);
- }
+ if (status.isOK() && onDuplicateKey)
+ status = onDuplicateKey(key);
}
if (status.isOK() && ret.getValue() == SpecialFormatInserted::LongTypeBitsInserted)
@@ -256,8 +254,8 @@ Status AbstractIndexAccessMethod::insertKeys(OperationContext* opCtx,
}
}
- if (result) {
- result->numInserted += keys.size() + multikeyMetadataKeys.size();
+ if (numInserted) {
+ *numInserted = keys.size() + multikeyMetadataKeys.size();
}
if (shouldMarkIndexAsMultikey(keys, multikeyMetadataKeys, multikeyPaths)) {
@@ -650,12 +648,8 @@ int64_t AbstractIndexAccessMethod::BulkBuilderImpl::getKeysInserted() const {
Status AbstractIndexAccessMethod::commitBulk(OperationContext* opCtx,
BulkBuilder* bulk,
bool dupsAllowed,
- set<RecordId>* dupRecords,
- std::vector<BSONObj>* dupKeysInserted) {
- // Cannot simultaneously report uninserted duplicates 'dupRecords' and inserted duplicates
- // 'dupKeysInserted'.
- invariant(!(dupRecords && dupKeysInserted));
-
+ KeyHandlerFn&& onDuplicateKey,
+ set<RecordId>* dupRecords) {
Timer timer;
std::unique_ptr<BulkBuilder::Sorter::Iterator> it(bulk->done());
@@ -726,8 +720,10 @@ Status AbstractIndexAccessMethod::commitBulk(OperationContext* opCtx,
previousKey = data.first.getOwned();
- if (isDup && dupsAllowed && dupKeysInserted) {
- dupKeysInserted->push_back(data.first.getOwned());
+ if (isDup) {
+ status = onDuplicateKey(data.first);
+ if (!status.isOK())
+ return status;
}
// If we're here either it's a dup and we're cool with it or the addKey went just fine.
diff --git a/src/mongo/db/index/index_access_method.h b/src/mongo/db/index/index_access_method.h
index d7d96588d18..5fe38414125 100644
--- a/src/mongo/db/index/index_access_method.h
+++ b/src/mongo/db/index/index_access_method.h
@@ -48,7 +48,6 @@ namespace mongo {
class BSONObjBuilder;
class MatchExpression;
struct UpdateTicket;
-struct InsertResult;
struct InsertDeleteOptions;
bool failIndexKeyTooLongParam();
@@ -68,6 +67,8 @@ class IndexAccessMethod {
IndexAccessMethod& operator=(const IndexAccessMethod&) = delete;
public:
+ using KeyHandlerFn = std::function<Status(const BSONObj&)>;
+
IndexAccessMethod() = default;
virtual ~IndexAccessMethod() = default;
@@ -90,7 +91,8 @@ public:
const BSONObj& obj,
const RecordId& loc,
const InsertDeleteOptions& options,
- InsertResult* result) = 0;
+ KeyHandlerFn&& onDuplicateKey,
+ int64_t* numInserted) = 0;
virtual Status insertKeys(OperationContext* opCtx,
const std::vector<BSONObj>& keys,
@@ -98,7 +100,8 @@ public:
const MultikeyPaths& multikeyPaths,
const RecordId& loc,
const InsertDeleteOptions& options,
- InsertResult* result) = 0;
+ KeyHandlerFn&& onDuplicateKey,
+ int64_t* numInserted) = 0;
/**
* Analogous to insertKeys above, but remove the keys instead of inserting them.
@@ -260,22 +263,14 @@ public:
* @param mayInterrupt - Is this commit interruptible (will cancel)
* @param dupsAllowed - If false and 'dupRecords' is not null, append with the RecordIds of
* the uninserted duplicates.
- * If true and 'dupKeys' is not null, append with the keys of the inserted
- * duplicates.
+ * @param onDuplicateKey - Will be called for each duplicate key inserted into the index.
* @param dupRecords - If not null, is filled with the RecordIds of uninserted duplicate keys.
- * If null, duplicate keys will return errors.
- * @param dupKeys - If not null and 'dupsAllowed' is true, is filled with the keys of inserted
- * duplicates.
- * If null, duplicates are inserted but not recorded.
- *
- * It is invalid and contradictory to pass both 'dupRecords' and 'dupKeys'.
*/
-
virtual Status commitBulk(OperationContext* opCtx,
BulkBuilder* bulk,
bool dupsAllowed,
- std::set<RecordId>* dupRecords,
- std::vector<BSONObj>* dupKeys) = 0;
+ KeyHandlerFn&& onDuplicateKey,
+ std::set<RecordId>* dupRecords) = 0;
/**
* Specifies whether getKeys should relax the index constraints or not, in order of most
@@ -376,15 +371,6 @@ public:
};
/**
- * Records number of keys inserted and duplicate keys inserted, if applicable.
- */
-struct InsertResult {
-public:
- std::int64_t numInserted{0};
- std::vector<BSONObj> dupsInserted;
-};
-
-/**
* Updates are two steps: verify that it's a valid update, and perform it.
* prepareUpdate fills out the UpdateStatus and update actually applies it.
*/
@@ -462,7 +448,8 @@ public:
const BSONObj& obj,
const RecordId& loc,
const InsertDeleteOptions& options,
- InsertResult* result) final;
+ KeyHandlerFn&& onDuplicateKey,
+ int64_t* numInserted) final;
Status insertKeys(OperationContext* opCtx,
const std::vector<BSONObj>& keys,
@@ -470,7 +457,8 @@ public:
const MultikeyPaths& multikeyPaths,
const RecordId& loc,
const InsertDeleteOptions& options,
- InsertResult* result) final;
+ KeyHandlerFn&& onDuplicateKey,
+ int64_t* numInserted) final;
Status removeKeys(OperationContext* opCtx,
const std::vector<BSONObj>& keys,
@@ -522,8 +510,8 @@ public:
Status commitBulk(OperationContext* opCtx,
BulkBuilder* bulk,
bool dupsAllowed,
- std::set<RecordId>* dupRecords,
- std::vector<BSONObj>* dupKeys) final;
+ KeyHandlerFn&& onDuplicateKey,
+ std::set<RecordId>* dupRecords) final;
void getKeys(const BSONObj& obj,
GetKeysMode mode,
diff --git a/src/mongo/db/index/index_build_interceptor.cpp b/src/mongo/db/index/index_build_interceptor.cpp
index 704b7d81d00..b7eb5b336b5 100644
--- a/src/mongo/db/index/index_build_interceptor.cpp
+++ b/src/mongo/db/index/index_build_interceptor.cpp
@@ -94,10 +94,9 @@ void IndexBuildInterceptor::deleteTemporaryTables(OperationContext* opCtx) {
}
}
-Status IndexBuildInterceptor::recordDuplicateKeys(OperationContext* opCtx,
- const std::vector<BSONObj>& keys) {
+Status IndexBuildInterceptor::recordDuplicateKey(OperationContext* opCtx, const BSONObj& key) {
invariant(_indexCatalogEntry->descriptor()->unique());
- return _duplicateKeyTracker->recordKeys(opCtx, keys);
+ return _duplicateKeyTracker->recordKey(opCtx, key);
}
Status IndexBuildInterceptor::checkDuplicateKeyConstraints(OperationContext* opCtx) const {
@@ -276,27 +275,24 @@ Status IndexBuildInterceptor::_applyWrite(OperationContext* opCtx,
auto accessMethod = _indexCatalogEntry->accessMethod();
if (opType == Op::kInsert) {
- InsertResult result;
- auto status = accessMethod->insertKeys(opCtx,
- {keySet.begin(), keySet.end()},
- {},
- MultikeyPaths{},
- opRecordId,
- options,
- &result);
+ int64_t numInserted;
+ auto status = accessMethod->insertKeys(
+ opCtx,
+ {keySet.begin(), keySet.end()},
+ {},
+ MultikeyPaths{},
+ opRecordId,
+ options,
+ [=](const BSONObj& duplicateKey) {
+ return options.getKeysMode == IndexAccessMethod::GetKeysMode::kEnforceConstraints
+ ? recordDuplicateKey(opCtx, duplicateKey)
+ : Status::OK();
+ },
+ &numInserted);
if (!status.isOK()) {
return status;
}
- if (result.dupsInserted.size() &&
- options.getKeysMode == IndexAccessMethod::GetKeysMode::kEnforceConstraints) {
- status = recordDuplicateKeys(opCtx, result.dupsInserted);
- if (!status.isOK()) {
- return status;
- }
- }
-
- int64_t numInserted = result.numInserted;
*keysInserted += numInserted;
opCtx->recoveryUnit()->onRollback(
[keysInserted, numInserted] { *keysInserted -= numInserted; });
diff --git a/src/mongo/db/index/index_build_interceptor.h b/src/mongo/db/index/index_build_interceptor.h
index 8f8d54bd737..70a7d28d1f6 100644
--- a/src/mongo/db/index/index_build_interceptor.h
+++ b/src/mongo/db/index/index_build_interceptor.h
@@ -81,10 +81,10 @@ public:
int64_t* const numKeysOut);
/**
- * Given a set of duplicate keys, record the keys for later verification by a call to
+ * Given a duplicate key, record the key for later verification by a call to
* checkDuplicateKeyConstraints();
*/
- Status recordDuplicateKeys(OperationContext* opCtx, const std::vector<BSONObj>& keys);
+ Status recordDuplicateKey(OperationContext* opCtx, const BSONObj& key);
/**
* Returns Status::OK if all previously recorded duplicate key constraint violations have been
diff --git a/src/mongo/dbtests/validate_tests.cpp b/src/mongo/dbtests/validate_tests.cpp
index e0f92c2c757..8968eb7ec71 100644
--- a/src/mongo/dbtests/validate_tests.cpp
+++ b/src/mongo/dbtests/validate_tests.cpp
@@ -37,6 +37,7 @@
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/index/index_access_method.h"
+#include "mongo/db/index/index_build_interceptor.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/service_context.h"
#include "mongo/dbtests/dbtests.h"
@@ -822,7 +823,7 @@ public:
{
WriteUnitOfWork wunit(&_opCtx);
int64_t numDeleted;
- InsertResult insertResult;
+ int64_t numInserted;
const BSONObj actualKey = BSON("a" << 1);
const BSONObj badKey = BSON("a" << -1);
InsertDeleteOptions options;
@@ -838,10 +839,10 @@ public:
nullptr);
auto removeStatus =
iam->removeKeys(&_opCtx, {keys.begin(), keys.end()}, id1, options, &numDeleted);
- auto insertStatus = iam->insert(&_opCtx, badKey, id1, options, &insertResult);
+ auto insertStatus = iam->insert(&_opCtx, badKey, id1, options, nullptr, &numInserted);
ASSERT_EQUALS(numDeleted, 1);
- ASSERT_EQUALS(insertResult.numInserted, 1);
+ ASSERT_EQUALS(numInserted, 1);
ASSERT_OK(removeStatus);
ASSERT_OK(insertStatus);
wunit.commit();
@@ -1570,11 +1571,12 @@ public:
IndexCatalog* indexCatalog = coll->getIndexCatalog();
- WriteUnitOfWork wunit(&_opCtx);
InsertDeleteOptions options;
options.logIfError = true;
options.dupsAllowed = true;
+ WriteUnitOfWork wunit(&_opCtx);
+
// Insert a record and its keys separately. We do this to bypass duplicate constraint
// checking. Inserting a record and all of its keys ensures that validation fails
// because there are duplicate keys, and not just because there are keys without
@@ -1583,11 +1585,17 @@ public:
&_opCtx, dupObj.objdata(), dupObj.objsize(), Timestamp());
ASSERT_OK(swRecordId);
+ wunit.commit();
+
// Insert the key on _id.
{
+ WriteUnitOfWork wunit(&_opCtx);
+
auto descriptor = indexCatalog->findIdIndex(&_opCtx);
- auto iam = const_cast<IndexAccessMethod*>(
- indexCatalog->getEntry(descriptor)->accessMethod());
+ auto entry = const_cast<IndexCatalogEntry*>(indexCatalog->getEntry(descriptor));
+ auto iam = entry->accessMethod();
+ auto interceptor = std::make_unique<IndexBuildInterceptor>(&_opCtx, entry);
+
BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
iam->getKeys(dupObj,
IndexAccessMethod::GetKeysMode::kRelaxConstraints,
@@ -1597,28 +1605,39 @@ public:
nullptr);
ASSERT_EQ(1ul, keys.size());
- InsertResult result;
- auto insertStatus = iam->insertKeys(&_opCtx,
- {keys.begin(), keys.end()},
- {},
- MultikeyPaths{},
- swRecordId.getValue(),
- options,
- &result);
-
- ASSERT_EQUALS(result.dupsInserted.size(), 0ul);
- ASSERT_EQUALS(result.numInserted, 1);
+ int64_t numInserted;
+ auto insertStatus = iam->insertKeys(
+ &_opCtx,
+ {keys.begin(), keys.end()},
+ {},
+ MultikeyPaths{},
+ swRecordId.getValue(),
+ options,
+ [this, &interceptor](const BSONObj& duplicateKey) {
+ return interceptor->recordDuplicateKey(&_opCtx, duplicateKey);
+ },
+ &numInserted);
+
+ wunit.commit();
+
+ ASSERT_OK(interceptor->checkDuplicateKeyConstraints(&_opCtx));
+ ASSERT_EQUALS(numInserted, 1);
ASSERT_OK(insertStatus);
+
+ interceptor->deleteTemporaryTables(&_opCtx);
}
// Insert the key on "a".
{
+ WriteUnitOfWork wunit(&_opCtx);
+
auto descriptor = indexCatalog->findIndexByName(&_opCtx, indexName);
- auto iam = const_cast<IndexAccessMethod*>(
- indexCatalog->getEntry(descriptor)->accessMethod());
+ auto entry = const_cast<IndexCatalogEntry*>(indexCatalog->getEntry(descriptor));
+ auto iam = entry->accessMethod();
+ auto interceptor = std::make_unique<IndexBuildInterceptor>(&_opCtx, entry);
BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
- InsertResult result;
+ int64_t numInserted;
iam->getKeys(dupObj,
IndexAccessMethod::GetKeysMode::kRelaxConstraints,
IndexAccessMethod::GetKeysContext::kReadOrAddKeys,
@@ -1626,19 +1645,26 @@ public:
nullptr,
nullptr);
ASSERT_EQ(1ul, keys.size());
- auto insertStatus = iam->insertKeys(&_opCtx,
- {keys.begin(), keys.end()},
- {},
- MultikeyPaths{},
- swRecordId.getValue(),
- options,
- &result);
-
- ASSERT_EQUALS(result.dupsInserted.size(), 1ul);
- ASSERT_EQUALS(result.numInserted, 1);
+ auto insertStatus = iam->insertKeys(
+ &_opCtx,
+ {keys.begin(), keys.end()},
+ {},
+ MultikeyPaths{},
+ swRecordId.getValue(),
+ options,
+ [this, &interceptor](const BSONObj& duplicateKey) {
+ return interceptor->recordDuplicateKey(&_opCtx, duplicateKey);
+ },
+ &numInserted);
+
+ wunit.commit();
+
+ ASSERT_NOT_OK(interceptor->checkDuplicateKeyConstraints(&_opCtx));
+ ASSERT_EQUALS(numInserted, 1);
ASSERT_OK(insertStatus);
+
+ interceptor->deleteTemporaryTables(&_opCtx);
}
- wunit.commit();
releaseDb();
}