Example #1
0
    // prefetch for an oplog operation
    void prefetchPagesForReplicatedOp(OperationContext* txn,
                                      Database* db,
                                      const repl::ReplSetImpl::IndexPrefetchConfig& prefetchConfig,
                                      const BSONObj& op) {
        const char *opField;
        const char *opType = op.getStringField("op");
        switch (*opType) {
        case 'i': // insert
        case 'd': // delete
            opField = "o";
            break;
        case 'u': // update
            opField = "o2";
            break;
        default:
            // prefetch ignores other ops
            return;
        }

        BSONObj obj = op.getObjectField(opField);
        const char *ns = op.getStringField("ns");

        Collection* collection = db->getCollection( txn, ns );
        if ( !collection )
            return;

        LOG(4) << "index prefetch for op " << *opType << endl;

        DEV txn->lockState()->assertAtLeastReadLocked(ns);

        // 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.
        //
        prefetchIndexPages(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 == 'u') &&
            // do not prefetch the data for capped collections because
            // they typically do not have an _id index for findById() to use.
            !collection->isCapped()) {
            prefetchRecordPages(txn, ns, obj);
        }
    }
Example #2
0
// 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);
    }
}