NIFI-3942 Added retry logic if a lookup fails due to InvalidDatabaseException which occurs if the underlying file was modified before we could refresh the reader
This closes #1831. Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/71cd497f Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/71cd497f Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/71cd497f Branch: refs/heads/master Commit: 71cd497fefd9b173f6b017f69a31fc7d57e906c7 Parents: f35e0ec Author: Bryan Bende <[email protected]> Authored: Fri May 19 17:58:52 2017 -0400 Committer: Mark Payne <[email protected]> Committed: Mon May 22 09:12:51 2017 -0400 ---------------------------------------------------------------------- .../nifi/lookup/maxmind/IPLookupService.java | 50 ++++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/71cd497f/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/IPLookupService.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/IPLookupService.java b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/IPLookupService.java index 88c611e..58ee4de 100644 --- a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/IPLookupService.java +++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/IPLookupService.java @@ -17,6 +17,7 @@ package org.apache.nifi.lookup.maxmind; +import com.maxmind.db.InvalidDatabaseException; import com.maxmind.geoip2.model.AnonymousIpResponse; import com.maxmind.geoip2.model.CityResponse; import com.maxmind.geoip2.model.ConnectionTypeResponse; @@ -188,16 +189,47 @@ public class IPLookupService extends AbstractControllerService implements Record } } - // assign to a local so we don't need a read lock, this way another thread can update the member variable reference - // while the current thread continues using the local reference - final DatabaseReader databaseReader = this.databaseReader; + // If an external process changes the underlying file before we have a chance to reload the reader, then we'll get an + // InvalidDatabaseException, so force a reload and then retry the lookup one time, if we still get an error then throw it + try { + final DatabaseReader databaseReader = this.databaseReader; + return doLookup(databaseReader, key); + } catch (InvalidDatabaseException idbe) { + if (dbWriteLock.tryLock()) { + try { + getLogger().debug("Attempting to reload database after InvalidDatabaseException"); + try { + final File dbFile = new File(databaseFile); + final String dbFileChecksum = getChecksum(dbFile); + loadDatabase(dbFile, dbFileChecksum); + databaseLastRefreshAttempt = System.currentTimeMillis(); + } catch (IOException ioe) { + throw new LookupFailureException("Error reloading database due to: " + ioe.getMessage(), ioe); + } + + getLogger().debug("Attempting to retry lookup after InvalidDatabaseException"); + try { + final DatabaseReader databaseReader = this.databaseReader; + return doLookup(databaseReader, key); + } catch (final Exception e) { + throw new LookupFailureException("Error performing look up: " + e.getMessage(), e); + } + } finally { + dbWriteLock.unlock(); + } + } else { + throw new LookupFailureException("Failed to lookup the key " + key + " due to " + idbe.getMessage(), idbe); + } + } + } + private Optional<Record> doLookup(final DatabaseReader databaseReader, final String key) throws LookupFailureException, InvalidDatabaseException { final InetAddress inetAddress; try { inetAddress = InetAddress.getByName(key); } catch (final IOException ioe) { getLogger().warn("Could not resolve the IP for value '{}'. This is usually caused by issue resolving the appropriate DNS record or " + - "providing the service with an invalid IP address", new Object[] {key}, ioe); + "providing the service with an invalid IP address", new Object[] {key}, ioe); return Optional.empty(); } @@ -207,6 +239,8 @@ public class IPLookupService extends AbstractControllerService implements Record final CityResponse cityResponse; try { cityResponse = databaseReader.city(inetAddress); + } catch (final InvalidDatabaseException idbe) { + throw idbe; } catch (final Exception e) { throw new LookupFailureException("Failed to lookup City information for IP Address " + inetAddress, e); } @@ -221,6 +255,8 @@ public class IPLookupService extends AbstractControllerService implements Record final IspResponse ispResponse; try { ispResponse = databaseReader.isp(inetAddress); + } catch (final InvalidDatabaseException idbe) { + throw idbe; } catch (final Exception e) { throw new LookupFailureException("Failed to lookup ISP information for IP Address " + inetAddress, e); } @@ -235,6 +271,8 @@ public class IPLookupService extends AbstractControllerService implements Record final DomainResponse domainResponse; try { domainResponse = databaseReader.domain(inetAddress); + } catch (final InvalidDatabaseException idbe) { + throw idbe; } catch (final Exception e) { throw new LookupFailureException("Failed to lookup Domain information for IP Address " + inetAddress, e); } @@ -249,6 +287,8 @@ public class IPLookupService extends AbstractControllerService implements Record final ConnectionTypeResponse connectionTypeResponse; try { connectionTypeResponse = databaseReader.connectionType(inetAddress); + } catch (final InvalidDatabaseException idbe) { + throw idbe; } catch (final Exception e) { throw new LookupFailureException("Failed to lookup Domain information for IP Address " + inetAddress, e); } @@ -268,6 +308,8 @@ public class IPLookupService extends AbstractControllerService implements Record final AnonymousIpResponse anonymousIpResponse; try { anonymousIpResponse = databaseReader.anonymousIp(inetAddress); + } catch (final InvalidDatabaseException idbe) { + throw idbe; } catch (final Exception e) { throw new LookupFailureException("Failed to lookup Anonymous IP Information for IP Address " + inetAddress, e); }
