Skip to content

Commit fc85b18

Browse files
committed
Replace ByteBuffer use with Buffer and SingleBuffer
1 parent c9400f6 commit fc85b18

File tree

8 files changed

+39
-41
lines changed

8 files changed

+39
-41
lines changed

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,27 @@
66
import java.io.IOException;
77
import java.io.InputStream;
88
import java.io.RandomAccessFile;
9-
import java.nio.ByteBuffer;
109
import java.nio.channels.FileChannel;
11-
import java.nio.channels.FileChannel.MapMode;
1210

1311
final class BufferHolder {
1412
// DO NOT PASS OUTSIDE THIS CLASS. Doing so will remove thread safety.
15-
private final ByteBuffer buffer;
13+
private final Buffer buffer;
1614

1715
BufferHolder(File database, FileMode mode) throws IOException {
1816
try (
1917
final RandomAccessFile file = new RandomAccessFile(database, "r");
2018
final FileChannel channel = file.getChannel()
2119
) {
2220
if (mode == FileMode.MEMORY) {
23-
final ByteBuffer buf = ByteBuffer.wrap(new byte[(int) channel.size()]);
24-
if (channel.read(buf) != buf.capacity()) {
21+
final SingleBuffer buf = SingleBuffer.wrap(new byte[(int) channel.size()]);
22+
if (buf.readFrom(channel) != buf.capacity()) {
2523
throw new IOException("Unable to read "
2624
+ database.getName()
2725
+ " into memory. Unexpected end of stream.");
2826
}
2927
this.buffer = buf.asReadOnlyBuffer();
3028
} else {
31-
this.buffer = channel.map(MapMode.READ_ONLY, 0, channel.size()).asReadOnlyBuffer();
29+
this.buffer = SingleBuffer.mapFromChannel(channel);
3230
}
3331
}
3432
}
@@ -50,14 +48,14 @@ final class BufferHolder {
5048
while (-1 != (br = stream.read(bytes))) {
5149
baos.write(bytes, 0, br);
5250
}
53-
this.buffer = ByteBuffer.wrap(baos.toByteArray()).asReadOnlyBuffer();
51+
this.buffer = SingleBuffer.wrap(baos.toByteArray()).asReadOnlyBuffer();
5452
}
5553

5654
/*
57-
* Returns a duplicate of the underlying ByteBuffer. The returned ByteBuffer
55+
* Returns a duplicate of the underlying Buffer. The returned Buffer
5856
* should not be shared between threads.
5957
*/
60-
ByteBuffer get() {
58+
Buffer get() {
6159
// The Java API docs for buffer state:
6260
//
6361
// Buffers are not safe for use by multiple concurrent threads. If a buffer is to be
@@ -70,7 +68,7 @@ ByteBuffer get() {
7068
// * https://github.com/maxmind/MaxMind-DB-Reader-java/issues/65
7169
// * https://github.com/maxmind/MaxMind-DB-Reader-java/pull/69
7270
//
73-
// Given that we are not modifying the original ByteBuffer in any way and all currently
71+
// Given that we are not modifying the original Buffer in any way and all currently
7472
// known and most reasonably imaginable implementations of duplicate() only do read
7573
// operations on the original buffer object, the risk of not synchronizing this call seems
7674
// relatively low and worth taking for the performance benefit when lookups are being done

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
* @param cls the class of the value
1111
* @param type the type of the value
1212
*/
13-
public record CacheKey<T>(int offset, Class<T> cls, java.lang.reflect.Type type) {
13+
public record CacheKey<T>(long offset, Class<T> cls, java.lang.reflect.Type type) {
1414
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package com.maxmind.db;
22

3-
record CtrlData(Type type, int ctrlByte, int offset, int size) {
3+
record CtrlData(Type type, int ctrlByte, long offset, int size) {
44
}

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ class Decoder {
3434

3535
private final CharsetDecoder utfDecoder = UTF_8.newDecoder();
3636

37-
private final ByteBuffer buffer;
37+
private final Buffer buffer;
3838

3939
private final ConcurrentHashMap<Class<?>, CachedConstructor<?>> constructors;
4040

41-
Decoder(NodeCache cache, ByteBuffer buffer, long pointerBase) {
41+
Decoder(NodeCache cache, Buffer buffer, long pointerBase) {
4242
this(
4343
cache,
4444
buffer,
@@ -49,7 +49,7 @@ class Decoder {
4949

5050
Decoder(
5151
NodeCache cache,
52-
ByteBuffer buffer,
52+
Buffer buffer,
5353
long pointerBase,
5454
ConcurrentHashMap<Class<?>, CachedConstructor<?>> constructors
5555
) {
@@ -61,7 +61,7 @@ class Decoder {
6161

6262
private final NodeCache.Loader cacheLoader = this::decode;
6363

64-
<T> T decode(int offset, Class<T> cls) throws IOException {
64+
<T> T decode(long offset, Class<T> cls) throws IOException {
6565
if (offset >= this.buffer.capacity()) {
6666
throw new InvalidDatabaseException(
6767
"The MaxMind DB file's data section contains bad data: "
@@ -73,7 +73,7 @@ <T> T decode(int offset, Class<T> cls) throws IOException {
7373
}
7474

7575
private <T> DecodedValue decode(CacheKey<T> key) throws IOException {
76-
int offset = key.offset();
76+
long offset = key.offset();
7777
if (offset >= this.buffer.capacity()) {
7878
throw new InvalidDatabaseException(
7979
"The MaxMind DB file's data section contains bad data: "
@@ -132,8 +132,8 @@ private <T> DecodedValue decode(Class<T> cls, java.lang.reflect.Type genericType
132132

133133
DecodedValue decodePointer(long pointer, Class<?> cls, java.lang.reflect.Type genericType)
134134
throws IOException {
135-
int targetOffset = (int) pointer;
136-
int position = buffer.position();
135+
long targetOffset = pointer;
136+
long position = buffer.position();
137137

138138
CacheKey<?> key = new CacheKey<>(targetOffset, cls, genericType);
139139
DecodedValue o = cache.get(key, cacheLoader);
@@ -185,10 +185,10 @@ private <T> Object decodeByType(
185185
}
186186
}
187187

188-
private String decodeString(int size) throws CharacterCodingException {
189-
int oldLimit = buffer.limit();
188+
private String decodeString(long size) throws CharacterCodingException {
189+
long oldLimit = buffer.limit();
190190
buffer.limit(buffer.position() + size);
191-
String s = utfDecoder.decode(buffer).toString();
191+
String s = buffer.decode(utfDecoder);
192192
buffer.limit(oldLimit);
193193
return s;
194194
}
@@ -221,7 +221,7 @@ private int decodeInteger(int base, int size) {
221221
return Decoder.decodeInteger(this.buffer, base, size);
222222
}
223223

224-
static int decodeInteger(ByteBuffer buffer, int base, int size) {
224+
static int decodeInteger(Buffer buffer, int base, int size) {
225225
int integer = base;
226226
for (int i = 0; i < size; i++) {
227227
integer = (integer << 8) | (buffer.get() & 0xFF);
@@ -412,7 +412,7 @@ private <T> Object decodeMapIntoObject(int size, Class<T> cls)
412412

413413
Integer parameterIndex = parameterIndexes.get(key);
414414
if (parameterIndex == null) {
415-
int offset = this.nextValueOffset(this.buffer.position(), 1);
415+
long offset = this.nextValueOffset(this.buffer.position(), 1);
416416
this.buffer.position(offset);
417417
continue;
418418
}
@@ -485,7 +485,7 @@ private static <T> String getParameterName(
485485
+ " is not annotated with MaxMindDbParameter.");
486486
}
487487

488-
private int nextValueOffset(int offset, int numberToSkip)
488+
private long nextValueOffset(long offset, int numberToSkip)
489489
throws InvalidDatabaseException {
490490
if (numberToSkip == 0) {
491491
return offset;
@@ -518,7 +518,7 @@ private int nextValueOffset(int offset, int numberToSkip)
518518
return nextValueOffset(offset, numberToSkip - 1);
519519
}
520520

521-
private CtrlData getCtrlData(int offset)
521+
private CtrlData getCtrlData(long offset)
522522
throws InvalidDatabaseException {
523523
if (offset >= this.buffer.capacity()) {
524524
throw new InvalidDatabaseException(
@@ -566,7 +566,7 @@ private byte[] getByteArray(int length) {
566566
return Decoder.getByteArray(this.buffer, length);
567567
}
568568

569-
private static byte[] getByteArray(ByteBuffer buffer, int length) {
569+
private static byte[] getByteArray(Buffer buffer, int length) {
570570
byte[] bytes = new byte[length];
571571
buffer.get(bytes);
572572
return bytes;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public final class Networks<T> implements Iterator<DatabaseRecord<T>> {
1919
private final Stack<NetworkNode> nodes;
2020
private NetworkNode lastNode;
2121
private final boolean includeAliasedNetworks;
22-
private final ByteBuffer buffer; /* Stores the buffer for Next() calls */
22+
private final Buffer buffer; /* Stores the buffer for Next() calls */
2323
private final Class<T> typeParameterClass;
2424

2525
/**

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ private Reader(BufferHolder bufferHolder, String name, NodeCache cache) throws I
128128
}
129129
this.cache = cache;
130130

131-
ByteBuffer buffer = bufferHolder.get();
132-
int start = this.findMetadataStart(buffer, name);
131+
Buffer buffer = bufferHolder.get();
132+
long start = this.findMetadataStart(buffer, name);
133133

134134
Decoder metadataDecoder = new Decoder(this.cache, buffer, start);
135135
this.metadata = metadataDecoder.decode(start, Metadata.class);
@@ -177,7 +177,7 @@ public <T> DatabaseRecord<T> getRecord(InetAddress ipAddress, Class<T> cls)
177177
int record = traverseResult[0];
178178

179179
int nodeCount = this.metadata.getNodeCount();
180-
ByteBuffer buffer = this.getBufferHolder().get();
180+
Buffer buffer = this.getBufferHolder().get();
181181
T dataRecord = null;
182182
if (record > nodeCount) {
183183
// record is a data pointer
@@ -264,7 +264,7 @@ private int startNode(int bitLength) {
264264
return 0;
265265
}
266266

267-
private int findIpV4StartNode(ByteBuffer buffer)
267+
private int findIpV4StartNode(Buffer buffer)
268268
throws InvalidDatabaseException {
269269
if (this.metadata.getIpVersion() == 4) {
270270
return 0;
@@ -337,7 +337,7 @@ public <T> Networks<T> networksWithin(
337337
*/
338338
private int[] traverseTree(byte[] ip, int bitCount)
339339
throws ClosedDatabaseException, InvalidDatabaseException {
340-
ByteBuffer buffer = this.getBufferHolder().get();
340+
Buffer buffer = this.getBufferHolder().get();
341341
int bitLength = ip.length * 8;
342342
int record = this.startNode(bitLength);
343343
int nodeCount = this.metadata.getNodeCount();
@@ -355,7 +355,7 @@ record = this.readNode(buffer, record, bit);
355355
return new int[]{record, i};
356356
}
357357

358-
int readNode(ByteBuffer buffer, int nodeNumber, int index)
358+
int readNode(Buffer buffer, int nodeNumber, int index)
359359
throws InvalidDatabaseException {
360360
// index is the index of the record within the node, which
361361
// can either be 0 or 1.
@@ -389,7 +389,7 @@ int readNode(ByteBuffer buffer, int nodeNumber, int index)
389389
}
390390

391391
<T> T resolveDataPointer(
392-
ByteBuffer buffer,
392+
Buffer buffer,
393393
int pointer,
394394
Class<T> cls
395395
) throws IOException {
@@ -421,12 +421,12 @@ <T> T resolveDataPointer(
421421
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
422422
* an issue, but I suspect it won't be.
423423
*/
424-
private int findMetadataStart(ByteBuffer buffer, String databaseName)
424+
private long findMetadataStart(Buffer buffer, String databaseName)
425425
throws InvalidDatabaseException {
426-
int fileSize = buffer.capacity();
426+
long fileSize = buffer.capacity();
427427

428428
FILE:
429-
for (int i = 0; i < fileSize - METADATA_START_MARKER.length + 1; i++) {
429+
for (long i = 0; i < fileSize - METADATA_START_MARKER.length + 1; i++) {
430430
for (int j = 0; j < METADATA_START_MARKER.length; j++) {
431431
byte b = buffer.get(fileSize - i - j - 1);
432432
if (b != METADATA_START_MARKER[METADATA_START_MARKER.length - j

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ public void testArrays() throws IOException {
399399

400400
@Test
401401
public void testInvalidControlByte() {
402-
ByteBuffer buffer = ByteBuffer.wrap(new byte[] {0x0, 0xF});
402+
SingleBuffer buffer = SingleBuffer.wrap(new byte[] {0x0, 0xF});
403403

404404
Decoder decoder = new Decoder(new CHMCache(), buffer, 0);
405405
InvalidDatabaseException ex = assertThrows(
@@ -418,7 +418,7 @@ private static <T> void testTypeDecoding(Type type, Map<T, byte[]> tests)
418418
byte[] input = entry.getValue();
419419

420420
String desc = "decoded " + type.name() + " - " + expect;
421-
ByteBuffer buffer = ByteBuffer.wrap(input);
421+
SingleBuffer buffer = SingleBuffer.wrap(input);
422422

423423
Decoder decoder = new TestDecoder(cache, buffer, 0);
424424

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
final class TestDecoder extends Decoder {
77

8-
TestDecoder(NodeCache cache, ByteBuffer buffer, long pointerBase) {
8+
TestDecoder(NodeCache cache, SingleBuffer buffer, long pointerBase) {
99
super(cache, buffer, pointerBase);
1010
}
1111

0 commit comments

Comments
 (0)