Beispiel #1
0
    void Lock::CollectionLock::relockWithMode(LockMode mode, Lock::DBLock& dbLock ) {
        if (supportsDocLocking() || enableCollectionLocking) {
            _lockState->unlock(_id);
        }

        dbLock.relockWithMode( mode );

        if (supportsDocLocking() || enableCollectionLocking) {
            _lockState->lock(_id, mode);
        }
    }
Beispiel #2
0
void Lock::CollectionLock::relockAsDatabaseExclusive(Lock::DBLock& dbLock) {
    if (supportsDocLocking() || enableCollectionLocking) {
        _lockState->unlock(_id);
    }

    dbLock.relockWithMode(MODE_X);

    if (supportsDocLocking() || enableCollectionLocking) {
        // don't need the lock, but need something to unlock in the destructor
        _lockState->lock(_id, MODE_IX);
    }
}
Beispiel #3
0
    bool PlanYieldPolicy::yield(RecordFetcher* fetcher) {
        invariant(_planYielding);

        OperationContext* opCtx = _planYielding->getOpCtx();
        invariant(opCtx);

        // All YIELD_AUTO plans will get here eventually when the elapsed tracker triggers that it's
        // time to yield. Whether or not we will actually yield (doc-level locking systems won't),
        // we need to check if this operation has been interrupted. Throws if the interrupt flag is
        // set.
        opCtx->checkForInterrupt();

        if (supportsDocLocking()) {
            // Doc-level locking is supported, so no need to release locks.
            return true;
        }

        // No need to yield if the collection is NULL.
        if (NULL == _planYielding->collection()) {
            return true;
        }

        _planYielding->saveState();

        // Release and reacquire locks.
        QueryYield::yieldAllLocks(opCtx, fetcher);

        _elapsedTracker.resetLastTime();

        return _planYielding->restoreState(opCtx);
    }
Beispiel #4
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);
        }
    }
Beispiel #5
0
Lock::CollectionLock::CollectionLock(Locker* lockState, StringData ns, LockMode mode)
    : _id(RESOURCE_COLLECTION, ns), _lockState(lockState) {
    massert(28538, "need a non-empty collection name", nsIsFull(ns));

    dassert(_lockState->isDbLockedForMode(nsToDatabaseSubstring(ns),
                                          isSharedLockMode(mode) ? MODE_IS : MODE_IX));
    if (supportsDocLocking()) {
        _lockState->lock(_id, mode);
    } else {
        _lockState->lock(_id, isSharedLockMode(mode) ? MODE_S : MODE_X);
    }
}
Beispiel #6
0
    void WorkingSetCommon::prepareForSnapshotChange(WorkingSet* workingSet) {
        dassert(supportsDocLocking());

        for (WorkingSet::iterator it = workingSet->begin(); it != workingSet->end(); ++it) {
            if (it->state == WorkingSetMember::LOC_AND_IDX) {
                it->isSuspicious = true;
            }
            else if (it->state == WorkingSetMember::LOC_AND_UNOWNED_OBJ) {
                // We already have the data so convert directly to owned state.
                it->obj.setValue(it->obj.value().getOwned());
                it->state = WorkingSetMember::LOC_AND_OWNED_OBJ;
            }
        }
    }
Beispiel #7
0
    void Lock::DBLock::lockDB() {
        const bool isRead = (_mode == newlm::MODE_S || _mode == newlm::MODE_IS);
        TrackLockAcquireTime a(isRead ? 'r' : 'w');

        _lockState->lockGlobal(isRead ? newlm::MODE_IS : newlm::MODE_IX);

        if (supportsDocLocking() || isRead) {
            _lockState->lock(_id, _mode);
        }
        else {
            _lockState->lock(_id, newlm::MODE_X);
        }

        resetTime();
    }
Beispiel #8
0
 Lock::CollectionLock::CollectionLock(Locker* lockState,
                                      const StringData& ns,
                                      LockMode mode)
     : _id(RESOURCE_COLLECTION, ns),
       _lockState(lockState) {
     const bool isRead = (mode == MODE_S || mode == MODE_IS);
     massert(28538, "need a non-empty collection name", nsIsFull(ns));
     dassert(_lockState->isDbLockedForMode(nsToDatabaseSubstring(ns),
                                           isRead ? MODE_IS : MODE_IX));
     if (supportsDocLocking()) {
         _lockState->lock(_id, mode);
     } else if (enableCollectionLocking) {
         _lockState->lock(_id, isRead ? MODE_S : MODE_X);
     }
 }
