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

tech.ydb.table.impl.pool.StatefulSession Maven / Gradle / Ivy

package tech.ydb.table.impl.pool;

import java.time.Clock;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.concurrent.ThreadSafe;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tech.ydb.core.StatusCode;
import tech.ydb.table.impl.BaseSession;
import tech.ydb.table.rpc.TableRpc;

/**
 *
 * @author Aleksandr Gorshenin
 */
@ThreadSafe
abstract class StatefulSession extends BaseSession {
    private static final Logger logger = LoggerFactory.getLogger(SessionPool.class);

    private final Clock clock;
    private final AtomicReference state;

    protected StatefulSession(String id, Clock clock, TableRpc tableRpc, boolean keepQueryText) {
        super(id, tableRpc, keepQueryText);
        this.clock = clock;
        this.state = new AtomicReference<>(new State(Status.IDLE, clock.instant()));
    }

    @Override
    protected void updateSessionState(Throwable th, StatusCode code, boolean gracefulShutdown) {
        State current = state.get();
        while (!state.compareAndSet(current, current.updated(clock.instant(), th, code, gracefulShutdown))) {
            current = state.get();
        }
        if (logger.isTraceEnabled()) {
            logger.trace("{} updated => {}, {}", toString(), state.get().status, state.get().lastUpdate);
        }
    }

    public State state() {
        return state.get();
    }

    private boolean switchState(State current, State next) {
        return next != null && state.compareAndSet(current, next);
    }

    private enum Status {
        IDLE,
        ACTIVE,
        NEED_SHUTDOWN,
        KEEPALIVE,
        BROKEN;
    }

    public class State {
        private final Status status;
        private final Instant lastActive;
        private final Instant lastUpdate;

        private State(Status status, Instant now) {
            this.status = status;
            this.lastActive = now;
            this.lastUpdate = now;
        }

        private State(Status status, Instant lastActive, Instant lastUpdate) {
            this.status = status;
            this.lastActive = lastActive;
            this.lastUpdate = lastUpdate;
        }

        public Instant lastActive() {
            return this.lastActive;
        }
        public Instant lastUpdate() {
            return this.lastUpdate;
        }

        public boolean needShutdown() {
            return this.status == Status.BROKEN || this.status == Status.NEED_SHUTDOWN;
        }

        public boolean switchToActive(Instant now) {
            return switchState(this, nextState(Status.ACTIVE, now));
        }

        public boolean switchToKeepAlive(Instant now) {
            return switchState(this, nextState(Status.KEEPALIVE, now));
        }

        public boolean switchToIdle(Instant now) {
            return switchState(this, nextState(Status.IDLE, now));
        }

        public boolean switchToBroken(Instant now) {
            return switchState(this, nextState(Status.BROKEN, now));
        }

        private State updated(Instant now, Throwable th, StatusCode code, boolean shutdownHint) {
            // Broken state never will be updated
            if (status == Status.BROKEN) {
                return this;
            }

            // Check problems
            boolean broken = th != null
                    || (code.isTransportError() && code != StatusCode.CLIENT_RESOURCE_EXHAUSTED)
                    || code == StatusCode.BAD_SESSION
                    || code == StatusCode.SESSION_BUSY
                    || code == StatusCode.INTERNAL_ERROR;

            // and if we found it state switch to broken status
            if (broken) {
                return new State(Status.BROKEN, lastActive, now);
            }

            if (status == Status.NEED_SHUTDOWN) {
                return new State(status, now);
            }

            if (status == Status.ACTIVE) {
                if (shutdownHint) {
                    return new State(Status.NEED_SHUTDOWN, now);
                }
                return new State(status, now);
            }

            return new State(status, lastActive, now);
        }

        private State nextState(Status nextStatus, Instant now) {
            // Broken and need shutdown states never will be changed
            if (status == Status.BROKEN || status == Status.NEED_SHUTDOWN) {
                return null;
            }

            if (nextStatus == Status.BROKEN) {
                return new State(Status.BROKEN, lastActive, now);
            }

            if (nextStatus == Status.ACTIVE) {
                return new State(nextStatus, now);
            }

            return new State(nextStatus, lastActive, now);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy