void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* txn,
                                                    repl::StorageInterface* storageInterface) {
    if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) {
        std::vector<std::string> dbNames;
        StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine();
        storageEngine->listDatabases(&dbNames);

        for (auto&& dbName : dbNames) {
            if (dbName != "local") {
                return;
            }
        }

        // Insert featureCompatibilityDocument into admin.system.version.
        txn->setReplicatedWrites(false);
        NamespaceString nss(FeatureCompatibilityVersion::kCollection);
        CollectionOptions options;
        uassertStatusOK(storageInterface->createCollection(txn, nss, options));
        uassertStatusOK(storageInterface->insertDocument(
            txn,
            nss,
            BSON("_id" << FeatureCompatibilityVersion::kParameterName
                       << FeatureCompatibilityVersion::kVersionField
                       << FeatureCompatibilityVersion::kVersion34)));

        // Update server parameter.
        serverGlobalParams.featureCompatibilityVersion.store(
            ServerGlobalParams::FeatureCompatibilityVersion_34);
    }
}
Пример #2
0
    bool WriteCmd::run(const string& dbName,
                       BSONObj& cmdObj,
                       int options,
                       string& errMsg,
                       BSONObjBuilder& result,
                       bool fromRepl) {

        // Can't be run on secondaries (logTheOp() == false, slaveOk() == false).
        dassert( !fromRepl );

        BatchedCommandRequest request( _writeType );
        BatchedCommandResponse response;

        if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) {
            // Batch parse failure
            response.setOk( false );
            response.setErrCode( 99999 );
            response.setErrMessage( errMsg );
            result.appendElements( response.toBSON() );

            // TODO
            // There's a pending issue about how to report response here. If we use
            // the command infra-structure, we should reuse the 'errmsg' field. But
            // we have already filed that message inside the BatchCommandResponse.
            // return response.getOk();
            return true;
        }

        // Note that this is a runCommmand, and therefore, the database and the collection name
        // are in different parts of the grammar for the command. But it's more convenient to
        // work with a NamespaceString. We built it here and replace it in the parsed command.
        // Internally, everything work with the namespace string as opposed to just the
        // collection name.
        NamespaceString nss(dbName, request.getNS());
        request.setNS(nss.ns());

        {
            // Commands with locktype == NONE need to acquire a Context in order to set
            // CurOp::_ns.  Setting a CurOp's namespace is necessary for higher-level
            // functionality (e.g. profiling) to operate on the correct database (note that
            // WriteBatchExecutor doesn't do this for us, since its job is to create child CurOp
            // objects and operate on them).
            //
            // Acquire ReadContext momentarily, for satisfying this purpose.
            Client::ReadContext ctx( dbName + ".$cmd" );
        }

        WriteBatchExecutor writeBatchExecutor(&cc(), &globalOpCounters, lastError.get());

        writeBatchExecutor.executeBatch( request, &response );

        result.appendElements( response.toBSON() );

        // TODO
        // There's a pending issue about how to report response here. If we use
        // the command infra-structure, we should reuse the 'errmsg' field. But
        // we have already filed that message inside the BatchCommandResponse.
        // return response.getOk();
        return true;
    }
    void MMAPV1DatabaseCatalogEntry::_fillInEntry_inlock( OperationContext* txn,
                                                          const StringData& ns,
                                                          Entry* entry ) {
        NamespaceDetails* details = _namespaceIndex.details( ns );
        invariant( details );

        entry->catalogEntry.reset( new NamespaceDetailsCollectionCatalogEntry( ns,
                                                                               details,
                                                                               _getIndexRecordStore_inlock(),
                                                                               this ) );

        NamespaceString nss( ns );

        auto_ptr<NamespaceDetailsRSV1MetaData> md( new NamespaceDetailsRSV1MetaData( ns,
                                                                                     details,
                                                                                     _getNamespaceRecordStore_inlock() ) );

        if ( details->isCapped ) {
            entry->recordStore.reset( new CappedRecordStoreV1( txn,
                                                               NULL, //TOD(ERH) this will blow up :)
                                                               ns,
                                                               md.release(),
                                                               &_extentManager,
                                                               nss.coll() == "system.indexes" ) );
        }
        else {
            entry->recordStore.reset( new SimpleRecordStoreV1( txn,
                                                               ns,
                                                               md.release(),
                                                               &_extentManager,
                                                               nss.coll() == "system.indexes" ) );
        }
    }
