All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vesoft.nebula.driver.graph.net.NebulaPool Maven / Gradle / Ivy

The newest version!
package com.vesoft.nebula.driver.graph.net;

import com.vesoft.nebula.driver.graph.data.HostAddress;
import com.vesoft.nebula.driver.graph.exception.IOErrorException;
import com.vesoft.nebula.driver.graph.utils.AddressUtil;
import java.io.Serializable;
import java.net.UnknownHostException;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class NebulaPool implements Serializable {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private       GenericObjectPool pool;
    private       LoadBalancer                    loadBalancer;
    private final AtomicBoolean                   hasInit  = new AtomicBoolean(false);
    private final AtomicBoolean                   isClosed = new AtomicBoolean(false);
    private       long                            maxWaitMills;


    public static NebulaPool.Builder builder(String addresses, String userName) {
        return builder(addresses, userName, null);
    }

    public static NebulaPool.Builder builder(String addresses, String userName, String password) {
        return new NebulaPool.Builder(addresses, userName, password);
    }

    private NebulaPool(Builder builder) throws IOErrorException {
        if (hasInit.get()) {
            return;
        }
        this.maxWaitMills = builder.maxWaitMills;

        this.loadBalancer = new RoundRobinLoadBalancer(
                builder.address,
                builder.userName,
                builder.authOptions,
                builder.strictlyServerHealthy,
                builder.healthCheckTimeMills);

        if (!loadBalancer.isServersOK()) {
            loadBalancer.close();
            logger.error("servers status is not ok, please check the server status or network.");
            throw new IOErrorException(IOErrorException.E_SERVER_BAD, "Servers status is not ok.");
        }
        // pool config
        GenericObjectPoolConfig objConfig = new GenericObjectPoolConfig();
        objConfig.setMaxIdle(builder.maxClientSize);
        objConfig.setMinIdle(builder.minClientSize);
        objConfig.setMaxTotal(builder.maxClientSize);
        objConfig.setBlockWhenExhausted(builder.blockWhenExhausted);
        objConfig.setMaxWaitMillis(builder.maxWaitMills);
        objConfig.setTimeBetweenEvictionRunsMillis(builder.idleEvictScheduleMills);
        objConfig.setMinEvictableIdleTimeMillis(builder.minEvictableIdleTimeMillis);
        // just test the validation when session is idle.
        if (builder.healthCheckTimeMills > 0) {
            objConfig.setTestWhileIdle(true);
            objConfig.setTimeBetweenEvictionRunsMillis(builder.healthCheckTimeMills);
        }

        ClientPoolFactory factory = new ClientPoolFactory(
                loadBalancer,
                builder.userName,
                builder.authOptions,
                builder.connectTimeoutMills,
                builder.requestTimeoutMills,
                builder.scanParallel,
                builder.workingGraph,
                builder.timeZone,
                builder.schemaName,
                builder.parameters);
        pool = new GenericObjectPool<>(factory, objConfig);
        hasInit.compareAndSet(false, true);
    }


    /**
     * get NebulaClient from pool
     */
    public NebulaClient getClient() throws Exception {
        return pool.borrowObject(maxWaitMills);
    }

    /**
     * return the client to object pool
     *
     * @param client NebulaClient
     */
    public void returnClient(NebulaClient client) {
        if (client.isClosed()) {
            try {
                pool.invalidateObject(client);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            pool.returnObject(client);
        }
    }


    public void close() {
        loadBalancer.close();
        pool.close();
    }

    /**
     * get the active sessions of NebulaClient
     *
     * @return number of sessions which are being used
     */
    public int getActiveSessions() {
        return pool.getNumActive();
    }

    /**
     * get the idle sessions of NebulaClient
     *
     * @return number of sessions which are idle
     */
    public int getIdleSessions() {
        return pool.getNumIdle();
    }

    /**
     * get the execute requests waiting to get session
     *
     * @return number of execute requests waiting to get session
     */
    public int getWaiters() {
        return pool.getNumWaiters();
    }


    public static class Builder {
        private final List   address;
        private final String              userName;
        private final String              password;
        private       Map authOptions = new HashMap<>();

        private int maxClientSize = Constants.DEFAULT_MAX_CLIENT_SIZE;
        private int minClientSize = Constants.DEFAULT_MIN_CLIENT_SIZE;

        private long connectTimeoutMills = Constants.DEFAULT_CONNECT_TIMEOUT_MS;
        private long requestTimeoutMills = Constants.DEFAULT_REQUEST_TIMEOUT_MS;

        // The healthCheckTime for schedule check the health of session, unit: millisecond
        private long healthCheckTimeMills = Constants.DEFAULT_HEALTH_CHECK_TIME_MS;

        // if block when session is exhausted, if false, throw exception.
        private boolean blockWhenExhausted = Constants.DEFAULT_BLOCK_WHEN_EXHAUSTED;

        // the max wait time if blockWhenExhausted is true. if value is less than 0, always wait.
        // unit: millisecond
        private long maxWaitMills = Constants.DEFAULT_MAX_WAIT_MS;

        // the schedule time for test the idle session and evict it. if value is less than 0,
        // never evict the idle sessions.
        private long idleEvictScheduleMills = Constants.DEFAULT_IDLE_EVICT_SCHEDULE_MS;

        // the min idle time for idle session
        private long minEvictableIdleTimeMillis = Constants.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MS;

        // if need all servers are strictly healthy.
        // if true, all addresses must be available, if false, at least one address is available.
        private boolean strictlyServerHealthy = Constants.DEFAULT_STRICT_SERVER_HEALTHY;

        private String workingGraph = null;

        // the time zone, used to parse ZonedTime and ZonedDatetime
        private ZoneId              timeZone     = null;
        private String              schemaName   = null;
        private Map parameters   = new HashMap<>();
        private int                 scanParallel = Constants.DEFAULT_SCAN_PARALLEL;

        /**
         * Builder for {@link NebulaPool}
         *
         * @param addresses graphd servers address
         * @param userName  username
         * @param password  password for user
         */
        public Builder(String addresses, String userName, String password) {
            try {
                this.address = AddressUtil.validateAddress(addresses);
            } catch (UnknownHostException e) {
                throw new RuntimeException(e);
            }
            this.userName = userName;
            this.password = password;
        }

        /**
         * config the auth options for user
         *
         * @param authOptions map of auth options
         * @return NebulaPool.Builder
         */
        public Builder withAuthOptions(Map authOptions) {
            if (authOptions != null) {
                this.authOptions.putAll(authOptions);
            }
            return this;
        }

        /**
         * config the max client size for pool
         *
         * @param maxClientSize max client size
         * @return NebulaPool.Builder
         */
        public Builder withMaxClientSize(int maxClientSize) {
            if (maxClientSize < 1) {
                throw new IllegalArgumentException("maxClientSize cannot be less than 1.");
            }
            this.maxClientSize = maxClientSize;
            return this;
        }

        /**
         * config the min client size for pool
         *
         * @param minClientSize min client size
         * @return NebulaPool.Builder
         */
        public Builder withMinClientSize(int minClientSize) {
            if (minClientSize < 0) {
                throw new IllegalArgumentException("minClientSize cannot be less than 0.");
            }
            this.minClientSize = minClientSize;
            return this;
        }

        /**
         * config the timeout for tcp connect, unit: ms
         * the value must be larger than 0 and smaller than Integer.MAX_VALUE in jdk 8.
         *
         * @param connectTimeoutMills timeout ms
         * @return NebulaPool.Builder
         */
        public Builder withConnectTimeoutMills(long connectTimeoutMills) {
            if (connectTimeoutMills <= 0
                    || connectTimeoutMills > Constants.DEFAULT_MAX_TIMEOUT_MS) {
                this.connectTimeoutMills = Constants.DEFAULT_MAX_TIMEOUT_MS;
            } else {
                this.connectTimeoutMills = connectTimeoutMills;
            }
            return this;
        }

        /**
         * config the timeout for rpc request, unit: ms
         * the value should be larger than 0 and smaller than Integer.MAX_VALUE in jdk 8.
         *
         * @param requestTimeoutMills timeout ms
         * @return NebulaPool.Builder
         */
        public Builder withRequestTimeoutMills(long requestTimeoutMills) {
            if (requestTimeoutMills <= 0
                    || requestTimeoutMills > Constants.DEFAULT_MAX_TIMEOUT_MS) {
                this.requestTimeoutMills = Constants.DEFAULT_MAX_TIMEOUT_MS;
            } else {
                this.requestTimeoutMills = requestTimeoutMills;
            }
            return this;
        }

        /**
         * config time to periodically check the health of graphd servers
         *
         * @param healthCheckTimeMills health check time for graphd servers
         * @return NebulaPool.Builder
         */
        public Builder withHealthCheckTimeMills(long healthCheckTimeMills) {
            this.healthCheckTimeMills = Math.max(healthCheckTimeMills, 0);
            return this;
        }

        /**
         * config if block and wait when object in NebulaPool is exhausted.
         * if false, then throw exception immediately when there's no idle object in NebulaPool.
         *
         * @param blockWhenExhausted if block when NebulaPool is exhausted
         * @return NebulaPool.Builder
         */
        public Builder withBlockWhenExhausted(boolean blockWhenExhausted) {
            this.blockWhenExhausted = blockWhenExhausted;
            return this;
        }

        /**
         * config the maximum wait time that the getClient should block before throwing
         * exception when the NebulaPool is exhausted and blockWhenExhausted is true. unit: ms
         * if the value is not positive, then always wait.
         *
         * @param maxWaitMills maximum time
         * @return NebulaPool.Builder
         */
        public Builder withMaxWaitMills(long maxWaitMills) {
            this.maxWaitMills = maxWaitMills <= 0 ? Long.MAX_VALUE : maxWaitMills;
            return this;
        }

        /**
         * config the schedule time to evict the idle object in NebulaPool.
         *
         * @param idleEvictScheduleMills sleep time between runs of the idle object evict task,
         *                               if the value is not positive, do not run the evict task.
         * @return NebulaPool.Builder
         */
        public Builder withIdleEvictScheduleMills(long idleEvictScheduleMills) {
            this.idleEvictScheduleMills = idleEvictScheduleMills;
            return this;
        }

        /**
         * config the minimum idle time for object in NebulaPool before it is eligible for
         * eviction by the evict task. unit: ms
         *
         * @param minEvictableIdleTimeMillis minimum idle for object in pool, if the value is
         *                                   not positive, do not evict any idle object
         * @return NebulaPool.Builder
         */
        public Builder withMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
            this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
            return this;
        }

        /**
         * config whether to require all graphd servers are all strictly available.
         *
         * @param strictlyServerHealthy whether the servers are strictly healthy.
         *                              if true, all servers must be available,
         *                              if false, at least one server must be available.
         * @return NebulaPool.Builder
         */
        public Builder withStrictlyServerHealthy(boolean strictlyServerHealthy) {
            this.strictlyServerHealthy = strictlyServerHealthy;
            return this;
        }

        /**
         * config the initial working graph for NebulaClient in NebulaPool
         *
         * @param workingGraph working graph name
         * @return NebulaPool.Builder
         */
        public Builder withWorkingGraph(String workingGraph) {
            this.workingGraph = workingGraph;
            return this;
        }

        /**
         * config the initial ZonedId for NebulaClient in NebulaPool
         *
         * @param zoneId zone id
         * @return NebulaPool.Builder
         */
        public Builder withTimeZone(ZoneId zoneId) {
            this.timeZone = zoneId;
            return this;
        }

        /**
         * config the initial schema for NebulaClient in NebulaPool
         *
         * @param schemaName schema name
         * @return NebulaPool.Builder
         */
        public Builder withSchemaName(String schemaName) {
            this.schemaName = schemaName;
            return this;
        }

        /**
         * config the parameters for NebulaClient in NebulaPool
         * session set value $key=value
         *
         * @param parameters map of parameter key and value
         * @return NebulaPool.Builder
         */
        public Builder withParameters(Map parameters) {
            if (parameters != null) {
                this.parameters = parameters;
            }
            return this;
        }


        /**
         * add the parameter into parameters for NebulaClient in NebulaPool
         * session set value $key=value
         *
         * @param paramName map of parameter key and value
         * @return NebulaPool.Builder
         */
        public Builder addParameter(String paramName, String value) {
            if (paramName != null) {
                this.parameters.put(paramName, value);
            }
            return this;
        }

        /**
         * config the parallel for data scan
         *
         * @param scanParallel number of the concurrency for data scan
         * @return NebulaClient.Builder
         */
        public Builder withScanParallel(int scanParallel) {
            this.scanParallel = scanParallel;
            return this;
        }

        public void check() {
            if (address == null) {
                throw new IllegalArgumentException("Graph addresses cannot be empty.");
            }
            if (userName == null || userName.trim().isEmpty()) {
                throw new IllegalArgumentException("user name cannot be empty.");
            }
            if (authOptions.isEmpty() && (password == null || password.trim().isEmpty())) {
                throw new IllegalArgumentException(
                        "auth options and password cannot be empty at the same time.");
            }
        }

        /**
         * build a new {@link NebulaPool} with configs
         */
        public NebulaPool build() throws IOErrorException {
            check();
            if (password != null) {
                this.authOptions.put("password", password);
            }
            return new NebulaPool(this);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy