Beispiel #1
0
    def _handle_primary(self, conn):
        _, number, num_requests, checkpoint = utils.recv(conn)

        while checkpoint is not None:
            self._print(f'Received checkpoint (#{number}) {checkpoint}')

            if int(num_requests) > self._num_requests:
                with self._lock:
                    self._state = checkpoint
                    self._num_requests = int(num_requests)
                    for request in self._log:
                        self._state.update(int(request))
                    self._log = []

            try:
                utils.send(conn, self._identifier, number, 'ok')
                _, number, num_requests, checkpoint = utils.recv(conn)
            except Exception:
                with self._lock:
                    if self._primary_index is not None:
                        self._print('Connection closed by Primary')
                        self._connected[self._primary_index] = False
                        self._primary_index = None
                time.sleep(1 + random.random() * 5)
                self._elect()
                return

        with self._lock:
            if self._primary_index is not None:
                self._print('Connection closed by Primary')
                self._connected[self._primary_index] = False
                self._primary_index = None
        time.sleep(1 + random.random() * 5)
        self._elect()
    def _handle_lfd(self, conn, lfd_identifier):
        self._print(f'Connection from LFD {lfd_identifier}')

        _, _, message, _ = utils.recv(conn)
        while message is not None:
            if not self._rm_connected:
                self._connect()
            if message == 'add':
                self._members.append(lfd_identifier)
                self._print(f'Added member {lfd_identifier}')
                self._print(f'Current members: {self._members}')
                if self._rm_connected:
                    utils.send(self._rm_sock, lfd_identifier, 0, 'add')
            elif message == 'remove':
                self._members.remove(lfd_identifier)
                self._print(f'Removed member {lfd_identifier}')
                self._print(f'Current members: {self._members}')
                if self._rm_connected:
                    utils.send(self._rm_sock, lfd_identifier, 0, 'remove')
            _, _, message, _ = utils.recv(conn)

        self._print(f'Connection closed by LFD {lfd_identifier}')
        if lfd_identifier in self._members:
            self._members.remove(lfd_identifier)
            self._print(f'Removed member {lfd_identifier}')
            self._print(f'Current members: {self._members}')
Beispiel #3
0
    def _handle_lfd(self, conn, lfd_identifier):
        self._print(f'Connection from LFD {lfd_identifier}')

        _, number, heartbeat, _ = utils.recv(conn)
        while heartbeat is not None:
            utils.send(conn, self._identifier, number, heartbeat)
            _, number, heartbeat, _ = utils.recv(conn)

        self._print(f'Connection closed by LFD {lfd_identifier}')
    def _heartbeat(self):
        # connect to server
        connected, server_identifier = self._connect()

        # connect to gfd
        self._print(f'Connecting to GFD at {self._gfd_hostport}')
        self._gfd_sock.connect(utils.address(self._gfd_hostport))

        utils.send(self._gfd_sock, self._identifier, 0, 'lfd')
        gfd_identifier, _, _, _ = utils.recv(self._gfd_sock)
        # make sure gfd is still connected
        if gfd_identifier is None:
            self._gfd_sock.close()
            self._gfd_sock = socket.socket()
            self._print('Connection closed by GFD at ' f'{self._gfd_hostport}')
            return
        self._print(f'Connected to GFD {gfd_identifier}')
        member = False

        number = 1
        while True:
            if not connected:
                connected, server_identifier = self._connect()
            if connected:
                self._print(f'Sending heartbeat #{number} to Server '
                            f'{server_identifier}')
                utils.send(self._server_sock, self._identifier, number,
                           'heartbeat')

                _, res_number, response, _ = utils.recv(self._server_sock)
                if response is None:
                    self._print(f'No response from Server {server_identifier}')
                    self._server_sock.close()
                    self._server_sock = socket.socket()
                    connected = False
                    if member:
                        self._print(f'Alerting GFD')
                        utils.send(self._gfd_sock, self._identifier, 0,
                                   'remove')
                        member = False
                else:
                    self._print(
                        f'Heartbeat response #{res_number} from Server '
                        f'{server_identifier}')
                    if not member:
                        self._print(f'Registering membership with GFD')
                        utils.send(self._gfd_sock, self._identifier, 0, 'add')
                        member = True

                number += 1
            time.sleep(self._interval)
