Exemplo n.º 1
0
AutoGetOrCreateDb::AutoGetOrCreateDb(OperationContext* opCtx, StringData ns, LockMode mode)
    : _dbLock(opCtx, ns, mode), _db(dbHolder().get(opCtx, ns)) {
    invariant(mode == MODE_IX || mode == MODE_X);
    _justCreated = false;
    // If the database didn't exist, relock in MODE_X
    if (_db == NULL) {
        if (mode != MODE_X) {
            _dbLock.relockWithMode(MODE_X);
        }
        _db = dbHolder().openDb(opCtx, ns);
        _justCreated = true;
    }
}
Exemplo n.º 2
0
void profile(OperationContext* txn, const Client& c, int op, CurOp& currentOp) {
    // initialize with 1kb to start, to avoid realloc later
    // doing this outside the dblock to improve performance
    BufBuilder profileBufBuilder(1024);

    try {
        // NOTE: It's kind of weird that we lock the op's namespace, but have to for now since
        // we're sometimes inside the lock already
        Lock::DBWrite lk( currentOp.getNS() );
        if (dbHolder()._isLoaded(nsToDatabase(currentOp.getNS()), storageGlobalParams.dbpath)) {
            Client::Context cx(currentOp.getNS(), storageGlobalParams.dbpath, false);
            _profile(txn, c, cx.db(),
                     currentOp, profileBufBuilder);
        }
        else {
            mongo::log() << "note: not profiling because db went away - probably a close on: "
                         << currentOp.getNS() << endl;
        }
    }
    catch (const AssertionException& assertionEx) {
        warning() << "Caught Assertion while trying to profile " << opToString(op)
                  << " against " << currentOp.getNS()
                  << ": " << assertionEx.toString() << endl;
    }
}
Exemplo n.º 3
0
    /*static*/
    string Database::duplicateUncasedName(const string &name, set< string > *duplicates) {
        if ( duplicates ) {
            duplicates->clear();
        }

        vector<string> others;
        StorageEngine* storageEngine = getGlobalEnvironment()->getGlobalStorageEngine();
        storageEngine->listDatabases(&others);

        set<string> allShortNames;
        dbHolder().getAllShortNames(allShortNames);

        others.insert( others.end(), allShortNames.begin(), allShortNames.end() );

        for ( unsigned i=0; i<others.size(); i++ ) {

            if ( strcasecmp( others[i].c_str() , name.c_str() ) )
                continue;

            if ( strcmp( others[i].c_str() , name.c_str() ) == 0 )
                continue;

            if ( duplicates ) {
                duplicates->insert( others[i] );
            } else {
                return others[i];
            }
        }
        if ( duplicates ) {
            return duplicates->empty() ? "" : *duplicates->begin();
        }
        return "";
    }
Exemplo n.º 4
0
void dropAllDatabasesExceptLocal(OperationContext* txn) {
    ScopedTransaction transaction(txn, MODE_X);
    Lock::GlobalWrite lk(txn->lockState());

    vector<string> n;
    StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine();
    storageEngine->listDatabases(&n);

    if (n.size() == 0)
        return;
    log() << "dropAllDatabasesExceptLocal " << n.size();

    repl::getGlobalReplicationCoordinator()->dropAllSnapshots();
    for (vector<string>::iterator i = n.begin(); i != n.end(); i++) {
        if (*i != "local") {
            MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
                Database* db = dbHolder().get(txn, *i);
                // This is needed since dropDatabase can't be rolled back.
                // This is safe be replaced by "invariant(db);dropDatabase(txn, db);" once fixed
                if (db == nullptr) {
                    log() << "database disappeared after listDatabases but before drop: " << *i;
                } else {
                    Database::dropDatabase(txn, db);
                }
            }
            MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "dropAllDatabasesExceptLocal", *i);
        }
    }
