Пример #1
0
 def interval(self, a, b, bajo_exclude=False, alto_exclude=False, widget=True, where=""):
     intervalo = Interval(a, b, lexclude=bajo_exclude, rexclude=alto_exclude)
     print("el intervalo es "+str(intervalo))
     tabla = 'widget' if widget else 'page'
     todo = self.query("*", tabla, where=where)
     sol = []
     for x in todo:
         hash = int(x[1], 16)
         s = "para hash="+str(hash)
         if(intervalo.__contains__(hash)):
             s += "  "+str(True)
             sol.append(x)
         print(s)
     return sol
 def interval(self,
              a,
              b,
              bajo_exclude=False,
              alto_exclude=False,
              widget=True,
              where=""):
     intervalo = Interval(a,
                          b,
                          lexclude=bajo_exclude,
                          rexclude=alto_exclude)
     print("el intervalo es " + str(intervalo))
     tabla = 'widget' if widget else 'page'
     todo = self.query(
         "*", tabla,
         where=where)  # lista de tuplas donde el estado es replicado
     sol = []
     for x in todo:
         hash = int(x[1], 16)
         if (intervalo.__contains__(hash)):
             sol.append(x)
     return sol
Пример #3
0
    def __init__(self,
                 ip: str,
                 port: int,
                 ID: int,
                 functionBitNumber: int,
                 widget=True):
        super(Chord, self).__init__()

        self.sucessor_list_size = 3
        self.sucessor_list = utils.SucessorList(self.sucessor_list_size)
        self.widget = widget
        self._functionBitNumber = functionBitNumber
        self.port = port
        self.ip = ip
        self._chordId = ID
        self._uri = None
        self._ns_uri = None
        self._ns = None

        self._data_manager_uri = None
        self._pot = int(pow(2, self._functionBitNumber))

        self.node_list = utils.NodeList(
            {
                'chordId': self._chordId,
                'address': self.address,
                'uri': self.uri,
                'manager_uri': self.data_manager_uri
            }, 10, self._pot)
        # la 3ra columna es un diccionario, chordId:int con el ip:puerto en str, y el uri del nodo, uri del data manager
        self._fingerTable = []

        startIndex = int((self._chordId + pow(2, 0)) % self._pot)
        startIndexPlus = int((self._chordId + pow(2, 1)) %
                             self._pot)  # tengo q ver si esta suma es correcta

        for index in range(self._functionBitNumber):
            self._fingerTable.append({
                'start':
                startIndex,
                'interval':
                Interval(startIndex, startIndexPlus, rexclude=True),
                'node': {}
            })

            startIndex = startIndexPlus
            startIndexPlus = int(
                (self._chordId + pow(2, index + 2)) % self._pot)

        self._sucessor = None
        self._predecessor = None
Пример #4
0
    def closest_preceding_finger(self, key: int) -> dict:
        interval = Interval(self.chordId, key, True, True)

        for index in range(self._functionBitNumber - 1, -1, -1):
            if len(self._fingerTable[index]['node']) > 0 and self._fingerTable[
                    index]['node']['chordId'] in interval:
                return {
                    'chordId': self._fingerTable[index]['node']['chordId'],
                    'address': self._fingerTable[index]['node']['address'],
                    'uri': self._fingerTable[index]['node']['uri'],
                    'manager_uri':
                    self._fingerTable[index]['node']['manager_uri']
                }

        return {
        }  # solo pasa si no he actualizado mi tabla de finger o si la llave es = mi y yo soy el sucesor d todas
Пример #5
0
    def notify(self, node: dict) -> None:
        isDeath = True

        print(notify_title +
              'haciendole ping a mi predecesor a ver si esta vivo')

        # region Verificando si mi predecesor esta vivo

        # mi predecesor puede ser none, el primer notify q se me hace si no soy el primer nodo en la red
        if self.predecessor:
            with Pyro4.Proxy(self.predecessor['uri']) as remoteNode:
                remoteNode._pyroTimeout = 7
                try:
                    isDeath = not remoteNode.ping()
                # si esta muerto devuelve CommunicationError
                except (
                        Pyro4.errors.CommunicationError,
                        Pyro4.errors.TimeoutError,
                ):
                    pass
            # de otra forma solo puede devolver TimeoutError o ConnectionClosedError, u otra q el qiera

        # endregion

        print(notify_title + 'mi predecesor esta muerto: ' + str(isDeath))

        if self.predecessor is None or isDeath or node['chordId'] in \
                Interval(self.predecessor['chordId'], self.chordId, lexclude=True, rexclude=True):
            # si esta muerto agregarlo a la lista de nodos potenciales q pueden haber quedado en otro anillo
            if isDeath and self.predecessor and self.predecessor not in self.node_list:
                self.node_list.add(self.predecessor)

            self.predecessor = node
            if isDeath:
                # me hago cargo de los datos q estan entre mi nuevo predecesor y yo
                with Pyro4.Proxy(self.data_manager_uri) as data_manager:
                    data_manager.change_labels_interval(
                        self.predecessor['chordId'],
                        self.chordId,
                        estado_req='replicado',
                        estado_final='propio',
                        bajo_exclude=True,
                        alto_exclude=False,
                        widget=self.widget)

        print(notify_title + 'mi predecesor ahora es: ')
        utils.print_node(self.predecessor)
