def update_storage_leader(self, space_id, part_id, address: HostAddr): """if the storage leader change, storage client need to call this function :param space_id: :param part_id: :param address: HostAddr, if the address is None, it means the leader can't connect, choose the peer as leader :return: coid """ with self._lock: if space_id not in self._space_id_names.keys(): logger.error("Space name:{} is not found".format(space_id)) return space_name = self._space_id_names.get(space_id) if part_id not in self._storage_leader[space_name].keys(): logger.error("part_id:{} is not found".format(space_name)) return if address is not None: self._storage_leader[space_name][part_id] = address return part_addresses = self._space_caches[space_name].parts_alloc.get( part_id) for part_addr in part_addresses: if part_addr == address: continue self._storage_leader[space_name][part_id] = part_addr
def close(self): """close the connection :return: void """ try: self._connection._iprot.trans.close() except Exception as e: logger.error('Close connection to {}:{} failed:{}'.format( self._ip, self._port, e))
def update_leader(self, leader): """update the leader meta info when happen leader change :param leader: the address of meta leader :eturn: """ try: self._leader = (leader.host, leader.port) self.open() except Exception as e: logger.error(e)
def close(self): """close the GraphStorageClient :return: """ try: for conn in self._connections: conn.close() except Exception as e: logger.error('Close connection failed: {}'.format(e)) raise
def init(self, addresses, configs, ssl_conf=None): """init the connection pool :param addresses: the graphd servers' addresses :param configs: the config of the pool :param ssl_conf: the config of SSL socket :return: if all addresses are ok, return True else return False. """ if self._close: logger.error('The pool has init or closed.') raise RuntimeError('The pool has init or closed.') self._configs = configs self._ssl_configs = ssl_conf for address in addresses: if address not in self._addresses: try: ip = socket.gethostbyname(address[0]) except Exception: raise InValidHostname(str(address[0])) ip_port = (ip, address[1]) self._addresses.append(ip_port) self._addresses_status[ip_port] = self.S_BAD self._connections[ip_port] = deque() self.update_servers_status() # detect the services self._period_detect() # init min connections ok_num = self.get_ok_servers_num() if ok_num < len(self._addresses): raise RuntimeError( 'The services status exception: {}'.format(self._get_services_status()) ) conns_per_address = int(self._configs.min_connection_pool_size / ok_num) if self._ssl_configs is None: for addr in self._addresses: for i in range(0, conns_per_address): connection = Connection() connection.open(addr[0], addr[1], self._configs.timeout) self._connections[addr].append(connection) else: for addr in self._addresses: for i in range(0, conns_per_address): connection = Connection() connection.open_SSL( addr[0], addr[1], self._configs.timeout, self._ssl_configs ) self._connections[addr].append(connection) return True
def get_connection(self): """get available connection :return: Connection """ with self._lock: if self._close: logger.error('The pool is closed') raise NotValidConnectionException() try: ok_num = self.get_ok_servers_num() if ok_num == 0: return None max_con_per_address = int( self._configs.max_connection_pool_size / ok_num ) try_count = 0 while try_count <= len(self._addresses): self._pos = (self._pos + 1) % len(self._addresses) addr = self._addresses[self._pos] if self._addresses_status[addr] == self.S_OK: for connection in self._connections[addr]: if not connection.is_used: if connection.ping(): connection.is_used = True logger.info('Get connection to {}'.format(addr)) return connection if len(self._connections[addr]) < max_con_per_address: connection = Connection() if self._ssl_configs is None: connection.open(addr[0], addr[1], self._configs.timeout) else: connection.open_SSL( addr[0], addr[1], self._configs.timeout, self._ssl_configs, ) connection.is_used = True self._connections[addr].append(connection) logger.info('Get connection to {}'.format(addr)) return connection else: for connection in list(self._connections[addr]): if not connection.is_used: self._connections[addr].remove(connection) try_count = try_count + 1 return None except Exception as ex: logger.error('Get connection failed: {}'.format(ex)) return None
def close(self): """close all connections in pool :return: void """ with self._lock: for addr in self._connections.keys(): for connection in self._connections[addr]: if connection.is_used: logger.error( 'The connection using by someone, but now want to close it' ) connection.close() self._close = True
def next(self): """get scan data result :return: VertexResult or EdgeResult """ conns = self._graph_storage_client.get_conns() num = len(conns) if num == 0: raise RuntimeError('There is no storage connection') logger.debug('Graph storage client num: {}'.format(num)) exceptions = [] result = [] with concurrent.futures.ThreadPoolExecutor(num) as executor: do_scan = [] for i, conn in enumerate(conns): future = executor.submit( do_scan_job, conns[i], self._parts_manager, self._req, self._is_vertex, self._partial_success, ) do_scan.append(future) for future in concurrent.futures.as_completed(do_scan): if future.exception() is not None: logger.error(future.exception()) exceptions.append(future.exception()) else: ret, data_sets = future.result() if ret is not None: logger.error('Scan failed: {}'.format(ret)) exceptions.append( RuntimeError('Scan failed: {}'.format(ret))) continue if len(data_sets) != 0: result.extend(data_sets) self._parts_manager.reset_jobs() if len(exceptions) == 0: if len(result) == 0: logger.warning('Get empty result') return None else: if self._is_vertex: return VertexResult(result, self._decode_type) else: return EdgeResult(result, self._decode_type) else: raise exceptions[0]
def _create_connection(self): """create GraphStorageConnection :return: GraphStorageConnection """ if self._storage_addrs is None: self._storage_addrs = self._meta_cache.get_all_storage_addrs() if len(self._storage_addrs) == 0: raise RuntimeError('Get storage address from meta cache is empty') try: for addr in self._storage_addrs: conn = GraphStorageConnection(addr, self._time_out, self._meta_cache) conn.open() self._connections.append(conn) except Exception as e: logger.error('Create storage connection failed: {}'.format(e)) raise
def do_scan_job(storage_connection, parts_manager, in_req, scan_vertex=True, partial_success=False): data_sets = [] req = copy.deepcopy(in_req) while True: is_finished = False # the part without next, it means is finished if parts_manager.is_finish(): break part_info = parts_manager.get_part(storage_connection.storage_addr()) if part_info is None: parts_manager.wait_task() continue else: if part_info.cursor is not None: parts = {part_info.part_id: part_info.cursor} else: parts = {part_info.part_id: ScanCursor()} req.parts = parts logger.debug('Scan =====> req: {}'.format(req)) try: if scan_vertex: resp = storage_connection.scan_vertex(req) else: resp = storage_connection.scan_edge(req) logger.debug('Scan <==== get resp: {}'.format(resp)) if len(resp.result.failed_parts) != 0: if resp.result.failed_parts[ 0].code == ErrorCode.E_LEADER_CHANGED: if resp.result.failed_parts[0].leader is None: logger.error( 'Happen leader change, but the leader is None') raise RuntimeError( 'Happen leader change, but the leader is None') parts_manager.update_part_leader( resp.result.failed_parts[0].part_id, resp.result.failed_parts[0].leader, ) logger.warning( 'part_id {} has leader change, ' 'old leader is {}, new leader is {}'.format( part_info.part_id, storage_connection.storage_addr(), resp.result.failed_parts[0].leader, )) storage_connection.update_leader_info( req.space_id, req.part_id, resp.result.failed_parts[0].leader, ) continue error = 'Query storage: {}, part id: {} failed: {}'.format( storage_connection.storage_addr(), part_info.part_id, resp.result.failed_parts[0].code, ) if not partial_success: logger.error(error) parts_manager.set_stop() return error, [] logger.error(error) is_finished = True continue part_info.has_done = True cursor = parts[part_info.part_id] resp_cursor = resp.cursors[part_info.part_id] part_info.cursor = cursor if resp_cursor.next_cursor: cursor.next_cursor = resp_cursor.next_cursor logger.debug("Get next next_cursor: {}".format( resp_cursor.next_cursor)) else: is_finished = True logger.debug("resp.props size: {}".format(len( resp.props.rows))) if len(resp.props.column_names) == 0: return ( 'Part id: {} return empty column names'.format( part_info.part_id), None, ) if len(resp.props.rows) == 0: continue data_sets.append(resp.props) except Exception as e: import traceback logger.error(traceback.format_exc()) parts_manager.set_stop() return str(e), None finally: parts_manager.update_part_info(part_info, is_finished) return None, data_sets
def _load_all(self): """load all space info and schema info from meta services :eturn: void """ try: spaces = self._meta_client.list_spaces() space_caches = {} space_id_names = {} for space in spaces: space_id = space.id.get_space_id() space_cache = MetaCache.SpaceCache() space_cache.space_id = space_id space_cache.space_name = space.name.decode('utf-8') space_id_names[space_id] = space_cache.space_name tags = self._meta_client.list_tags(space_id) edges = self._meta_client.list_edges(space_id) parts_alloc = self._meta_client.get_parts_alloc(space_id) for tag in tags: tag_name = tag.tag_name.decode(self._decode_type) if tag_name not in space_cache.tag_items.keys(): space_cache.tag_items[tag_name] = tag else: if space_cache.tag_items[ tag_name].version < tag.version: space_cache.tag_items[tag_name] = tag for edge in edges: edge_name = edge.edge_name.decode(self._decode_type) if edge_name not in space_cache.edge_items.keys(): space_cache.edge_items[edge_name] = edge else: if space_cache.edge_items[ edge_name].version < edge.version: space_cache.edge_items[edge_name] = edge space_cache.edge_items[edge.edge_name.decode( self._decode_type)] = edge space_cache.parts_alloc = parts_alloc space_caches[space.name.decode( self._decode_type)] = space_cache hosts = self._meta_client.list_hosts() storage_addrs = [] for host_item in hosts: storage_addrs.append(host_item.hostAddr) with self._lock: self._storage_addrs = storage_addrs self._space_caches = space_caches self._space_id_names = space_id_names for space_name in self._space_caches.keys(): if space_name in self._storage_leader.keys(): continue parts_alloc = self._space_caches[space_name].parts_alloc self._storage_leader[space_name] = {} for part_id in parts_alloc: self._storage_leader[space_name][ part_id] = parts_alloc[part_id][0] except Exception as x: logger.error('Update meta data failed: {}'.format(x)) import traceback logger.error(traceback.format_exc())