Exemplo n.º 5
0
/*static*/
string Database::duplicateUncasedName( bool inholderlock, const string &name, const string &path, set< string > *duplicates ) {
    Lock::assertAtLeastReadLocked(name);

    if ( duplicates ) {
        duplicates->clear();
    }

    vector<string> others;
    getDatabaseNames( others , path );

    set<string> allShortNames;
    dbHolder().getAllShortNames( allShortNames );

    others.insert( others.end(), allShortNames.begin(), allShortNames.end() );

    for ( unsigned i=0; i<others.size(); i++ ) {

        if ( strcasecmp( others[i].c_str() , name.c_str() ) )
            continue;

        if ( strcmp( others[i].c_str() , name.c_str() ) == 0 )
            continue;

        if ( duplicates ) {
            duplicates->insert( others[i] );
        } else {
            return others[i];
        }
    }
    if ( duplicates ) {
        return duplicates->empty() ? "" : *duplicates->begin();
    }
    return "";
}
Exemplo n.º 6
0
    void IndexBuilder::run() {
        Client::initThread(name().c_str());
        LOG(2) << "IndexBuilder building index " << _index;

        OperationContextImpl txn;

        Lock::ParallelBatchWriterMode::iAmABatchParticipant(txn.lockState());

        txn.getClient()->getAuthorizationSession()->grantInternalAuthorization();

        txn.getCurOp()->reset(HostAndPort(), dbInsert);
        NamespaceString ns(_index["ns"].String());

        ScopedTransaction transaction(&txn, MODE_IX);
        Lock::DBLock dlk(txn.lockState(), ns.db(), MODE_X);
        Client::Context ctx(&txn, ns.getSystemIndexesCollection());

        Database* db = dbHolder().get(&txn, ns.db().toString());

        Status status = _build(&txn, db, true, &dlk);
        if ( !status.isOK() ) {
            error() << "IndexBuilder could not build index: " << status.toString();
            fassert(28555, ErrorCodes::isInterruption(status.code()));
        }

        txn.getClient()->shutdown();
    }
Exemplo n.º 7
0
    void AutoGetCollectionForRead::_init() {
        massert(28535, "need a non-empty collection name", !_nss.coll().empty());

        // TODO: Client::Context legacy, needs to be removed
        _txn->getCurOp()->ensureStarted();
        _txn->getCurOp()->setNS(_nss.toString());

        // Lock both the DB and the collection (DB is locked in the constructor), because this is
        // necessary in order to to shard version checking.
        const ResourceId resId(RESOURCE_COLLECTION, _nss);
        const LockMode collLockMode = supportsDocLocking() ? MODE_IS : MODE_S;

        invariant(LOCK_OK == _txn->lockState()->lock(resId, collLockMode));

        // Shard version check needs to be performed under the collection lock
        ensureShardVersionOKOrThrow(_nss);

        // At this point, we are locked in shared mode for the database by the DB lock in the
        // constructor, so it is safe to load the DB pointer.
        _db = dbHolder().get(_txn, _nss.db());
        if (_db != NULL) {
            // TODO: Client::Context legacy, needs to be removed
            _txn->getCurOp()->enter(_nss.toString().c_str(), _db->getProfilingLevel());

            _coll = _db->getCollection(_txn, _nss);
        }
    }
Exemplo n.º 8
0
    void profile(OperationContext* txn, const Client& c, int op, CurOp& currentOp) {
        // initialize with 1kb to start, to avoid realloc later
        // doing this outside the dblock to improve performance
        BufBuilder profileBufBuilder(1024);

        try {
            // NOTE: It's kind of weird that we lock the op's namespace, but have to for now since
            // we're sometimes inside the lock already
            Lock::DBWrite lk(txn->lockState(), currentOp.getNS() );
            if (dbHolder().get(txn, nsToDatabase(currentOp.getNS())) != NULL) {
                // We are ok with the profiling happening in a different WUOW from the actual op.
                WriteUnitOfWork wunit(txn->recoveryUnit());
                Client::Context cx(txn, currentOp.getNS(), false);
                _profile(txn, c, cx.db(), currentOp, profileBufBuilder);
                wunit.commit();
            }
            else {
                mongo::log() << "note: not profiling because db went away - probably a close on: "
                             << currentOp.getNS() << endl;
            }
        }
        catch (const AssertionException& assertionEx) {
            warning() << "Caught Assertion while trying to profile " << opToString(op)
                      << " against " << currentOp.getNS()
                      << ": " << assertionEx.toString() << endl;
        }
    }
