// prefetch for an oplog operation void prefetchPagesForReplicatedOp(OperationContext* opCtx, Database* db, const OplogEntry& oplogEntry) { invariant(db); const ReplSettings::IndexPrefetchConfig prefetchConfig = ReplicationCoordinator::get(opCtx)->getIndexPrefetchConfig(); // Prefetch ignores non-CRUD operations. if (!oplogEntry.isCrudOpType()) { return; } // This will have to change for engines other than MMAP V1, because they might not have // means for directly prefetching pages from the collection. For this purpose, acquire S // lock on the database, instead of optimizing with IS. const auto& nss = oplogEntry.getNamespace(); Lock::CollectionLock collLock(opCtx->lockState(), nss.ns(), MODE_S); Collection* collection = db->getCollection(opCtx, nss); if (!collection) { return; } auto opType = oplogEntry.getOpType(); LOG(4) << "index prefetch for op " << OpType_serializer(opType); // should we prefetch index pages on updates? if the update is in-place and doesn't change // indexed values, it is actually slower - a lot slower if there are a dozen indexes or // lots of multikeys. possible variations (not all mutually exclusive): // 1) current behavior: full prefetch // 2) don't do it for updates // 3) don't do multikey indexes for updates // 4) don't prefetchIndexPages on some heuristic; e.g., if it's an $inc. // 5) if not prefetching index pages (#2), we should do it if we are upsertings and it // will be an insert. to do that we could do the prefetchRecordPage first and if DNE // then we do #1. // // note that on deletes 'obj' does not have all the keys we would want to prefetch on. // a way to achieve that would be to prefetch the record first, and then afterwards do // this part. // auto obj = oplogEntry.getOperationToApply(); invariant(!obj.isEmpty()); prefetchIndexPages(opCtx, collection, prefetchConfig, obj); // do not prefetch the data for inserts; it doesn't exist yet // // we should consider doing the record prefetch for the delete op case as we hit the record // when we delete. note if done we only want to touch the first page. // // update: do record prefetch. if ((opType == OpTypeEnum::kUpdate) && // do not prefetch the data for capped collections because // they typically do not have an _id index for findById() to use. !collection->isCapped()) { prefetchRecordPages(opCtx, db, nss.ns().c_str(), obj); } }
std::pair<BSONObj, RecordId> RollbackTest::makeCRUDOp(OpTypeEnum opType, Timestamp ts, UUID uuid, StringData nss, BSONObj o, boost::optional<BSONObj> o2, int recordId) { invariant(opType != OpTypeEnum::kCommand); BSONObjBuilder bob; bob.append("ts", ts); bob.append("op", OpType_serializer(opType)); uuid.appendToBuilder(&bob, "ui"); bob.append("ns", nss); bob.append("o", o); if (o2) { bob.append("o2", *o2); } return std::make_pair(bob.obj(), RecordId(recordId)); }