示例#1
0
文件: prefetch.cpp 项目: i80and/mongo
// 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);
    }
}
示例#2
0
StatusWith<std::set<NamespaceString>> RollbackImpl::_namespacesForOp(const OplogEntry& oplogEntry) {
    NamespaceString opNss = oplogEntry.getNamespace();
    OpTypeEnum opType = oplogEntry.getOpType();
    std::set<NamespaceString> namespaces;

    // No namespaces for a no-op.
    if (opType == OpTypeEnum::kNoop) {
        return std::set<NamespaceString>();
    }

    // CRUD ops have the proper namespace in the operation 'ns' field.
    if (opType == OpTypeEnum::kInsert || opType == OpTypeEnum::kUpdate ||
        opType == OpTypeEnum::kDelete) {
        return std::set<NamespaceString>({opNss});
    }

    // If the operation is a command, then we need to extract the appropriate namespaces from the
    // command object, as opposed to just using the 'ns' field of the oplog entry itself.
    if (opType == OpTypeEnum::kCommand) {
        auto obj = oplogEntry.getObject();
        auto firstElem = obj.firstElement();

        // Does not handle 'applyOps' entries.
        invariant(oplogEntry.getCommandType() != OplogEntry::CommandType::kApplyOps,
                  "_namespacesForOp does not handle 'applyOps' oplog entries.");

        switch (oplogEntry.getCommandType()) {
            case OplogEntry::CommandType::kRenameCollection: {
                // Add both the 'from' and 'to' namespaces.
                namespaces.insert(NamespaceString(firstElem.valuestrsafe()));
                namespaces.insert(NamespaceString(obj.getStringField("to")));
                break;
            }
            case OplogEntry::CommandType::kDropDatabase: {
                // There is no specific namespace to save for a drop database operation.
                break;
            }
            case OplogEntry::CommandType::kDbCheck:
            case OplogEntry::CommandType::kConvertToCapped:
            case OplogEntry::CommandType::kEmptyCapped: {
                // These commands do not need to be supported by rollback. 'convertToCapped' should
                // always be converted to lower level DDL operations, and 'emptycapped' is a
                // testing-only command.
                std::string message = str::stream() << "Encountered unsupported command type '"
                                                    << firstElem.fieldName()
                                                    << "' during rollback.";
                return Status(ErrorCodes::UnrecoverableRollbackError, message);
            }
            case OplogEntry::CommandType::kCreate:
            case OplogEntry::CommandType::kDrop:
            case OplogEntry::CommandType::kCreateIndexes:
            case OplogEntry::CommandType::kDropIndexes:
            case OplogEntry::CommandType::kCollMod: {
                // For all other command types, we should be able to parse the collection name from
                // the first command argument.
                try {
                    auto cmdNss = CommandHelpers::parseNsCollectionRequired(opNss.db(), obj);
                    namespaces.insert(cmdNss);
                } catch (const DBException& ex) {
                    return ex.toStatus();
                }
                break;
            }
            case OplogEntry::CommandType::kApplyOps:
            default:
                // Every possible command type should be handled above.
                MONGO_UNREACHABLE
        }
    }