blob: 4a1267cb31a2ca26b0a51f06d05f87ae47eed40d [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2012-2014 Monty Program Ab
// Copyright (c) 2015-2021 MariaDB Corporation Ab
package org.mariadb.jdbc.export;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import org.mariadb.jdbc.HostAddress;
/** Failover (High-availability) mode */
public enum HaMode {
/** replication mode : first is primary, other are replica */
REPLICATION("replication") {
public Optional<HostAddress> getAvailableHost(
List<HostAddress> hostAddresses,
ConcurrentMap<HostAddress, Long> denyList,
boolean primary) {
return HaMode.getAvailableRoundRobinHost(this, hostAddresses, denyList, primary);
}
},
/** sequential: driver will always connect according to connection string order */
SEQUENTIAL("sequential") {
public Optional<HostAddress> getAvailableHost(
List<HostAddress> hostAddresses,
ConcurrentMap<HostAddress, Long> denyList,
boolean primary) {
return getAvailableHostInOrder(hostAddresses, denyList, primary);
}
},
/**
* load-balance: driver will connect to any host using round-robin, permitting balancing
* connections
*/
LOADBALANCE("load-balance") {
public Optional<HostAddress> getAvailableHost(
List<HostAddress> hostAddresses,
ConcurrentMap<HostAddress, Long> denyList,
boolean primary) {
return HaMode.getAvailableRoundRobinHost(this, hostAddresses, denyList, primary);
}
},
/** no ha-mode. Connect to first host only */
NONE("") {
public Optional<HostAddress> getAvailableHost(
List<HostAddress> hostAddresses,
ConcurrentMap<HostAddress, Long> denyList,
boolean primary) {
return hostAddresses.isEmpty() ? Optional.empty() : Optional.of(hostAddresses.get(0));
}
};
private final String value;
private HostAddress lastRoundRobinPrimaryHost = null;
private HostAddress lastRoundRobinSecondaryHost = null;
HaMode(String value) {
this.value = value;
}
/**
* Get HAMode from values or aliases
*
* @param value value or alias
* @return HaMode if corresponding mode is found
*/
public static HaMode from(String value) {
for (HaMode haMode : values()) {
if (haMode.value.equalsIgnoreCase(value) || haMode.name().equalsIgnoreCase(value)) {
return haMode;
}
}
throw new IllegalArgumentException(
String.format("Wrong argument value '%s' for HaMode", value));
}
/**
* return hosts of corresponding type (primary or not) without blacklisted hosts. hosts in
* blacklist reaching blacklist timeout will be present. order corresponds to connection string
* order.
*
* @param hostAddresses hosts
* @param denyList blacklist
* @param primary returns primary hosts or replica
* @return list without denied hosts
*/
public static Optional<HostAddress> getAvailableHostInOrder(
List<HostAddress> hostAddresses, ConcurrentMap<HostAddress, Long> denyList, boolean primary) {
// use in order not blacklisted server
for (HostAddress hostAddress : hostAddresses) {
if (hostAddress.primary == primary) {
if (!denyList.containsKey(hostAddress)) return Optional.of(hostAddress);
if (denyList.get(hostAddress) < System.currentTimeMillis()) {
// timeout reached
denyList.remove(hostAddress);
return Optional.of(hostAddress);
}
}
}
return Optional.empty();
}
/**
* return hosts of corresponding type (primary or not) without blacklisted hosts. hosts in
* blacklist reaching blacklist timeout will be present, RoundRobin Order.
*
* @param haMode current haMode
* @param hostAddresses hosts
* @param denyList blacklist
* @param primary returns primary hosts or replica
* @return list without denied hosts
*/
public static Optional<HostAddress> getAvailableRoundRobinHost(
HaMode haMode,
List<HostAddress> hostAddresses,
ConcurrentMap<HostAddress, Long> denyList,
boolean primary) {
HostAddress lastChosenHost =
primary ? haMode.lastRoundRobinPrimaryHost : haMode.lastRoundRobinSecondaryHost;
List<HostAddress> loopList;
if (lastChosenHost == null) {
loopList = hostAddresses;
} else {
int lastChosenIndex = hostAddresses.indexOf(lastChosenHost);
loopList = new ArrayList<>();
loopList.addAll(hostAddresses.subList(lastChosenIndex + 1, hostAddresses.size()));
loopList.addAll(hostAddresses.subList(0, lastChosenIndex + 1));
}
for (HostAddress hostAddress : loopList) {
if (hostAddress.primary == primary) {
if (denyList.containsKey(hostAddress)) {
// take in account denied server that have reached denied timeout
if (denyList.get(hostAddress) > System.currentTimeMillis()) {
continue;
} else {
denyList.remove(hostAddress);
}
}
if (primary) {
haMode.lastRoundRobinPrimaryHost = hostAddress;
} else {
haMode.lastRoundRobinSecondaryHost = hostAddress;
}
return Optional.of(hostAddress);
}
}
return Optional.empty();
}
/**
* List of hosts without blacklist entries, ordered according to HA mode
*
* @param hostAddresses hosts
* @param denyList hosts temporary denied
* @param primary type
* @return list without denied hosts
*/
public abstract Optional<HostAddress> getAvailableHost(
List<HostAddress> hostAddresses, ConcurrentMap<HostAddress, Long> denyList, boolean primary);
}