void FeatureCompatibilityVersion::_runUpdateCommand(OperationContext* opCtx,
                                                    UpdateBuilder builder) {
    DBDirectClient client(opCtx);
    NamespaceString nss(NamespaceString::kServerConfigurationNamespace);

    BSONObjBuilder updateCmd;
    updateCmd.append("update", nss.coll());
    {
        BSONArrayBuilder updates(updateCmd.subarrayStart("updates"));
        {
            BSONObjBuilder updateSpec(updates.subobjStart());
            {
                BSONObjBuilder queryFilter(updateSpec.subobjStart("q"));
                queryFilter.append("_id", FeatureCompatibilityVersionParser::kParameterName);
            }
            {
                BSONObjBuilder updateMods(updateSpec.subobjStart("u"));
                builder(std::move(updateMods));
            }
            updateSpec.appendBool("upsert", true);
        }
    }
    updateCmd.append(WriteConcernOptions::kWriteConcernField, WriteConcernOptions::Majority);

    // Update the featureCompatibilityVersion document stored in the server configuration
    // collection.
    BSONObj updateResult;
    client.runCommand(nss.db().toString(), updateCmd.obj(), updateResult);
    uassertStatusOK(getStatusFromWriteCommandReply(updateResult));
}
Пример #5
0
        virtual bool run(OperationContext* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
            string coll = cmdObj[ "captrunc" ].valuestrsafe();
            uassert( 13416, "captrunc must specify a collection", !coll.empty() );
            NamespaceString nss( dbname, coll );
            int n = cmdObj.getIntField( "n" );
            bool inc = cmdObj.getBoolField( "inc" ); // inclusive range?

            Client::WriteContext ctx(txn,  nss.ns() );
            Collection* collection = ctx.ctx().db()->getCollection( txn, nss.ns() );
            massert( 13417, "captrunc collection not found or empty", collection);

            boost::scoped_ptr<PlanExecutor> exec(
                InternalPlanner::collectionScan(txn, nss.ns(), collection,
                                                InternalPlanner::BACKWARD));

            DiskLoc end;
            // We remove 'n' elements so the start is one past that
            for( int i = 0; i < n + 1; ++i ) {
                PlanExecutor::ExecState state = exec->getNext(NULL, &end);
                massert( 13418, "captrunc invalid n", PlanExecutor::ADVANCED == state);
            }
            collection->temp_cappedTruncateAfter( txn, end, inc );
            ctx.commit();
            return true;
        }
Пример #6
0
void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* txn) {
    std::vector<std::string> dbNames;
    StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine();
    storageEngine->listDatabases(&dbNames);

    for (auto&& dbName : dbNames) {
        if (dbName != "local") {
            return;
        }
    }

    if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) {

        // Insert featureCompatibilityDocument into admin.system.version.
        // Do not use writeConcern majority, because we may be holding locks.
        NamespaceString nss(FeatureCompatibilityVersion::kCollection);
        DBDirectClient client(txn);
        BSONObj result;
        client.runCommand(
            nss.db().toString(),
            BSON("insert" << nss.coll() << "documents"
                          << BSON_ARRAY(BSON("_id" << FeatureCompatibilityVersion::kParameterName
                                                   << FeatureCompatibilityVersion::kVersionField
                                                   << FeatureCompatibilityVersion::kVersion34))),
            result);
        auto status = getStatusFromCommandResult(result);
        if (!status.isOK() && status != ErrorCodes::InterruptedAtShutdown) {
            uassertStatusOK(status);
        }

        // Update server parameter.
        serverGlobalParams.featureCompatibilityVersion.store(
            ServerGlobalParams::FeatureCompatibilityVersion_34);
    }
}
void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* opCtx,
                                                    repl::StorageInterface* storageInterface) {
    if (!isCleanStartUp())
        return;

    // If the server was not started with --shardsvr, the default featureCompatibilityVersion on
    // clean startup is the upgrade version. If it was started with --shardsvr, the default
    // featureCompatibilityVersion is the downgrade version, so that it can be safely added to a
    // downgrade version cluster. The config server will run setFeatureCompatibilityVersion as part
    // of addShard.
    const bool storeUpgradeVersion = serverGlobalParams.clusterRole != ClusterRole::ShardServer;

    UnreplicatedWritesBlock unreplicatedWritesBlock(opCtx);
    NamespaceString nss(NamespaceString::kServerConfigurationNamespace);

    {
        CollectionOptions options;
        options.uuid = CollectionUUID::gen();
        uassertStatusOK(storageInterface->createCollection(opCtx, nss, options));
    }

    // We then insert the featureCompatibilityVersion document into the server configuration
    // collection. The server parameter will be updated on commit by the op observer.
    uassertStatusOK(storageInterface->insertDocument(
        opCtx,
        nss,
        repl::TimestampedBSONObj{
            BSON("_id" << FeatureCompatibilityVersionParser::kParameterName
                       << FeatureCompatibilityVersionParser::kVersionField
                       << (storeUpgradeVersion ? FeatureCompatibilityVersionParser::kVersion40
                                               : FeatureCompatibilityVersionParser::kVersion36)),
            Timestamp()},
        repl::OpTime::kUninitializedTerm));  // No timestamp or term because this write is not
                                             // replicated.
}
Пример #8
0
void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) {
    uassert(40284,
            "featureCompatibilityVersion must be '3.4' or '3.2'",
            version == FeatureCompatibilityVersion::kVersion34 ||
                version == FeatureCompatibilityVersion::kVersion32);

    // Update admin.system.version.
    NamespaceString nss(FeatureCompatibilityVersion::kCollection);
    BSONObjBuilder updateCmd;
    updateCmd.append("update", nss.coll());
    updateCmd.append(
        "updates",
        BSON_ARRAY(BSON("q" << BSON("_id" << FeatureCompatibilityVersion::kParameterName) << "u"
                            << BSON(FeatureCompatibilityVersion::kVersionField << version)
                            << "upsert"
                            << true)));
    updateCmd.append("writeConcern",
                     BSON("w"
                          << "majority"));
    DBDirectClient client(txn);
    BSONObj result;
    client.runCommand(nss.db().toString(), updateCmd.obj(), result);
    uassertStatusOK(getStatusFromCommandResult(result));
    uassertStatusOK(getWriteConcernStatusFromCommandResult(result));

    // Update server parameter.
    if (version == FeatureCompatibilityVersion::kVersion34) {
        serverGlobalParams.featureCompatibilityVersion.store(
            ServerGlobalParams::FeatureCompatibilityVersion_34);
    } else if (version == FeatureCompatibilityVersion::kVersion32) {
        serverGlobalParams.featureCompatibilityVersion.store(
            ServerGlobalParams::FeatureCompatibilityVersion_32);
    }
}
    RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getRecordStore( OperationContext* txn,
                                                                   const StringData& ns ) {

        // XXX TODO - CACHE

        NamespaceString nss( ns );
        NamespaceDetails* details = _namespaceIndex.details( ns );
        if ( !details ) {
            return NULL;
        }

        auto_ptr<NamespaceDetailsRSV1MetaData> md( new NamespaceDetailsRSV1MetaData( ns,
                                                                                     details,
                                                                                     _getNamespaceRecordStore( txn, ns ) ) );

        if ( details->isCapped ) {
            return new CappedRecordStoreV1( txn,
                                            NULL, //TOD(ERH) this will blow up :)
                                            ns,
                                            md.release(),
                                            &_extentManager,
                                            nss.coll() == "system.indexes" );
        }

        return new SimpleRecordStoreV1( txn,
                                        ns,
                                        md.release(),
                                        &_extentManager,
                                        nss.coll() == "system.indexes" );
    }
