org.postgresql.hostchooser.MultiHostChooser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of postgresql Show documentation
Show all versions of postgresql Show documentation
PostgreSQL JDBC Driver JDBC4
/*
* Copyright (c) 2014, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.hostchooser;
import static java.util.Collections.shuffle;
import org.postgresql.PGProperty;
import org.postgresql.util.HostSpec;
import org.postgresql.util.PSQLException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
/**
* HostChooser that keeps track of known host statuses.
*/
class MultiHostChooser implements HostChooser {
private HostSpec[] hostSpecs;
private final HostRequirement targetServerType;
private int hostRecheckTime;
private boolean loadBalance;
MultiHostChooser(HostSpec[] hostSpecs, HostRequirement targetServerType,
Properties info) {
this.hostSpecs = hostSpecs;
this.targetServerType = targetServerType;
try {
hostRecheckTime = PGProperty.HOST_RECHECK_SECONDS.getInt(info) * 1000;
loadBalance = PGProperty.LOAD_BALANCE_HOSTS.getBoolean(info);
} catch (PSQLException e) {
throw new RuntimeException(e);
}
}
@Override
public Iterator iterator() {
Iterator res = candidateIterator();
if (!res.hasNext()) {
// In case all the candidate hosts are unavailable or do not match, try all the hosts just in case
List allHosts = Arrays.asList(hostSpecs);
if (loadBalance) {
allHosts = new ArrayList<>(allHosts);
shuffle(allHosts);
}
res = withReqStatus(targetServerType, allHosts).iterator();
}
return res;
}
private Iterator candidateIterator() {
if ( targetServerType != HostRequirement.preferSecondary
&& targetServerType != HostRequirement.preferPrimary ) {
return getCandidateHosts(targetServerType).iterator();
}
HostRequirement preferredServerType =
targetServerType == HostRequirement.preferSecondary
? HostRequirement.secondary
: HostRequirement.primary;
// preferSecondary tries to find secondary hosts first
// Note: sort does not work here since there are "unknown" hosts,
// and that "unknown" might turn out to be master, so we should discard that
// if other secondaries exist
// Same logic as the above works for preferPrimary if we replace "secondary"
// with "primary" and vice versa
List preferred = getCandidateHosts(preferredServerType);
List any = getCandidateHosts(HostRequirement.any);
if ( !preferred.isEmpty() && !any.isEmpty()
&& preferred.get(preferred.size() - 1).hostSpec.equals(any.get(0).hostSpec)) {
// When the last preferred host's hostspec is the same as the first in "any" list, there's no need
// to attempt to connect it as "preferred"
// Note: this is only an optimization
preferred = rtrim(1, preferred);
}
return append(preferred, any).iterator();
}
private List getCandidateHosts(HostRequirement hostRequirement) {
List candidates =
GlobalHostStatusTracker.getCandidateHosts(hostSpecs, hostRequirement, hostRecheckTime);
if (loadBalance) {
shuffle(candidates);
}
return withReqStatus(hostRequirement, candidates);
}
private List withReqStatus(final HostRequirement requirement, final List hosts) {
return new AbstractList() {
@Override
public CandidateHost get(int index) {
return new CandidateHost(hosts.get(index), requirement);
}
@Override
public int size() {
return hosts.size();
}
};
}
private List append(final List a, final List b) {
return new AbstractList() {
@Override
public T get(int index) {
return index < a.size() ? a.get(index) : b.get(index - a.size());
}
@Override
public int size() {
return a.size() + b.size();
}
};
}
private List rtrim(final int size, final List a) {
return new AbstractList() {
@Override
public T get(int index) {
return a.get(index);
}
@Override
public int size() {
return Math.max(0, a.size() - size);
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy