/** * Copyright (C) 2014 MongoDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #include "mongo/platform/basic.h" #include #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/lock_manager_test_help.h" #include "mongo/unittest/unittest.h" namespace mongo { using std::string; TEST(DConcurrency, GlobalRead) { MMAPV1LockerImpl ls; Lock::GlobalRead globalRead(&ls); ASSERT(ls.isR()); } TEST(DConcurrency, GlobalWrite) { MMAPV1LockerImpl ls; Lock::GlobalWrite globalWrite(&ls); ASSERT(ls.isW()); } TEST(DConcurrency, GlobalWriteAndGlobalRead) { MMAPV1LockerImpl ls; Lock::GlobalWrite globalWrite(&ls); ASSERT(ls.isW()); { Lock::GlobalRead globalRead(&ls); ASSERT(ls.isW()); } ASSERT(ls.isW()); } TEST(DConcurrency, GlobalLockS_Timeout) { MMAPV1LockerImpl ls; Lock::GlobalLock globalWrite(&ls, MODE_X, 0); ASSERT(globalWrite.isLocked()); { MMAPV1LockerImpl lsTry; Lock::GlobalLock globalReadTry(&lsTry, MODE_S, 1); ASSERT(!globalReadTry.isLocked()); } } TEST(DConcurrency, GlobalLockX_Timeout) { MMAPV1LockerImpl ls; Lock::GlobalLock globalWrite(&ls, MODE_X, 0); ASSERT(globalWrite.isLocked()); { MMAPV1LockerImpl lsTry; Lock::GlobalLock globalWriteTry(&lsTry, MODE_X, 1); ASSERT(!globalWriteTry.isLocked()); } } TEST(DConcurrency, GlobalLockS_NoTimeoutDueToGlobalLockS) { MMAPV1LockerImpl ls; Lock::GlobalRead globalRead(&ls); MMAPV1LockerImpl lsTry; Lock::GlobalLock globalReadTry(&lsTry, MODE_S, 1); ASSERT(globalReadTry.isLocked()); } TEST(DConcurrency, GlobalLockX_TimeoutDueToGlobalLockS) { MMAPV1LockerImpl ls; Lock::GlobalRead globalRead(&ls); MMAPV1LockerImpl lsTry; Lock::GlobalLock globalWriteTry(&lsTry, MODE_X, 1); ASSERT(!globalWriteTry.isLocked()); } TEST(DConcurrency, GlobalLockS_TimeoutDueToGlobalLockX) { MMAPV1LockerImpl ls; Lock::GlobalWrite globalWrite(&ls); MMAPV1LockerImpl lsTry; Lock::GlobalLock globalReadTry(&lsTry, MODE_S, 1); ASSERT(!globalReadTry.isLocked()); } TEST(DConcurrency, GlobalLockX_TimeoutDueToGlobalLockX) { MMAPV1LockerImpl ls; Lock::GlobalWrite globalWrite(&ls); MMAPV1LockerImpl lsTry; Lock::GlobalLock globalWriteTry(&lsTry, MODE_X, 1); ASSERT(!globalWriteTry.isLocked()); } TEST(DConcurrency, TempReleaseGlobalWrite) { MMAPV1LockerImpl ls; Lock::GlobalWrite globalWrite(&ls); { Lock::TempRelease tempRelease(&ls); ASSERT(!ls.isLocked()); } ASSERT(ls.isW()); } TEST(DConcurrency, TempReleaseRecursive) { MMAPV1LockerImpl ls; Lock::GlobalWrite globalWrite(&ls); Lock::DBLock lk(&ls, "SomeDBName", MODE_X); { Lock::TempRelease tempRelease(&ls); ASSERT(ls.isW()); ASSERT(ls.isDbLockedForMode("SomeDBName", MODE_X)); } ASSERT(ls.isW()); } TEST(DConcurrency, DBLockTakesS) { MMAPV1LockerImpl ls; Lock::DBLock dbRead(&ls, "db", MODE_S); const ResourceId resIdDb(RESOURCE_DATABASE, string("db")); ASSERT(ls.getLockMode(resIdDb) == MODE_S); } TEST(DConcurrency, DBLockTakesX) { MMAPV1LockerImpl ls; Lock::DBLock dbWrite(&ls, "db", MODE_X); const ResourceId resIdDb(RESOURCE_DATABASE, string("db")); ASSERT(ls.getLockMode(resIdDb) == MODE_X); } TEST(DConcurrency, DBLockTakesISForAdminIS) { DefaultLockerImpl ls; Lock::DBLock dbRead(&ls, "admin", MODE_IS); ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_IS); } TEST(DConcurrency, DBLockTakesSForAdminS) { DefaultLockerImpl ls; Lock::DBLock dbRead(&ls, "admin", MODE_S); ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_S); } TEST(DConcurrency, DBLockTakesXForAdminIX) { DefaultLockerImpl ls; Lock::DBLock dbWrite(&ls, "admin", MODE_IX); ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_X); } TEST(DConcurrency, DBLockTakesXForAdminX) { DefaultLockerImpl ls; Lock::DBLock dbWrite(&ls, "admin", MODE_X); ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_X); } TEST(DConcurrency, MultipleWriteDBLocksOnSameThread) { MMAPV1LockerImpl ls; Lock::DBLock r1(&ls, "db1", MODE_X); Lock::DBLock r2(&ls, "db1", MODE_X); ASSERT(ls.isDbLockedForMode("db1", MODE_X)); } TEST(DConcurrency, MultipleConflictingDBLocksOnSameThread) { MMAPV1LockerImpl ls; Lock::DBLock r1(&ls, "db1", MODE_X); Lock::DBLock r2(&ls, "db1", MODE_S); ASSERT(ls.isDbLockedForMode("db1", MODE_X)); ASSERT(ls.isDbLockedForMode("db1", MODE_S)); } TEST(DConcurrency, IsDbLockedForSMode) { const std::string dbName("db"); MMAPV1LockerImpl ls; Lock::DBLock dbLock(&ls, dbName, MODE_S); ASSERT(ls.isDbLockedForMode(dbName, MODE_IS)); ASSERT(!ls.isDbLockedForMode(dbName, MODE_IX)); ASSERT(ls.isDbLockedForMode(dbName, MODE_S)); ASSERT(!ls.isDbLockedForMode(dbName, MODE_X)); } TEST(DConcurrency, IsDbLockedForXMode) { const std::string dbName("db"); MMAPV1LockerImpl ls; Lock::DBLock dbLock(&ls, dbName, MODE_X); ASSERT(ls.isDbLockedForMode(dbName, MODE_IS)); ASSERT(ls.isDbLockedForMode(dbName, MODE_IX)); ASSERT(ls.isDbLockedForMode(dbName, MODE_S)); ASSERT(ls.isDbLockedForMode(dbName, MODE_X)); } TEST(DConcurrency, IsCollectionLocked_DB_Locked_IS) { const std::string ns("db1.coll"); MMAPV1LockerImpl ls; Lock::DBLock dbLock(&ls, "db1", MODE_IS); { Lock::CollectionLock collLock(&ls, ns, MODE_IS); ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); ASSERT(!ls.isCollectionLockedForMode(ns, MODE_IX)); // TODO: This is TRUE because Lock::CollectionLock converts IS lock to S ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); ASSERT(!ls.isCollectionLockedForMode(ns, MODE_X)); } { Lock::CollectionLock collLock(&ls, ns, MODE_S); ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); ASSERT(!ls.isCollectionLockedForMode(ns, MODE_IX)); ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); ASSERT(!ls.isCollectionLockedForMode(ns, MODE_X)); } } TEST(DConcurrency, IsCollectionLocked_DB_Locked_IX) { const std::string ns("db1.coll"); MMAPV1LockerImpl ls; Lock::DBLock dbLock(&ls, "db1", MODE_IX); { Lock::CollectionLock collLock(&ls, ns, MODE_IX); // TODO: This is TRUE because Lock::CollectionLock converts IX lock to X ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); ASSERT(ls.isCollectionLockedForMode(ns, MODE_IX)); ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); ASSERT(ls.isCollectionLockedForMode(ns, MODE_X)); } { Lock::CollectionLock collLock(&ls, ns, MODE_X); ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); ASSERT(ls.isCollectionLockedForMode(ns, MODE_IX)); ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); ASSERT(ls.isCollectionLockedForMode(ns, MODE_X)); } } } // namespace mongo