package com.mongodb.internal.connection;
import com.mongodb.MongoException;
import com.mongodb.MongoInternalException;
import com.mongodb.ServerAddress;
import com.mongodb.connection.ClusterId;
import com.mongodb.connection.ClusterType;
import com.mongodb.diagnostics.logging.Logger;
import com.mongodb.diagnostics.logging.Loggers;
import com.mongodb.internal.dns.DnsResolver;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.mongodb.internal.connection.ServerAddressHelper.createServerAddress;
class DefaultDnsSrvRecordMonitor implements DnsSrvRecordMonitor {
private static final Logger LOGGER = Loggers.getLogger("cluster");
private final String hostName;
private final long rescanFrequencyMillis;
private final long noRecordsRescanFrequencyMillis;
private final DnsSrvRecordInitializer dnsSrvRecordInitializer;
private final DnsResolver dnsResolver;
private final Thread monitorThread;
private volatile boolean isClosed;
DefaultDnsSrvRecordMonitor(final String hostName, final long rescanFrequencyMillis, final long noRecordsRescanFrequencyMillis,
final DnsSrvRecordInitializer dnsSrvRecordInitializer, final ClusterId clusterId,
final DnsResolver dnsResolver) {
this.hostName = hostName;
this.rescanFrequencyMillis = rescanFrequencyMillis;
this.noRecordsRescanFrequencyMillis = noRecordsRescanFrequencyMillis;
this.dnsSrvRecordInitializer = dnsSrvRecordInitializer;
this.dnsResolver = dnsResolver;
monitorThread = new Thread(new DnsSrvRecordMonitorRunnable(), "cluster-" + clusterId + "-srv-" + hostName);
monitorThread.setDaemon(true);
}
@Override
public void start() {
monitorThread.start();
}
@Override
public void close() {
isClosed = true;
monitorThread.interrupt();
}
private class DnsSrvRecordMonitorRunnable implements Runnable {
private Set<ServerAddress> currentHosts = Collections.emptySet();
private ClusterType clusterType = ClusterType.UNKNOWN;
@Override
public void run() {
while (!isClosed && shouldContinueMonitoring()) {
try {
List<String> resolvedHostNames = dnsResolver.resolveHostFromSrvRecords(hostName);
Set<ServerAddress> hosts = createServerAddressSet(resolvedHostNames);
if (isClosed) {
return;
}
if (!hosts.equals(currentHosts)) {
try {
dnsSrvRecordInitializer.initialize(hosts);
currentHosts = hosts;
} catch (RuntimeException e) {
LOGGER.warn("Exception in monitor thread during notification of DNS resolution state change", e);
}
}
} catch (MongoException e) {
if (currentHosts.isEmpty()) {
dnsSrvRecordInitializer.initialize(e);
}
LOGGER.info("Exception while resolving SRV records", e);
} catch (RuntimeException e) {
if (currentHosts.isEmpty()) {
dnsSrvRecordInitializer.initialize(new MongoInternalException("Unexpected runtime exception", e));
}
LOGGER.info("Unexpected runtime exception while resolving SRV record", e);
}
try {
Thread.sleep(getRescanFrequencyMillis());
} catch (InterruptedException e) {
}
clusterType = dnsSrvRecordInitializer.getClusterType();
}
}
private boolean shouldContinueMonitoring() {
return clusterType == ClusterType.UNKNOWN || clusterType == ClusterType.SHARDED;
}
private long getRescanFrequencyMillis() {
return currentHosts.isEmpty() ? noRecordsRescanFrequencyMillis : rescanFrequencyMillis;
}
private Set<ServerAddress> createServerAddressSet(final List<String> resolvedHostNames) {
Set<ServerAddress> hosts = new HashSet<ServerAddress>(resolvedHostNames.size());
for (String host : resolvedHostNames) {
hosts.add(createServerAddress(host));
}
return hosts;
}
}
}