org.postgresql.quickautobalance.ConnectionInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mogdb-jdbc Show documentation
Show all versions of mogdb-jdbc Show documentation
Java JDBC driver for MogDB
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package io.mogdb.quickautobalance;
import io.mogdb.PGProperty;
import io.mogdb.core.QueryExecutor;
import io.mogdb.core.SetupQueryRunner;
import io.mogdb.jdbc.PgConnection;
import io.mogdb.jdbc.StatementCancelState;
import io.mogdb.log.Log;
import io.mogdb.log.Logger;
import io.mogdb.util.GT;
import io.mogdb.util.HostSpec;
import io.mogdb.util.PSQLException;
import io.mogdb.util.PSQLState;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Objects;
import java.util.Properties;
/**
* Connection info used in quick auto balance.
*/
public class ConnectionInfo {
/**
* Default maxIdleTimeBeforeTerminal.
*/
public static final long DEFAULT_MAX_IDLE_TIME_BEFORE_TERMINAL = 30L;
public static final String ENABLE_QUICK_AUTO_BALANCE_PARAMS = "true";
private static final long MAX_IDLE_TIME_BEFORE_TERMINAL_MAX_VALUE = 9223372036854775L;
private static Log LOGGER = Logger.getLogger(ConnectionInfo.class.getName());
private final PgConnection pgConnection;
private final long createTimeStamp;
private final String autoBalance;
private boolean enableQuickAutoBalance;
// max idle time of connection, units: second
private long maxIdleTimeBeforeTerminal;
private final HostSpec hostSpec;
private volatile StatementCancelState connectionState;
// the timestamp when state change last time
private volatile long stateLastChangedTimeStamp;
@Override
public int hashCode() {
return Objects.hash(pgConnection, createTimeStamp, autoBalance, enableQuickAutoBalance,
maxIdleTimeBeforeTerminal, hostSpec);
}
public ConnectionInfo(PgConnection pgConnection, Properties properties, HostSpec hostSpec)
throws PSQLException {
this.pgConnection = pgConnection;
this.connectionState = StatementCancelState.IDLE;
this.createTimeStamp = System.currentTimeMillis();
this.stateLastChangedTimeStamp = createTimeStamp;
this.autoBalance = properties.getProperty("autoBalance", "");
this.maxIdleTimeBeforeTerminal = DEFAULT_MAX_IDLE_TIME_BEFORE_TERMINAL;
this.hostSpec = hostSpec;
this.maxIdleTimeBeforeTerminal = parseMaxIdleTimeBeforeTerminal(properties);
this.enableQuickAutoBalance = parseEnableQuickAutoBalance(properties);
}
/**
* Parse enableQuickAutoBalance.
*
* @param properties properties
* @return enableQuickAutoBalance
* @throws PSQLException EnableQuickAutoBalance parsed failed.
*/
public static boolean parseEnableQuickAutoBalance(Properties properties) throws PSQLException {
if (EnableQuickAutoBalanceParams.TRUE.getValue()
.equals(PGProperty.ENABLE_QUICK_AUTO_BALANCE.get(properties))) {
return true;
} else if (EnableQuickAutoBalanceParams.FALSE.getValue()
.equals(PGProperty.ENABLE_QUICK_AUTO_BALANCE.get(properties))) {
return false;
} else {
throw new PSQLException(
GT.tr("Parameter enableQuickAutoBalance={0} parsed failed, value range: '{true, false'}).",
PGProperty.ENABLE_QUICK_AUTO_BALANCE.get(properties)), PSQLState.INVALID_PARAMETER_VALUE);
}
}
/**
* Parse maxIdleTimeBeforeTerminal.
*
* @param properties properties
* @return maxIdleTimeBeforeTerminal
* @throws PSQLException MaxIdleTimeBeforeTerminal parse failed.
*/
public static long parseMaxIdleTimeBeforeTerminal(Properties properties) throws PSQLException {
long inputMaxIdleTime;
try {
String param = PGProperty.MAX_IDLE_TIME_BEFORE_TERMINAL.get(properties);
inputMaxIdleTime = Long.parseLong(param);
if (inputMaxIdleTime >= MAX_IDLE_TIME_BEFORE_TERMINAL_MAX_VALUE) {
throw new PSQLException(
GT.tr("Parameter maxIdleTimeBeforeTerminal={0} can not be bigger than {1}, value range: long & [0,{1}).",
String.valueOf(inputMaxIdleTime), String.valueOf(MAX_IDLE_TIME_BEFORE_TERMINAL_MAX_VALUE)),
PSQLState.INVALID_PARAMETER_VALUE);
}
if (inputMaxIdleTime < 0) {
throw new PSQLException(
GT.tr("Parameter maxIdleTimeBeforeTerminal={0} can not be less than 0, value range: long & [0,{1}).",
String.valueOf(inputMaxIdleTime), String.valueOf(MAX_IDLE_TIME_BEFORE_TERMINAL_MAX_VALUE)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} catch (NumberFormatException e) {
throw new PSQLException(
GT.tr("Parameter maxIdleTimeBeforeTerminal parsed failed, value range: long & [0,{0}).",
String.valueOf(MAX_IDLE_TIME_BEFORE_TERMINAL_MAX_VALUE)), PSQLState.INVALID_PARAMETER_TYPE);
}
return inputMaxIdleTime;
}
enum EnableQuickAutoBalanceParams {
TRUE("true"),
FALSE("false");
private final String value;
EnableQuickAutoBalanceParams(String value) {
this.value = value;
}
/**
* Get value.
*
* @return value
*/
public String getValue() {
return this.value;
}
}
public StatementCancelState getConnectionState() {
return connectionState;
}
public synchronized void setConnectionState(StatementCancelState state) {
if (state != null && !connectionState.equals(state)) {
connectionState = state;
stateLastChangedTimeStamp = System.currentTimeMillis();
}
}
public long getMaxIdleTimeBeforeTerminal() {
return maxIdleTimeBeforeTerminal;
}
public String getAutoBalance() {
return autoBalance;
}
public PgConnection getPgConnection() {
return pgConnection;
}
@Override
public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final ConnectionInfo that = (ConnectionInfo) o;
return createTimeStamp == that.createTimeStamp && enableQuickAutoBalance == that.enableQuickAutoBalance &&
maxIdleTimeBeforeTerminal == that.maxIdleTimeBeforeTerminal && pgConnection.equals(that.pgConnection) &&
autoBalance.equals(that.autoBalance) && hostSpec.equals(that.hostSpec);
}
/**
* Check whether the connection can be closed.
* The judgement conditions are as follows:
* 1. The connection enables quickAutoBalance.
* 2. The quickAutoBalance start time is later than the connection create time.
* 3. The connection state is idle.
* 4. The connection keeps idle at least maxIdleTimeBeforeTerminal seconds.
*
* @param quickAutoBalanceStartTime quickAutoBalance start time
* @return whether the connection can be closed
*/
public synchronized boolean checkConnectionCanBeClosed(long quickAutoBalanceStartTime) {
if (pgConnection == null) {
return false;
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(GT.tr("checkConnectionCanBeClosed: server ip={0}, enableQuickAutoBalance={1}, " +
"quickAutoBalanceStartTime={2}, createTimeStamp={3}, connectionState={4}, " +
"stateLastChangedTimeStamp={5}, currentTimeMillis={6}",
hostSpec.toString(), isEnableQuickAutoBalance(), quickAutoBalanceStartTime, createTimeStamp,
connectionState, stateLastChangedTimeStamp, System.currentTimeMillis()));
}
if (!isEnableQuickAutoBalance()) {
return false;
}
if (quickAutoBalanceStartTime < createTimeStamp) {
return false;
}
if (!connectionState.equals(StatementCancelState.IDLE)) {
return false;
}
return System.currentTimeMillis() - stateLastChangedTimeStamp > maxIdleTimeBeforeTerminal * 1000;
}
public boolean isEnableQuickAutoBalance() {
return enableQuickAutoBalance;
}
/**
* Check whether a connection is valid.
*
* @return whether a connection is valid
*/
public boolean checkConnectionIsValid() {
boolean isConnectionValid;
try {
QueryExecutor queryExecutor = pgConnection.getQueryExecutor();
byte[][] bit = SetupQueryRunner.run(queryExecutor, "select 1", true);
if (bit == null) {
return false;
}
String result = queryExecutor.getEncoding().decode(bit[0]);
isConnectionValid = result != null && result.equals("1");
} catch (SQLException | IOException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(GT.tr("CheckConnectionIsValid failed."));
}
isConnectionValid = false;
}
return isConnectionValid;
}
/**
* get hostSpec
*
* @return hostSpec
*/
public HostSpec getHostSpec() {
return hostSpec;
}
}