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
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
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
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)
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
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