def run(self):
     self.mutex = LamportMutex(path=self.mutex_path,
                               id=self.id,
                               port=self.port,
                               ids=self.ids,
                               ports=self.ports,
                               logger=self.logger)
     if self.stress_mode:
         self.run_stress_mode()
Beispiel #2
0
    def setUp(self):
        self.mutex_path = '../mutex.txt'
        self.logger = Logger(off=True)
        self.other_ids = [i for i in range(1, 10)]
        self.other_ports = [8100 + i for i in range(1, 10)]

        self.mutex = LamportMutex(self.mutex_path, 0, 8000,
                                  self.other_ids, self.other_ports, self.logger)
        self.mutex.tear_down()  # kill real connection

        # mock API
        mock_api = MockAPI(self.other_ids)
        self.mutex.api = mock_api
Beispiel #3
0
class TestMutex(TestCase):

    def setUp(self):
        self.mutex_path = '../mutex.txt'
        self.logger = Logger(off=True)
        self.other_ids = [i for i in range(1, 10)]
        self.other_ports = [8100 + i for i in range(1, 10)]

        self.mutex = LamportMutex(self.mutex_path, 0, 8000,
                                  self.other_ids, self.other_ports, self.logger)
        self.mutex.tear_down()  # kill real connection

        # mock API
        mock_api = MockAPI(self.other_ids)
        self.mutex.api = mock_api

    def test__mutex_lock(self):
        # acquire mutex
        self.assertEqual(self.mutex.lock(), True)

        # if mutex was locked resource must be unavailable:
        with open(self.mutex_path, 'w') as f:
            with self.assertRaises(BlockingIOError):
                fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)

        self.mutex.unlock()  # release mutex

    def test__mutex_unlock(self):
        # acquire mutex
        self.assertEqual(self.mutex.lock(), True)
        self.mutex.unlock()  # release mutex

        # resource must be available:
        with open(self.mutex_path, 'w') as f:
            fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
Beispiel #4
0
    def setUp(self):
        self.mutex_path = '../mutex.txt'
        self.logger = Logger(off=True)
        self.logger.warn('Ignore logger error during tests!')
        self.other_ids = [i for i in range(1, 10)]
        self.other_ports = [8100 + i for i in range(1, 10)]

        self.mutex = LamportMutex(self.mutex_path, 0, 8000,
                                  self.other_ids, self.other_ports, self.logger)
        self.mutex.tear_down()  # kill real connection

        # mock connection
        self.mock_connection = MockConnection(0, 8000, self.other_ids,
                                              self.other_ports, self.mutex.api.on_response)
        self.mutex.api.connection = self.mock_connection
Beispiel #5
0
class TestAPI(TestCase):

    def setUp(self):
        self.mutex_path = '../mutex.txt'
        self.logger = Logger(off=True)
        self.logger.warn('Ignore logger error during tests!')
        self.other_ids = [i for i in range(1, 10)]
        self.other_ports = [8100 + i for i in range(1, 10)]

        self.mutex = LamportMutex(self.mutex_path, 0, 8000,
                                  self.other_ids, self.other_ports, self.logger)
        self.mutex.tear_down()  # kill real connection

        # mock connection
        self.mock_connection = MockConnection(0, 8000, self.other_ids,
                                              self.other_ports, self.mutex.api.on_response)
        self.mutex.api.connection = self.mock_connection

    def test__API_with_correct_answers(self):
        """
        mock connection works correctly
        """
        self.mock_connection.state = MockConnection.CORRECT_NUM_OF_CONFIRMATIONS

        # mutex must be acquired
        self.assertEqual(self.mutex.lock(), True)  # acquire mutex
        self.mutex.unlock()  # release mutex

    def test__API_with_wrong_answer(self):
        """
        mock connection send less confirmation than required
        """
        self.mock_connection.state = MockConnection.WRONG_NUM_OF_CONFIRMATIONS

        # timeout supposed to be here
        self.assertEqual(self.mutex.lock(), False)  # acquire mutex

    def test__API_without_answer(self):
        """
        actually is the same that previous one
        """
        self.mock_connection.state = MockConnection.NO_CONFIRMATIONS

        # timeout supposed to be here
        self.assertEqual(self.mutex.lock(), False)  # acquire mutex

    def test__API_increment_clock(self):
        """
        test whether clock increment works correctly
        """
        self.mock_connection.state = MockConnection.CORRECT_NUM_OF_CONFIRMATIONS

        # simulate request
        other_time = 10
        self.mock_connection.simulate_request_from_other_process(other_time)  # time bigger than ours
        # add 1 after receiving
        # add one more 1 after sending confirmation
        self.assertEqual(self.mutex.api.clock, other_time + 2)

        # now out time is equal to other_time + 2
        # let's receive 'release' message with older time than ours now:
        self.mock_connection.simulate_release_from_other_process(other_time + 1, 0)
        # our time is supposed to be equal to other_time + 3 now:
        # because we only increment it once when receive 'release' message
        self.assertEqual(self.mutex.api.clock, other_time + 3)

    def test__API_other_locks_earlier(self):
        """
        check that we await until mutex is released before lock it
        """
        # mock connection
        self. mock_connection.state = MockConnection.CORRECT_NUM_OF_CONFIRMATIONS

        # simulate request
        self.mock_connection.simulate_request_from_other_process(-1)  # earlier than our time

        # simulate release after 1.5s
        delay = 2
        thread = Thread(target=self.mock_connection.simulate_release_from_other_process, args=(2, delay))
        thread.start()

        start = time()
        self.mutex.lock()

        # locked only after ~2s => OK
        self.assertGreaterEqual(time(), start + delay)

        self.mutex.unlock()

    def test__API_other_locks_later(self):
        """
        lock mutex if our process is first in the queue
        """
        self.mock_connection.state = MockConnection.CORRECT_NUM_OF_CONFIRMATIONS

        # simulate release after 1.5s
        delay = 1.5
        thread = Thread(target=self.mock_connection.simulate_release_from_other_process, args=(1, delay))
        thread.start()

        start = time()
        self.mutex.lock()

        # simulate request
        self.mock_connection.simulate_request_from_other_process(10)  # later than our time

        # locked before delay passed=> OK
        self.assertLess(time(), start + delay)

        self.mutex.unlock()
