Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/java/com/maxmind/db/ClosedDatabaseException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.maxmind.db;

import java.io.IOException;

/**
* Signals that the underlying database has been closed.
*/
public class ClosedDatabaseException extends IOException {

private static final long serialVersionUID = 1L;

ClosedDatabaseException() {
super("The MaxMind DB has been closed.");
}
}
19 changes: 14 additions & 5 deletions src/main/java/com/maxmind/db/Reader.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.InputStream;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicReference;

import com.fasterxml.jackson.databind.JsonNode;

Expand All @@ -21,7 +22,7 @@ public final class Reader implements Closeable {

private final int ipV4Start;
private final Metadata metadata;
private final BufferHolder bufferHolder;
private final AtomicReference<BufferHolder> bufferHolderReference;

/**
* The file mode to use when opening a MaxMind DB.
Expand Down Expand Up @@ -81,9 +82,9 @@ public Reader(File database, FileMode fileMode) throws IOException {
}

private Reader(BufferHolder bufferHolder, String name) throws IOException {
this.bufferHolder = bufferHolder;
this.bufferHolderReference = new AtomicReference<BufferHolder>(bufferHolder);

ByteBuffer buffer = this.bufferHolder.get();
ByteBuffer buffer = bufferHolder.get();
int start = this.findMetadataStart(buffer, name);

Decoder metadataDecoder = new Decoder(buffer, start);
Expand All @@ -102,14 +103,22 @@ private Reader(BufferHolder bufferHolder, String name) throws IOException {
* if a file I/O error occurs.
*/
public JsonNode get(InetAddress ipAddress) throws IOException {
ByteBuffer buffer = this.bufferHolder.get();
ByteBuffer buffer = getBufferHolder().get();
int pointer = this.findAddressInTree(buffer, ipAddress);
if (pointer == 0) {
return null;
}
return this.resolveDataPointer(buffer, pointer);
}

private BufferHolder getBufferHolder() throws ClosedDatabaseException {
BufferHolder bufferHolder = bufferHolderReference.get();
if (bufferHolder == null) {
throw new ClosedDatabaseException();
}
return bufferHolder;
}

private int findAddressInTree(ByteBuffer buffer, InetAddress address)
throws InvalidDatabaseException {
byte[] rawAddress = address.getAddress();
Expand Down Expand Up @@ -241,6 +250,6 @@ Metadata getMetadata() {
*/
@Override
public void close() throws IOException {
this.bufferHolder.close();
bufferHolderReference.getAndSet(null).close();
}
}
18 changes: 15 additions & 3 deletions src/test/java/com/maxmind/db/MultiThreadedTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ public JsonNode call() throws UnknownHostException, IOException,
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
.toURI();
final Reader reader = new Reader(new File(file));
return reader.get(InetAddress.getByName("::1.1.1.0"));
try {
return reader.get(InetAddress.getByName("::1.1.1.0"));
} finally {
reader.close();
}
}
};
MultiThreadedTest.runThreads(task);
Expand All @@ -45,7 +49,11 @@ public void streamThreadTest() throws IOException, InterruptedException,
final Reader reader = new Reader(ReaderTest.class.getResource(
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
.openStream());
MultiThreadedTest.threadTest(reader);
try {
MultiThreadedTest.threadTest(reader);
} finally {
reader.close();
}
}

@Test
Expand All @@ -54,7 +62,11 @@ public void mmapThreadTest() throws IOException, InterruptedException,
URI file = ReaderTest.class.getResource(
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();
final Reader reader = new Reader(new File(file));
MultiThreadedTest.threadTest(reader);
try {
MultiThreadedTest.threadTest(reader);
} finally {
reader.close();
}
}

private static void threadTest(final Reader reader) throws InterruptedException,
Expand Down
88 changes: 58 additions & 30 deletions src/test/java/com/maxmind/db/ReaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import java.util.HashMap;
import java.util.Map;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
Expand All @@ -27,6 +29,20 @@
public class ReaderTest {
private final ObjectMapper om = new ObjectMapper();

private Reader testReader;

@Before
public void setupReader() {
testReader = null;
}

@After
public void teardownReader() throws IOException {
if (testReader != null) {
testReader.close();
}
}

@Test
public void test() throws IOException, URISyntaxException {
for (long recordSize : new long[] { 24, 28, 32 }) {
Expand All @@ -37,15 +53,14 @@ public void test() throws IOException, URISyntaxException {
Reader reader = new Reader(new File(file));
try {
this.testMetadata(reader, ipVersion, recordSize);
if (ipVersion == 4) {
this.testIpV4(reader, file);
} else {
this.testIpV6(reader, file);
}
} finally {
reader.close();
}

if (ipVersion == 4) {
this.testIpV4(reader, file);
} else {
this.testIpV6(reader, file);
}
}
}
}
Expand All @@ -57,8 +72,8 @@ public void testNoIpV4SearchTreeFile() throws IOException,
"/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb")
.toURI();

