Improve logging, correctly handle redemption, use a thread-pool

cusax-fix
Ingo Bauersachs 13 years ago
parent ca2b2738e3
commit 9426348317

@ -10,6 +10,7 @@
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*;
import net.java.sip.communicator.service.dns.*; import net.java.sip.communicator.service.dns.*;
import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.*;
@ -43,13 +44,13 @@ public class ParallelResolverImpl
* class and its instances for logging output. * class and its instances for logging output.
*/ */
private static final Logger logger = Logger private static final Logger logger = Logger
.getLogger(ParallelResolverImpl.class.getName()); .getLogger(ParallelResolverImpl.class);
/** /**
* Indicates whether we are currently in a mode where all DNS queries are * Indicates whether we are currently in a mode where all DNS queries are
* sent to both the primary and the backup DNS servers. * sent to both the primary and the backup DNS servers.
*/ */
private static boolean redundantMode = false; private volatile static boolean redundantMode = false;
/** /**
* The currently configured number of milliseconds that we need to wait * The currently configured number of milliseconds that we need to wait
@ -87,11 +88,15 @@ public class ParallelResolverImpl
*/ */
private ExtendedResolver backupResolver; private ExtendedResolver backupResolver;
/** Thread pool that processes the backup queries. */
private ExecutorService backupQueriesPool;
/** /**
* Creates a new instance of this class. * Creates a new instance of this class.
*/ */
ParallelResolverImpl() ParallelResolverImpl()
{ {
backupQueriesPool = Executors.newCachedThreadPool();
DnsUtilActivator.getConfigurationService() DnsUtilActivator.getConfigurationService()
.addPropertyChangeListener(this); .addPropertyChangeListener(this);
initProperties(); initProperties();
@ -117,9 +122,9 @@ private void initProperties()
} }
catch(UnknownHostException exc) catch(UnknownHostException exc)
{ {
logger.warn("Oh! Seems like our primary DNS is down!" logger
+ "Don't panic! We'll try to fall back to " .warn("Seems like the primary DNS is down, trying fallback to "
+ customResolverIP); + customResolverIP);
} }
if(resolverAddress == null) if(resolverAddress == null)
@ -178,7 +183,7 @@ private void setBackupServers(InetSocketAddress[] backupServers)
//this shouldn't be thrown since we don't do any DNS querying //this shouldn't be thrown since we don't do any DNS querying
//in here. this is why we take an InetSocketAddress as a param. //in here. this is why we take an InetSocketAddress as a param.
throw new IllegalStateException("The impossible just happened: " throw new IllegalStateException("The impossible just happened: "
+"we could not initialize our backup DNS resolver"); + "we could not initialize our backup DNS resolver");
} }
} }
@ -193,23 +198,12 @@ private void setBackupServers(InetSocketAddress[] backupServers)
public Message send(Message query) public Message send(Message query)
throws IOException throws IOException
{ {
ParallelResolution resolution = new ParallelResolution(query); ParallelResolution resolution = new ParallelResolution(query);
resolution.sendFirstQuery(); resolution.sendFirstQuery();
//make a copy of the redundant mode variable in case we are currently
//completed a redemption that started earlier.
boolean redundantModeCopy;
synchronized(redemptionLock)
{
redundantModeCopy = redundantMode;
}
//if we are not in redundant mode we should wait a bit and see how this //if we are not in redundant mode we should wait a bit and see how this
//goes. if we get a reply we could return bravely. //goes. if we get a reply we could return bravely.
if(!redundantModeCopy) if(!redundantMode)
{ {
if(resolution.waitForResponse(currentDnsPatience)) if(resolution.waitForResponse(currentDnsPatience))
{ {
@ -222,16 +216,17 @@ public Message send(Message query)
{ {
redundantMode = true; redundantMode = true;
redemptionStatus = currentDnsRedemption; redemptionStatus = currentDnsRedemption;
logger.info("Primary DNS seems laggy as we got no " logger.info("Primary DNS seems laggy: "
+"response for " + currentDnsPatience + "ms. " + "no response for " + query.getQuestion().getName()
+ "Enabling redundant mode."); + "/" + Type.string(query.getQuestion().getType())
+ " after " + currentDnsPatience + "ms. "
+ "Enabling redundant mode.");
} }
} }
} }
//we are definitely in redundant mode now //we are definitely in redundant mode now
resolution.sendBackupQueries(); resolution.sendBackupQueries();
resolution.waitForResponse(0); resolution.waitForResponse(0);
//check if it is time to end redundant mode. //check if it is time to end redundant mode.
@ -270,7 +265,7 @@ public Message send(Message query)
*/ */
public Object sendAsync(final Message query, final ResolverListener listener) public Object sendAsync(final Message query, final ResolverListener listener)
{ {
return null; throw new UnsupportedOperationException("Not implemented");
} }
/** /**
@ -448,7 +443,7 @@ private boolean isResponseSatisfactory(Message response)
* our default and backup servers and returns as soon as we get one or until * our default and backup servers and returns as soon as we get one or until
* our default resolver fails. * our default resolver fails.
*/ */
private class ParallelResolution extends Thread private class ParallelResolution implements Runnable
{ {
/** /**
* The query that we have sent to the default and backup DNS servers. * The query that we have sent to the default and backup DNS servers.
@ -459,7 +454,7 @@ private class ParallelResolution extends Thread
* The field where we would store the first incoming response to our * The field where we would store the first incoming response to our
* query. * query.
*/ */
public Message response; private volatile Message response;
/** /**
* The field where we would store the first error we receive from a DNS * The field where we would store the first error we receive from a DNS
@ -470,12 +465,12 @@ private class ParallelResolution extends Thread
/** /**
* Indicates whether we are still waiting for an answer from someone * Indicates whether we are still waiting for an answer from someone
*/ */
private boolean done = false; private volatile boolean done = false;
/** /**
* Indicates that a response was received from the primary resolver. * Indicates that a response was received from the primary resolver.
*/ */
private boolean primaryResolverRespondedFirst = true; private volatile boolean primaryResolverRespondedFirst = true;
/** /**
* Creates a {@link ParallelResolution} for the specified <tt>query</tt> * Creates a {@link ParallelResolution} for the specified <tt>query</tt>
@ -485,7 +480,6 @@ private class ParallelResolution extends Thread
*/ */
public ParallelResolution(final Message query) public ParallelResolution(final Message query)
{ {
super("ParallelResolutionThread");
this.query = query; this.query = query;
} }
@ -495,7 +489,7 @@ public ParallelResolution(final Message query)
*/ */
public void sendFirstQuery() public void sendFirstQuery()
{ {
start(); ParallelResolverImpl.this.backupQueriesPool.execute(this);
} }
/** /**
@ -509,19 +503,24 @@ public void run()
{ {
localResponse = defaultResolver.send(query); localResponse = defaultResolver.send(query);
} }
catch (SocketTimeoutException exc)
{
logger.info("Default DNS resolver timed out.");
this.exception = exc;
}
catch (Throwable exc) catch (Throwable exc)
{ {
logger.info("Exception occurred during parallel DNS resolving" + logger.info("Default DNS resolver failed", exc);
exc, exc);
this.exception = exc; this.exception = exc;
} }
//if the backup resolvers had already replied we ignore the
//reply of the primary one whatever it was.
if(done)
return;
synchronized(this) synchronized(this)
{ {
//if the backup resolvers had already replied we ignore the
//reply of the primary one whatever it was.
if(done)
return;
//if there was a response we're only done if it is satisfactory //if there was a response we're only done if it is satisfactory
if( localResponse != null if( localResponse != null
&& isResponseSatisfactory(localResponse)) && isResponseSatisfactory(localResponse))
@ -529,6 +528,7 @@ && isResponseSatisfactory(localResponse))
response = localResponse; response = localResponse;
done = true; done = true;
} }
notify(); notify();
} }
} }
@ -538,47 +538,58 @@ && isResponseSatisfactory(localResponse))
*/ */
public void sendBackupQueries() public void sendBackupQueries()
{ {
logger.info("Send DNS queries to backup resolvers");
//yes. a second thread in the thread ... it's ugly but it works //yes. a second thread in the thread ... it's ugly but it works
//and i do want to keep code simple to read ... this whole parallel //and i do want to keep code simple to read ... this whole parallel
//resolving is complicated enough as it is. //resolving is complicated enough as it is.
new Thread(){ backupQueriesPool.execute(new Runnable(){
@Override @Override
public void run() public void run()
{ {
synchronized(ParallelResolution.this) if (done)
{ {
if (done) return;
return; }
Message localResponse = null;
try
{
localResponse = backupResolver.send(query);
}
catch (Throwable exc)
{
logger.info("Exception occurred during backup "
+"DNS resolving" + exc);
//keep this so that we can rethrow it Message localResponse = null;
exception = exc; try
} {
//if the default resolver has already replied we logger.info("Sending query for "
//ignore the reply of the backup ones. + query.getQuestion().getName() + "/"
if(done) + Type.string(query.getQuestion().getType())
return; + " to backup resolvers");
localResponse = backupResolver.send(query);
}
catch (Throwable exc)
{
logger.info("Exception occurred during backup "
+"DNS resolving" + exc);
//keep this so that we can rethrow it
exception = exc;
}
//if the default resolver has already replied we
//ignore the reply of the backup ones.
if(done)
{
return;
}
synchronized(ParallelResolution.this)
{
//contrary to responses from the primary resolver, //contrary to responses from the primary resolver,
//in this case we don't care whether the response is //in this case we don't care whether the response is
//satisfying: if it isn't, there's nothing we can do //satisfying: if it isn't, there's nothing we can do
response = localResponse; if (response == null)
done = true; {
response = localResponse;
primaryResolverRespondedFirst = false;
}
done = true;
ParallelResolution.this.notify(); ParallelResolution.this.notify();
} }
} }
}.start(); });
} }
/** /**
@ -636,6 +647,11 @@ public Message returnResponseOrThrowUp()
{ {
return response; return response;
} }
else if (exception instanceof SocketTimeoutException)
{
logger.warn("DNS resolver timed out");
throw (IOException) exception;
}
else if (exception instanceof IOException) else if (exception instanceof IOException)
{ {
logger.warn("IO exception while using DNS resolver", exception); logger.warn("IO exception while using DNS resolver", exception);
@ -664,6 +680,7 @@ else if (exception instanceof Error)
@SuppressWarnings("serial") @SuppressWarnings("serial")
private final Set<String> configNames = new HashSet<String>(5) private final Set<String> configNames = new HashSet<String>(5)
{{ {{
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_ENABLED);
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER); add(DnsUtilActivator.PNAME_BACKUP_RESOLVER);
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_FALLBACK_IP); add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_FALLBACK_IP);
add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_PORT); add(DnsUtilActivator.PNAME_BACKUP_RESOLVER_PORT);

Loading…
Cancel
Save