Beispiel #5
0
    def _connect(self, index):
        try:
            sock = self._server_socks[index]
            server_hostport = self._server_hostports[index]
            sock.connect(utils.address(server_hostport))

            utils.send(sock, self._identifier, 0, 'server')
            identifier, number, _, state = utils.recv(sock)

            # make sure server is still connected
            if identifier is None:
                sock.close()
                self._server_socks[index] = socket.socket()
                self._connected[index] = False
            else:
                self._print(f'Connected to Server {identifier}')
                # update state
                if number > self._num_requests:
                    with self._lock:
                        self._print('Updating state')
                        self._state = state
                        self._num_requests = number
                        if self._log:
                            self._print('Clearing log')
                        for request in self._log:
                            self._state.update(int(request))
                        self._log = []
                        self._ready = True
                self._ready = True
                self._connected[index] = True
        except Exception:
            self._connected[index] = False
    def _handle_gfd(self, conn, gfd_identifier):
        self._print(f'Connection from GFD {gfd_identifier}')

        identifier, _, message, _ = utils.recv(conn)
        while message is not None:
            if message == 'add':
                self._members.append(identifier)
                self._print(f'Added member {identifier}')
                self._print(f'Current members: {self._members}')
            elif message == 'remove':
                self._members.remove(identifier)
                self._print(f'Removed member {identifier}')
                self._print(f'Current members: {self._members}')
            identifier, _, message, _ = utils.recv(conn)

        self._print(f'Connection closed by GFD {gfd_identifier}')
        for member in self._members:
            self._members.remove(member)
            self._print(f'Removed member {member}')
        self._print(f'Current members: {self._members}')
    def _listen(self):
        self._print(f'Starting at hostport {self._hostport}')
        self._sock.listen()

        while True:
            conn, _ = self._sock.accept()
            identifier, number, data, _ = utils.recv(conn)
            utils.send(conn, self._identifier, number, 'rm')
            # check for gfd
            if data == 'gfd':
                Thread(target=self._handle_gfd, args=[conn,
                                                      identifier]).start()
Beispiel #8
0
    def _handle_client(self, conn, client_identifier):
        self._print(f'Connection from Client {client_identifier}')

        _, number, request, _ = utils.recv(conn)
        while request is not None:
            self._print(f'Received (#{number}) {request} from Client '
                        f'{client_identifier}')

            with self._lock:
                if (not self._ready
                        or (not self.is_active() and not self.is_primary())):
                    self._log.append(request)
                    self._print('Added request to log')
                    utils.send(conn, self._identifier, number, 'ok')
                else:
                    response = self._state.update(int(request))
                    self._num_requests += 1
                    self._print(f'Sending (#{number}) {response} to Client '
                                f'{client_identifier}')
                    utils.send(conn, self._identifier, number, response)

            _, number, request, _ = utils.recv(conn)

        self._print(f'Connection closed by Client {client_identifier}')
Beispiel #9
0
 def _run_active(self, conn, identifier, number, data):
     while True:
         # check connection type
         if data == 'lfd':
             utils.send(conn, self._identifier, number, 'server')
             self._handle_lfd(conn, identifier)
             return
         if data == 'client':
             utils.send(conn, self._identifier, number, 'server')
             self._handle_client(conn, identifier)
             return
         if data == 'server':
             utils.send(conn, self._identifier, self._num_requests,
                        'server', self._state)
         if data is None:
             return
         identifier, number, data, _ = utils.recv(conn)
    def _connect(self):
        try:
            self._print(f'Connecting to server at {self._server_hostport}')
            self._server_sock.connect(utils.address(self._server_hostport))

            utils.send(self._server_sock, self._identifier, 0, 'lfd')
            server_identifier, _, _, _ = utils.recv(self._server_sock)
            # make sure server is still connected
            if server_identifier is None:
                self._server_sock.close()
                self._server_sock = socket.socket()
                self._print('Connection closed by server at '
                            f'{self._server_hostport}')
                return False, server_identifier
            self._print(f'Connected to Server {server_identifier}')
            return True, server_identifier
        except Exception:
            return False, None
    def _connect(self):
        try:
            self._print(f'Connecting to RM at {self._rm_hostport}')
            self._rm_sock.connect(utils.address(self._rm_hostport))

            utils.send(self._rm_sock, self._identifier, 0, 'gfd')
            rm_identifier, _, _, _ = utils.recv(self._rm_sock)
            # make sure rm is still connected
            if rm_identifier is None:
                self._rm_sock.close()
                self._rm_sock = socket.socket()
                self._print('Connection closed by RM at '
                            f'{self._rm_hostport}')
                self._rm_connected = False
            self._print(f'Connected to RM {rm_identifier}')
            self._rm_connected = True
        except Exception:
            self._rm_connected = False
