Status IndexBuildInterceptor::_applyWrite(OperationContext* opCtx, const BSONObj& operation, const InsertDeleteOptions& options, int64_t* const keysInserted, int64_t* const keysDeleted) { const BSONObj key = operation["key"].Obj(); 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}); auto accessMethod = _indexCatalogEntry->accessMethod(); if (opType == Op::kInsert) { InsertResult result; auto status = accessMethod->insertKeys(opCtx, keySet, SimpleBSONObjComparator::kInstance.makeBSONObjSet(), MultikeyPaths{}, opRecordId, options, &result); 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; }); } else { invariant(opType == Op::kDelete); DEV invariant(strcmp(operation.getStringField("op"), "d") == 0); int64_t numDeleted; Status s = accessMethod->removeKeys(opCtx, keySet, opRecordId, options, &numDeleted); if (!s.isOK()) { return s; } *keysDeleted += numDeleted; opCtx->recoveryUnit()->onRollback( [keysDeleted, numDeleted] { *keysDeleted -= numDeleted; }); } return Status::OK(); }
MojErr MojDbIndex::update(const MojObject* newObj, const MojObject* oldObj, MojDbStorageTxn* txn, bool forcedel) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(isOpen()); MojAssert(newObj || oldObj); // figure out which versions we include bool includeOld = includeObj(oldObj); bool includeNew = includeObj(newObj); if (includeNew && !includeOld) { // we include the new but not the old, so just put all the new keys MojAssert(newObj); KeySet newKeys; MojErr err = getKeys(*newObj, newKeys); MojErrCheck(err); err = insertKeys(newKeys, txn); MojErrCheck(err); err = notifyWatches(newKeys, txn); MojErrCheck(err); LOG_DEBUG("[db_mojodb] IndexAdd: %s; Keys= %zu \n", this->m_name.data(), newKeys.size()); } else if (includeOld && !includeNew) { // we include the old but not the new objects, so del all the old keys MojAssert(oldObj); KeySet oldKeys; MojErr err = getKeys(*oldObj, oldKeys); MojErrCheck(err); err = delKeys(oldKeys, txn, forcedel); MojErrCheck(err); err = notifyWatches(oldKeys, txn); MojErrCheck(err); LOG_DEBUG("[db_mojodb] IndexDel: %s; Keys= %zu \n", this->name().data(), oldKeys.size()); } else if (includeNew && includeOld) { // we include old and new objects MojAssert(newObj && oldObj); KeySet newKeys; MojErr err = getKeys(*newObj, newKeys); MojErrCheck(err); KeySet oldKeys; err = getKeys(*oldObj, oldKeys); MojErrCheck(err); // we need to put the keys that are in the new set, but not in the old KeySet keysToPut; err = newKeys.diff(oldKeys, keysToPut); MojErrCheck(err); // we need to del the keys that are in the old set, but not in the new KeySet keysToDel; err = oldKeys.diff(newKeys, keysToDel); MojErrCheck(err); err = insertKeys(keysToPut, txn); MojErrCheck(err); err = delKeys(keysToDel, txn, forcedel); LOG_DEBUG("[db_mojodb] IndexMerge: %s; OldKeys= %zu; NewKeys= %zu; Dropped= %zu; Added= %zu ; err = %d\n", this->name().data(), oldKeys.size(), newKeys.size(), keysToDel.size(), keysToPut.size(), (int)err); MojErrCheck(err); // notify on union of old and new keys err = newKeys.put(oldKeys); MojErrCheck(err); err = notifyWatches(newKeys, txn); MojErrCheck(err); } return MojErrNone; }