in wrapper/src/main/java/software/amazon/jdbc/plugin/failover2/FailoverConnectionPlugin.java [394:494]
protected ReaderFailoverResult getReaderFailoverConnection(long failoverEndTimeNano) throws TimeoutException {
// The roles in this list might not be accurate, depending on whether the new topology has become available yet.
final List<HostSpec> hosts = this.pluginService.getHosts();
final Set<HostSpec> readerCandidates = hosts.stream()
.filter(hostSpec -> HostRole.READER.equals(hostSpec.getRole()))
.collect(Collectors.toSet());
final HostSpec originalWriter = hosts.stream()
.filter(hostSpec -> HostRole.WRITER.equals(hostSpec.getRole()))
.findFirst()
.orElse(null);
boolean isOriginalWriterStillWriter = false;
do {
// First, try all original readers
final Set<HostSpec> remainingReaders = new HashSet<>(readerCandidates);
while (!remainingReaders.isEmpty() && System.nanoTime() < failoverEndTimeNano) {
HostSpec readerCandidate;
try {
readerCandidate =
this.pluginService.getHostSpecByStrategy(
new ArrayList<>(remainingReaders),
HostRole.READER,
this.failoverReaderHostSelectorStrategySetting);
} catch (UnsupportedOperationException | SQLException ex) {
LOGGER.finest(
Utils.logTopology(
new ArrayList<>(remainingReaders),
Messages.get("Failover.errorSelectingReaderHost", new Object[]{ex.getMessage()})));
break;
}
if (readerCandidate == null) {
LOGGER.finest(
Utils.logTopology(new ArrayList<>(remainingReaders), Messages.get("Failover.readerCandidateNull")));
break;
}
try {
Connection candidateConn = this.pluginService.connect(readerCandidate, this.properties, this);
// Since the roles in the host list might not be accurate, we execute a query to check the instance's role.
HostRole role = this.pluginService.getHostRole(candidateConn);
if (role == HostRole.READER || this.failoverMode != STRICT_READER) {
HostSpec updatedHostSpec = new HostSpec(readerCandidate, role);
return new ReaderFailoverResult(candidateConn, updatedHostSpec);
}
// The role is WRITER or UNKNOWN, and we are in STRICT_READER mode, so the connection is not valid.
remainingReaders.remove(readerCandidate);
candidateConn.close();
if (role == HostRole.WRITER) {
// The reader candidate is actually a writer, which is not valid when failoverMode is STRICT_READER.
// We will remove it from the list of reader candidates to avoid retrying it in future iterations.
readerCandidates.remove(readerCandidate);
} else {
LOGGER.fine(
Messages.get("Failover.strictReaderUnknownHostRole", new Object[]{readerCandidate.getUrl()}));
}
} catch (SQLException ex) {
remainingReaders.remove(readerCandidate);
}
}
// We were not able to connect to any of the original readers. We will try connecting to the original writer,
// which may have been demoted to a reader.
if (originalWriter == null || System.nanoTime() > failoverEndTimeNano) {
// No writer was found in the original topology, or we have timed out.
continue;
}
if (this.failoverMode == STRICT_READER && isOriginalWriterStillWriter) {
// The original writer has been verified, so it is not valid when in STRICT_READER mode.
continue;
}
// Try the original writer, which may have been demoted to a reader.
try {
Connection candidateConn = this.pluginService.connect(originalWriter, this.properties, this);
HostRole role = this.pluginService.getHostRole(candidateConn);
if (role == HostRole.READER || this.failoverMode != STRICT_READER) {
HostSpec updatedHostSpec = new HostSpec(originalWriter, role);
return new ReaderFailoverResult(candidateConn, updatedHostSpec);
}
// The role is WRITER or UNKNOWN, and we are in STRICT_READER mode, so the connection is not valid.
candidateConn.close();
if (role == HostRole.WRITER) {
isOriginalWriterStillWriter = true;
} else {
LOGGER.fine(Messages.get("Failover.strictReaderUnknownHostRole", new Object[]{originalWriter.getUrl()}));
}
} catch (SQLException ex) {
LOGGER.fine(Messages.get("Failover.failedReaderConnection", new Object[]{originalWriter.getUrl()}));
}
} while (System.nanoTime() < failoverEndTimeNano); // All hosts failed. Keep trying until we hit the timeout.
throw new TimeoutException(Messages.get("Failover.failoverReaderTimeout"));
}