Skip to content

Commit db70f14

Browse files
authored
Merge pull request #276 from lmdbjava/gh-249-remove-unsignedkey
* Fixes gh-249 - Remove MDB_UNSIGNEDKEY flag. * Add a builder for Dbi that makes the choice of comparator more clear. * Deprecate all `Env.openDbi()` methods. The builder is now the only way to create a Dbi. * Add MDB_INTEGERKEY specific comparators to ByteBufferProxy, ByteBufProxy and DirectBufferProxy. * Deprecate all methods that take a `XxxFlags...` varargs param. * Add XxxFlagSet interfaces and factory methods so users can pre-compute a FlagSet (and thus its mask value). * Change `BufferProxy.getComparator()` to take the DbiFlagSet as an argument so the proxy can return a comparator compatible with the flags. * Allow `mdb_cmp` to be used for CursorIterable start/stop key comparisons. * Deprecate all `Env.Builder.open()` methods. * Add a single new `Env.Builder.open(final Path path)` method. * Add `Env.Builder` methods for setting/adding flags. * Add `Env.Builder` methods for setting the file permissions. * Add `Env.Builder` method for setting the map size with a ByteUnit. * Fixes gh-267 - BACKWARD_AT_LEAST and BACKWARD_CLOSED is not returning expected ranges of results when using DUPSORT.
2 parents 77919c3 + 850c4e2 commit db70f14

File tree

83 files changed

+9992
-1414
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+9992
-1414
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ dependency-reduced-pom.xml
1616
gpg-sign.json
1717
mvn-sync.json
1818
secrets.tar
19-
lmdb
2019
pom.xml.versionsBackup