Exemplo n.º 9
0
/*static*/
string Database::duplicateUncasedName(const string& name, set<string>* duplicates) {
    if (duplicates) {
        duplicates->clear();
    }

    set<string> allShortNames;
    dbHolder().getAllShortNames(allShortNames);

    for (const auto& dbname : allShortNames) {
        if (strcasecmp(dbname.c_str(), name.c_str()))
            continue;

        if (strcmp(dbname.c_str(), name.c_str()) == 0)
            continue;

        if (duplicates) {
            duplicates->insert(dbname);
        } else {
            return dbname;
        }
    }
    if (duplicates) {
        return duplicates->empty() ? "" : *duplicates->begin();
    }
    return "";
}
Exemplo n.º 10
0
        bool run(OperationContext* txn,
                 const string& dbname,
                 BSONObj& jsobj,
                 int,
                 string& errmsg,
                 BSONObjBuilder& result,
                 bool /*fromRepl*/) {

            Lock::DBRead lk( txn->lockState(), dbname );

            const Database* d = dbHolder().get( txn, dbname );
            const DatabaseCatalogEntry* dbEntry = NULL;

            list<string> names;
            if ( d ) {
                dbEntry = d->getDatabaseCatalogEntry();
                dbEntry->getCollectionNamespaces( &names );
                names.sort();
            }

            scoped_ptr<MatchExpression> matcher;
            if ( jsobj["filter"].isABSONObj() ) {
                StatusWithMatchExpression parsed =
                    MatchExpressionParser::parse( jsobj["filter"].Obj() );
                if ( !parsed.isOK() ) {
                    return appendCommandStatus( result, parsed.getStatus() );
                }
                matcher.reset( parsed.getValue() );
            }

            BSONArrayBuilder arr;

            for ( list<string>::const_iterator i = names.begin(); i != names.end(); ++i ) {
                string ns = *i;

                StringData collection = nsToCollectionSubstring( ns );
                if ( collection == "system.namespaces" ) {
                    continue;
                }

                BSONObjBuilder b;
                b.append( "name", collection );

                CollectionOptions options =
                    dbEntry->getCollectionCatalogEntry( txn, ns )->getCollectionOptions(txn);
                b.append( "options", options.toBSON() );

                BSONObj maybe = b.obj();
                if ( matcher && !matcher->matchesBSON( maybe ) ) {
                    continue;
                }

                arr.append( maybe );
            }

            result.append( "collections", arr.arr() );

            return true;
        }
Exemplo n.º 11
0
    void Client::Context::_finishInit() {
        _db = dbHolder().openDb(_txn, _ns, &_justCreated);
        invariant(_db);

        if( _doVersion ) checkNotStale();

        _client->_curOp->enter(_ns.c_str(), _db->getProfilingLevel());
    }
Exemplo n.º 12
0
    void Client::Context::_finishInit() {
        _db = dbHolder().getOrCreate(_txn, _ns, _justCreated);
        invariant(_db);

        if( _doVersion ) checkNotStale();

        _client->_curOp->enter( this );
    }
Exemplo n.º 13
0
    void TxnCompleteHooksImpl::noteTxnAbortedFileOps(const set<string> &namespaces, const set<string> &dbs) {
        for (set<string>::const_iterator i = namespaces.begin(); i != namespaces.end(); i++) {
            const char *ns = i->c_str();

            // We cannot be holding a read lock at this point, since we're in one of two situations:
            // - Single-statement txn is aborting. If it did fileops, it had to hold a write lock,
            //   and therefore it still is.
            // - Multi-statement txn is aborting. The only way to do this is through a command that
            //   takes no lock, therefore we're not read locked.
            verify(!Lock::isReadLocked());

            // If something is already write locked we must be in the single-statement case, so
            // assert that the write locked namespace is this one.
            if (Lock::somethingWriteLocked()) {
                verify(Lock::isWriteLocked(ns));
            }

            // The ydb requires that a txn closes any dictionaries it created beforeaborting.
            // Hold a write lock while trying to close the namespace in the nsindex.
            Lock::DBWrite lk(ns);
            if (dbHolder().__isLoaded(ns, dbpath)) {
                scoped_ptr<Client::Context> ctx(cc().getContext() == NULL ?
                                                new Client::Context(ns) : NULL);
                // Pass aborting = true to close_ns(), which hints to the implementation
                // that the calling transaction is about to abort.
                (void) nsindex(ns)->close_ns(ns, true);
            }
        }

        for (set<string>::const_iterator it = dbs.begin(); it != dbs.end(); ++it) {
            const string &db = *it;

            // The same locking rules above apply here.
            verify(!Lock::isReadLocked());
            if (Lock::somethingWriteLocked()) {
                verify(Lock::isWriteLocked(db));
            }

            Lock::DBWrite lk(db);
            if (dbHolder().__isLoaded(db, dbpath)) {
                scoped_ptr<Client::Context> ctx(cc().getContext() == NULL ?
                                                new Client::Context(db) : NULL);
                nsindex(db.c_str())->rollbackCreate();
            }
        }
    }