class DaemonProcess(Daemon):
    mutex = None

    def __init__(self,
                 pidfile,
                 path=None,
                 id=None,
                 port=None,
                 ids=None,
                 ports=None,
                 logger=None,
                 debug=False,
                 stress_mode=False):
        """
        :param path: path to the mutex file. for example mutex.txt
        :param logger: instance of logger
        :param id: self id
        :param port: self port
        :param ids: ids of other processes
        :param ports: ports of other processes
        :param stress_mode: in stress mode process acquires and releases mutex in loop while alive
        """
        self.id = id
        self.mutex_path = path
        self.port = port
        self.ids = ids
        self.ports = ports
        self.logger = logger
        self.stress_mode = stress_mode
        signal(SIGUSR1, self.__lock)
        signal(SIGUSR2, self.__unlock)
        super().__init__(pidfile, debug)

    def signal_term_handler(self, signum, frame):
        self.mutex.tear_down()
        super().signal_term_handler(signum, frame)

    def run(self):
        self.mutex = LamportMutex(path=self.mutex_path,
                                  id=self.id,
                                  port=self.port,
                                  ids=self.ids,
                                  ports=self.ports,
                                  logger=self.logger)
        if self.stress_mode:
            self.run_stress_mode()

    def run_stress_mode(self):
        self.logger.warn("{} wait other processes...".format(self.id))
        while not self.mutex.api.ping_all():
            continue
        self.logger.warn("{} run stress mode".format(self.id))
        while 1:
            if self.__lock(None, None):
                self.__unlock(None, None)

    def get_pid(self):
        try:
            with open(self.pidfile, 'r') as pf:
                pid = int(pf.read().strip())
        except IOError:
            pid = None

        return pid

    def lock(self):
        pid = self.get_pid()

        if not pid:
            message = "pidfile %s does not exist. Daemon not running?\n"
            sys.stderr.write(message % self.pidfile)
            return

        os.kill(pid, SIGUSR1)

    def unlock(self):
        pid = self.get_pid()

        if not pid:
            message = "pidfile %s does not exist. Daemon not running?\n"
            sys.stderr.write(message % self.pidfile)
            return

        os.kill(pid, SIGUSR2)

    def __lock(self, signum, frame):
        return self.mutex.lock()

    def __unlock(self, signum, frame):
        self.mutex.unlock()
Beispiel #7
0
                                            parser.parse_arguments(sys.argv, logger)
        logger = Logger(debug=debug,
                        out='{}/{}.log'.format(settings.logs_path, id))
        if daemon:
            daemon = DaemonProcess(pidfile="{}/{}.pid".format(
                settings.pids_path, id),
                                   path=mutex_path,
                                   id=id,
                                   port=port,
                                   ids=ids,
                                   ports=ports,
                                   logger=logger,
                                   debug=debug,
                                   stress_mode=stress_mode)
            daemon.start()
        else:
            mutex = LamportMutex(path=mutex_path,
                                 id=id,
                                 port=port,
                                 ids=ids,
                                 ports=ports,
                                 logger=logger)
            sleep(
                1)  # sleep for a while because socket doesn't open immediately
            if stress_mode:
                run_stress_mode()
            else:
                run_interactive_app()
    except ValueError:
        exit(0)