Пример #10
0
    void run() {
        string ns = "unittests.rollback_create_collection";
        const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
        OperationContext& opCtx = *opCtxPtr;
        NamespaceString nss(ns);
        dropDatabase(&opCtx, nss);

        Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X);
        OldClientContext ctx(&opCtx, ns);
        {
            WriteUnitOfWork uow(&opCtx);
            ASSERT(!collectionExists(&ctx, ns));
            auto options = capped ? BSON("capped" << true << "size" << 1000) : BSONObj();
            ASSERT_OK(userCreateNS(
                &opCtx, ctx.db(), ns, options, CollectionOptions::parseForCommand, defaultIndexes));
            ASSERT(collectionExists(&ctx, ns));
            if (!rollback) {
                uow.commit();
            }
        }
        if (rollback) {
            ASSERT(!collectionExists(&ctx, ns));
        } else {
            ASSERT(collectionExists(&ctx, ns));
        }
    }
Пример #11
0
 Status checkAuthForCommand(ClientBasic* client,
                            const std::string& dbname,
                            const BSONObj& cmdObj) override {
     NamespaceString nss(parseNs(dbname, cmdObj));
     auto hasTerm = cmdObj.hasField(kTermField);
     return AuthorizationSession::get(client)->checkAuthForFind(nss, hasTerm);
 }
Пример #12
0
Collection* Database::createCollection(OperationContext* txn,
                                       StringData ns,
                                       const CollectionOptions& options,
                                       bool createIdIndex) {
    massert(17399, "collection already exists", getCollection(ns) == NULL);
    massertNamespaceNotIndex(ns, "createCollection");
    invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X));

    if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer &&
        !(ns.startsWith("config.") || ns.startsWith("local.") || ns.startsWith("admin."))) {
        uasserted(14037, "can't create user databases on a --configsvr instance");
    }

    if (NamespaceString::normal(ns)) {
        // This check only applies for actual collections, not indexes or other types of ns.
        uassert(17381,
                str::stream() << "fully qualified namespace " << ns << " is too long "
                              << "(max is "
                              << NamespaceString::MaxNsCollectionLen
                              << " bytes)",
                ns.size() <= NamespaceString::MaxNsCollectionLen);
    }

    NamespaceString nss(ns);
    uassert(17316, "cannot create a blank collection", nss.coll() > 0);
    uassert(28838, "cannot create a non-capped oplog collection", options.capped || !nss.isOplog());

    audit::logCreateCollection(&cc(), ns);

    txn->recoveryUnit()->registerChange(new AddCollectionChange(txn, this, ns));

    Status status = _dbEntry->createCollection(txn, ns, options, true /*allocateDefaultSpace*/);
    massertNoTraceStatusOK(status);


    Collection* collection = _getOrCreateCollectionInstance(txn, ns);
    invariant(collection);
    _collections[ns] = collection;

    if (createIdIndex) {
        if (collection->requiresIdIndex()) {
            if (options.autoIndexId == CollectionOptions::YES ||
                options.autoIndexId == CollectionOptions::DEFAULT) {
                IndexCatalog* ic = collection->getIndexCatalog();
                uassertStatusOK(ic->createIndexOnEmptyCollection(txn, ic->getDefaultIdIndexSpec()));
            }
        }

        if (nss.isSystem()) {
            authindex::createSystemIndexes(txn, collection);
        }
    }

    auto opObserver = getGlobalServiceContext()->getOpObserver();
    if (opObserver)
        opObserver->onCreateCollection(txn, nss, options);

    return collection;
}
Пример #13
0
 string Command::parseNsFullyQualified(const string& dbname, const BSONObj& cmdObj) const { 
     string s = cmdObj.firstElement().valuestr();
     NamespaceString nss(s);
     // these are for security, do not remove:
     massert(15962, "need to specify namespace" , !nss.db.empty() );
     massert(15966, str::stream() << "dbname not ok in Command::parseNsFullyQualified: " << dbname , dbname == nss.db || dbname == "admin" );
     return s;
 }