Exemplo n.º 14
0
void OldClientContext::_finishInit() {
    _db = dbHolder().get(_txn, _ns);
    if (_db) {
        _justCreated = false;
    } else {
        invariant(_txn->lockState()->isDbLockedForMode(nsToDatabaseSubstring(_ns), MODE_X));
        _db = dbHolder().openDb(_txn, _ns, &_justCreated);
        invariant(_db);
    }

    if (_doVersion) {
        _checkNotStale();
    }

    stdx::lock_guard<Client> lk(*_txn->getClient());
    CurOp::get(_txn)->enter_inlock(_ns.c_str(), _db->getProfilingLevel());
}
Exemplo n.º 15
0
 // Profile the current op in an alternate transaction
 void lockedDoProfile(const Client& c, int op, CurOp& currentOp) {
     if ( dbHolder().__isLoaded( nsToDatabase( currentOp.getNS() ) , dbpath ) ) {
         Client::Context ctx(currentOp.getNS(), dbpath);
         Client::AlternateTransactionStack altStack;
         Client::Transaction txn(DB_SERIALIZABLE);
         profile(c, op, currentOp);
         txn.commit();
     }
 }
Exemplo n.º 16
0
    void Client::Context::_finishInit() {
        OperationContextImpl txn; // TODO get rid of this once reads require transactions
        _db = dbHolder().getOrCreate(&txn, _ns, _justCreated);
        invariant(_db);

        if( _doVersion ) checkNotStale();

        _client->_curOp->enter( this );
    }
Exemplo n.º 17
0
TEST_F(SyncTailTest, SyncApplyInsertDocumentCollectionMissing) {
    {
        Lock::GlobalWrite globalLock(_txn->lockState());
        bool justCreated = false;
        Database* db = dbHolder().openDb(_txn.get(), "test", &justCreated);
        ASSERT_TRUE(db);
        ASSERT_TRUE(justCreated);
    }
    _testSyncApplyInsertDocument(MODE_X);
}
Exemplo n.º 18
0
        bool run(OperationContext* txn, const string& dbname , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
            vector< string > dbNames;
            globalStorageEngine->listDatabases( &dbNames );

            vector< BSONObj > dbInfos;

            set<string> seen;
            intmax_t totalSize = 0;
            for ( vector< string >::iterator i = dbNames.begin(); i != dbNames.end(); ++i ) {
                BSONObjBuilder b;
                b.append( "name", *i );

                intmax_t size = dbSize( i->c_str() );
                b.append( "sizeOnDisk", (double) size );
                totalSize += size;

                {
                    Client::ReadContext rc(txn, *i );
                    b.appendBool( "empty", rc.ctx().db()->getDatabaseCatalogEntry()->isEmpty() );
                }

                dbInfos.push_back( b.obj() );

                seen.insert( i->c_str() );
            }

            set<string> allShortNames;
            {
                Lock::GlobalRead lk(txn->lockState());
                dbHolder().getAllShortNames(allShortNames);
            }

            for ( set<string>::iterator i = allShortNames.begin(); i != allShortNames.end(); i++ ) {
                string name = *i;

                if ( seen.count( name ) )
                    continue;

                BSONObjBuilder b;
                b.append( "name" , name );
                b.append( "sizeOnDisk" , (double)1.0 );

                {
                    Client::ReadContext ctx(txn, name);
                    b.appendBool( "empty", ctx.ctx().db()->getDatabaseCatalogEntry()->isEmpty() );
                }

                dbInfos.push_back( b.obj() );
            }

            result.append( "databases", dbInfos );
            result.append( "totalSize", double( totalSize ) );
            return true;
        }
