def stabilize(self): try: s = self.send(self.state.successor, 'get_predecessor') resp = s.recv(1024).decode('utf-8') if resp != 'None': x_ip, x_port = resp.split(':') x = Address(x_ip, x_port) s.close() if in_range(x.__hash__(), self.state.id, self.state.successor.__hash__()): self.state.lock.acquire() self.state.finger[0] = x.__hash__() self.state.successor = x self.state.addr_dict[str(x.__hash__())] = x self.state.lock.release() # else: except: self.state.lock.acquire() del self.state.addr_dict[str(self.state.successor.__hash__())] self.state.successor = self.state.local_address self.state.finger[0] = self.state.id self.state.lock.release() self.send(self.state.successor, 'notify {} {}'.format(self.state.ip, self.state.port)).close()
def fix_finger(self): self.state.lock.acquire() self.state.i = self.state.i + 1 if self.state.i > M: self.state.i = 1 s = self.send(self.state.local_address, 'find_successor {}'.format((self.state.id + pow(2, self.state.i-1)) % 2**M)) n_ip, n_port = s.recv(1024).decode('utf-8').split(':') n = Address(n_ip, n_port) s.close() self.state.addr_dict[str(n.__hash__())] = n self.state.finger[self.state.i-1] = n.__hash__() # debug(self, "Finger:", self.state.finger) self.state.lock.release()
def notify(self, ip, port): n_ = Address(ip, port) if self.state.predecessor == None or\ in_range(n_.__hash__(), self.state.predecessor.__hash__(), self.state.id): self.state.lock.acquire() self.state.predecessor = n_ self.state.lock.release()
class State: def __init__(self, port=8000): self.in_ring = False # becomes True when this node has created or joined a ring self.ip = socket.gethostbyname(socket.gethostname()) self.port = port self.local_address = Address(self.ip, self.port) self.id = self.local_address.__hash__() self.predecessor = None self.successor = None self.finger = [None] * M # contains finger nodes' Chord ids self.addr_dict = { } # key: a Chord id; value: corresponding Address (IP/port) self.i = 1 self.lock = Lock()
def __init__(self, address): # ip addresses self._address = address self._base_address = address[0] # all slots, a ring nodes = [None for x in range(NUM_SLOTS)] self._nodes = nodes # create an initial nodes and add it to the Chord ring addr = Address(self._base_address) index = addr.__hash__() # avoid collision of hashing while self._nodes[index] is not None: index = (index + 1) % NUM_SLOTS self._nodes[index] = Node(addr, self) for x in range(1, len(address)): self.addNode(address[x], self._base_address)
class Local(object): def __init__(self, local_address, remote_address=None): self.address_ = Address(quick_lazy_ip(), local_address.port) self.local_addr = local_address print("self id = %s" % self.id()) self.shutdown_ = False # list of successors self.successors_ = [] # join the DHT self.join(remote_address) # we don't have deamons until we start self.daemons_ = {} # initially no commands self.command_ = [] # is this id within our range? def is_ours(self, id): assert id >= 0 and id < SIZE return inrange(id, self.predecessor_.id(1), self.id(1)) def shutdown(self): self.shutdown_ = Trues self.socket_.shutdown(socket.SHUT_RDWR) self.socket_.close() # logging function def log(self, info): f = open("./chord.log", "a+") f.write(str(self.id()) + " : " + info + "\n") f.close() #print str(self.id()) + " : " + info def start(self): # start the daemons self.daemons_['run'] = Daemon(self, 'run') self.daemons_['fix_fingers'] = Daemon(self, 'fix_fingers') self.daemons_['stabilize'] = Daemon(self, 'stabilize') self.daemons_['update_successors'] = Daemon(self, 'update_successors') for key in self.daemons_: self.daemons_[key].start() self.log("started") def ping(self): return True def join(self, remote_address=None): # initially just set successor print "joining" self.finger_ = [None for x in range(LOGSIZE)] self.predecessor_ = None if remote_address: print "poking", remote_address remote = Remote(remote_address) print "fingering" self.finger_[0] = remote.find_successor(self.id()) else: self.finger_[0] = self print "joined" self.log("joined") @repeat_and_sleep(STABILIZE_INT) @retry_on_socket_error(STABILIZE_RET) def stabilize(self): self.log("stabilize") suc = self.successor() # We may have found that x is our new successor iff # - x = pred(suc(n)) # - x exists # - x is in range (n, suc(n)) # - [n+1, suc(n)) is non-empty # fix finger_[0] if successor failed if suc.id() != self.finger_[0].id(): self.finger_[0] = suc x = suc.predecessor() if x != None and \ inrange(x.id(), self.id(1), suc.id()) and \ self.id(1) != suc.id() and \ x.ping(): self.finger_[0] = x # We notify our new successor about us self.successor().notify(self) # Keep calling us return True def notify(self, remote): # Someone thinks they are our predecessor, they are iff # - we don't have a predecessor # OR # - the new node r is in the range (pred(n), n) # OR # - our previous predecessor is dead self.log("notify") if self.predecessor() == None or \ inrange(remote.id(), self.predecessor().id(1), self.id()) or \ not self.predecessor().ping(): self.predecessor_ = remote @repeat_and_sleep(FIX_FINGERS_INT) def fix_fingers(self): # Randomly select an entry in finger_ table and update its value self.log("fix_fingers") i = random.randrange(LOGSIZE - 1) + 1 self.finger_[i] = self.find_successor(self.id(1 << i)) # Keep calling us return True @repeat_and_sleep(UPDATE_SUCCESSORS_INT) @retry_on_socket_error(UPDATE_SUCCESSORS_RET) def update_successors(self): self.log("update successor") suc = self.successor() # if we are not alone in the ring, calculate if suc.id() != self.id(): successors = [suc] suc_list = suc.get_successors() if suc_list and len(suc_list): successors += suc_list # if everything worked, we update self.successors_ = successors return True def get_successors(self): self.log("get_successors") return [(node.address_.ip, node.address_.port) for node in self.successors_[:N_SUCCESSORS - 1]] def id(self, offset=0): return (self.address_.__hash__() + offset) % SIZE def successor(self): # We make sure to return an existing successor, there `might` # be redundance between finger_[0] and successors_[0], but # it doesn't harm for remote in [self.finger_[0]] + self.successors_: #print remote.address_ if remote.ping(): self.finger_[0] = remote return remote print("No successor available, aborting") self.shutdown_ = True sys.exit(-1) def predecessor(self): return self.predecessor_ #@retry_on_socket_error(FIND_SUCCESSOR_RET) def find_successor(self, id): # The successor of a key can be us iff # - we have a pred(n) # - id is in (pred(n), n] self.log("find_successor") if self.predecessor() and \ inrange(id, self.predecessor().id(1), self.id(1)): return self node = self.find_predecessor(id) return node.successor() #@retry_on_socket_error(FIND_PREDECESSOR_RET) def find_predecessor(self, id): self.log("find_predecessor") node = self # If we are alone in the ring, we are the pred(id) if node.successor().id() == node.id(): return node while not inrange(id, node.id(1), node.successor().id(1)): node = node.closest_preceding_finger(id) return node def closest_preceding_finger(self, id): # first fingers in decreasing distance, then successors in # increasing distance. self.log("closest_preceding_finger") for remote in reversed(self.successors_ + self.finger_): if remote != None and inrange(remote.id(), self.id(1), id) and remote.ping(): return remote return self def run(self): # should have a threadpool here :/ # listen to incomming connections self.socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket_.bind((self.local_addr.ip, int(self.local_addr.port))) self.socket_.listen(10) while 1: self.log("run loop") try: conn, addr = self.socket_.accept() except socket.error: self.shutdown_ = True break request = read_from_socket(conn) command = request.split(' ')[0] # we take the command out request = request[len(command) + 1:] # defaul : "" = not respond anything result = json.dumps("") if command == 'get_successor': successor = self.successor() result = json.dumps( (successor.address_.ip, successor.address_.port)) if command == 'get_predecessor': # we can only reply if we have a predecessor if self.predecessor_ != None: predecessor = self.predecessor_ result = json.dumps( (predecessor.address_.ip, predecessor.address_.port)) if command == 'find_successor': successor = self.find_successor(int(request)) result = json.dumps( (successor.address_.ip, successor.address_.port)) if command == 'closest_preceding_finger': closest = self.closest_preceding_finger(int(request)) result = json.dumps( (closest.address_.ip, closest.address_.port)) if command == 'notify': npredecessor = Address( request.split(' ')[0], int(request.split(' ')[1])) self.notify(Remote(npredecessor)) if command == 'get_successors': result = json.dumps(self.get_successors()) # or it could be a user specified operation for t in self.command_: if command == t[0]: result = t[1](request) send_to_socket(conn, result) conn.close() if command == 'shutdown': self.socket_.close() self.shutdown_ = True self.log("shutdown started") break self.log("execution terminated") def register_command(self, cmd, callback): self.command_.append((cmd, callback)) def unregister_command(self, cmd): pass
class Local(object): def __init__(self, local_address, remote_address = None): self.address_ = Address(quick_lazy_ip(),local_address.port) self.local_addr = local_address print("self id = %s" % self.id()) self.shutdown_ = False # list of successors self.successors_ = [] # join the DHT self.join(remote_address) # we don't have deamons until we start self.daemons_ = {} # initially no commands self.command_ = [] # is this id within our range? def is_ours(self, id): assert id >= 0 and id < SIZE return inrange(id, self.predecessor_.id(1), self.id(1)) def shutdown(self): self.shutdown_ = Trues self.socket_.shutdown(socket.SHUT_RDWR) self.socket_.close() # logging function def log(self, info): f = open("./chord.log", "a+") f.write(str(self.id()) + " : " + info + "\n") f.close() #print str(self.id()) + " : " + info def start(self): # start the daemons self.daemons_['run'] = Daemon(self, 'run') self.daemons_['fix_fingers'] = Daemon(self, 'fix_fingers') self.daemons_['stabilize'] = Daemon(self, 'stabilize') self.daemons_['update_successors'] = Daemon(self, 'update_successors') for key in self.daemons_: self.daemons_[key].start() self.log("started") def ping(self): return True def join(self, remote_address = None): # initially just set successor print "joining" self.finger_ = [None for x in range(LOGSIZE)] self.predecessor_ = None if remote_address: print "poking", remote_address remote = Remote(remote_address) print "fingering" self.finger_[0] = remote.find_successor(self.id()) else: self.finger_[0] = self print "joined" self.log("joined") @repeat_and_sleep(STABILIZE_INT) @retry_on_socket_error(STABILIZE_RET) def stabilize(self): self.log("stabilize") suc = self.successor() # We may have found that x is our new successor iff # - x = pred(suc(n)) # - x exists # - x is in range (n, suc(n)) # - [n+1, suc(n)) is non-empty # fix finger_[0] if successor failed if suc.id() != self.finger_[0].id(): self.finger_[0] = suc x = suc.predecessor() if x != None and \ inrange(x.id(), self.id(1), suc.id()) and \ self.id(1) != suc.id() and \ x.ping(): self.finger_[0] = x # We notify our new successor about us self.successor().notify(self) # Keep calling us return True def notify(self, remote): # Someone thinks they are our predecessor, they are iff # - we don't have a predecessor # OR # - the new node r is in the range (pred(n), n) # OR # - our previous predecessor is dead self.log("notify") if self.predecessor() == None or \ inrange(remote.id(), self.predecessor().id(1), self.id()) or \ not self.predecessor().ping(): self.predecessor_ = remote @repeat_and_sleep(FIX_FINGERS_INT) def fix_fingers(self): # Randomly select an entry in finger_ table and update its value self.log("fix_fingers") i = random.randrange(LOGSIZE - 1) + 1 self.finger_[i] = self.find_successor(self.id(1<<i)) # Keep calling us return True @repeat_and_sleep(UPDATE_SUCCESSORS_INT) @retry_on_socket_error(UPDATE_SUCCESSORS_RET) def update_successors(self): self.log("update successor") suc = self.successor() # if we are not alone in the ring, calculate if suc.id() != self.id(): successors = [suc] suc_list = suc.get_successors() if suc_list and len(suc_list): successors += suc_list # if everything worked, we update self.successors_ = successors return True def get_successors(self): self.log("get_successors") return [(node.address_.ip, node.address_.port) for node in self.successors_[:N_SUCCESSORS-1]] def id(self, offset = 0): return (self.address_.__hash__() + offset) % SIZE def successor(self): # We make sure to return an existing successor, there `might` # be redundance between finger_[0] and successors_[0], but # it doesn't harm for remote in [self.finger_[0]] + self.successors_: #print remote.address_ if remote.ping(): self.finger_[0] = remote return remote print("No successor available, aborting") self.shutdown_ = True sys.exit(-1) def predecessor(self): return self.predecessor_ #@retry_on_socket_error(FIND_SUCCESSOR_RET) def find_successor(self, id): # The successor of a key can be us iff # - we have a pred(n) # - id is in (pred(n), n] self.log("find_successor") if self.predecessor() and \ inrange(id, self.predecessor().id(1), self.id(1)): return self node = self.find_predecessor(id) return node.successor() #@retry_on_socket_error(FIND_PREDECESSOR_RET) def find_predecessor(self, id): self.log("find_predecessor") node = self # If we are alone in the ring, we are the pred(id) if node.successor().id() == node.id(): return node while not inrange(id, node.id(1), node.successor().id(1)): node = node.closest_preceding_finger(id) return node def closest_preceding_finger(self, id): # first fingers in decreasing distance, then successors in # increasing distance. self.log("closest_preceding_finger") for remote in reversed(self.successors_ + self.finger_): if remote != None and inrange(remote.id(), self.id(1), id) and remote.ping(): return remote return self def run(self): # should have a threadpool here :/ # listen to incomming connections self.socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket_.bind((self.local_addr.ip, int(self.local_addr.port))) self.socket_.listen(10) while 1: self.log("run loop") try: conn, addr = self.socket_.accept() except socket.error: self.shutdown_ = True break request = read_from_socket(conn) command = request.split(' ')[0] # we take the command out request = request[len(command) + 1:] # defaul : "" = not respond anything result = json.dumps("") if command == 'get_successor': successor = self.successor() result = json.dumps((successor.address_.ip, successor.address_.port)) if command == 'get_predecessor': # we can only reply if we have a predecessor if self.predecessor_ != None: predecessor = self.predecessor_ result = json.dumps((predecessor.address_.ip, predecessor.address_.port)) if command == 'find_successor': successor = self.find_successor(int(request)) result = json.dumps((successor.address_.ip, successor.address_.port)) if command == 'closest_preceding_finger': closest = self.closest_preceding_finger(int(request)) result = json.dumps((closest.address_.ip, closest.address_.port)) if command == 'notify': npredecessor = Address(request.split(' ')[0], int(request.split(' ')[1])) self.notify(Remote(npredecessor)) if command == 'get_successors': result = json.dumps(self.get_successors()) # or it could be a user specified operation for t in self.command_: if command == t[0]: result = t[1](request) send_to_socket(conn, result) conn.close() if command == 'shutdown': self.socket_.close() self.shutdown_ = True self.log("shutdown started") break self.log("execution terminated") def register_command(self, cmd, callback): self.command_.append((cmd, callback)) def unregister_command(self, cmd): pass