Beispiel #12
0
 def _run_passive(self, conn, identifier, number, data):
     while True:
         # check connection type
         if data == 'lfd':
             utils.send(conn, self._identifier, number, 'server')
             self._handle_lfd(conn, identifier)
             return
         if data == 'client':
             utils.send(conn, self._identifier, number, 'server')
             self._handle_client(conn, identifier)
             return
         if data == 'server':
             utils.send(conn, self._identifier, self._num_requests,
                        'server', self._state)
         elif data == 'elect':
             with self._lock:
                 if not self.is_primary() and self._primary_index is None:
                     utils.send(conn, self._identifier, number, 'approve')
                 elif self._primary_index is not None:
                     utils.send(conn, self._identifier, number,
                                'disapprove')
                 else:
                     utils.send(conn, self._identifier, number,
                                'primary|' + self._hostport)
         elif data is not None and 'primary' in data:
             with self._lock:
                 if self._primary_index is None:
                     self._print('Primary: ' + identifier)
                 self._primary = False
                 self._ready = False
                 server_hostport = data.split('|')[1]
                 self._primary_index = self._server_hostports.index(
                     server_hostport)
             utils.send(conn, self._identifier, number, 'backup')
             self._handle_primary(conn)
         elif data == 'backup':
             if self.is_primary():
                 self._handle_backup(conn, identifier)
                 return
         if data is None:
             return
         identifier, number, data, _ = utils.recv(conn)
Beispiel #13
0
    def _listen(self):
        self._print(f'Starting at hostport {self._hostport}')
        self._sock.listen()
        for i, connected in enumerate(self._connected):
            if not connected:
                self._connect(i)
        self._elect()

        while True:
            for i, connected in enumerate(self._connected):
                if not connected:
                    self._connect(i)
            conn, _ = self._sock.accept()
            identifier, number, data, _ = utils.recv(conn)
            if self.is_active():
                Thread(target=self._run_active,
                       args=[conn, identifier, number, data]).start()
            else:
                Thread(target=self._run_passive,
                       args=[conn, identifier, number, data]).start()
Beispiel #14
0
    def _handle_backup(self, conn, identifier):
        number = 1
        while True:
            self._print(f'Sending checkpoint (#{number}) {self._state} to '
                        f'Server {identifier}')
            try:
                utils.send(conn,
                           self._identifier,
                           number,
                           self._num_requests,
                           state=self._state)
                _, _, res, _ = utils.recv(conn)
            except Exception:
                res = None
            if res is None:
                self._print(f'Connection closed by Server {identifier}')
                return

            number += 1
            time.sleep(self._interval)
Beispiel #15
0
 def _elect(self):
     for i in range(len(self._server_socks)):
         sock = self._server_socks[i]
         try:
             utils.send(sock, self._identifier, 0, 'elect')
             identifier, number, data, _ = utils.recv(sock)
             self._lock.acquire()
             if self._primary_index is not None:
                 self._lock.release()
                 return
             if data is not None and 'primary' in data:
                 self._primary = False
                 self._ready = False
                 self._primary_index = i
                 utils.send(sock, self._identifier, number, 'backup')
                 self._print('Primary: ' + identifier)
                 self._lock.release()
                 Thread(target=self._run_passive,
                        args=[sock, identifier, number, data]).start()
                 return
             if data == 'approve':
                 self._primary = True
                 self._ready = True
                 self._primary_index = None
                 utils.send(sock, self._identifier, number,
                            'primary|' + self._hostport)
                 self._print('Elected Primary')
                 self._lock.release()
                 Thread(target=self._run_passive,
                        args=[sock, identifier, number, data]).start()
                 return
             self._lock.release()
         except Exception:
             pass
     # no other servers have responded
     with self._lock:
         self._primary = True
         self._ready = True
         self._primary_index = None
     self._print('Default Primary')