Exemplo n.º 19
0
Arquivo: db.cpp Projeto: Machyne/mongo
/**
 * Due to SERVER-23274, versions 3.2.0 through 3.2.4 of MongoDB incorrectly mark the final output
 * collections of aggregations with $out stages as temporary on most replica set secondaries. Rather
 * than risk deleting collections that the user did not intend to be temporary when newer nodes
 * start up or get promoted to be replica set primaries, newer nodes clear the temp flags left by
 * these versions.
 */
bool isSubjectToSERVER23299(OperationContext* txn) {
    // We are already called under global X lock as part of the startup sequence
    invariant(txn->lockState()->isW());

    if (storageGlobalParams.readOnly) {
        return false;
    }

    // Ensure that the local database is open since we are still early in the server startup
    // sequence
    dbHolder().openDb(txn, startupLogCollectionName.db());

    // Only used as a shortcut to obtain a reference to the startup log collection
    AutoGetCollection autoColl(txn, startupLogCollectionName, MODE_IS);

    // No startup log or an empty one means either that the user was not running an affected
    // version, or that they manually deleted the startup collection since they last started an
    // affected version.
    LOG(1) << "Checking node for SERVER-23299 eligibility";
    if (!autoColl.getCollection()) {
        LOG(1) << "Didn't find " << startupLogCollectionName;
        return false;
    }
    LOG(1) << "Checking node for SERVER-23299 applicability - reading startup log";
    BSONObj lastStartupLogDoc;
    if (!Helpers::getLast(txn, startupLogCollectionName.ns().c_str(), lastStartupLogDoc)) {
        return false;
    }
    std::vector<int> versionComponents;
    try {
        for (auto elem : lastStartupLogDoc["buildinfo"]["versionArray"].Obj()) {
            versionComponents.push_back(elem.Int());
        }
        uassert(40050,
                str::stream() << "Expected three elements in buildinfo.versionArray; found "
                              << versionComponents.size(),
                versionComponents.size() >= 3);
    } catch (const DBException& ex) {
        log() << "Last entry of " << startupLogCollectionName
              << " has no well-formed  buildinfo.versionArray field; ignoring " << causedBy(ex);
        return false;
    }
    LOG(1)
        << "Checking node for SERVER-23299 applicability - checking version 3.2.x for x in [0, 4]";
    if (versionComponents[0] != 3)
        return false;
    if (versionComponents[1] != 2)
        return false;
    if (versionComponents[2] > 4)
        return false;
    LOG(1) << "Node eligible for SERVER-23299";
    return true;
}
Exemplo n.º 20
0
    void dropCollection() {
        ScopedTransaction transaction(&_txn, MODE_X);
        Lock::DBLock dbLock(_txn.lockState(), nss.db(), MODE_X);
        Database* database = dbHolder().get(&_txn, nss.db());
        if (!database) {
            return;
        }

        WriteUnitOfWork wuow(&_txn);
        database->dropCollection(&_txn, nss.ns());
        wuow.commit();
    }
Exemplo n.º 21
0
    TEST(DBHelperTests, FindDiskLocs) {

        DBDirectClient client;
        OperationContextImpl txn;

        // Some unique tag we can use to make sure we're pulling back the right data
        OID tag = OID::gen();
        client.remove( ns, BSONObj() );

        int numDocsInserted = 10;
        for ( int i = 0; i < numDocsInserted; ++i ) {
            client.insert( ns, BSON( "_id" << i << "tag" << tag ) );
        }

        long long maxSizeBytes = 1024 * 1024 * 1024;

        set<DiskLoc> locs;
        long long numDocsFound;
        long long estSizeBytes;
        {
            // search _id range (0, 10)
            Lock::DBRead lk(txn.lockState(), ns);

            KeyRange range( ns,
                            BSON( "_id" << 0 ),
                            BSON( "_id" << numDocsInserted ),
                            BSON( "_id" << 1 ) );

            Status result = Helpers::getLocsInRange( &txn,
                                                     range,
                                                     maxSizeBytes,
                                                     &locs,
                                                     &numDocsFound,
                                                     &estSizeBytes );

            ASSERT_EQUALS( result, Status::OK() );
            ASSERT_EQUALS( numDocsFound, numDocsInserted );
            ASSERT_NOT_EQUALS( estSizeBytes, 0 );
            ASSERT_LESS_THAN( estSizeBytes, maxSizeBytes );

            Database* db = dbHolder().get(
                                    &txn, nsToDatabase(range.ns), storageGlobalParams.dbpath);
            const Collection* collection = db->getCollection(&txn, ns);

            // Make sure all the disklocs actually correspond to the right info
            for ( set<DiskLoc>::const_iterator it = locs.begin(); it != locs.end(); ++it ) {
                const BSONObj obj = collection->docFor(*it);
                ASSERT_EQUALS(obj["tag"].OID(), tag);
            }
        }
    }