Beispiel #9
0
void Lock::DBLock::relockWithMode(LockMode newMode) {
    // 2PL would delay the unlocking
    invariant(!_locker->inAWriteUnitOfWork());

    // Not allowed to change global intent
    invariant(!isSharedLockMode(_mode) || isSharedLockMode(newMode));

    _locker->unlock(_id);
    _mode = newMode;

    if (supportsDocLocking() || enableCollectionLocking) {
        invariant(LOCK_OK == _locker->lock(_id, _mode));
    } else {
        invariant(LOCK_OK == _locker->lock(_id, isSharedLockMode(_mode) ? MODE_S : MODE_X));
    }
}
Beispiel #10
0
Lock::CollectionLock::CollectionLock(Locker* lockState,
                                     StringData ns,
                                     LockMode mode,
                                     Date_t deadline)
    : _id(RESOURCE_COLLECTION, ns), _result(LOCK_INVALID), _lockState(lockState) {
    massert(28538, "need a non-empty collection name", nsIsFull(ns));

    dassert(_lockState->isDbLockedForMode(nsToDatabaseSubstring(ns),
                                          isSharedLockMode(mode) ? MODE_IS : MODE_IX));
    LockMode actualLockMode = mode;
    if (!supportsDocLocking()) {
        actualLockMode = isSharedLockMode(mode) ? MODE_S : MODE_X;
    }

    _result = _lockState->lock(_id, actualLockMode, deadline);
    invariant(_result == LOCK_OK || deadline != Date_t::max());
}
Beispiel #11
0
    void Lock::DBRead::unlockDB() {

        if (supportsDocLocking()) {
            if (nsIsFull(_ns)) {
                const newlm::ResourceId resIdCollection(newlm::RESOURCE_COLLECTION, _ns);
                _lockState->unlock(resIdCollection);
            }
        }

        const StringData db = nsToDatabaseSubstring(_ns);
        const newlm::ResourceId resIdDb(newlm::RESOURCE_DATABASE, db);
        _lockState->unlock(resIdDb);

        // The last release reports time the lock was held
        if (_lockState->unlockGlobal()) {
            recordTime();
        }
    }
Beispiel #12
0
    Lock::DBLock::DBLock(Locker* lockState, const StringData& db, LockMode mode)
        : ScopedLock(lockState),
          _id(RESOURCE_DATABASE, db),
          _lockState(lockState),
          _mode(mode) {

        massert(28539, "need a valid database name", !db.empty() && nsIsDbOnly(db));

        const bool isRead = (_mode == MODE_S || _mode == MODE_IS);

        _lockState->lockGlobal(isRead ? MODE_IS : MODE_IX);
        if (supportsDocLocking() || enableCollectionLocking) {
            _lockState->lock(_id, _mode);
        }
        else {
            _lockState->lock(_id, isRead ? MODE_S : MODE_X);
        }
    }
Beispiel #13
0
 Lock::CollectionLock::CollectionLock(Locker* lockState,
                                      const StringData& ns,
                                      newlm::LockMode mode)
     : _id(newlm::RESOURCE_COLLECTION, ns),
       _lockState(lockState) {
     const bool isRead = (mode == newlm::MODE_S || mode == newlm::MODE_IS);
     dassert(!ns.empty());
     dassert(nsIsFull(ns));
     dassert(_lockState->isLockHeldForMode(newlm::ResourceId(newlm::RESOURCE_DATABASE,
                                                             nsToDatabaseSubstring(ns)),
                                           isRead ? newlm::MODE_IS : newlm::MODE_IX));
     if (supportsDocLocking()) {
         _lockState->lock(_id, mode);
     }
     else {
         _lockState->lock(_id, isRead ? newlm::MODE_S : newlm::MODE_X);
     }
 }
Beispiel #14
0
void WorkingSetCommon::prepareForSnapshotChange(WorkingSet* workingSet) {
    dassert(supportsDocLocking());

    for (auto id : workingSet->getAndClearYieldSensitiveIds()) {
        if (workingSet->isFree(id)) {
            continue;
        }

        // We may see the same member twice, so anything we do here should be idempotent.
        WorkingSetMember* member = workingSet->get(id);
        if (member->getState() == WorkingSetMember::LOC_AND_IDX) {
            member->isSuspicious = true;
        } else if (member->getState() == WorkingSetMember::LOC_AND_OBJ) {
            // Need to make sure that the data is owned, as underlying storage can change during a
            // yield.
            member->makeObjOwned();
        }
    }
}
Beispiel #15
0
    void Lock::DBLock::relockWithMode(const LockMode newMode) {
        const bool wasRead = (_mode == MODE_S || _mode == MODE_IS);
        const bool isRead = (newMode == MODE_S || newMode == MODE_IS);

        invariant (!_lockState->inAWriteUnitOfWork()); // 2PL would delay the unlocking
        invariant(!wasRead || isRead); // Not allowed to change global intent

        _lockState->unlock(_id);
        _mode = newMode;

        if (supportsDocLocking() || enableCollectionLocking) {
            _lockState->lock(_id, _mode);
            dassert(_lockState->isLockHeldForMode(_id, _mode));
        }
        else {
            LockMode effectiveMode = isRead ? MODE_S : MODE_X;
            _lockState->lock(_id, effectiveMode);
            dassert(_lockState->isLockHeldForMode(_id, effectiveMode));
        }
    }
