org.postgresql.hostchooser.MultiHostChooser Maven / Gradle / Ivy
/*
* 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.lang.Boolean.parseBoolean;
import static java.lang.Integer.parseInt;
import static java.util.Arrays.asList;
import static java.util.Collections.shuffle;
import static java.util.Collections.sort;
import org.postgresql.hostchooser.GlobalHostStatusTracker.HostSpecStatus;
import org.postgresql.util.HostSpec;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
/**
* HostChooser that keeps track of known host statuses.
*/
public class MultiHostChooser implements HostChooser {
private HostSpec[] hostSpecs;
private final HostRequirement targetServerType;
private int hostRecheckTime;
private boolean loadBalance;
protected MultiHostChooser(HostSpec[] hostSpecs, HostRequirement targetServerType,
Properties info) {
this.hostSpecs = hostSpecs;
this.targetServerType = targetServerType;
hostRecheckTime = parseInt(info.getProperty("hostRecheckSeconds", "10")) * 1000;
loadBalance = parseBoolean(info.getProperty("loadBalanceHosts", "false"));
}
@Override
public Iterator iterator() {
List candidates =
GlobalHostStatusTracker.getCandidateHosts(hostSpecs, targetServerType, hostRecheckTime);
// if no candidates are suitable (all wrong type or unavailable) then we try original list in
// order
if (candidates.isEmpty()) {
return asList(hostSpecs).iterator();
}
if (candidates.size() == 1) {
return asList(candidates.get(0).host).iterator();
}
sortCandidates(candidates);
shuffleGoodHosts(candidates);
return extractHostSpecs(candidates).iterator();
}
private void sortCandidates(List candidates) {
if (targetServerType == HostRequirement.any) {
return;
}
sort(candidates, new HostSpecByTargetServerTypeComparator());
}
private void shuffleGoodHosts(List candidates) {
if (!loadBalance) {
return;
}
int count;
for (count = 1; count < candidates.size(); count++) {
HostSpecStatus hostSpecStatus = candidates.get(count);
if (hostSpecStatus.status != null
&& !targetServerType.allowConnectingTo(hostSpecStatus.status)) {
break;
}
}
if (count == 1) {
return;
}
List goodHosts = candidates.subList(0, count);
shuffle(goodHosts);
}
private List extractHostSpecs(List hostSpecStatuses) {
List hostSpecs = new ArrayList(hostSpecStatuses.size());
for (HostSpecStatus hostSpecStatus : hostSpecStatuses) {
hostSpecs.add(hostSpecStatus.host);
}
return hostSpecs;
}
class HostSpecByTargetServerTypeComparator implements Comparator {
@Override
public int compare(HostSpecStatus o1, HostSpecStatus o2) {
int r1 = rank(o1.status, targetServerType);
int r2 = rank(o2.status, targetServerType);
return r1 == r2 ? 0 : r1 > r2 ? -1 : 1;
}
private int rank(HostStatus status, HostRequirement targetServerType) {
if (status == HostStatus.ConnectFail) {
return -1;
}
switch (targetServerType) {
case master:
return status == HostStatus.Master || status == null ? 1 : 0;
case slave:
return status == HostStatus.Slave || status == null ? 1 : 0;
case preferSlave:
return status == HostStatus.Slave || status == null ? 2
: status == HostStatus.Master ? 1 : 0;
default:
return 0;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy