Skip to content

Commit 5da6e35

Browse files
committed
Merge branch 'drop-buffer-on-close' of github.com:divolte/MaxMind-DB-Reader-java into divolte-drop-buffer-on-close
2 parents 111d668 + 096a204 commit 5da6e35

File tree

4 files changed

+102
-38
lines changed

4 files changed

+102
-38
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.maxmind.db;
2+
3+
import java.io.IOException;
4+
5+
/**
6+
* Signals that the underlying database has been closed.
7+
*/
8+
public class ClosedDatabaseException extends IOException {
9+
10+
private static final long serialVersionUID = 1L;
11+
12+
ClosedDatabaseException() {
13+
super("The MaxMind DB has been closed.");
14+
}
15+
}

src/main/java/com/maxmind/db/Reader.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.io.InputStream;
77
import java.net.InetAddress;
88
import java.nio.ByteBuffer;
9+
import java.util.concurrent.atomic.AtomicReference;
910

1011
import com.fasterxml.jackson.databind.JsonNode;
1112

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

2223
private final int ipV4Start;
2324
private final Metadata metadata;
24-
private final BufferHolder bufferHolder;
25+
private final AtomicReference<BufferHolder> bufferHolderReference;
2526

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

8384
private Reader(BufferHolder bufferHolder, String name) throws IOException {
84-
this.bufferHolder = bufferHolder;
85+
this.bufferHolderReference = new AtomicReference<BufferHolder>(bufferHolder);
8586

86-
ByteBuffer buffer = this.bufferHolder.get();
87+
ByteBuffer buffer = bufferHolder.get();
8788
int start = this.findMetadataStart(buffer, name);
8889

8990
Decoder metadataDecoder = new Decoder(buffer, start);
@@ -102,14 +103,22 @@ private Reader(BufferHolder bufferHolder, String name) throws IOException {
102103
* if a file I/O error occurs.
103104
*/
104105
public JsonNode get(InetAddress ipAddress) throws IOException {
105-
ByteBuffer buffer = this.bufferHolder.get();
106+
ByteBuffer buffer = getBufferHolder().get();
106107
int pointer = this.findAddressInTree(buffer, ipAddress);
107108
if (pointer == 0) {
108109
return null;
109110
}
110111
return this.resolveDataPointer(buffer, pointer);
111112
}
112113

114+
private BufferHolder getBufferHolder() throws ClosedDatabaseException {
115+
BufferHolder bufferHolder = bufferHolderReference.get();
116+
if (bufferHolder == null) {
117+
throw new ClosedDatabaseException();
118+
}
119+
return bufferHolder;
120+
}
121+
113122
private int findAddressInTree(ByteBuffer buffer, InetAddress address)
114123
throws InvalidDatabaseException {
115124
byte[] rawAddress = address.getAddress();
@@ -241,6 +250,6 @@ Metadata getMetadata() {
241250
*/
242251
@Override
243252
public void close() throws IOException {
244-
// Nothing to do for now.
253+
bufferHolderReference.getAndSet(null).close();
245254
}
246255
}

src/test/java/com/maxmind/db/MultiThreadedTest.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ public JsonNode call() throws UnknownHostException, IOException,
3333
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
3434
.toURI();
3535
final Reader reader = new Reader(new File(file));
36-
return reader.get(InetAddress.getByName("::1.1.1.0"));
36+
try {
37+
return reader.get(InetAddress.getByName("::1.1.1.0"));
38+
} finally {
39+
reader.close();
40+
}
3741
}
3842
};
3943
MultiThreadedTest.runThreads(task);
@@ -45,7 +49,11 @@ public void streamThreadTest() throws IOException, InterruptedException,
4549
final Reader reader = new Reader(ReaderTest.class.getResource(
4650
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
4751
.openStream());
48-
MultiThreadedTest.threadTest(reader);
52+
try {
53+
MultiThreadedTest.threadTest(reader);
54+
} finally {
55+
reader.close();
56+
}
4957
}
5058

5159
@Test
@@ -54,7 +62,11 @@ public void mmapThreadTest() throws IOException, InterruptedException,
5462
URI file = ReaderTest.class.getResource(
5563
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();
5664
final Reader reader = new Reader(new File(file));
57-
MultiThreadedTest.threadTest(reader);
65+
try {
66+
MultiThreadedTest.threadTest(reader);
67+
} finally {
68+
reader.close();
69+
}
5870
}
5971

6072
private static void threadTest(final Reader reader) throws InterruptedException,

src/test/java/com/maxmind/db/ReaderTest.java

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import java.util.HashMap;
1717
import java.util.Map;
1818

19+
import org.junit.After;
20+
import org.junit.Before;
1921
import org.junit.Rule;
2022
import org.junit.Test;
2123
import org.junit.rules.ExpectedException;
@@ -27,6 +29,20 @@
2729
public class ReaderTest {
2830
private final ObjectMapper om = new ObjectMapper();
2931

32+
private Reader testReader;
33+
34+
@Before
35+
public void setupReader() {
36+
testReader = null;
37+
}
38+
39+
@After
40+
public void teardownReader() throws IOException {
41+
if (testReader != null) {
42+
testReader.close();
43+
}
44+
}
45+
3046
@Test
3147
public void test() throws IOException, URISyntaxException {
3248
for (long recordSize : new long[] { 24, 28, 32 }) {
@@ -37,15 +53,14 @@ public void test() throws IOException, URISyntaxException {
3753
Reader reader = new Reader(new File(file));
3854
try {
3955
this.testMetadata(reader, ipVersion, recordSize);
56+
if (ipVersion == 4) {
57+
this.testIpV4(reader, file);
58+
} else {
59+
this.testIpV6(reader, file);
60+
}
4061
} finally {
4162
reader.close();
4263
}
43-
44-
if (ipVersion == 4) {
45-
this.testIpV4(reader, file);
46-
} else {
47-
this.testIpV6(reader, file);
48-
}
4964
}
5065
}
5166
}
@@ -57,8 +72,8 @@ public void testNoIpV4SearchTreeFile() throws IOException,
5772
"/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb")
5873
.toURI();
5974

60-
Reader reader = new Reader(new File(file));
61-
this.testNoIpV4SearchTree(reader);
75+
testReader = new Reader(new File(file));
76+
this.testNoIpV4SearchTree(testReader);
6277
}
6378

