Skip to content

Commit a69181e

Browse files
author
Andrew Snare
committed
Discard the reference to the underlying buffer during close(), and throw ClosedDatabaseException on subsequent database access.
Currently clients can continue to access the database even after it has been closed. This prevents that, and should also help ensure the underlying database is garbage collected.
1 parent 0b91040 commit a69181e

3 files changed

Lines changed: 47 additions & 11 deletions

File tree

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-
this.bufferHolder.close();
253+
bufferHolderReference.getAndSet(null).close();
245254
}
246255
}

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,14 @@ public void test() throws IOException, URISyntaxException {
3737
Reader reader = new Reader(new File(file));
3838
try {
3939
this.testMetadata(reader, ipVersion, recordSize);
40+
if (ipVersion == 4) {
41+
this.testIpV4(reader, file);
42+
} else {
43+
this.testIpV6(reader, file);
44+
}
4045
} finally {
4146
reader.close();
4247
}
43-
44-
if (ipVersion == 4) {
45-
this.testIpV4(reader, file);
46-
} else {
47-
this.testIpV6(reader, file);
48-
}
4948
}
5049
}
5150
}
@@ -290,6 +289,19 @@ private void testBrokenDataPointer(Reader reader) throws IOException,
290289
reader.get(InetAddress.getByName("1.1.1.16"));
291290
}
292291

292+
@Test
293+
public void testClosedReaderThrowsException() throws IOException, URISyntaxException {
294+
URI file = ReaderTest.class.getResource(
295+
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();
296+
Reader reader = new Reader(new File(file));
297+
298+
this.thrown.expect(ClosedDatabaseException.class);
299+
this.thrown.expectMessage("The MaxMind DB has been closed.");
300+
301+
reader.close();
302+
reader.get(InetAddress.getByName("1.1.1.16"));
303+
}
304+
293305
private void testMetadata(Reader reader, int ipVersion, long recordSize) {
294306

295307
Metadata metadata = reader.getMetadata();

0 commit comments

Comments
 (0)