pom.xml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
<agrona.version>1.22.0</agrona.version>
3030
<assertj.version>3.27.6</assertj.version>
3131
<buildnumber-maven-plugin.version>3.2.1</buildnumber-maven-plugin.version>
32-
<byteunits.version>0.9.1</byteunits.version>
3332
<central-publishing-maven-plugin.version>0.9.0</central-publishing-maven-plugin.version>
3433
<fmt-maven-plugin.version>2.29</fmt-maven-plugin.version>
3534
<google-java-format.version>1.28.0</google-java-format.version>
@@ -85,12 +84,6 @@
8584
<version>${guava.version}</version>
8685
<scope>test</scope>
8786
</dependency>
88-
<dependency>
89-
<groupId>com.jakewharton.byteunits</groupId>
90-
<artifactId>byteunits</artifactId>
91-
<version>${byteunits.version}</version>
92-
<scope>test</scope>
93-
</dependency>
9487
<dependency>
9588
<groupId>io.netty</groupId>
9689
<artifactId>netty-buffer</artifactId>
@@ -146,6 +139,7 @@
146139
<excludes>
147140
<exclude>LICENSE.txt</exclude>
148141
<exclude>**/*.md</exclude>
142+
<exclude>**/*.csv</exclude>
149143
<exclude>lmdb/**</exclude>
150144
<exclude>licenses/**</exclude>
151145
</excludes>
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
* Copyright © 2016-2025 The LmdbJava Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.lmdbjava;
17+
18+
import java.util.Collection;
19+
import java.util.Collections;
20+
import java.util.EnumSet;
21+
import java.util.Iterator;
22+
import java.util.Objects;
23+
import java.util.Set;
24+
import java.util.function.Function;
25+
import java.util.function.Supplier;
26+
27+
/**
28+
* Encapsulates an immutable set of flags and the associated bit mask for the flags in the set.
29+
*
30+
* @param <T> The type of the flags in this set. Must extend {@link MaskedFlag} and {@link Enum<T>}.
31+
*/
32+
abstract class AbstractFlagSet<T extends Enum<T> & MaskedFlag> implements FlagSet<T> {
33+
34+
private final Set<T> flags;
35+
private final int mask;
36+
37+
protected AbstractFlagSet(final EnumSet<T> flags) {
38+
Objects.requireNonNull(flags);
39+
this.mask = MaskedFlag.mask(flags);
40+
this.flags = Collections.unmodifiableSet(Objects.requireNonNull(flags));
41+
}
42+
43+
@Override
44+
public int getMask() {
45+
return mask;
46+
}
47+
48+
@Override
49+
public Set<T> getFlags() {
50+
return flags;
51+
}
52+
53+
@Override
54+
public boolean isSet(final T flag) {
55+
// Probably cheaper to compare the masks than to use EnumSet.contains()
56+
return flag != null && MaskedFlag.isSet(mask, flag);
57+
}
58+
59+
/**
60+
* @return The number of flags in this set.
61+
*/
62+
@Override
63+
public int size() {
64+
return flags.size();
65+
}
66+
67+
/**
68+
* @return True if this set is empty.
69+
*/
70+
@Override
71+
public boolean isEmpty() {
72+
return flags.isEmpty();
73+
}
74+
75+
/**
76+
* @return The {@link Iterator} for this set.
77+
*/
78+
@Override
79+
public Iterator<T> iterator() {
80+
return flags.iterator();
81+
}
82+
83+
@Override
84+
public String toString() {
85+
return FlagSet.asString(this);
86+
}
87+
88+
static class AbstractEmptyFlagSet<T extends MaskedFlag> implements FlagSet<T> {
89+
90+
@Override
91+
public int getMask() {
92+
return MaskedFlag.EMPTY_MASK;
93+
}
94+
95+
@Override
96+
public Set<T> getFlags() {
97+
return Collections.emptySet();
98+
}
99+
100+
@Override
101+
public boolean isSet(final T flag) {
102+
return false;
103+
}
104+
105+
@Override
106+
public boolean areAnySet(final FlagSet<T> flags) {
107+
return false;
108+
}
109+
110+
@Override
111+
public int size() {
112+
return 0;
113+
}
114+
115+
@Override
116+
public boolean isEmpty() {
117+
return true;
118+
}
119+
120+
@Override
121+
public Iterator<T> iterator() {
122+
return Collections.emptyIterator();
123+
}
124+
125+
@Override
126+
public String toString() {
127+
return FlagSet.asString(this);
128+
}
129+
}
130+
131+
/**
132+
* A builder for creating a {@link AbstractFlagSet}.
133+
*
134+
* @param <E> The type of flag to be held in the {@link AbstractFlagSet}
135+
* @param <S> The type of the {@link AbstractFlagSet} implementation.
136+
*/
137+
public static final class Builder<E extends Enum<E> & MaskedFlag, S extends FlagSet<E>> {
138+
139+
final Class<E> type;
140+
final EnumSet<E> enumSet;
141+
final Function<EnumSet<E>, S> constructor;
142+
final Function<E, S> singletonSetConstructor;
143+
final Supplier<S> emptySetSupplier;
144+
145+
Builder(
146+
final Class<E> type,
147+
final Function<EnumSet<E>, S> constructor,
148+
final Function<E, S> singletonSetConstructor,
149+
final Supplier<S> emptySetSupplier) {
150+
this.type = type;
151+
this.enumSet = EnumSet.noneOf(type);
152+
this.constructor = Objects.requireNonNull(constructor);
153+
this.singletonSetConstructor = Objects.requireNonNull(singletonSetConstructor);
154+
this.emptySetSupplier = Objects.requireNonNull(emptySetSupplier);
155+
}
156+
157+
/**
158+
* Replaces any flags already set in the builder with the contents of the passed flags {@link
159+
* Collection}
160+
*
161+
* @param flags The flags to set in the builder.
162+
* @return this builder instance.
163+
*/
164+
public Builder<E, S> setFlags(final Collection<E> flags) {
165+
clear();
166+
if (flags != null) {
167+
for (E flag : flags) {
168+
if (flag != null) {
169+
enumSet.add(flag);
170+
}
171+
}
172+
}
173+
return this;
174+
}
175+
176+
/**
177+
* Replaces any flags already set in the builder with the passed flags.
178+
*
179+
* @param flags The flags to set in the builder.
180+
* @return this builder instance.
181+
*/
182+
@SafeVarargs
183+
public final Builder<E, S> setFlags(final E... flags) {
184+
clear();
185+
if (flags != null) {
186+
for (E flag : flags) {
187+
if (flag != null) {
188+
if (!type.equals(flag.getClass())) {
189+
throw new IllegalArgumentException("Unexpected type " + flag.getClass());
190+
}
191+
enumSet.add(flag);
192+
}
193+
}
194+
}
195+
return this;
196+
}
197+
198+
/**
199+
* Adds a single flag in the builder.
200+
*
201+
* @param flag The flag to set in the builder.
202+
* @return this builder instance.
203+
*/
204+
public Builder<E, S> addFlag(final E flag) {
205+
if (flag != null) {
206+
enumSet.add(flag);
207+
}
208+
return this;
209+
}
210+
211+
/**
212+
* Adds multiple flag in the builder.
213+
*
214+
* @param flags The flags to set in the builder.
215+
* @return this builder instance.
216+
*/
217+
public Builder<E, S> addFlags(final Collection<E> flags) {
218+
if (flags != null) {
219+
enumSet.addAll(flags);
220+
}
221+
return this;
222+
}
223+
224+
/**
225+
* Clears any flags already set in this {@link Builder}
226+
*
227+
* @return this builder instance.
228+
*/
229+
public Builder<E, S> clear() {
230+
enumSet.clear();
231+
return this;
232+
}
233+
234+
/**
235+
* Build the {@link DbiFlagSet}
236+
*
237+
* @return A
238+
*/
239+
public S build() {
240+
final int size = enumSet.size();
241+
if (size == 0) {
242+
return emptySetSupplier.get();
243+
} else if (size == 1) {
244+
return singletonSetConstructor.apply(enumSet.stream().findFirst().get());
245+
} else {
246+
return constructor.apply(enumSet);
247+
}
248+
}
249+
}
250+
}

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

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616
package org.lmdbjava;
1717