Пример #6
0
    def find_predecessor(self, key: int) -> dict:
        actualNode = {
            'chordId': self.chordId,
            'address': self.address,
            'uri': self.uri,
            'manager_uri': self.data_manager_uri
        }

        actualNodeId = self.chordId
        actualNodeSucessorId = self.sucessor['chordId']

        while len(actualNode) > 0 and key not in Interval(
                actualNodeId, actualNodeSucessorId, lexclude=True):
            # actualNode puede estar muerto
            try:
                with Pyro4.Proxy(actualNode['uri']) as remoteNode:
                    remoteNode._pyroTimeout = 7
                    actualNode = remoteNode.closest_preceding_finger(key)

            except (
                    Pyro4.errors.CommunicationError,
                    Pyro4.errors.TimeoutError,
            ):
                actualNode = {}
            # esta muerto, preguntarle a mi sucesor

            actualNodeId = actualNode.get(
                'chordId', None)  # en el caso de q sea vacio o este muerto

            if actualNode:  # si es no vacio
                try:
                    with Pyro4.Proxy(actualNode['uri']) as remoteNode:
                        actualNodeSucessorId = remoteNode.sucessor[
                            'chordId']  # ese sucesor pudiera estar muerto!!!!!!
                except Pyro4.errors.CommunicationError:
                    actualNode = {}
                # suceden cosas tan locas como q el sucesor del actualNode puede ser None puesto q se cayo y aun el
                # stabilize no ha terminado de actualizarlo
        return actualNode  # retorna el dict id, ip:port, uri, manager_uri