Reader reader = new Reader(new File(file));
this.testNoIpV4SearchTree(reader);
testReader = new Reader(new File(file));
this.testNoIpV4SearchTree(testReader);
}

@Test
Expand All @@ -67,8 +82,8 @@ public void testNoIpV4SearchTreeURL() throws IOException,
InputStream stream = ReaderTest.class.getResource(
"/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb")
.openStream();
Reader reader = new Reader(stream);
this.testNoIpV4SearchTree(reader);
testReader = new Reader(stream);
this.testNoIpV4SearchTree(testReader);
}

private void testNoIpV4SearchTree(Reader reader) throws IOException,
Expand All @@ -85,8 +100,8 @@ public void testDecodingTypesFile() throws URISyntaxException, IOException {
URI file = ReaderTest.class.getResource(
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();

Reader reader = new Reader(new File(file));
this.testDecodingTypes(reader);
testReader = new Reader(new File(file));
this.testDecodingTypes(testReader);
}

@Test
Expand All @@ -95,8 +110,8 @@ public void testDecodingTypesURL() throws URISyntaxException, IOException {
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
.openStream();

Reader reader = new Reader(stream);
this.testDecodingTypes(reader);
testReader = new Reader(stream);
this.testDecodingTypes(testReader);
}

private void testDecodingTypes(Reader reader) throws URISyntaxException,
Expand Down Expand Up @@ -148,8 +163,8 @@ public void testZerosFile() throws URISyntaxException, IOException {
URI file = ReaderTest.class.getResource(
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();

Reader reader = new Reader(new File(file));
this.testZeros(reader);
testReader = new Reader(new File(file));
this.testZeros(testReader);
}

@Test
Expand All @@ -158,8 +173,8 @@ public void testZerosURL() throws URISyntaxException, IOException {
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
.openStream();

Reader reader = new Reader(stream);
this.testZeros(reader);
testReader = new Reader(stream);
this.testZeros(testReader);
}

private void testZeros(Reader reader) throws URISyntaxException,
Expand Down Expand Up @@ -197,8 +212,8 @@ public void testBrokenDatabaseFile() throws URISyntaxException, IOException {
"/maxmind-db/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb")
.toURI();

Reader reader = new Reader(new File(file));
this.testBrokenDatabase(reader);
testReader = new Reader(new File(file));
this.testBrokenDatabase(testReader);
}

@Test
Expand All @@ -208,8 +223,8 @@ public void testBrokenDatabaseURL() throws URISyntaxException, IOException {
"/maxmind-db/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb")
.openStream();

Reader reader = new Reader(stream);
this.testBrokenDatabase(reader);
testReader = new Reader(stream);
this.testBrokenDatabase(testReader);
}

private void testBrokenDatabase(Reader reader) throws URISyntaxException,
Expand All @@ -230,8 +245,8 @@ public void testBrokenSearchTreePointerFile() throws URISyntaxException,
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
.toURI();

Reader reader = new Reader(new File(file));
this.testBrokenSearchTreePointer(reader);
testReader = new Reader(new File(file));
this.testBrokenSearchTreePointer(testReader);
}

@Test
Expand All @@ -242,8 +257,8 @@ public void testBrokenSearchTreePointerURL() throws URISyntaxException,
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
.openStream();

Reader reader = new Reader(stream);
this.testBrokenSearchTreePointer(reader);
testReader = new Reader(stream);
this.testBrokenSearchTreePointer(testReader);
}

private void testBrokenSearchTreePointer(Reader reader)
Expand All @@ -264,8 +279,8 @@ public void testBrokenDataPointerFile() throws IOException,
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
.toURI();

Reader reader = new Reader(new File(file));
this.testBrokenDataPointer(reader);
testReader = new Reader(new File(file));
this.testBrokenDataPointer(testReader);
}

@Test
Expand All @@ -276,8 +291,8 @@ public void testBrokenDataPointerURL() throws IOException,
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
.openStream();

Reader reader = new Reader(stream);
this.testBrokenDataPointer(reader);
testReader = new Reader(stream);
this.testBrokenDataPointer(testReader);
}

private void testBrokenDataPointer(Reader reader) throws IOException,
Expand All @@ -290,6 +305,19 @@ private void testBrokenDataPointer(Reader reader) throws IOException,
reader.get(InetAddress.getByName("1.1.1.16"));
}

@Test
public void testClosedReaderThrowsException() throws IOException, URISyntaxException {
URI file = ReaderTest.class.getResource(
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();
Reader reader = new Reader(new File(file));

this.thrown.expect(ClosedDatabaseException.class);
this.thrown.expectMessage("The MaxMind DB has been closed.");

reader.close();
reader.get(InetAddress.getByName("1.1.1.16"));
}

private void testMetadata(Reader reader, int ipVersion, long recordSize) {

Metadata metadata = reader.getMetadata();
Expand Down