Beispiel #16
0
        void run() {
            if ( supportsDocLocking() ) {
                return;
            }

            auto_ptr<PlanExecutor> run(getCollscan());
            BSONObj obj;

            // Read some of it.
            for (int i = 0; i < 10; ++i) {
                ASSERT_EQUALS(PlanExecutor::ADVANCED, run->getNext(&obj, NULL));
                ASSERT_EQUALS(i, obj["foo"].numberInt());
            }

            // Register it.
            run->saveState();
            registerExecutor(run.get());
            // At this point it's safe to yield.  forceYield would do that.  Let's now simulate some
            // stuff going on in the yield.

            // Delete some data, namely the next 2 things we'd expect.
            _client.remove(ns(), BSON("foo" << 10));
            _client.remove(ns(), BSON("foo" << 11));

            // At this point, we're done yielding.  We recover our lock.

            // Unregister the runner.
            deregisterExecutor(run.get());

            // And clean up anything that happened before.
            run->restoreState(&_opCtx);

            // Make sure that the runner moved forward over the deleted data.  We don't see foo==10
            // or foo==11.
            for (int i = 12; i < N(); ++i) {
                ASSERT_EQUALS(PlanExecutor::ADVANCED, run->getNext(&obj, NULL));
                ASSERT_EQUALS(i, obj["foo"].numberInt());
            }

            ASSERT_EQUALS(PlanExecutor::IS_EOF, run->getNext(&obj, NULL));
        }
void WorkingSetCommon::prepareForSnapshotChange(WorkingSet* workingSet) {
    if (!supportsDocLocking()) {
        // Non doc-locking storage engines use invalidations, so we don't need to examine the
        // buffered working set ids. But we do need to clear the set of ids in order to keep our
        // memory utilization in check.
        workingSet->getAndClearYieldSensitiveIds();
        return;
    }

    for (auto id : workingSet->getAndClearYieldSensitiveIds()) {
        if (workingSet->isFree(id)) {
            continue;
        }

        // We may see the same member twice, so anything we do here should be idempotent.
        WorkingSetMember* member = workingSet->get(id);
        if (member->getState() == WorkingSetMember::RID_AND_IDX) {
            member->isSuspicious = true;
        }
    }
}
Beispiel #18
0
    void Lock::DBRead::lockDB() {
        TrackLockAcquireTime a('r');

        const StringData db = nsToDatabaseSubstring(_ns);
        const newlm::ResourceId resIdDb(newlm::RESOURCE_DATABASE, db);

        _lockState->lockGlobal(newlm::MODE_IS);

        if (supportsDocLocking()) {
            _lockState->lock(resIdDb, newlm::MODE_IS);

            if (nsIsFull(_ns)) {
                const newlm::ResourceId resIdCollection(newlm::RESOURCE_COLLECTION, _ns);
                _lockState->lock(resIdCollection, newlm::MODE_IS);
            }
        }
        else {
            _lockState->lock(resIdDb, newlm::MODE_S);
        }

        resetTime();
    }
Beispiel #19
0
Lock::DBLock::DBLock(Locker* locker, StringData db, LockMode mode)
    : _id(RESOURCE_DATABASE, db),
      _locker(locker),
      _mode(mode),
      _globalLock(locker, isSharedLockMode(_mode) ? MODE_IS : MODE_IX, UINT_MAX) {
    massert(28539, "need a valid database name", !db.empty() && nsIsDbOnly(db));

    // Need to acquire the flush lock
    _locker->lockMMAPV1Flush();

    if (supportsDocLocking() || enableCollectionLocking) {
        // The check for the admin db is to ensure direct writes to auth collections
        // are serialized (see SERVER-16092).
        if ((_id == resourceIdAdminDB) && !isSharedLockMode(_mode)) {
            _mode = MODE_X;
        }

        invariant(LOCK_OK == _locker->lock(_id, _mode));
    } else {
        invariant(LOCK_OK == _locker->lock(_id, isSharedLockMode(_mode) ? MODE_S : MODE_X));
    }
}
Beispiel #20
0
void Lock::OplogIntentWriteLock::serializeIfNeeded() {
    if (!supportsDocLocking() && !_serialized) {
        oplogSerialization.lock();
        _serialized = true;
    }
}
Beispiel #21
0
Lock::CollectionLock::~CollectionLock() {
    if (supportsDocLocking() || enableCollectionLocking) {
        _lockState->unlock(_id);
    }
}