Skip to content

Commit f71e2fe

Browse files
pstutzbp-alex
authored andcommitted
Put: Special flag handling and Cursor/Dbi alignment (#40)
* Communicate with return value instead of with exception These are expected cases and initialising exceptions is costly. * Only checking if required. * Fully aligned Cursor.put with Dbi.put * Added tests for Cursor.put and Dbi.put They cover the MDB_NOOVERWRITE and MDB_NODUPDATA special cases. * Removed check guard. * Removed null check, as txn is guaranteed to be non-null Also removed final else in both Dbi/Cursor. * Removed unused import
1 parent 4259048 commit f71e2fe

4 files changed

Lines changed: 79 additions & 21 deletions

File tree

src/main/java/org/lmdbjava/Cursor.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,15 @@
2323
import static java.util.Objects.requireNonNull;
2424
import jnr.ffi.Pointer;
2525
import jnr.ffi.byref.NativeLongByReference;
26+
27+
import static org.lmdbjava.Dbi.KeyExistsException.MDB_KEYEXIST;
2628
import static org.lmdbjava.Dbi.KeyNotFoundException.MDB_NOTFOUND;
2729
import static org.lmdbjava.Env.SHOULD_CHECK;
2830
import static org.lmdbjava.Library.LIB;
31+
import static org.lmdbjava.MaskedFlag.isSet;
2932
import static org.lmdbjava.MaskedFlag.mask;
33+
import static org.lmdbjava.PutFlags.MDB_NODUPDATA;
34+
import static org.lmdbjava.PutFlags.MDB_NOOVERWRITE;
3035
import static org.lmdbjava.PutFlags.MDB_RESERVE;
3136
import static org.lmdbjava.ResultCodeMapper.checkRc;
3237
import static org.lmdbjava.SeekOp.MDB_FIRST;
@@ -187,14 +192,15 @@ public boolean prev() {
187192
* Store by cursor.
188193
*
189194
* <p>
190-
* This function stores key/data pairs into the database. The cursor is
191-
* positioned at the new item, or on failure usually near it.
195+
* This function stores key/data pairs into the database.
192196
*
193197
* @param key key to store
194198
* @param val data to store
195199
* @param op options for this operation
200+
* @return true if the value was put, false if MDB_NOOVERWRITE or
201+
* MDB_NODUPDATA were set and the key/value existed already.
196202
*/
197-
public void put(final T key, final T val, final PutFlags... op) {
203+
public boolean put(final T key, final T val, final PutFlags... op) {
198204
if (SHOULD_CHECK) {
199205
requireNonNull(key);
200206
requireNonNull(val);
@@ -204,11 +210,19 @@ public void put(final T key, final T val, final PutFlags... op) {
204210
}
205211
kv.keyIn(key);
206212
kv.valIn(val);
207-
final int flags = mask(op);
208-
checkRc(LIB.mdb_cursor_put(ptrCursor, kv.pointerKey(), kv.pointerVal(),
209-
flags));
210-
kv.keyOut();
211-
kv.valOut();
213+
final int mask = mask(op);
214+
final int rc = LIB.mdb_cursor_put(ptrCursor, kv.pointerKey(), kv.pointerVal(),
215+
mask);
216+
if (rc == MDB_KEYEXIST) {
217+
if (isSet(mask, MDB_NOOVERWRITE)) {
218+
kv.valOut(); // marked as in,out in LMDB C docs
219+
} else if (!isSet(mask, MDB_NODUPDATA)) {
220+
checkRc(rc);
221+
}
222+
return false;
223+
}
224+
checkRc(rc);
225+
return true;
212226
}
213227

214228
/**

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import static org.lmdbjava.Library.RUNTIME;
3636
import static org.lmdbjava.MaskedFlag.isSet;
3737
import static org.lmdbjava.MaskedFlag.mask;
38+
import static org.lmdbjava.PutFlags.MDB_NODUPDATA;
3839
import static org.lmdbjava.PutFlags.MDB_NOOVERWRITE;
3940
import static org.lmdbjava.PutFlags.MDB_RESERVE;
4041
import static org.lmdbjava.ResultCodeMapper.checkRc;
@@ -289,8 +290,10 @@ public void put(final T key, final T val) {
289290
* @param key key to store in the database (not null)
290291
* @param val value to store in the database (not null)
291292
* @param flags Special options for this operation
293+
* @return true if the value was put, false if MDB_NOOVERWRITE or
294+
* MDB_NODUPDATA were set and the key/value existed already.
292295
*/
293-
public void put(final Txn<T> txn, final T key, final T val,
296+
public boolean put(final Txn<T> txn, final T key, final T val,
294297
final PutFlags... flags) {
295298
if (SHOULD_CHECK) {
296299
requireNonNull(txn);
@@ -304,10 +307,16 @@ public void put(final Txn<T> txn, final T key, final T val,
304307
final int mask = mask(flags);
305308
final int rc = LIB.mdb_put(txn.pointer(), ptr, txn.kv().pointerKey(), txn
306309
.kv().pointerVal(), mask);
307-
if (rc == MDB_KEYEXIST && isSet(mask, MDB_NOOVERWRITE)) {
308-
txn.kv().valOut(); // marked as in,out in LMDB C docs
310+
if (rc == MDB_KEYEXIST) {
311+
if (isSet(mask, MDB_NOOVERWRITE)) {
312+
txn.kv().valOut(); // marked as in,out in LMDB C docs
313+
} else if (!isSet(mask, MDB_NODUPDATA)) {
314+
checkRc(rc);
315+
}
316+
return false;
309317
}
310318
checkRc(rc);
319+
return true;
311320
}
312321

313322
/**

src/test/java/org/lmdbjava/CursorTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import static org.lmdbjava.Env.create;
4343
import static org.lmdbjava.EnvFlags.MDB_NOSUBDIR;
4444
import static org.lmdbjava.PutFlags.MDB_APPENDDUP;
45+
import static org.lmdbjava.PutFlags.MDB_NODUPDATA;
4546
import static org.lmdbjava.PutFlags.MDB_NOOVERWRITE;
4647
import static org.lmdbjava.SeekOp.MDB_FIRST;
4748
import static org.lmdbjava.TestUtils.DB_1;
@@ -195,6 +196,31 @@ public void renewTxRw() {
195196
}
196197
}
197198

199+
@Test
200+
public void returnValueForNoOverwrite() {
201+
final Dbi<ByteBuffer> db = env.openDbi(DB_1, MDB_CREATE);
202+
try (Txn<ByteBuffer> txn = env.txnWrite()) {
203+
final Cursor<ByteBuffer> c = db.openCursor(txn);
204+
// ok
205+
assertThat(c.put(bb(5), bb(6), MDB_NOOVERWRITE), is(true));
206+
// fails, but gets exist val
207+
assertThat(c.put(bb(5), bb(8), MDB_NOOVERWRITE), is(false));
208+
assertThat(c.val().getInt(0), is(6));
209+
}
210+
}
211+
212+
@Test
213+
public void returnValueForNoDupData() {
214+
final Dbi<ByteBuffer> db = env.openDbi(DB_1, MDB_CREATE, MDB_DUPSORT);
215+
try (Txn<ByteBuffer> txn = env.txnWrite()) {
216+
final Cursor<ByteBuffer> c = db.openCursor(txn);
217+
// ok
218+
assertThat(c.put(bb(5), bb(6), MDB_NODUPDATA), is(true));
219+
assertThat(c.put(bb(5), bb(7), MDB_NODUPDATA), is(true));
220+
assertThat(c.put(bb(5), bb(6), MDB_NODUPDATA), is(false));
221+
}
222+
}
223+
198224
@Test
199225
public void repeatedCloseCausesNotError() {
200226
final Dbi<ByteBuffer> db = env.openDbi(DB_1, MDB_CREATE, MDB_DUPSORT);

src/test/java/org/lmdbjava/DbiTest.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@
4343
import org.junit.Test;
4444
import org.junit.rules.TemporaryFolder;
4545
import org.lmdbjava.Dbi.DbFullException;
46-
import org.lmdbjava.Dbi.KeyExistsException;
4746
import static org.lmdbjava.DbiFlags.MDB_CREATE;
4847
import static org.lmdbjava.DbiFlags.MDB_DUPSORT;
4948
import org.lmdbjava.Env.MapFullException;
5049
import static org.lmdbjava.Env.create;
5150
import static org.lmdbjava.EnvFlags.MDB_NOSUBDIR;
5251
import static org.lmdbjava.GetOp.MDB_SET_KEY;
5352
import org.lmdbjava.LmdbNativeException.ConstantDerviedException;
53+
import static org.lmdbjava.PutFlags.MDB_NODUPDATA;
5454
import static org.lmdbjava.PutFlags.MDB_NOOVERWRITE;
5555
import static org.lmdbjava.TestUtils.DB_1;
5656
import static org.lmdbjava.TestUtils.ba;
@@ -120,20 +120,29 @@ public void getName() {
120120
assertThat(db.getName(), is(DB_1));
121121
}
122122

123-
@Test(expected = KeyExistsException.class)
124-
public void keyExistsException() {
123+
@Test
124+
public void returnValueForNoOverwrite() {
125125
final Dbi<ByteBuffer> db = env.openDbi(DB_1, MDB_CREATE);
126126
try (Txn<ByteBuffer> txn = env.txnWrite()) {
127-
db.put(txn, bb(5), bb(6), MDB_NOOVERWRITE); // ok
128-
try {
129-
db.put(txn, bb(5), bb(8), MDB_NOOVERWRITE); // fails, but gets exist val
130-
} catch (final KeyExistsException ke) {
131-
assertThat(txn.val().getInt(0), is(6));
132-
throw ke;
133-
}
127+
// ok
128+
assertThat(db.put(txn, bb(5), bb(6), MDB_NOOVERWRITE), is(true));
129+
// fails, but gets exist val
130+
assertThat(db.put(txn, bb(5), bb(8), MDB_NOOVERWRITE), is(false));
131+
assertThat(txn.val().getInt(0), is(6));
134132
}
135133
}
136134

135+
@Test
136+
public void returnValueForNoDupData() {
137+
final Dbi<ByteBuffer> db = env.openDbi(DB_1, MDB_CREATE, MDB_DUPSORT);
138+
try (Txn<ByteBuffer> txn = env.txnWrite()) {
139+
// ok
140+
assertThat(db.put(txn, bb(5), bb(6), MDB_NODUPDATA), is(true));
141+
assertThat(db.put(txn, bb(5), bb(7), MDB_NODUPDATA), is(true));
142+
assertThat(db.put(txn, bb(5), bb(6), MDB_NODUPDATA), is(false));
143+
}
144+
}
145+
137146
@Test
138147
public void putAbortGet() {
139148
final Dbi<ByteBuffer> db = env.openDbi(DB_1, MDB_CREATE);

0 commit comments

Comments
 (0)