6479
@Test
@@ -67,8 +82,8 @@ public void testNoIpV4SearchTreeURL() throws IOException,
6782
InputStream stream = ReaderTest.class.getResource(
6883
"/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb")
6984
.openStream();
70-
Reader reader = new Reader(stream);
71-
this.testNoIpV4SearchTree(reader);
85+
testReader = new Reader(stream);
86+
this.testNoIpV4SearchTree(testReader);
7287
}
7388

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

88-
Reader reader = new Reader(new File(file));
89-
this.testDecodingTypes(reader);
103+
testReader = new Reader(new File(file));
104+
this.testDecodingTypes(testReader);
90105
}
91106

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

98-
Reader reader = new Reader(stream);
99-
this.testDecodingTypes(reader);
113+
testReader = new Reader(stream);
114+
this.testDecodingTypes(testReader);
100115
}
101116

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

151-
Reader reader = new Reader(new File(file));
152-
this.testZeros(reader);
166+
testReader = new Reader(new File(file));
167+
this.testZeros(testReader);
153168
}
154169

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

161-
Reader reader = new Reader(stream);
162-
this.testZeros(reader);
176+
testReader = new Reader(stream);
177+
this.testZeros(testReader);
163178
}
164179

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

200-
Reader reader = new Reader(new File(file));
201-
this.testBrokenDatabase(reader);
215+
testReader = new Reader(new File(file));
216+
this.testBrokenDatabase(testReader);
202217
}
203218

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

211-
Reader reader = new Reader(stream);
212-
this.testBrokenDatabase(reader);
226+
testReader = new Reader(stream);
227+
this.testBrokenDatabase(testReader);
213228
}
214229

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

233-
Reader reader = new Reader(new File(file));
234-
this.testBrokenSearchTreePointer(reader);
248+
testReader = new Reader(new File(file));
249+
this.testBrokenSearchTreePointer(testReader);
235250
}
236251

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

245-
Reader reader = new Reader(stream);
246-
this.testBrokenSearchTreePointer(reader);
260+
testReader = new Reader(stream);
261+
this.testBrokenSearchTreePointer(testReader);
247262
}
248263

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

267-
Reader reader = new Reader(new File(file));
268-
this.testBrokenDataPointer(reader);
282+
testReader = new Reader(new File(file));
283+
this.testBrokenDataPointer(testReader);
269284
}
270285

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

279-
Reader reader = new Reader(stream);
280-
this.testBrokenDataPointer(reader);
294+
testReader = new Reader(stream);
295+
this.testBrokenDataPointer(testReader);
281296
}
282297

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

308+
@Test
309+
public void testClosedReaderThrowsException() throws IOException, URISyntaxException {
310+
URI file = ReaderTest.class.getResource(
311+
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();
312+
Reader reader = new Reader(new File(file));
313+
314+
this.thrown.expect(ClosedDatabaseException.class);
315+
this.thrown.expectMessage("The MaxMind DB has been closed.");
316+
317+
reader.close();
318+
reader.get(InetAddress.getByName("1.1.1.16"));
319+
}
320+
293321
private void testMetadata(Reader reader, int ipVersion, long recordSize) {
294322

295323
Metadata metadata = reader.getMetadata();

0 commit comments

Comments
 (0)