Exemplo n.º 22
0
OldClientWriteContext::OldClientWriteContext(OperationContext* opCtx, const std::string& ns)
    : _txn(opCtx),
      _nss(ns),
      _autodb(opCtx, _nss.db(), MODE_IX),
      _collk(opCtx->lockState(), ns, MODE_IX),
      _c(opCtx, ns, _autodb.getDb(), _autodb.justCreated()) {
    _collection = _c.db()->getCollection(ns);
    if (!_collection && !_autodb.justCreated()) {
        // relock database in MODE_X to allow collection creation
        _collk.relockAsDatabaseExclusive(_autodb.lock());
        Database* db = dbHolder().get(_txn, ns);
        invariant(db == _c.db());
    }
}
Exemplo n.º 23
0
    void profile(OperationContext* txn, const Client& c, int op, CurOp& currentOp) {
        // initialize with 1kb to start, to avoid realloc later
        // doing this outside the dblock to improve performance
        BufBuilder profileBufBuilder(1024);

        bool tryAgain = false;
        while ( 1 ) {
            try {
                // NOTE: It's kind of weird that we lock the op's namespace, but have to for now
                // since we're sometimes inside the lock already
                const string dbname(nsToDatabase(currentOp.getNS()));
                scoped_ptr<Lock::DBLock> lk;

                // todo: this can be slow, perhaps can re-work
                if ( !txn->lockState()->isDbLockedForMode( dbname, MODE_IX ) ) {
                    lk.reset( new Lock::DBLock( txn->lockState(),
                                                dbname,
                                                tryAgain ? MODE_X : MODE_IX) );
                }
                Database* db = dbHolder().get(txn, dbname);
                if (db != NULL) {
                    // We want the profiling to happen in a different WUOW from the actual op.
                    Lock::CollectionLock clk(txn->lockState(), db->getProfilingNS(), MODE_X);
                    WriteUnitOfWork wunit(txn);
                    Client::Context cx(txn, currentOp.getNS(), false);
                    if ( !_profile(txn, c, cx.db(), currentOp, profileBufBuilder ) && lk.get() ) {
                        if ( tryAgain ) {
                            // we couldn't profile, but that's ok, we should have logged already
                            break;
                        }
                        // we took an IX lock, so now we try again with an X lock
                        tryAgain = true;
                        continue;
                    }
                    wunit.commit();
                }
                else {
                    mongo::log() << "note: not profiling because db went away - "
                                 << "probably a close on: " << currentOp.getNS();
                }
                return;
            }
            catch (const AssertionException& assertionEx) {
                warning() << "Caught Assertion while trying to profile " << opToString(op)
                          << " against " << currentOp.getNS()
                          << ": " << assertionEx.toString() << endl;
                return;
            }
        }
    }
