Esempio n. 1
0
 def setUp(self):
     self.manager = DefaultLockManager()
     self.lockfunc = lambda x: None
Esempio n. 2
0
def test():
    from pysqlite2.lock_manager import DefaultLockManager, set_lock_manager
    set_lock_manager(DefaultLockManager())
    runner = unittest.TextTestRunner()
    runner.run(suite())
Esempio n. 3
0
class LockManagerTests(unittest.TestCase):

    def setUp(self):
        self.manager = DefaultLockManager()
        self.lockfunc = lambda x: None

    def tearDown(self):
        self.manager = None

    def _print(self, message):
        # print fmt
        pass

    def CheckDisabledByDefault(self):
        """The lock manager is disabled by default."""
        self.assertEqual(get_lock_manager(), None)

    def CheckSharedLocks(self):
        """Check that we can acquire many shared locks concurrently."""
        for client in range(10):
            self.manager.lock(self.lockfunc, "filename", LOCK_SHARED, client)
        self._print(self.manager)
        for client in range(10):
            self.manager.unlock("filename", LOCK_NONE, client)
        self._print(self.manager)
        self.assertTrue(self.manager.is_idle())

    def CheckDetectDeadlock(self):
        """Checks that shared can not be raised to a higher level if a reserved lock exists."""
        self.manager.lock(self.lockfunc, "filename", LOCK_RESERVED, "first")

        self.manager.lock(self.lockfunc, "filename", LOCK_SHARED, "second")
        self.assertRaises(DeadlockError, self.manager.lock, self.lockfunc, "filename", LOCK_RESERVED, "second")
        self.assertRaises(DeadlockError, self.manager.lock, self.lockfunc, "filename", LOCK_EXCLUSIVE, "second")

    def CheckUnlockWithoutLock(self):
        """Checks that unlock without first locking is harmless (SQLite seems to do it sometimes)."""
        self.manager.unlock("filename", LOCK_NONE, "client")

    def CheckRaiseLower(self):
        """Checks that the lock level can go up and down all the way."""
        self.manager.lock(self.lockfunc, "filename", LOCK_SHARED, "client")
        self.manager.lock(self.lockfunc, "filename", LOCK_RESERVED, "client")
        self.manager.lock(self.lockfunc, "filename", LOCK_EXCLUSIVE, "client")
        self.manager.unlock("filename", LOCK_RESERVED, "client")
        self.manager.unlock("filename", LOCK_SHARED, "client")
        self.manager.unlock("filename", LOCK_NONE, "client")
        self.assertTrue(self.manager.is_idle())

    def CheckExclusiveBlocksShared(self):
        """Check that a shared lock must wait while an exclusive lock is set."""
        self.manager.lock(self.lockfunc, "filename", LOCK_EXCLUSIVE, "exclusive")

        def shared_locker():
            self.manager.lock(self.lockfunc, "filename", LOCK_SHARED, "shared")
        t = threading.Thread(target=shared_locker)
        t.start()
        t.join(0.1)
        self._print(self.manager)
        self.assertTrue(t.is_alive())

        self.manager.unlock("filename", LOCK_NONE, "exclusive")
        t.join()
        self._print(self.manager)
        self.assertFalse(self.manager.is_idle())

    def CheckPendingBlocksShared(self):
        """Check that a pending lock blocks further shared locks."""
        self.manager.lock(self.lockfunc, "filename", LOCK_SHARED, "shared_1")
        self.manager.lock(self.lockfunc, "filename", LOCK_SHARED, "shared_2")

        def exclusive_locker():
            self.manager.lock(self.lockfunc, "filename", LOCK_EXCLUSIVE, "exclusive")

        def shared_locker():
            self.manager.lock(self.lockfunc, "filename", LOCK_SHARED, "shared_blocked")


        self._print("An exclusive lock will block now (going to PENDING first)")
        t_exclusive = threading.Thread(target=exclusive_locker)
        t_exclusive.start()
        t_exclusive.join(0.1)
        self._print(self.manager)
        self.assertTrue(t_exclusive.is_alive())
        self.assertEqual(self.manager._filelocks["filename"]._lock_holders["exclusive"], LOCK_PENDING)

        self._print("A shared lock will be added to the end of the queue")
        t_shared = threading.Thread(target=shared_locker)
        t_shared.start()
        t_shared.join(0.1)
        self._print(self.manager)
        self.assertTrue(t_shared.is_alive())
        self.assertTrue("shared_blocked" not in self.manager._filelocks["filename"]._lock_holders)

        self._print("Unblocking the exclusive locker")
        self.manager.unlock("filename", LOCK_NONE, "shared_1")
        self.manager.unlock("filename", LOCK_NONE, "shared_2")
        t_exclusive.join()
        self._print(self.manager)

        # Shared lock must still be blocked
        t_shared.join(0.1)
        self.assertTrue(t_shared.is_alive())
        self.assertTrue("shared_blocked" not in self.manager._filelocks["filename"]._lock_holders)

        self._print("Unblocking the shared locker")
        self.manager.unlock("filename", LOCK_NONE, "exclusive")
        t_shared.join()

        self._print(self.manager)
        self.assertFalse(self.manager.is_idle())
        self.manager.unlock("filename", LOCK_NONE, "shared_blocked")
        self.assertTrue(self.manager.is_idle())

    def CheckMutualExclusion(self):
        """Checks that RESERVED or higher locks are mutually exclusive."""

        def locker_thread(clientname):
            try:
                for level in lock_sequence:
                    self.manager.lock(self.lockfunc, "filename", level, clientname)
                    time.sleep(0.05)
                active_threads.add(threading.current_thread())
                # In case the mutual exclusion does not work, this gives other threads
                # the chance to take over.
                time.sleep(0.1)
                concurrent_threads.append(set(active_threads))
                active_threads.discard(threading.current_thread())
                self.manager.unlock("filename", LOCK_NONE, clientname)
            except Exception, e:
                traceback.print_exc()
                exceptions.append(e)

        for lock_sequence in [LOCK_RESERVED, LOCK_EXCLUSIVE], [LOCK_RESERVED], [LOCK_EXCLUSIVE]:
            active_threads = set()
            concurrent_threads = []
            exceptions = []

            threads = [threading.Thread(target=locker_thread, args=(name,), name=name)
                    for name in ("Locker Thread #{0}".format(i) for i in range(5))]
            for thread in threads:
                thread.start()
            for thread in threads:
                thread.join()
            self.assertFalse(exceptions, "Exceptions in threads for lock sequence {0!r}: {1!r}.".format(lock_sequence, exceptions))
            for entry in concurrent_threads:
                self.assertTrue(len(entry) == 1, "Concurrent threads detected via lock sequence {0!r}: {1!r}".format(lock_sequence, entry))