Пример #14
0
    bool ClusterWriteCmd::run( const string& dbName,
                               BSONObj& cmdObj,
                               int options,
                               string& errMsg,
                               BSONObjBuilder& result,
                               bool ) {

        BatchedCommandRequest request( _writeType );
        BatchedCommandResponse response;

        // TODO: if we do namespace parsing, push this to the type
        if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) {
            // Batch parse failure
            response.setOk( false );
            response.setN( 0 );
            response.setErrCode( ErrorCodes::FailedToParse );
            response.setErrMessage( errMsg );

            dassert( response.isValid( &errMsg ) );
            result.appendElements( response.toBSON() );

            // TODO
            // There's a pending issue about how to report response here. If we use
            // the command infra-structure, we should reuse the 'errmsg' field. But
            // we have already filed that message inside the BatchCommandResponse.
            // return response.getOk();
            return true;
        }

        NamespaceString nss( dbName, request.getNS() );
        request.setNS( nss.ns() );

        // App-level validation of a create index insert
        if ( request.isInsertIndexRequest() ) {
            if ( request.sizeWriteOps() != 1 || request.isWriteConcernSet() ) {
                // Invalid request to create index
                response.setOk( false );
                response.setN( 0 );
                response.setErrCode( ErrorCodes::CannotCreateIndex );
                response.setErrMessage( "invalid batch request for index creation" );

                dassert( response.isValid( &errMsg ) );
                result.appendElements( response.toBSON() );

                return false;
            }
        }

        clusterWrite( request, &response, true /* autosplit */ );
        result.appendElements( response.toBSON() );

        // TODO
        // There's a pending issue about how to report response here. If we use
        // the command infra-structure, we should reuse the 'errmsg' field. But
        // we have already filed that message inside the BatchCommandResponse.
        // return response.getOk();
        return true;
    }
Пример #15
0
    void run() {
        string ns = "unittests.rollback_set_index_head";
        const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
        OperationContext& opCtx = *opCtxPtr;
        NamespaceString nss(ns);
        dropDatabase(&opCtx, nss);
        createCollection(&opCtx, nss);

        AutoGetDb autoDb(&opCtx, nss.db(), MODE_X);

        Collection* coll = autoDb.getDb()->getCollection(&opCtx, nss);
        IndexCatalog* catalog = coll->getIndexCatalog();

        string idxName = "a";
        BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName << "v"
                                 << static_cast<int>(kIndexVersion));

        {
            WriteUnitOfWork uow(&opCtx);
            ASSERT_OK(catalog->createIndexOnEmptyCollection(&opCtx, spec));
            uow.commit();
        }

        IndexDescriptor* indexDesc = catalog->findIndexByName(&opCtx, idxName);
        invariant(indexDesc);
        const IndexCatalogEntry* ice = catalog->getEntry(indexDesc);
        invariant(ice);
        HeadManager* headManager = ice->headManager();

        const RecordId oldHead = headManager->getHead(&opCtx);
        ASSERT_EQ(oldHead, ice->head(&opCtx));

        const RecordId dummyHead(123, 456);
        ASSERT_NE(oldHead, dummyHead);

        // END SETUP / START TEST

        {
            WriteUnitOfWork uow(&opCtx);

            headManager->setHead(&opCtx, dummyHead);

            ASSERT_EQ(ice->head(&opCtx), dummyHead);
            ASSERT_EQ(headManager->getHead(&opCtx), dummyHead);

            if (!rollback) {
                uow.commit();
            }
        }

        if (rollback) {
            ASSERT_EQ(ice->head(&opCtx), oldHead);
            ASSERT_EQ(headManager->getHead(&opCtx), oldHead);
        } else {
            ASSERT_EQ(ice->head(&opCtx), dummyHead);
            ASSERT_EQ(headManager->getHead(&opCtx), dummyHead);
        }
    }
