Skip to content

Commit 3524995

Browse files
committed
Refactor Comparator handling (fixes #199)
1 parent e4cf6e9 commit 3524995

File tree

11 files changed

+157
-110
lines changed

11 files changed

+157
-110
lines changed

src/main/java/org/lmdbjava/BufferProxy.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import static java.lang.Long.BYTES;
2424

25+
import java.util.Comparator;
26+
2527
import jnr.ffi.Pointer;
2628

2729
/**
@@ -61,17 +63,16 @@ public abstract class BufferProxy<T> {
6163
protected abstract T allocate();
6264

6365
/**
64-
* Compare the two buffers.
66+
* Get a suitable default {@link Comparator} given the provided flags.
6567
*
6668
* <p>
67-
* Implemented as a protected method to discourage use of the buffer proxy
68-
* in collections etc (given by design it wraps a temporary value only).
69+
* The provided comparator must strictly match the lexicographical order of
70+
* keys in the native LMDB database.
6971
*
70-
* @param o1 left operand
71-
* @param o2 right operand
72-
* @return as per {@link Comparable}
72+
* @param flags for the database
73+
* @return a comparator that can be used (never null)
7374
*/
74-
protected abstract int compare(T o1, T o2);
75+
protected abstract Comparator<T> getComparator(DbiFlags... flags);
7576

7677
/**
7778
* Deallocate a buffer that was previously provided by {@link #allocate()}.

src/main/java/org/lmdbjava/ByteArrayProxy.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import static org.lmdbjava.Library.RUNTIME;
2525

2626
import java.util.Arrays;
27+
import java.util.Comparator;
2728

2829
import jnr.ffi.Pointer;
2930
import jnr.ffi.provider.MemoryManager;
@@ -78,7 +79,6 @@ protected byte[] allocate() {
7879
return new byte[0];
7980
}
8081

81-
@Override
8282
protected int compare(final byte[] o1, final byte[] o2) {
8383
return compareArrays(o1, o2);
8484
}
@@ -93,6 +93,11 @@ protected byte[] getBytes(final byte[] buffer) {
9393
return Arrays.copyOf(buffer, buffer.length);
9494
}
9595

96+
@Override
97+
protected Comparator<byte[]> getComparator(final DbiFlags... flags) {
98+
return this::compare;
99+
}
100+
96101
@Override
97102
protected void in(final byte[] buffer, final Pointer ptr,
98103
final long ptrAddr) {

src/main/java/org/lmdbjava/ByteBufProxy.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import static org.lmdbjava.UnsafeAccess.UNSAFE;
2626

2727
import java.lang.reflect.Field;
28+
import java.util.Comparator;
2829

2930
import io.netty.buffer.ByteBuf;
3031
import io.netty.buffer.PooledByteBufAllocator;
@@ -106,11 +107,15 @@ protected ByteBuf allocate() {
106107
throw new IllegalStateException("Netty buffer must be " + NAME);
107108
}
108109

109-
@Override
110110
protected int compare(final ByteBuf o1, final ByteBuf o2) {
111111
return o1.compareTo(o2);
112112
}
113113

114+
@Override
115+
protected Comparator<ByteBuf> getComparator(final DbiFlags... flags) {
116+
return this::compare;
117+
}
118+
114119
@Override
115120
protected void deallocate(final ByteBuf buff) {
116121
buff.release();

src/main/java/org/lmdbjava/ByteBufferProxy.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@
2626
import static java.nio.ByteOrder.BIG_ENDIAN;
2727
import static java.nio.ByteOrder.LITTLE_ENDIAN;
2828
import static java.util.Objects.requireNonNull;
29+
import static org.lmdbjava.DbiFlags.MDB_INTEGERKEY;
2930
import static org.lmdbjava.Env.SHOULD_CHECK;
31+
import static org.lmdbjava.MaskedFlag.isSet;
32+
import static org.lmdbjava.MaskedFlag.mask;
3033
import static org.lmdbjava.UnsafeAccess.UNSAFE;
3134

3235
import java.lang.reflect.Field;
3336
import java.nio.Buffer;
3437
import java.nio.ByteBuffer;
3538
import java.util.ArrayDeque;
39+
import java.util.Comparator;
3640

3741
import jnr.ffi.Pointer;
3842

@@ -189,7 +193,21 @@ protected final ByteBuffer allocate() {
189193
}
190194

191195
@Override
192-
protected final int compare(final ByteBuffer o1, final ByteBuffer o2) {
196+
protected Comparator<ByteBuffer> getComparator(final DbiFlags... flags) {
197+
final int flagInt = mask(flags);
198+
if (isSet(flagInt, MDB_INTEGERKEY)) {
199+
return this::compareCustom;
200+
}
201+
return this::compareDefault;
202+
}
203+
204+
protected final int compareDefault(final ByteBuffer o1,
205+
final ByteBuffer o2) {
206+
return o1.compareTo(o2);
207+
}
208+
209+
protected final int compareCustom(final ByteBuffer o1,
210+
final ByteBuffer o2) {
193211
return compareBuff(o1, o2);
194212
}
195213

src/main/java/org/lmdbjava/Dbi.java

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -56,38 +56,35 @@ public final class Dbi<T> {
5656

5757
private final ComparatorCallback ccb;
5858
private boolean cleaned;
59-
private final Comparator<T> compFunc;
59+
private final Comparator<T> comparator;
6060
private final Env<T> env;
6161
private final byte[] name;
62-
private final BufferProxy<T> proxy;
6362
private final Pointer ptr;
6463

6564
Dbi(final Env<T> env, final Txn<T> txn, final byte[] name,
66-
final Comparator<T> comparator, final DbiFlags... flags) {
65+
final Comparator<T> comparator, final boolean nativeCb,
66+
final BufferProxy<T> proxy, final DbiFlags... flags) {
6767
this.env = env;
6868
this.name = name == null ? null : Arrays.copyOf(name, name.length);
69+
this.comparator = comparator;
6970
final int flagsMask = mask(flags);
7071
final Pointer dbiPtr = allocateDirect(RUNTIME, ADDRESS);
7172
checkRc(LIB.mdb_dbi_open(txn.pointer(), name, flagsMask, dbiPtr));
7273
ptr = dbiPtr.getPointer(0);
73-
if (comparator == null) {
74-
proxy = null;
75-
compFunc = null;
76-
ccb = null;
77-
} else {
78-
this.proxy = txn.getProxy();
79-
this.compFunc = comparator;
74+
if (nativeCb) {
8075
this.ccb = (keyA, keyB) -> {
8176
final T compKeyA = proxy.allocate();
8277
final T compKeyB = proxy.allocate();
8378
proxy.out(compKeyA, keyA, keyA.address());
8479
proxy.out(compKeyB, keyB, keyB.address());
85-
final int result = compFunc.compare(compKeyA, compKeyB);
80+
final int result = this.comparator.compare(compKeyA, compKeyB);
8681
proxy.deallocate(compKeyA);
8782
proxy.deallocate(compKeyB);
8883
return result;
8984
};
9085
LIB.mdb_set_compare(txn.pointer(), ptr, ccb);
86+
} else {
87+
ccb = null;
9188
}
9289
}
9390

@@ -265,51 +262,20 @@ public CursorIterable<T> iterate(final Txn<T> txn) {
265262
}
266263

267264
/**
268-
* Iterate the database in accordance with the provided {@link KeyRange} and
269-
* default {@link Comparator}.
265+
* Iterate the database in accordance with the provided {@link KeyRange}.
270266
*
271267
* @param txn transaction handle (not null; not committed)
272268
* @param range range of acceptable keys (not null)
273269
* @return iterator (never null)
274270
*/
275271
public CursorIterable<T> iterate(final Txn<T> txn, final KeyRange<T> range) {
276-
return iterate(txn, range, null);
277-
}
278-
279-
/**
280-
* Iterate the database in accordance with the provided {@link KeyRange} and
281-
* {@link Comparator}.
282-
*
283-
* <p>
284-
* If a comparator is provided, it must reflect the same ordering as LMDB uses
285-
* for cursor operations (eg first, next, last, previous etc).
286-
*
287-
* <p>
288-
* If a null comparator is provided, any comparator provided when opening the
289-
* database is used. If no database comparator was specified, the buffer's
290-
* default comparator is used. Such buffer comparators reflect LMDB's default
291-
* lexicographical order.
292-
*
293-
* @param txn transaction handle (not null; not committed)
294-
* @param range range of acceptable keys (not null)
295-
* @param comparator custom comparator for keys (may be null)
296-
* @return iterator (never null)
297-
*/
298-
public CursorIterable<T> iterate(final Txn<T> txn, final KeyRange<T> range,
299-
final Comparator<T> comparator) {
300272
if (SHOULD_CHECK) {
301273
requireNonNull(txn);
302274
requireNonNull(range);
303275
env.checkNotClosed();
304276
txn.checkReady();
305277
}
306-
final Comparator<T> useComp;
307-
if (comparator == null) {
308-
useComp = compFunc == null ? txn.comparator() : compFunc;
309-
} else {
310-
useComp = comparator;
311-
}
312-
return new CursorIterable<>(txn, this, range, useComp);
278+
return new CursorIterable<>(txn, this, range, comparator);
313279
}
314280

315281
/*

src/main/java/org/lmdbjava/DirectBufferProxy.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import java.nio.ByteBuffer;
3030
import java.util.ArrayDeque;
31+
import java.util.Comparator;
3132

3233
import jnr.ffi.Pointer;
3334
import org.agrona.DirectBuffer;
@@ -111,7 +112,6 @@ protected DirectBuffer allocate() {
111112
}
112113
}
113114

114-
@Override
115115
protected int compare(final DirectBuffer o1, final DirectBuffer o2) {
116116
return compareBuff(o1, o2);
117117
}
@@ -129,6 +129,11 @@ protected byte[] getBytes(final DirectBuffer buffer) {
129129
return dest;
130130
}
131131

132+
@Override
133+
protected Comparator<DirectBuffer> getComparator(final DbiFlags... flags) {
134+
return this::compare;
135+
}
136+
132137
@Override
133138
protected void in(final DirectBuffer buffer, final Pointer ptr,
134139
final long ptrAddr) {

0 commit comments

Comments
 (0)