1818
import static java.lang.Long.BYTES;
19-
import static org.lmdbjava.DbiFlags.MDB_INTEGERKEY;
20-
import static org.lmdbjava.DbiFlags.MDB_UNSIGNEDKEY;
21-
import static org.lmdbjava.MaskedFlag.isSet;
22-
import static org.lmdbjava.MaskedFlag.mask;
2319

2420
import java.util.Comparator;
2521
import jnr.ffi.Pointer;
@@ -75,30 +71,22 @@ protected BufferProxy() {}
7571
* <p>The provided comparator must strictly match the lexicographical order of keys in the native
7672
* LMDB database.
7773
*
78-
* @param flags for the database
74+
* @param dbiFlagSet The {@link DbiFlags} set for the database.
7975
* @return a comparator that can be used (never null)
8076
*/
81-
protected Comparator<T> getComparator(DbiFlags... flags) {
82-
final int intFlag = mask(flags);
83-
84-
return isSet(intFlag, MDB_INTEGERKEY) || isSet(intFlag, MDB_UNSIGNEDKEY)
85-
? getUnsignedComparator()
86-
: getSignedComparator();
87-
}
77+
public abstract Comparator<T> getComparator(final DbiFlagSet dbiFlagSet);
8878

8979
/**
90-
* Get a suitable default {@link Comparator} to compare numeric key values as signed.
80+
* Get a suitable default {@link Comparator}
9181
*
92-
* @return a comparator that can be used (never null)
93-
*/
94-
protected abstract Comparator<T> getSignedComparator();
95-
96-
/**
97-
* Get a suitable default {@link Comparator} to compare numeric key values as unsigned.
82+
* <p>The provided comparator must strictly match the lexicographical order of keys in the native
83+
* LMDB database.
9884
*
9985
* @return a comparator that can be used (never null)
10086
*/
101-
protected abstract Comparator<T> getUnsignedComparator();
87+
public Comparator<T> getComparator() {
88+
return getComparator(DbiFlagSet.empty());
89+
}
10290

10391
/**
10492
* Called when the <code>MDB_val</code> should be set to reflect the passed buffer. This buffer
@@ -138,4 +126,13 @@ protected Comparator<T> getComparator(DbiFlags... flags) {
138126
final KeyVal<T> keyVal() {
139127
return new KeyVal<>(this);
140128
}
129+
130+
/**
131+
* Create a new {@link Key} to hold pointers for this buffer proxy.
132+
*
133+
* @return a non-null key holder
134+
*/
135+
final Key<T> key() {
136+
return new Key<>(this);
137+
}
141138
}

0 commit comments

Comments
 (0)