Beispiel #1
0
    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
Beispiel #2
0
    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))
Beispiel #3
0
    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
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #10
0
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
Beispiel #11
0
    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())