Exemplo n.º 24
0
    bool Database::openExistingFile( int n ) { 
        assert(this);
        Lock::assertWriteLocked(name);
        {
            // must not yet be visible to others as we aren't in the db's write lock and 
            // we will write to _files vector - thus this assert.
            bool loaded = dbHolder().__isLoaded(name, path);
            assert( !loaded );
        }
        // additionally must be in the dbholder mutex (no assert for that yet)

        // todo: why here? that could be bad as we may be read locked only here
        namespaceIndex.init();

        if ( n < 0 || n >= DiskLoc::MaxFiles ) {
            massert( 15924 , str::stream() << "getFile(): bad file number value " << n << " (corrupt db?): run repair", false);
        }

        {
            if( n < (int) _files.size() && _files[n] ) {
                dlog(2) << "openExistingFile " << n << " is already open" << endl;
                return true;
            }
        }

        {
            boost::filesystem::path fullName = fileName( n );
            string fullNameString = fullName.string();
            MongoDataFile *df = new MongoDataFile(n);
            try {
                if( !df->openExisting( fullNameString.c_str() ) ) { 
                    delete df;
                    return false;
                }
            }
            catch ( AssertionException& ) {
                delete df;
                throw;
            }
            while ( n >= (int) _files.size() ) {
                _files.push_back(0);
            }
            _files[n] = df;
        }

        return true;
    }
Exemplo n.º 25
0
    void dropDatabase(OperationContext* txn, Database* db ) {
        invariant( db );

        string name = db->name(); // just to have safe
        LOG(1) << "dropDatabase " << name << endl;

        txn->lockState()->assertWriteLocked( name );

        BackgroundOperation::assertNoBgOpInProgForDb(name.c_str());

        audit::logDropDatabase( currentClient.get(), name );

        dbHolder().close( txn, name );
        db = NULL; // d is now deleted

        getGlobalEnvironment()->getGlobalStorageEngine()->dropDatabase( txn, name );
    }
Exemplo n.º 26
0
    /** "read lock, and set my context, all in one operation" 
     *  This handles (if not recursively locked) opening an unopened database.
     */
    Client::ReadContext::ReadContext(
                OperationContext* txn, const string& ns, bool doVersion) {
        {
            _lk.reset(new Lock::DBRead(txn->lockState(), ns));
            Database *db = dbHolder().get(txn, ns);
            if( db ) {
                _c.reset(new Context(txn, ns, db, doVersion));
                return;
            }
        }

        // we usually don't get here, so doesn't matter how fast this part is
        {
            DEV log(LogComponent::kStorage)
                << "_DEBUG ReadContext db wasn't open, will try to open " << ns << endl;
            if (txn->lockState()->isW()) {
                // write locked already
                WriteUnitOfWork wunit(txn);
                DEV RARELY log(LogComponent::kStorage)
                    << "write locked on ReadContext construction " << ns << endl;
                _c.reset(new Context(txn, ns, doVersion));
                wunit.commit();
            }
            else if (!txn->lockState()->isRecursive()) {
                _lk.reset(0);
                {
                    Lock::GlobalWrite w(txn->lockState());
                    WriteUnitOfWork wunit(txn);
                    Context c(txn, ns, doVersion);
                    wunit.commit();
                }

                // db could be closed at this interim point -- that is ok, we will throw, and don't mind throwing.
                _lk.reset(new Lock::DBRead(txn->lockState(), ns));
                _c.reset(new Context(txn, ns, doVersion));
            }
            else { 
                uasserted(15928, str::stream() << "can't open a database from a nested read lock " << ns);
            }
        }

        // todo: are receipts of thousands of queries for a nonexisting database a potential 
        //       cause of bad performance due to the write lock acquisition above?  let's fix that.
        //       it would be easy to first check that there is at least a .ns file, or something similar.
    }
Exemplo n.º 27
0
    void dropDatabase(OperationContext* txn, Database* db ) {
        invariant( db );

        // Store the name so we have if for after the db object is deleted
        const string name = db->name();
        LOG(1) << "dropDatabase " << name << endl;

        invariant(txn->lockState()->isDbLockedForMode(name, MODE_X));

        BackgroundOperation::assertNoBgOpInProgForDb(name.c_str());

        audit::logDropDatabase( currentClient.get(), name );

        dbHolder().close( txn, name );
        db = NULL; // d is now deleted

        getGlobalEnvironment()->getGlobalStorageEngine()->dropDatabase( txn, name );
    }