Пример #7
0
    def stabilize(self):
        # todo tengo q comprobar q este codigo no afecte los demas por estarse ejecutando concurrente
        # todo be careful with references in returning type of methods
        # region si mi sucesor se murio coge el primer vivo de la lista de sucesores
        sucessor_is_alive = False
        # se le hace ping a mi sucesor
        ancent_sucessor = self.sucessor

        with Pyro4.Proxy(self.sucessor['uri']) as remoteNode:
            try:
                remoteNode._pyroTimeout = 7
                sucessor_is_alive = remoteNode.ping()

            except (
                    Pyro4.errors.CommunicationError,
                    Pyro4.errors.TimeoutError,
            ):
                pass  # esta muerto

        print(stabilize_title +
              'haciendole ping a mi sucesor para ver si esta vivo: ' +
              str(sucessor_is_alive))
        # si no esta vivo, se selecciona el primero vivo de la lista de sucesores
        if not sucessor_is_alive:
            temp, sucessor_is_alive = utils.first_alive(self.sucessor_list)
            # se murio mi sucesor, puede haber qedado en otra red
            if self.sucessor not in self.node_list:
                self.node_list.add(self.sucessor)

            if sucessor_is_alive: self.sucessor = temp
            # todo esto es otro parche, implica q mi sucesor puede esta muerto pero nunca sera none, sucesor zombi

            print(stabilize_title +
                  'mi sucesor no esta vivo, ahora mi sucesor es: ')
            utils.print_node(self.sucessor)

        # endregion

        # region buscar el predecesor de mi sucesor, si esta vivo ver si pertenece a un intervalo mas carcano a mi
        # se le pide ahora el predecesor a mi sucesor, si no tengo sucesor va a lanzar excepcion
        sucessor_predecessor = None
        try:
            with Pyro4.Proxy(self.sucessor['uri']) as remoteNode:
                remoteNode._pyroTimeout = 7
                sucessor_predecessor = remoteNode.predecessor

            with Pyro4.Proxy(sucessor_predecessor['uri']) as remoteNode:
                remoteNode.ping()

        except (
                Pyro4.errors.CommunicationError,
                Pyro4.errors.TimeoutError,
        ):
            sucessor_predecessor = None

        print(stabilize_title + 'el predecesor de mi sucesor es: ')
        utils.print_node(sucessor_predecessor)

        # se verifica q este vivo y en el intervalo en el q el pudiera ser mi nuevo sucesor
        if sucessor_predecessor and sucessor_predecessor[
                'chordId'] in Interval(self.chordId,
                                       self.sucessor['chordId'],
                                       lexclude=True,
                                       rexclude=True):
            self.sucessor = sucessor_predecessor  # de ser asi es mi nuevo sucesor

            print(
                stabilize_title +
                'ahora mi sucesor es, puesto q esta mas cerca a mi intervalo: '
            )
            utils.print_node(self.sucessor)
        # endregion
        # creo un comparador para el intervalo (sucessor, yo), a ese van a pertenecer todos mis sucesores potenciales
        interval_compare = utils.IntervalCompare(
            Interval(self.sucessor['chordId'],
                     self.chordId,
                     lexclude=True,
                     rexclude=True), self._functionBitNumber)

        print(stabilize_title +
              'verificando q tengo sucesor para actualizar lista ')

        # region si tengo sucesor, se le pide su lista, se estabiliza, se eliminan los muertos
        if sucessor_is_alive:  # si tengo un sucesor, le pido su lista de sucesores, la estabilizo, hago la mia por
            # la de el
            sucessor_list_of_sucessor = None
            sucessor_sucessor = None
            ancent_sucessor_list = self.sucessor_list  # nos qedamos con la anterior lista de sucesores para
            # compararla con la nueva, de esta forma a los q ya no esten en la nueva se les quita
            # las llaves y a los q estan se les da como replicado esto garantiza q siempre las
            # llaves se encuentren replicadas en mi lista de sucesores

            with Pyro4.Proxy(self.sucessor['uri']) as remoteNode:
                try:
                    remoteNode._pyroTimeout = 7  # por si acaso
                    sucessor_list_of_sucessor = remoteNode.get_sucessor_list  # todo se supone q me devuelva una lista
                    sucessor_sucessor = remoteNode.sucessor  # no una clase sucesorlist
                except (
                        Pyro4.errors.CommunicationError,
                        Pyro4.errors.TimeoutError,
                ):
                    return
            # si mi sucesor se cayo aqi no tiene sentido q actualice mi lista por la de el ni nada mas, retorno
            # inmediato para volver a ejecutar el stabilize y buscar en mi lista uno q este vivo

            self.sucessor_list = utils.Stabilizer.stabilize(
                sucessor_list_of_sucessor, interval_compare, sucessor_sucessor)

            # region code de mantenimiento de llaves

            # pueden haber nodos muertos
            nodes_not_in_new_list = self._node_difference(
                ancent_sucessor_list, self.sucessor_list)
            # todo mi predecesor puede cambiar en medio de to-do este movimiento, lo mejor q se puede hacer es guardarlo
            # antes de entrar al stabilize, aunq se puede dejar q el nuevo predecesor arregle el lio
            self._remove_data_old_sucessors(nodes_not_in_new_list)
            self._remove_data_old_sucessor(ancent_sucessor)
            # cabe el problema de que se tenga mucha gente haciendo join y q no le de tiempo a alguno decirle al q
            # guardaba sus llaves anteriormente q las pase a replicadas o las borre esto es un caso en el q un nodo q
            # tenga llaves como propias aunq el no sea el q las guarde las va a seguir teniendo, qedan llaves basura
            # para evitar esto es necesario un proceso por detras q se encargue de borrar estas llaves

            # ademas de este problema esta tambien q solo le estoy borrando las llaves a los nodos q estaban en mi
            # anterior lista de sucesores q no estan en la actual, se las tengo q borrar a mi sucesor tambien, o sea, si
            # mi sucesor es distinto q mi anterior sucesor y no esta en la lista de sucesores tengo q eliminarle las
            # llaves

            # name hash state params code
            if self.predecessor and self.predecessor['chordId'] != self.chordId:
                with Pyro4.Proxy(self.data_manager_uri) as manager:
                    # es un problema tanto mantener el proxy abierto e iterar sobre el, de una forma si se cae se jodio la
                    # cosa de la otra se carga demasiadoa memoria, mejor iterar e ir guardando en el disco, para despues
                    # leer

                    for item in manager.get_interval(
                            a=self.predecessor['chordId'],
                            b=self.chordId,
                            bajo_exclude=True,
                            alto_exclude=False,
                            widget=self.widget):
                        # obligado ademas de esto es necesario un proceso por detras q se encargue de pasar a replicado o
                        # eliminar o pasar a replicadas aquellas llaves q se encuentran en otro intervalo q no sea mi
                        # predecesor y yo

                        for node in self.sucessor_list:
                            if node:
                                try:
                                    with Pyro4.Proxy(node['manager_uri']
                                                     ) as remoteManager:

                                        remoteManager.append_item(
                                            item[0],
                                            manager.get_item(
                                                item[0],
                                                widget=self.widget)[-1],
                                            widget=self.widget,
                                            params=item[3],
                                            estado='replicado')
                                        # todo el predecesor puede ser nil
                                        # todo esto lo estoy haciendo por cada nodo por cada item, cascara, modificar esto
                                        remoteManager.change_labels_interval(
                                            a=self.predecessor['chordId'],
                                            b=self.chordId,
                                            bajo_exclude=True,
                                            alto_exclude=False,
                                            estado_req='propio',
                                            estado_final='replicado',
                                            widget=self.widget)

                                except (
                                        Pyro4.errors.TimeoutError,
                                        Pyro4.errors.CommunicationError,
                                ):
                                    pass

                    # se las paso a replicado a mi nuevo sucesor si este no soy yo, otro parche
                    if self.sucessor['chordId'] != self.chordId:
                        for item in manager.get_interval(
                                a=self.predecessor['chordId'],
                                b=self.chordId,
                                bajo_exclude=True,
                                alto_exclude=False,
                                widget=self.widget):
                            try:
                                with Pyro4.Proxy(self.sucessor['manager_uri']
                                                 ) as remoteManager:
                                    remoteManager._pyroTimeout = 7

                                    remoteManager.append_item(
                                        item[0],
                                        manager.get_item(
                                            item[0], widget=self.widget)[-1],
                                        widget=self.widget,
                                        params=item[3],
                                        estado='replicado')

                                    remoteManager.change_labels_interval(
                                        a=self.predecessor['chordId'],
                                        b=self.chordId,
                                        bajo_exclude=True,
                                        alto_exclude=False,
                                        estado_req='propio',
                                        estado_final='replicado',
                                        widget=self.widget)

                            except (
                                    Pyro4.errors.TimeoutError,
                                    Pyro4.errors.CommunicationError,
                            ):
                                pass

            # endregion

            print(stabilize_title +
                  'se le pidio la lista de sucesores a mi sucesor')
            utils.print_sucessor_list(self.sucessor_list)

        deaths_number = utils.Stabilizer.deleteDeath(self.sucessor_list,
                                                     interval_compare)
        # endregion

        print(stabilize_title + 'eliminando los muertos: ')
        # esto es completamente innecesario, si no tengo sucesor es pq todos estan muertos en mi lista, aqi puede ir un
        # if tengo sucesor, else es q no tengo pq se murio y no habia nadie vivo en mi lista, finally eliminar los
        # muertos, esto es para mayor belleza del codigo
        # region si todos estan muertos y no tengo sucesor, yo soy mi sucesor
        if not sucessor_is_alive and deaths_number == self.sucessor_list_size:
            # hacer broadcast a ver si hay otro nodo distinto de mi, si es asi el sera mi sucesor
            new_sucessor = self._get_a_chord()
            if new_sucessor:
                self.sucessor = new_sucessor
            else:
                self.sucessor = {
                    'chordId': self.chordId,
                    'address': self.address,
                    'uri': self.uri,
                    'manager_uri': self.data_manager_uri
                }
                # soy el sucesor de todas las llaves, ponerlo en mi finger, podria dar palo con el fix finger, van a
                # haber dos hilos escribiendo al mismo tiempo, hay q ponerle un lock a la finger cuando se vaya a
                # escribir
                # for index in range(self._functionBitNumber):
                #     self._fingerTable[index]['node'] = {'chordId': self.chordId, 'address': self.address,
                #                                         'uri': self.uri,
                #                                         'manager_uri': self.data_manager_uri}

                print(stabilize_title + 'ahora mi sucesor soy yo ')
        # endregion

        print(stabilize_title + 'el numero de muertos es: ' +
              str(deaths_number))
        print(stabilize_title + 'notificando de mi prescencia')
        print(stabilize_title + 'mi sucesor es: ')
        utils.print_node(self.sucessor)

        # esto puede ser un problema a la hora de la concurrencia puesto q se escribe una propiedad, mas nadie deberia
        # estarla usando, hasta q se termine de escribir, todo problema de concurrencia
        # en el caso de q se halla caido justo cuando voy a notificarle sencillamente paso, y espero a q se vuelva a
        # estabilizar, q se busq el primer vivo en la lista, etc
        try:
            with Pyro4.Proxy(self.sucessor['uri']) as remoteNode:
                remoteNode._pyroTimeout = 7
                # el unico palo q puede dar aqi es q este muerto mi sucesor
                utils.print_node({
                    'chordId': self.chordId,
                    'address': self.address,
                    'uri': self.uri,
                    'manager_uri': self.data_manager_uri
                })

                remoteNode.notify({
                    'chordId': self.chordId,
                    'address': self.address,
                    'uri': self.uri,
                    'manager_uri': self.data_manager_uri
                })
        except (
                Pyro4.errors.CommunicationError,
                Pyro4.errors.TimeoutError,
        ):
            pass