Пример #16
0
void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) {
    uassert(40284,
            "featureCompatibilityVersion must be '3.4' or '3.2'. See "
            "http://dochub.mongodb.org/core/3.4-feature-compatibility.",
            version == FeatureCompatibilityVersionCommandParser::kVersion34 ||
                version == FeatureCompatibilityVersionCommandParser::kVersion32);

    DBDirectClient client(txn);
    NamespaceString nss(FeatureCompatibilityVersion::kCollection);

    if (version == FeatureCompatibilityVersionCommandParser::kVersion34) {
        // We build a v=2 index on the "admin.system.version" collection as part of setting the
        // featureCompatibilityVersion to 3.4. This is a new index version that isn't supported by
        // versions of MongoDB earlier than 3.4 that will cause 3.2 secondaries to crash when it is
        // replicated.
        std::vector<BSONObj> indexSpecs{k32IncompatibleIndexSpec};

        {
            ScopedTransaction transaction(txn, MODE_IX);
            AutoGetOrCreateDb autoDB(txn, nss.db(), MODE_X);

            uassert(ErrorCodes::NotMaster,
                    str::stream() << "Cannot set featureCompatibilityVersion to '" << version
                                  << "'. Not primary while attempting to create index on: "
                                  << nss.ns(),
                    repl::ReplicationCoordinator::get(txn->getServiceContext())
                        ->canAcceptWritesFor(nss));

            IndexBuilder builder(k32IncompatibleIndexSpec, false);
            auto status = builder.buildInForeground(txn, autoDB.getDb());
            uassertStatusOK(status);

            MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
                WriteUnitOfWork wuow(txn);
                getGlobalServiceContext()->getOpObserver()->onCreateIndex(
                    txn, autoDB.getDb()->getSystemIndexesName(), k32IncompatibleIndexSpec, false);
                wuow.commit();
            }
            MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "FeatureCompatibilityVersion::set", nss.ns());
        }

        // We then update the featureCompatibilityVersion document stored in the
        // "admin.system.version" collection. We do this after creating the v=2 index in order to
        // maintain the invariant that if the featureCompatibilityVersion is 3.4, then
        // 'k32IncompatibleIndexSpec' index exists on the "admin.system.version" collection.
        BSONObj updateResult;
        client.runCommand(nss.db().toString(),
                          makeUpdateCommand(version, WriteConcernOptions::Majority),
                          updateResult);
        uassertStatusOK(getStatusFromCommandResult(updateResult));
        uassertStatusOK(getWriteConcernStatusFromCommandResult(updateResult));

        // We then update the value of the featureCompatibilityVersion server parameter.
        serverGlobalParams.featureCompatibility.version.store(
            ServerGlobalParams::FeatureCompatibility::Version::k34);
    } else if (version == FeatureCompatibilityVersionCommandParser::kVersion32) {
Пример #17
0
TEST_F(SyncTailTest, MultiInitialSyncApplyPassesThroughSyncApplyErrorAfterFailingToRetryBadOp) {
    SyncTailWithLocalDocumentFetcher syncTail(BSON("_id" << 0 << "x" << 1));
    NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName());
    OplogEntry op(BSON("op"
                       << "x"
                       << "ns"
                       << nss.ns()));
    MultiApplier::OperationPtrs ops = {&op};
    ASSERT_EQUALS(ErrorCodes::BadValue, multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail));
}
Пример #18
0
    void Request::process( int attempt ) {
        init();
        int op = _m.operation();
        verify( op > dbMsg );

        int msgId = (int)(_m.header()->id);

        Timer t;
        LOG(3) << "Request::process begin ns: " << getns()
               << " msg id: " << msgId
               << " op: " << op
               << " attempt: " << attempt
               << endl;

        _d.markSet();

        bool iscmd = false;
        if ( op == dbKillCursors ) {
            cursorCache.gotKillCursors( _m );
            globalOpCounters.gotOp( op , iscmd );
        }
        else if ( op == dbQuery ) {
            NamespaceString nss(getns());
            iscmd = nss.isCommand() || nss.isSpecialCommand();

            if (iscmd) {
                int n = _d.getQueryNToReturn();
                uassert( 16978, str::stream() << "bad numberToReturn (" << n
                                              << ") for $cmd type ns - can only be 1 or -1",
                         n == 1 || n == -1 );

                STRATEGY->clientCommandOp(*this);
            }
            else {
                STRATEGY->queryOp( *this );
            }

            globalOpCounters.gotOp( op , iscmd );
        }
        else if ( op == dbGetMore ) {
            STRATEGY->getMore( *this );
            globalOpCounters.gotOp( op , iscmd );
        }
        else {
            STRATEGY->writeOp( op, *this );
            // globalOpCounters are handled by write commands.
        }

        LOG(3) << "Request::process end ns: " << getns()
               << " msg id: " << msgId
               << " op: " << op
               << " attempt: " << attempt
               << " " << t.millis() << "ms"
               << endl;
    }
Пример #19
0
    Collection* Database::createCollection( OperationContext* txn,
                                            const StringData& ns,
                                            const CollectionOptions& options,
                                            bool allocateDefaultSpace,
                                            bool createIdIndex ) {
        massert( 17399, "collection already exists", getCollection( txn, ns ) == NULL );
        massertNamespaceNotIndex( ns, "createCollection" );

        if ( serverGlobalParams.configsvr &&
             !( ns.startsWith( "config." ) ||
                ns.startsWith( "local." ) ||
                ns.startsWith( "admin." ) ) ) {
            uasserted(14037, "can't create user databases on a --configsvr instance");
        }

        if (NamespaceString::normal(ns)) {
            // This check only applies for actual collections, not indexes or other types of ns.
            uassert(17381, str::stream() << "fully qualified namespace " << ns << " is too long "
                                         << "(max is " << NamespaceString::MaxNsCollectionLen << " bytes)",
                    ns.size() <= NamespaceString::MaxNsCollectionLen);
        }

        NamespaceString nss( ns );
        uassert( 17316, "cannot create a blank collection", nss.coll() > 0 );

        audit::logCreateCollection( currentClient.get(), ns );

        txn->recoveryUnit()->registerChange( new AddCollectionChange(this, ns) );

        Status status = _dbEntry->createCollection(txn, ns,
                                                options, allocateDefaultSpace);
        massertStatusOK(status);

        Collection* collection = getCollection(txn, ns);
        invariant(collection);

        if ( createIdIndex ) {
            if ( collection->requiresIdIndex() ) {
                if ( options.autoIndexId == CollectionOptions::YES ||
                     options.autoIndexId == CollectionOptions::DEFAULT ) {
                    IndexCatalog* ic = collection->getIndexCatalog();
                    uassertStatusOK(
                        ic->createIndexOnEmptyCollection(txn, ic->getDefaultIdIndexSpec()));
                }
            }

            if ( nss.isSystem() ) {
                authindex::createSystemIndexes( txn, collection );
            }

        }

        return collection;
    }
Пример #20
0
void ChunkManager::calcInitSplitsAndShards(OperationContext* txn,
                                           const ShardId& primaryShardId,
                                           const vector<BSONObj>* initPoints,
                                           const set<ShardId>* initShardIds,
                                           vector<BSONObj>* splitPoints,
                                           vector<ShardId>* shardIds) const {
    verify(_chunkMap.size() == 0);

    Chunk c(this,
            _keyPattern.getKeyPattern().globalMin(),
            _keyPattern.getKeyPattern().globalMax(),
            primaryShardId);

    if (!initPoints || !initPoints->size()) {
        // discover split points
        const auto primaryShard = grid.shardRegistry()->getShard(txn, primaryShardId);
        auto targetStatus =
            primaryShard->getTargeter()->findHost({ReadPreference::PrimaryPreferred, TagSet{}});
        uassertStatusOK(targetStatus);

        NamespaceString nss(getns());
        auto result = grid.shardRegistry()->runCommand(
            txn, targetStatus.getValue(), nss.db().toString(), BSON("count" << nss.coll()));

        long long numObjects = 0;
        uassertStatusOK(result.getStatus());
        uassertStatusOK(Command::getStatusFromCommandResult(result.getValue()));
        uassertStatusOK(bsonExtractIntegerField(result.getValue(), "n", &numObjects));

        if (numObjects > 0)
            c.pickSplitVector(txn, *splitPoints, Chunk::MaxChunkSize);

        // since docs already exists, must use primary shard
        shardIds->push_back(primaryShardId);
    } else {
        // make sure points are unique and ordered
        set<BSONObj> orderedPts;
        for (unsigned i = 0; i < initPoints->size(); ++i) {
            BSONObj pt = (*initPoints)[i];
            orderedPts.insert(pt);
        }
        for (set<BSONObj>::iterator it = orderedPts.begin(); it != orderedPts.end(); ++it) {
            splitPoints->push_back(*it);
        }

        if (!initShardIds || !initShardIds->size()) {
            // If not specified, only use the primary shard (note that it's not safe for mongos
            // to put initial chunks on other shards without the primary mongod knowing).
            shardIds->push_back(primaryShardId);
        } else {
            std::copy(initShardIds->begin(), initShardIds->end(), std::back_inserter(*shardIds));
        }
    }
}
Пример #21
0
TEST_F(SyncTailTest, MultiSyncApplyFallsBackOnApplyingInsertsIndividuallyWhenGroupedInsertFails) {
    int seconds = 0;
    auto makeOp = [&seconds](const NamespaceString& nss) {
        return makeInsertDocumentOplogEntry(
            {Timestamp(Seconds(seconds), 0), 1LL}, nss, BSON("_id" << seconds++));
    };
    NamespaceString nss("test." + _agent.getSuiteName() + "_" + _agent.getTestName() + "_1");
    auto createOp = makeCreateCollectionOplogEntry({Timestamp(Seconds(seconds++), 0), 1LL}, nss);

    // Generate operations to apply:
    // {create}, {insert_1}, {insert_2}, .. {insert_(limit)}, {insert_(limit+1)}
    std::size_t limit = 64;
    MultiApplier::Operations insertOps;
    for (std::size_t i = 0; i < limit + 1; ++i) {
        insertOps.push_back(makeOp(nss));
    }
    MultiApplier::Operations operationsToApply;
    operationsToApply.push_back(createOp);
    std::copy(insertOps.begin(), insertOps.end(), std::back_inserter(operationsToApply));

    std::size_t numFailedGroupedInserts = 0;
    MultiApplier::Operations operationsApplied;
    auto syncApply = [&numFailedGroupedInserts,
                      &operationsApplied](OperationContext*, const BSONObj& op, bool) -> Status {
        // Reject grouped insert operations.
        if (op["o"].type() == BSONType::Array) {
            numFailedGroupedInserts++;
            return {ErrorCodes::OperationFailed, "grouped inserts not supported"};
        }
        operationsApplied.push_back(OplogEntry(op));
        return Status::OK();
    };

    MultiApplier::OperationPtrs ops;
    for (auto&& op : operationsToApply) {
        ops.push_back(&op);
    }
    ASSERT_OK(multiSyncApply_noAbort(_txn.get(), &ops, syncApply));

    // On failing to apply the grouped insert operation, multiSyncApply should apply the operations
    // as given in "operationsToApply":
    // {create}, {insert_1}, {insert_2}, .. {insert_(limit)}, {insert_(limit+1)}
    ASSERT_EQUALS(limit + 2, operationsApplied.size());
    ASSERT_EQUALS(createOp, operationsApplied[0]);

    for (std::size_t i = 0; i < limit + 1; ++i) {
        const auto& insertOp = insertOps[i];
        ASSERT_EQUALS(insertOp, operationsApplied[i + 1]);
    }

    // Ensure that multiSyncApply does not attempt to group remaining operations in first failed
    // grouped insert operation.
    ASSERT_EQUALS(1U, numFailedGroupedInserts);
}
Пример #22
0
TEST_F(SyncTailTest, MultiInitialSyncApplyDisablesDocumentValidationWhileApplyingOperations) {
    SyncTailWithOperationContextChecker syncTail;
    NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName());
    ASSERT_TRUE(_txn->writesAreReplicated());
    ASSERT_FALSE(documentValidationDisabled(_txn.get()));
    ASSERT_FALSE(_txn->lockState()->isBatchWriter());
    auto op = makeUpdateDocumentOplogEntry(
        {Timestamp(Seconds(1), 0), 1LL}, nss, BSON("_id" << 0), BSON("_id" << 0 << "x" << 2));
    MultiApplier::OperationPtrs ops = {&op};
    ASSERT_OK(multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail));
}
Пример #23
0
TEST_F(SyncTailTest, MultiInitialSyncApplyPassesThroughShouldSyncTailRetryError) {
    SyncTail syncTail(nullptr, SyncTail::MultiSyncApplyFunc(), nullptr);
    NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName());
    auto op = makeUpdateDocumentOplogEntry(
        {Timestamp(Seconds(1), 0), 1LL}, nss, BSON("_id" << 0), BSON("_id" << 0 << "x" << 2));
    ASSERT_THROWS_CODE(
        syncTail.shouldRetry(_txn.get(), op.raw), mongo::UserException, ErrorCodes::FailedToParse);
    MultiApplier::OperationPtrs ops = {&op};
    ASSERT_EQUALS(ErrorCodes::FailedToParse,
                  multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail));
}
 RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getIndexRecordStore( OperationContext* txn ) {
     NamespaceString nss( name(), "system.indexes" );
     RecordStoreV1Base* rs = _getRecordStore( txn, nss.ns() );
     if ( rs != NULL )
         return rs;
     CollectionOptions options;
     Status status = createCollection( txn, nss.ns(), options, true );
     massertStatusOK( status );
     rs = _getRecordStore( txn, nss.ns() );
     invariant( rs );
     return rs;
 }
