vesoft-inc / nebula-java

Client API and data importer of Nebula Graph in Java
Apache License 2.0
164 stars 121 forks source link

An lock-free implement for SessionPool #537

Closed awang12345 closed 8 months ago

awang12345 commented 10 months ago

nebula-java version:3.6.0 class: com.vesoft.nebula.client.graph.SessionPool desc The current implementation of session fetching does not perform well under high concurrency, because each session fetching is synchronous and all threads must wait for it in serial

new logic

private final AtomicInteger sessionCreatingCounter = new AtomicInteger();
private final Object sessionCreateWaiter = new Object();

/**
     * return an idle session
     */
private NebulaSession getSession() throws ClientServerIncompatibleException,
            AuthFailedException, IOErrorException, BindSpaceFailedException {
        final long startTime = System.nanoTime();
        final long timeout = startTime + this.connectWaitTimeoutNanos;
        while (true) {
            // if there are idle sessions, get session from queue
            if (idleSessionSize.get() > 0) {
                for (NebulaSession nebulaSession : sessionList) {
                    if (nebulaSession.isIdle() && nebulaSession.isIdleAndSetUsed()) {
                        idleSessionSize.decrementAndGet();
                        return nebulaSession;
                    }
                }
            }
            // if session size is less than max size, get session from pool
            if (sessionList.size() < maxSessionSize) {
                try {
                    if (sessionList.size() + sessionCreatingCounter.addAndGet(1) <= maxSessionSize) {
                        return createSessionObject(SessionState.USED);
                    }
                } finally {
                    sessionCreatingCounter.decrementAndGet();
                }
            }
            if (timeout <= System.nanoTime()) {
                break;
            }
            waitForIdleSession(timeout);
        }
        // if session size is equal to max size and no idle session here, throw exception
        throw new RuntimeException("no extra session available");
    }

 /**
     * release the NebulaSession when finished the execution.
     */
    private void returnSession(NebulaSession nebulaSession) {
        nebulaSession.isUsedAndSetIdle();
        idleSessionSize.incrementAndGet();
        notifyIdleSession();
    }

    private void waitForIdleSession(long timeout) {
        synchronized (sessionCreateWaiter) {
            try {
                sessionCreateWaiter.wait(TimeUnit.NANOSECONDS.toMillis(timeout - System.nanoTime()));
            } catch (InterruptedException e) {
                log.error("getSession error when wait for idle sessions, ", e);
                throw new RuntimeException(e);
            }
        }
    }

    private void notifyIdleSession() {
        synchronized (sessionCreateWaiter) {
            sessionCreateWaiter.notify();
        }
    }
Nicole00 commented 9 months ago

Thanks for your implementation for lock-free to get Session. For getSession, we need to support the retry times and wait time between every retry. And the wait time not mean the total cost time for GetSession, but mean the time to wait before next re-getSession. Maybe there's little inconsistent for retry times and wait time.

awang12345 commented 8 months ago

Thank you for the response