diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java index 99c013f..fc9e396 100644 --- a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java +++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java @@ -22,6 +22,7 @@ import org.fusesource.hawtjni.runtime.Callback; import org.fusesource.lmdbjni.EntryIterator.IteratorType; +import java.nio.ByteBuffer; import java.util.Comparator; import static org.fusesource.lmdbjni.JNI.*; @@ -345,6 +346,25 @@ public int put(Transaction tx, DirectBuffer key, DirectBuffer value, int flags) return rc; } + /** + * Just reserve space for data in the database, don't copy it. Return a pointer to the reserved space. + */ + public DirectBuffer reserve(Transaction tx, DirectBuffer key, int size) { + checkArgNotNull(key, "key"); + long address = tx.getBufferAddress(); + Unsafe.putLong(address, 0, key.capacity()); + Unsafe.putLong(address, 1, key.addressOffset()); + Unsafe.putLong(address, 2, size); + + int rc = mdb_put_address(tx.pointer(), pointer(), address, address + 2 * Unsafe.ADDRESS_SIZE, Constants.RESERVE); + checkErrorCode(rc); + int valSize = (int) Unsafe.getLong(address, 2); + long valAddress = Unsafe.getAddress(address, 3); + DirectBuffer empty = new DirectBuffer(0, 0); + empty.wrap(valAddress, valSize); + return empty; + } + /** * @see org.fusesource.lmdbjni.Database#put(Transaction, byte[], byte[], int) */ diff --git a/lmdbjni/src/test/java/org/fusesource/lmdbjni/ZeroCopyTest.java b/lmdbjni/src/test/java/org/fusesource/lmdbjni/ZeroCopyTest.java index c2b885c..6c535fa 100644 --- a/lmdbjni/src/test/java/org/fusesource/lmdbjni/ZeroCopyTest.java +++ b/lmdbjni/src/test/java/org/fusesource/lmdbjni/ZeroCopyTest.java @@ -8,12 +8,14 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static org.fusesource.lmdbjni.Constants.FIRST; import static org.fusesource.lmdbjni.Constants.NEXT; import static org.fusesource.lmdbjni.LMDBException.NOTFOUND; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertThat; public class ZeroCopyTest { @@ -159,5 +161,24 @@ public void testIteration() { assertThat(result.size(), is(2)); assertThat(result.get(0), is(18L)); assertThat(result.get(1), is(20L)); - } + } + + @Test + public void testReserve() { + byte[] key = new byte[] {1,2,3}; + byte[] val = new byte[] {3,2,1}; + + try (Transaction tx = env.createWriteTransaction()) { + DirectBuffer keyBuf = new DirectBuffer(ByteBuffer.allocateDirect(key.length)); + keyBuf.putBytes(0, key); + DirectBuffer valBuf = db.reserve(tx, keyBuf, val.length); + valBuf.putBytes(0, val); + tx.commit(); + } + + try (Transaction tx = env.createReadTransaction()) { + byte[] result = db.get(tx, key); + assertArrayEquals(result, val); + } + } }