Пример #25
0
TEST_F(SyncTailTest, MultiSyncApplyPassesThroughSyncApplyErrorAfterFailingToApplyOperation) {
    NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName());
    OplogEntry op(BSON("op"
                       << "x"
                       << "ns"
                       << nss.ns()));
    auto syncApply = [](OperationContext*, const BSONObj&, bool) -> Status {
        return {ErrorCodes::OperationFailed, ""};
    };
    MultiApplier::OperationPtrs ops = {&op};
    ASSERT_EQUALS(ErrorCodes::OperationFailed, multiSyncApply_noAbort(_txn.get(), &ops, syncApply));
}
Пример #26
0
NamespaceString Command::parseNsCollectionRequired(const string& dbname,
                                                   const BSONObj& cmdObj) const {
    // Accepts both BSON String and Symbol for collection name per SERVER-16260
    // TODO(kangas) remove Symbol support in MongoDB 3.0 after Ruby driver audit
    BSONElement first = cmdObj.firstElement();
    uassert(40072,
            str::stream() << "collection name has invalid type " << typeName(first.type()),
            first.canonicalType() == canonicalizeBSONType(mongo::String));
    NamespaceString nss(dbname, first.valuestr());
    uassert(ErrorCodes::InvalidNamespace, "Not a valid namespace", nss.isValid());
    return nss;
}
Пример #27
0
Collection* Database::createCollection(OperationContext* txn,
                                       StringData ns,
                                       const CollectionOptions& options,
                                       bool createIdIndex) {
    invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X));
    invariant(!options.isView());

    NamespaceString nss(ns);
    _checkCanCreateCollection(nss, options);
    audit::logCreateCollection(&cc(), ns);

    txn->recoveryUnit()->registerChange(new AddCollectionChange(txn, this, ns));

    Status status = _dbEntry->createCollection(txn, ns, options, true /*allocateDefaultSpace*/);
    massertNoTraceStatusOK(status);


    Collection* collection = _getOrCreateCollectionInstance(txn, ns);
    invariant(collection);
    _collections[ns] = collection;

    if (createIdIndex) {
        if (collection->requiresIdIndex()) {
            if (options.autoIndexId == CollectionOptions::YES ||
                options.autoIndexId == CollectionOptions::DEFAULT) {
                // The creation of the _id index isn't replicated and is instead implicit in the
                // creation of the collection. This means that the version of the _id index to build
                // is technically unspecified. However, we're able to use the
                // featureCompatibilityVersion of this server to determine the default index version
                // to use because we apply commands (opType == 'c') in their own batch. This
                // guarantees the write to the admin.system.version collection from the
                // "setFeatureCompatibilityVersion" command either happens entirely before the
                // collection creation or it happens entirely after.
                const auto featureCompatibilityVersion =
                    serverGlobalParams.featureCompatibilityVersion.load();
                IndexCatalog* ic = collection->getIndexCatalog();
                uassertStatusOK(ic->createIndexOnEmptyCollection(
                    txn, ic->getDefaultIdIndexSpec(featureCompatibilityVersion)));
            }
        }

        if (nss.isSystem()) {
            authindex::createSystemIndexes(txn, collection);
        }
    }

    auto opObserver = getGlobalServiceContext()->getOpObserver();
    if (opObserver)
        opObserver->onCreateCollection(txn, nss, options);

    return collection;
}
TEST_F(KVDropPendingIdentReaperTest, AddDropPendingIdentAcceptsNullDropTimestamp) {
    Timestamp nullDropTimestamp;
    NamespaceString nss("test.foo");
    constexpr auto ident = "myident"_sd;
    auto engine = getEngine();
    KVDropPendingIdentReaper reaper(engine);
    reaper.addDropPendingIdent(nullDropTimestamp, nss, ident);
    ASSERT_EQUALS(nullDropTimestamp, *reaper.getEarliestDropTimestamp());

    auto opCtx = makeOpCtx();
    reaper.dropIdentsOlderThan(opCtx.get(), {Seconds(100), 0});
    ASSERT_EQUALS(1U, engine->droppedIdents.size());
    ASSERT_EQUALS(ident, engine->droppedIdents.front());
}
Пример #29
0
TEST_F(SyncTailTest, MultiSyncApplyUsesLimitWhenGroupingInsertOperation) {
    int seconds = 0;
    auto makeOp = [&seconds](const NamespaceString& nss) {
        return makeInsertDocumentOplogEntry(
            {Timestamp(Seconds(seconds), 0), 1LL}, nss, BSON("_id" << seconds++));
    };
    NamespaceString nss("test." + _agent.getSuiteName() + "_" + _agent.getTestName() + "_1");
    auto createOp = makeCreateCollectionOplogEntry({Timestamp(Seconds(seconds++), 0), 1LL}, nss);

    // Generate operations to apply:
    // {create}, {insert_1}, {insert_2}, .. {insert_(limit)}, {insert_(limit+1)}
    std::size_t limit = 64;
    MultiApplier::Operations insertOps;
    for (std::size_t i = 0; i < limit + 1; ++i) {
        insertOps.push_back(makeOp(nss));
    }
    MultiApplier::Operations operationsToApply;
    operationsToApply.push_back(createOp);
    std::copy(insertOps.begin(), insertOps.end(), std::back_inserter(operationsToApply));
    MultiApplier::Operations operationsApplied;
    auto syncApply = [&operationsApplied](OperationContext*, const BSONObj& op, bool) {
        operationsApplied.push_back(OplogEntry(op));
        return Status::OK();
    };

    MultiApplier::OperationPtrs ops;
    for (auto&& op : operationsToApply) {
        ops.push_back(&op);
    }
    ASSERT_OK(multiSyncApply_noAbort(_txn.get(), &ops, syncApply));

    // multiSyncApply should combine operations as follows:
    // {create}, {grouped_insert}, {insert_(limit+1)}
    ASSERT_EQUALS(3U, operationsApplied.size());
    ASSERT_EQUALS(createOp, operationsApplied[0]);

    const auto& groupedInsertOp = operationsApplied[1];
    ASSERT_EQUALS(insertOps.front().getOpTime(), groupedInsertOp.getOpTime());
    ASSERT_EQUALS(insertOps.front().ns, groupedInsertOp.ns);
    ASSERT_EQUALS(BSONType::Array, groupedInsertOp.o.type());
    auto groupedInsertDocuments = groupedInsertOp.o.Array();
    ASSERT_EQUALS(limit, groupedInsertDocuments.size());
    for (std::size_t i = 0; i < limit; ++i) {
        const auto& insertOp = insertOps[i];
        ASSERT_EQUALS(insertOp.o.Obj(), groupedInsertDocuments[i].Obj());
    }

    // (limit + 1)-th insert operations should not be included in group of first (limit) inserts.
    ASSERT_EQUALS(insertOps.back(), operationsApplied[2]);
}
Пример #30
0
TEST_F(SyncTailTest,
       MultiInitialSyncApplyDoesNotRetryFailedUpdateIfDocumentIsMissingFromSyncSource) {
    BSONObj emptyDoc;
    SyncTailWithLocalDocumentFetcher syncTail(emptyDoc);
    NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName());
    auto op = makeUpdateDocumentOplogEntry(
        {Timestamp(Seconds(1), 0), 1LL}, nss, BSON("_id" << 0), BSON("_id" << 0 << "x" << 2));
    MultiApplier::OperationPtrs ops = {&op};
    ASSERT_OK(multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail));

    // Since the missing document is not found on the sync source, the collection referenced by
    // the failed operation should not be automatically created.
    ASSERT_FALSE(AutoGetCollectionForRead(_txn.get(), nss).getCollection());
}