Example #1
0
class RWLockTestCase(unittest.TestCase):
    def setUp(self):
        self.lock = RWLock()

    def test_readers(self):
        with self.lock.read_lock():
            self.assertEqual(self.lock.readers, 1)
            self.assertEqual(self.lock.writers, 0)
            self.assertFalse(self.lock.blocked_for_readers)
            self.assertTrue(self.lock.blocked_for_writers)

            # Multiple readers can hold the lock simultaneously
            with self.lock.read_lock():
                self.assertEqual(self.lock.readers, 2)
                self.assertEqual(self.lock.writers, 0)
                self.assertFalse(self.lock.blocked_for_readers)
                self.assertTrue(self.lock.blocked_for_writers)

    def test_writers(self):
        with self.lock.write_lock():
            self.assertEqual(self.lock.readers, 0)
            self.assertEqual(self.lock.writers, 1)
            self.assertTrue(self.lock.blocked_for_readers)
            self.assertTrue(self.lock.blocked_for_writers)

    def test_unlocked(self):
        self.assertEqual(self.lock.readers, 0)
        self.assertEqual(self.lock.writers, 0)
        self.assertFalse(self.lock.blocked_for_readers)
        self.assertFalse(self.lock.blocked_for_writers)
Example #2
0
    def __init__(self, config: configparser.ConfigParser):
        """
        Initialise the handler. The config is provided from the configuration file, which is guaranteed to have a
        [handler] section.

        Objects of this class *MUST* be thread-safe.

        :param config: Contents of the configuration file
        """
        self.config = config

        # Provide a lock so that our state can be protected during a reload
        self.lock = RWLock()

        # Implement initialisation as a reload
        self.handle_reload()
Example #3
0
class MessageHandler(ABC):
    """
    This is the base class for all message handlers. Subclassing this provides the most flexibility but it does require
    the most effort to implement correctly as well.
    """

    def __init__(self, config: configparser.ConfigParser):
        """
        Initialise the handler. The config is provided from the configuration file, which is guaranteed to have a
        [handler] section.

        Objects of this class *MUST* be thread-safe.

        :param config: Contents of the configuration file
        """
        self.config = config

        # Provide a lock so that our state can be protected during a reload
        self.lock = RWLock()

        # Implement initialisation as a reload
        self.handle_reload()

    def reload(self, new_config: configparser.ConfigParser):
        """
        This is called by the server on SIGHUP so the configuration can be reloaded, caches can be cleared etc.

        Subclasses shouldn't overwrite this method but the handle_reload() method, which will automatically be
        protected with a lock.

        :param new_config: The new configuration after the reload
        """
        with self.lock.write_lock():
            self.config = new_config
            self.handle_reload()

    # noinspection PyMethodMayBeStatic
    def handle_reload(self):
        """
        This method can be overwritten by subclasses to handle configuration reloads.
        """
        pass

    @abstractmethod
    def handle(self, received_message: RelayServerMessage, received_over_multicast: bool) -> Message or None:
        """
Example #4
0
 def setUp(self):
     self.lock = RWLock()