Exemplo n.º 28
0
void ServiceContextMongoDTest::_dropAllDBs(OperationContext* opCtx) {
    dropAllDatabasesExceptLocal(opCtx);

    Lock::GlobalWrite lk(opCtx);
    AutoGetDb autoDBLocal(opCtx, "local", MODE_X);
    const auto localDB = autoDBLocal.getDb();
    if (localDB) {
        writeConflictRetry(opCtx, "_dropAllDBs", "local", [&] {
            // Do not wrap in a WriteUnitOfWork until SERVER-17103 is addressed.
            autoDBLocal.getDb()->dropDatabase(opCtx, localDB);
        });
    }

    // dropAllDatabasesExceptLocal() does not close empty databases. However the holder still
    // allocates resources to track these empty databases. These resources not released by
    // dropAllDatabasesExceptLocal() will be leaked at exit unless we call DatabaseHolder::closeAll.
    dbHolder().closeAll(opCtx, "all databases dropped");
}
Exemplo n.º 29
0
        bool run(OperationContext* txn,
                 const string& dbname,
                 BSONObj& jsobj,
                 int,
                 string& errmsg,
                 BSONObjBuilder& result,
                 bool /*fromRepl*/) {

            Lock::DBRead lk( txn->lockState(), dbname );

            const Database* d = dbHolder().get( txn, dbname );
            const DatabaseCatalogEntry* dbEntry = NULL;

            list<string> names;
            if ( d ) {
                dbEntry = d->getDatabaseCatalogEntry();
                dbEntry->getCollectionNamespaces( &names );
                names.sort();
            }

            BSONArrayBuilder arr;

            for ( list<string>::const_iterator i = names.begin(); i != names.end(); ++i ) {
                string ns = *i;

                StringData collection = nsToCollectionSubstring( ns );
                if ( collection == "system.namespaces" ) {
                    continue;
                }

                BSONObjBuilder b;
                b.append( "name", collection );

                CollectionOptions options =
                    dbEntry->getCollectionCatalogEntry( txn, ns )->getCollectionOptions(txn);
                b.append( "options", options.toBSON() );

                arr.append( b.obj() );
            }

            result.append( "collections", arr.arr() );

            return true;
        }
Exemplo n.º 30
0
/**
 * Due to SERVER-23274, versions 3.2.0 through 3.2.4 of MongoDB incorrectly mark the final output
 * collections of aggregations with $out stages as temporary on most replica set secondaries. Rather
 * than risk deleting collections that the user did not intend to be temporary when newer nodes
 * start up or get promoted to be replica set primaries, newer nodes clear the temp flags left by
 * these versions.
 */
bool isSubjectToSERVER23299(OperationContext* txn) {
    if (storageGlobalParams.readOnly) {
        return false;
    }
    dbHolder().openDb(txn, startupLogCollectionName.db());
    AutoGetCollectionForRead autoColl(txn, startupLogCollectionName);
    // No startup log or an empty one means either that the user was not running an affected
    // version, or that they manually deleted the startup collection since they last started an
    // affected version.
    LOG(1) << "Checking node for SERVER-23299 eligibility";
    if (!autoColl.getCollection()) {
        LOG(1) << "Didn't find " << startupLogCollectionName;
        return false;
    }
    LOG(1) << "Checking node for SERVER-23299 applicability - reading startup log";
    BSONObj lastStartupLogDoc;
    if (!Helpers::getLast(txn, startupLogCollectionName.ns().c_str(), lastStartupLogDoc)) {
        return false;
    }
    std::vector<int> versionComponents;
    try {
        for (auto elem : lastStartupLogDoc["buildinfo"]["versionArray"].Obj()) {
            versionComponents.push_back(elem.Int());
        }
        uassert(40050,
                str::stream() << "Expected three elements in buildinfo.versionArray; found "
                              << versionComponents.size(),
                versionComponents.size() >= 3);
    } catch (const DBException& ex) {
        log() << "Last entry of " << startupLogCollectionName
              << " has no well-formed  buildinfo.versionArray field; ignoring " << causedBy(ex);
        return false;
    }
    LOG(1)
        << "Checking node for SERVER-23299 applicability - checking version 3.2.x for x in [0, 4]";
    if (versionComponents[0] != 3)
        return false;
    if (versionComponents[1] != 2)
        return false;
    if (versionComponents[2] > 4)
        return false;
    LOG(1) << "Node eligible for SERVER-23299";
    return true;
}