diff --git a/changelog.md b/changelog.md
new file mode 100644
index 0000000..c8c0b12
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,5 @@
+# [lmdbjni](https://github.com/fusesource/lmdbjni)
+
+## [lmdbjni 1.0](http://repo.fusesource.com/nexus/content/groups/public/org/fusesource/lmdbjni/lmdbjni-all/1.0), unreleased
+
+* Initial Release
diff --git a/license.txt b/license.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lmdbjni-all/pom.xml b/lmdbjni-all/pom.xml
new file mode 100755
index 0000000..f128e2f
--- /dev/null
+++ b/lmdbjni-all/pom.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+ 4.0.0
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-all
+ 99-master-SNAPSHOT
+ bundle
+
+ ${project.artifactId}
+ An uber jar which contains all the lmdbjni platform libraries and dependencies
+
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-osx
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-linux32
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-linux64
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-win32
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-win64
+ 99-master-SNAPSHOT
+
+
+
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ 2.3.7
+ true
+ true
+
+
+ ${project.artifactId}
+ ${project.groupId}.${project.artifactId}
+
+ org.fusesource.lmdbjni;version=${project.version},
+ org.iq80.leveldb*;version=${leveldb-api-version},
+
+
+ org.fusesource.hawtjni*,org.fusesource.lmdbjni.internal*,!*
+ LevelDB JNI
+ ${project.version}
+
+ *;groupId=org.fusesource.lmdbjni;inline=META-INF/native/*,
+
+ true
+
+ META-INF/native/windows32/lmdbjni.dll;osname=Win32;processor=x86,
+ META-INF/native/windows64/lmdbjni.dll;osname=Win32;processor=x86-64,
+ META-INF/native/osx/liblmdbjni.jnilib;osname=macosx;processor=x86,
+ META-INF/native/osx/liblmdbjni.jnilib;osname=macosx;processor=x86-64,
+ META-INF/native/linux32/liblmdbjni.so;osname=Linux;processor=x86,
+ META-INF/native/linux64/liblmdbjni.so;osname=Linux;processor=x86-64
+
+
+
+
+
+
+
+
diff --git a/lmdbjni-all/src/main/java/org/fusesource/leveldbjni/All.java b/lmdbjni-all/src/main/java/org/fusesource/leveldbjni/All.java
new file mode 100644
index 0000000..da47b07
--- /dev/null
+++ b/lmdbjni-all/src/main/java/org/fusesource/leveldbjni/All.java
@@ -0,0 +1,4 @@
+package org.fusesource.lmdbjni;
+
+public class All {
+}
\ No newline at end of file
diff --git a/lmdbjni-linux32/pom.xml b/lmdbjni-linux32/pom.xml
new file mode 100755
index 0000000..d7bdfac
--- /dev/null
+++ b/lmdbjni-linux32/pom.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+ 4.0.0
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-linux32
+ 99-master-SNAPSHOT
+
+ ${project.artifactId}
+ The lmdbjni linux 32 native libraries
+
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+
+
+
+
+ ${basedir}/../lmdbjni/src/test/java
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.3.1
+
+ ${basedir}/target/generated-sources/hawtjni/lib
+
+
+
+ org.fusesource.hawtjni
+ maven-hawtjni-plugin
+ ${hawtjni-version}
+
+
+
+ build
+
+ compile
+
+
+
+ lmdbjni
+ false
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ ${project.version}
+ native-src
+ zip
+
+
+ --with-lmdb=${env.LMDB_HOME}
+
+
+
+
+
+
+
diff --git a/lmdbjni-linux64/pom.xml b/lmdbjni-linux64/pom.xml
new file mode 100755
index 0000000..5fdb810
--- /dev/null
+++ b/lmdbjni-linux64/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+ 4.0.0
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-linux64
+ 99-master-SNAPSHOT
+
+ ${project.artifactId}
+ The lmdbjni linux 64 native libraries
+
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+
+
+
+
+ ${basedir}/../lmdbjni/src/test/java
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.3.1
+
+ ${basedir}/target/generated-sources/hawtjni/lib
+
+
+
+ org.fusesource.hawtjni
+ maven-hawtjni-plugin
+ ${hawtjni-version}
+
+
+
+ build
+
+
+
+
+ lmdbjni
+ false
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ ${project.version}
+ native-src
+ zip
+
+
+ --with-lmdb=${env.LMDB_HOME}
+
+
+
+
+
+
+
diff --git a/lmdbjni-osx/pom.xml b/lmdbjni-osx/pom.xml
new file mode 100755
index 0000000..4bd7c82
--- /dev/null
+++ b/lmdbjni-osx/pom.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+ 4.0.0
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-osx
+ 99-master-SNAPSHOT
+
+ ${project.artifactId}
+ The lmdbjni OS X universal native libraries
+
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+ test-jar
+ test
+
+
+
+
+ ${basedir}/../lmdbjni/src/test/java
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.3.1
+
+ ${basedir}/target/generated-sources/hawtjni/lib
+
+
+
+
+ org.fusesource.hawtjni
+ maven-hawtjni-plugin
+ ${hawtjni-version}
+
+
+
+ build
+
+
+
+
+ lmdbjni
+ false
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ ${project.version}
+ native-src
+ zip
+
+ osx
+
+ --with-lmdb=${env.LMDB_HOME}
+ --with-universal
+
+
+
+
+
+
+
diff --git a/lmdbjni-win32/pom.xml b/lmdbjni-win32/pom.xml
new file mode 100755
index 0000000..84abdb5
--- /dev/null
+++ b/lmdbjni-win32/pom.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+ 4.0.0
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-win32
+ 99-master-SNAPSHOT
+
+ ${project.artifactId}
+ The lmdbjni Windows 32 bit native libraries
+
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+
+
+
+
+ ${basedir}/../lmdbjni/src/test/java
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.3.1
+
+ ${basedir}/target/generated-sources/hawtjni/lib
+
+
+
+ org.fusesource.hawtjni
+ maven-hawtjni-plugin
+ ${hawtjni-version}
+
+
+
+ build
+
+ compile
+
+
+
+ lmdbjni
+ false
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ ${project.version}
+ native-src
+ zip
+
+ ${basedir}/../lmdbjni/target/generated-sources/hawtjni/native-package
+
+
+
+
+
+
diff --git a/lmdbjni-win64/pom.xml b/lmdbjni-win64/pom.xml
new file mode 100755
index 0000000..e758a86
--- /dev/null
+++ b/lmdbjni-win64/pom.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+ 4.0.0
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-win64
+ 99-master-SNAPSHOT
+
+ ${project.artifactId}
+ The lmdbjni Windows 64 bit native libraries
+
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+
+
+
+
+ ${basedir}/../lmdbjni/src/test/java
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.3.1
+
+ ${basedir}/target/generated-sources/hawtjni/lib
+
+
+
+ org.fusesource.hawtjni
+ maven-hawtjni-plugin
+ ${hawtjni-version}
+
+
+
+ build
+
+
+
+
+ lmdbjni
+ false
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ ${project.version}
+ native-src
+ zip
+
+ ${basedir}/../lmdbjni/target/generated-sources/hawtjni/native-package
+
+
+
+
+
+
diff --git a/lmdbjni/pom.xml b/lmdbjni/pom.xml
new file mode 100755
index 0000000..08ff5e0
--- /dev/null
+++ b/lmdbjni/pom.xml
@@ -0,0 +1,181 @@
+
+
+
+
+
+ 4.0.0
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+
+
+ org.fusesource.lmdbjni
+ lmdbjni
+ 99-master-SNAPSHOT
+ jar
+
+ ${project.artifactId}
+ lmdbjni is a jni library for acessing leveldb.
+
+
+ false
+
+
+
+
+ org.fusesource.hawtjni
+ hawtjni-runtime
+ ${hawtjni-version}
+
+
+ org.iq80.leveldb
+ leveldb-api
+ ${leveldb-api-version}
+
+
+
+
+
+
+ ${project.basedir}/src/main/resources
+ true
+
+ **/*
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ test-jar
+
+
+
+
+
+
+ org.fusesource.hawtjni
+ maven-hawtjni-plugin
+ ${hawtjni-version}
+
+
+
+ generate
+ package-source
+
+
+
+
+ ${skipAutogen}
+ lmdbjni
+ false
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.4.3
+
+ true
+ once
+ -ea
+ false
+ ${project.build.directory}
+
+ **/*
+
+
+ **/*Test.java
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.5
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ 2.0.1
+
+
+ bundle-manifest
+ process-classes
+
+ manifest
+
+
+
+ !org.fusesource.lmdbjni*,!org.fusesource.hawtjni*,sun.reflect;resolution:=optional,*
+
+
+
+
+
+
+ maven-jar-plugin
+
+
+ ${project.build.outputDirectory}/META-INF/MANIFEST.MF
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.2.1
+
+
+ attach-sources
+ package
+
+ jar-no-fork
+
+
+
+
+
+
+
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Cursor.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Cursor.java
new file mode 100644
index 0000000..225f105
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Cursor.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+
+import java.io.Closeable;
+
+import static org.fusesource.lmdbjni.JNI.*;
+import static org.fusesource.lmdbjni.Util.checkArgNotNull;
+import static org.fusesource.lmdbjni.Util.checkErrorCode;
+
+/**
+ * @author Hiram Chirino
+ */
+public class Cursor extends NativeObject implements Closeable {
+
+ private final Env env;
+
+ Cursor(Env env, long self) {
+ super(self);
+ this.env = env;
+ }
+
+ public void close() {
+ if( self!=0 ) {
+ mdb_cursor_close(self);
+ self=0;
+ }
+ }
+
+ public void renew(Transaction tx) {
+ checkErrorCode(mdb_cursor_renew(tx.pointer(), pointer()));
+ }
+
+ // TODO: implement mdb_cursor_txn
+ // TODO: implement mdb_cursor_dbi
+
+ public Entry get(CursorOp op) {
+ checkArgNotNull(op, "op");
+
+ Value key = new Value();
+ Value value = new Value();
+ int rc = mdb_cursor_get(pointer(), key, value, op.getValue());
+ if( rc == MDB_NOTFOUND ) {
+ return null;
+ }
+ checkErrorCode(rc);
+ return new Entry(key.toByteArray(), value.toByteArray());
+ }
+
+ public Entry seek(byte[] key, CursorOp op) {
+ checkArgNotNull(key, "key");
+ checkArgNotNull(op, "op");
+ NativeBuffer keyBuffer = NativeBuffer.create(key);
+ try {
+ Value keyValue = new Value(keyBuffer);
+ Value value = new Value();
+ int rc = mdb_cursor_get(pointer(), keyValue, value, op.getValue());
+ if( rc == MDB_NOTFOUND ) {
+ return null;
+ }
+ checkErrorCode(rc);
+ return new Entry(keyValue.toByteArray(), value.toByteArray());
+ } finally {
+ keyBuffer.delete();
+ }
+
+ }
+
+ public byte[] put(byte[] key, byte[] value, int flags) {
+ checkArgNotNull(key, "key");
+ checkArgNotNull(value, "value");
+ NativeBuffer keyBuffer = NativeBuffer.create(key);
+ try {
+ NativeBuffer valueBuffer = NativeBuffer.create(value);
+ try {
+ return put(keyBuffer, valueBuffer, flags);
+ } finally {
+ valueBuffer.delete();
+ }
+ } finally {
+ keyBuffer.delete();
+ }
+ }
+
+ private byte[] put(NativeBuffer keyBuffer, NativeBuffer valueBuffer, int flags) {
+ return put(new Value(keyBuffer), new Value(valueBuffer), flags);
+ }
+ private byte[] put(Value keySlice, Value valueSlice, int flags) {
+ mdb_cursor_put(pointer(), keySlice, valueSlice, flags);
+ return valueSlice.toByteArray();
+ }
+
+ public void delete() {
+ checkErrorCode(mdb_cursor_del(pointer(), 0));
+ }
+
+ public void deleteIncludingDups() {
+ checkErrorCode(mdb_cursor_del(pointer(), MDB_NODUPDATA));
+ }
+
+ public long count() {
+ long rc[] = new long[1];
+ checkErrorCode(mdb_cursor_count(pointer(), rc));
+ return rc[0];
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/CursorOp.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/CursorOp.java
new file mode 100644
index 0000000..ff89aea
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/CursorOp.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import static org.fusesource.lmdbjni.JNI.*;
+
+/**
+ * @author Hiram Chirino
+ */
+public enum CursorOp {
+
+ FIRST (MDB_FIRST ) ,
+ FIRST_DUP (MDB_FIRST_DUP ) ,
+ GET_BOTH (MDB_GET_BOTH ) ,
+ GET_BOTH_RANGE (MDB_GET_BOTH_RANGE) ,
+ GET_CURRENT (MDB_GET_CURRENT ) ,
+ GET_MULTIPLE (MDB_GET_MULTIPLE ) ,
+ LAST (MDB_LAST ) ,
+ LAST_DUP (MDB_LAST_DUP ) ,
+ NEXT (MDB_NEXT ) ,
+ NEXT_DUP (MDB_NEXT_DUP ) ,
+ NEXT_MULTIPLE (MDB_NEXT_MULTIPLE ) ,
+ NEXT_NODUP (MDB_NEXT_NODUP ) ,
+ PREV (MDB_PREV ) ,
+ PREV_DUP (MDB_PREV_DUP ) ,
+ PREV_NODUP (MDB_PREV_NODUP ) ,
+ SET (MDB_SET ) ,
+ SET_KEY (MDB_SET_KEY ) ,
+ SET_RANGE (MDB_SET_RANGE );
+
+ private final int value;
+
+ CursorOp(int value) {
+
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java
new file mode 100644
index 0000000..0688ae7
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java
@@ -0,0 +1,218 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+
+import java.io.Closeable;
+
+import static org.fusesource.lmdbjni.JNI.*;
+import static org.fusesource.lmdbjni.Util.checkArgNotNull;
+import static org.fusesource.lmdbjni.Util.checkErrorCode;
+
+/**
+ * @author Hiram Chirino
+ */
+public class Database extends NativeObject implements Closeable {
+
+ private final Env env;
+
+ Database(Env env, long self) {
+ super(self);
+ this.env = env;
+ }
+
+ public void close() {
+ if( self!=0 ) {
+ mdb_dbi_close(env.pointer(), self);
+ self=0;
+ }
+ }
+
+
+ public MDB_stat stat() {
+ Transaction tx = env.createTransaction();
+ try {
+ return stat(tx);
+ } finally {
+ tx.commit();
+ }
+ }
+
+ public MDB_stat stat(Transaction tx) {
+ checkArgNotNull(tx, "tx");
+ MDB_stat rc = new MDB_stat();
+ mdb_stat(tx.pointer(), pointer(), rc);
+ return rc;
+ }
+
+ public void drop(boolean delete) {
+ Transaction tx = env.createTransaction();
+ try {
+ drop(tx, delete);
+ } finally {
+ tx.commit();
+ }
+ }
+
+ public void drop(Transaction tx, boolean delete) {
+ checkArgNotNull(tx, "tx");
+ mdb_drop(tx.pointer(), pointer(), delete ? 1 : 0);
+ if( delete ) {
+ self=0;
+ }
+ }
+
+
+ public byte[] get(byte[] key) {
+ checkArgNotNull(key, "key");
+ Transaction tx = env.createTransaction();
+ try {
+ return get(tx, key);
+ } finally {
+ tx.commit();
+ }
+ }
+
+ public byte[] get(Transaction tx, byte[] key) {
+ checkArgNotNull(tx, "tx");
+ checkArgNotNull(key, "key");
+ NativeBuffer keyBuffer = NativeBuffer.create(key);
+ try {
+ return get(tx, keyBuffer);
+ } finally {
+ keyBuffer.delete();
+ }
+ }
+
+ private byte[] get(Transaction tx, NativeBuffer keyBuffer) {
+ return get(tx, new Value(keyBuffer));
+ }
+
+ private byte[] get(Transaction tx, Value key) {
+ Value value = new Value();
+ int rc = mdb_get(tx.pointer(), pointer(), key, value);
+ if( rc == MDB_NOTFOUND ) {
+ return null;
+ }
+ checkErrorCode(rc);
+ return value.toByteArray();
+ }
+
+ public byte[] put(byte[] key, byte[] value) {
+ return put(key, value, 0);
+ }
+
+ public byte[] put(byte[] key, byte[] value, int flags) {
+ checkArgNotNull(key, "key");
+ Transaction tx = env.createTransaction();
+ try {
+ return put(tx, key, value, flags);
+ } finally {
+ tx.commit();
+ }
+ }
+
+ public byte[] put(Transaction tx, byte[] key, byte[] value) {
+ return put(tx, key, value, 0);
+ }
+
+ public byte[] put(Transaction tx, byte[] key, byte[] value, int flags) {
+ checkArgNotNull(tx, "tx");
+ checkArgNotNull(key, "key");
+ checkArgNotNull(value, "value");
+ NativeBuffer keyBuffer = NativeBuffer.create(key);
+ try {
+ NativeBuffer valueBuffer = NativeBuffer.create(value);
+ try {
+ return put(tx, keyBuffer, valueBuffer, flags);
+ } finally {
+ valueBuffer.delete();
+ }
+ } finally {
+ keyBuffer.delete();
+ }
+ }
+
+ private byte[] put(Transaction tx, NativeBuffer keyBuffer, NativeBuffer valueBuffer, int flags) {
+ return put(tx, new Value(keyBuffer), new Value(valueBuffer), flags);
+ }
+
+ private byte[] put(Transaction tx, Value keySlice, Value valueSlice, int flags) {
+ mdb_put(tx.pointer(), pointer(), keySlice, valueSlice, flags);
+ return valueSlice.toByteArray();
+ }
+
+
+ public boolean delete(byte[] key) {
+ return delete(key, null);
+ }
+
+ public boolean delete(byte[] key, byte[] value) {
+ checkArgNotNull(key, "key");
+ Transaction tx = env.createTransaction();
+ try {
+ return delete(tx, key, value);
+ } finally {
+ tx.commit();
+ }
+ }
+
+ public boolean delete(Transaction tx, byte[] key) {
+ return delete(tx, key, null);
+ }
+
+ public boolean delete(Transaction tx, byte[] key, byte[] value) {
+ checkArgNotNull(tx, "tx");
+ checkArgNotNull(key, "key");
+ NativeBuffer keyBuffer = NativeBuffer.create(key);
+ try {
+ NativeBuffer valueBuffer = NativeBuffer.create(value);
+ try {
+ return delete(tx, keyBuffer, valueBuffer);
+ } finally {
+ if( valueBuffer!=null ) {
+ valueBuffer.delete();
+ }
+ }
+ } finally {
+ keyBuffer.delete();
+ }
+ }
+
+ private boolean delete(Transaction tx, NativeBuffer keyBuffer, NativeBuffer valueBuffer) {
+ return delete(tx, new Value(keyBuffer), Value.create(valueBuffer));
+ }
+
+ private boolean delete(Transaction tx, Value keySlice, Value valueSlice) {
+ int rc = mdb_del(tx.pointer(), pointer(), keySlice, valueSlice);
+ if( rc == MDB_NOTFOUND ) {
+ return false;
+ }
+ checkErrorCode(rc);
+ return true;
+ }
+
+
+ public Cursor openCursor(Transaction tx) {
+ long cursor[] = new long[1];
+ checkErrorCode(mdb_cursor_open(tx.pointer(), pointer(), cursor));
+ return new Cursor(env, cursor[0]);
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Entry.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Entry.java
new file mode 100644
index 0000000..aa781de
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Entry.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import java.util.Map;
+
+/**
+ * @author Hiram Chirino
+ */
+public class Entry implements Map.Entry {
+
+ private final byte[] key;
+ private final byte[] value;
+
+ public Entry(byte[] key, byte[] value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+
+ public byte[] getValue() {
+ return value;
+ }
+
+ public byte[] setValue(byte[] value) {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Env.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Env.java
new file mode 100644
index 0000000..8fd7e25
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Env.java
@@ -0,0 +1,167 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import java.io.Closeable;
+
+import static org.fusesource.lmdbjni.JNI.*;
+import static org.fusesource.lmdbjni.Util.*;
+
+/**
+ * @author Hiram Chirino
+ */
+public class Env extends NativeObject implements Closeable {
+
+ public static String version() {
+ return string(JNI.MDB_VERSION_STRING);
+ }
+
+ public Env() {
+ super(create());
+ setMaxDbs(1);
+ }
+
+ private static long create() {
+ long env_ptr[] = new long[1];
+ checkErrorCode(mdb_env_create(env_ptr));
+ return env_ptr[0];
+ }
+
+ public void open(String path) {
+ open(path, 0);
+ }
+
+ public void open(String path, int flags) {
+ open(path, flags, 0644);
+ }
+
+ public void open(String path, int flags, int mode) {
+ int rc = mdb_env_open(pointer(), path, flags, mode);
+ if( rc!=0 ) {
+ close();
+ }
+ checkErrorCode(rc);
+ }
+
+ public void close() {
+ if( self!=0 ) {
+ mdb_env_close(self);
+ self=0;
+ }
+ }
+
+ public void copy(String path) {
+ checkArgNotNull(path, "path");
+ checkErrorCode(mdb_env_copy(pointer(), path));
+ }
+
+ public void sync(boolean force) {
+ checkErrorCode(mdb_env_sync(pointer(), force ? 1 : 0));
+ }
+
+
+ public void setMapSize(long size) {
+ checkErrorCode(mdb_env_set_mapsize(pointer(), size));
+ }
+
+ public void setMaxDbs(long size) {
+ checkErrorCode(mdb_env_set_maxdbs(pointer(), size));
+ }
+
+ public long getMaxReaders() {
+ long rc[] = new long[1];
+ checkErrorCode(mdb_env_get_maxreaders(pointer(), rc));
+ return rc[0];
+ }
+ public void setMaxReaders(long size) {
+ checkErrorCode(mdb_env_set_maxreaders(pointer(), size));
+ }
+
+ public int getFlags() {
+ long[] flags = new long[1];
+ checkErrorCode(mdb_env_get_flags(pointer(), flags));
+ return (int) flags[0];
+ }
+
+ public void addFlags(int flags) {
+ checkErrorCode(mdb_env_set_flags(pointer(), flags, 1));
+ }
+
+ public void removeFlags(int flags) {
+ checkErrorCode(mdb_env_set_flags(pointer(), flags, 0));
+ }
+
+ public MDB_envinfo info() {
+ MDB_envinfo rc = new MDB_envinfo();
+ mdb_env_info(pointer(), rc);
+ return rc;
+ }
+
+ public MDB_stat stat() {
+ MDB_stat rc = new MDB_stat();
+ mdb_env_stat(pointer(), rc);
+ return rc;
+ }
+
+ public Transaction createTransaction() {
+ return createTransaction(null, false);
+ }
+ public Transaction createTransaction(boolean readOnly) {
+ return createTransaction(null, readOnly);
+ }
+ public Transaction createTransaction(Transaction parent) {
+ return createTransaction(parent, false);
+ }
+
+ public Transaction createTransaction(Transaction parent, boolean readOnly) {
+ long txpointer [] = new long[1];
+ checkErrorCode(mdb_txn_begin(pointer(), parent==null ? 0 : parent.pointer(), readOnly ? MDB_RDONLY : 0, txpointer));
+ return new Transaction(this, txpointer[0]);
+ }
+
+ public Database openDatabase(Transaction tx, String name, int flags) {
+ checkArgNotNull(tx, "tx");
+ checkArgNotNull(name, "name");
+ long dbi[] = new long[1];
+ checkErrorCode(mdb_dbi_open(tx.pointer(), name, flags, dbi));
+ return new Database(this, dbi[0]);
+ }
+
+ public Database openDatabase(String name) {
+ checkArgNotNull(name, "name");
+ return openDatabase(name, Flags.CREATE);
+ }
+ public Database openDatabase(String name, int flags) {
+ checkArgNotNull(name, "name");
+ Transaction tx = createTransaction();
+ try {
+ return openDatabase(tx, name, flags);
+ } finally {
+ tx.commit();
+ }
+ }
+
+ public static void pushMemoryPool(int size) {
+ NativeBuffer.pushMemoryPool(size);
+ }
+
+ public static void popMemoryPool() {
+ NativeBuffer.popMemoryPool();
+ }
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Flags.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Flags.java
new file mode 100644
index 0000000..ba2bb76
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Flags.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import static org.fusesource.lmdbjni.JNI.*;
+
+/**
+ * @author Hiram Chirino
+ */
+public class Flags {
+
+ public static final int FIXEDMAP = MDB_FIXEDMAP ;
+ public static final int NOSUBDIR = MDB_NOSUBDIR ;
+ public static final int NOSYNC = MDB_NOSYNC ;
+ public static final int RDONLY = MDB_RDONLY ;
+ public static final int NOMETASYNC = MDB_NOMETASYNC ;
+ public static final int WRITEMAP = MDB_WRITEMAP ;
+ public static final int MAPASYNC = MDB_MAPASYNC ;
+ public static final int NOTLS = MDB_NOTLS ;
+
+ //====================================================//
+ // Database Flags
+ //====================================================//
+ public static final int REVERSEKEY = MDB_REVERSEKEY ;
+ public static final int DUPSORT = MDB_DUPSORT ;
+ public static final int INTEGERKEY = MDB_INTEGERKEY ;
+ public static final int DUPFIXED = MDB_DUPFIXED ;
+ public static final int INTEGERDUP = MDB_INTEGERDUP ;
+ public static final int REVERSEDUP = MDB_REVERSEDUP ;
+ public static final int CREATE = MDB_CREATE ;
+
+ //====================================================//
+ // Write Flags
+ //====================================================//
+ public static final int NOOVERWRITE = MDB_NOOVERWRITE ;
+ public static final int NODUPDATA = MDB_NODUPDATA ;
+ public static final int CURRENT = MDB_CURRENT ;
+ public static final int RESERVE = MDB_RESERVE ;
+ public static final int APPEND = MDB_APPEND ;
+ public static final int APPENDDUP = MDB_APPENDDUP ;
+ public static final int MULTIPLE = MDB_MULTIPLE ;
+
+ public static final CursorOp FIRST = CursorOp.FIRST ;
+ public static final CursorOp FIRST_DUP = CursorOp.FIRST_DUP ;
+ public static final CursorOp GET_BOTH = CursorOp.GET_BOTH ;
+ public static final CursorOp GET_BOTH_RANGE = CursorOp.GET_BOTH_RANGE ;
+ public static final CursorOp GET_CURRENT = CursorOp.GET_CURRENT ;
+ public static final CursorOp GET_MULTIPLE = CursorOp.GET_MULTIPLE ;
+ public static final CursorOp LAST = CursorOp.LAST ;
+ public static final CursorOp LAST_DUP = CursorOp.LAST_DUP ;
+ public static final CursorOp NEXT = CursorOp.NEXT ;
+ public static final CursorOp NEXT_DUP = CursorOp.NEXT_DUP ;
+ public static final CursorOp NEXT_MULTIPLE = CursorOp.NEXT_MULTIPLE ;
+ public static final CursorOp NEXT_NODUP = CursorOp.NEXT_NODUP ;
+ public static final CursorOp PREV = CursorOp.PREV ;
+ public static final CursorOp PREV_DUP = CursorOp.PREV_DUP ;
+ public static final CursorOp PREV_NODUP = CursorOp.PREV_NODUP ;
+ public static final CursorOp SET = CursorOp.SET ;
+ public static final CursorOp SET_KEY = CursorOp.SET_KEY ;
+ public static final CursorOp SET_RANGE = CursorOp.SET_RANGE ;
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/JNI.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/JNI.java
new file mode 100644
index 0000000..27c2e78
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/JNI.java
@@ -0,0 +1,639 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import org.fusesource.hawtjni.runtime.*;
+
+import static org.fusesource.hawtjni.runtime.ClassFlag.STRUCT;
+import static org.fusesource.hawtjni.runtime.ClassFlag.TYPEDEF;
+import static org.fusesource.hawtjni.runtime.FieldFlag.CONSTANT;
+import static org.fusesource.hawtjni.runtime.MethodFlag.CONSTANT_GETTER;
+import static org.fusesource.hawtjni.runtime.MethodFlag.CONSTANT_INITIALIZER;
+import static org.fusesource.hawtjni.runtime.ArgFlag.*;
+
+/**
+ * This class holds all the native constant, structure and function mappings.
+ *
+ * @author Hiram Chirino
+ */
+@JniClass
+class JNI {
+
+ public static final Library LIBRARY = new Library("lmdbjni", JNI.class);
+
+ static {
+ JNI.LIBRARY.load();
+ init();
+ }
+
+ @JniMethod(flags = {CONSTANT_INITIALIZER})
+ private static final native void init();
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // Posix APIs:
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ @JniMethod(flags={CONSTANT_GETTER})
+ public static final native int errno();
+
+ @JniMethod(cast="char *")
+ public static final native long strerror(int errnum);
+
+ public static final native int strlen(
+ @JniArg(cast="const char *")long s);
+
+ @JniMethod(cast="void *")
+ public static final native long malloc(
+ @JniArg(cast="size_t") long size);
+
+ public static final native void free(
+ @JniArg(cast="void *") long self);
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // Additional Helpers
+ //
+ ///////////////////////////////////////////////////////////////////////
+ public static final native void buffer_copy (
+ @JniArg(cast="const void *", flags={NO_OUT, CRITICAL}) byte[] src,
+ @JniArg(cast="size_t") long srcPos,
+ @JniArg(cast="void *") long dest,
+ @JniArg(cast="size_t") long destPos,
+ @JniArg(cast="size_t") long length);
+
+ public static final native void buffer_copy (
+ @JniArg(cast="const void *") long src,
+ @JniArg(cast="size_t") long srcPos,
+ @JniArg(cast="void *", flags={NO_IN, CRITICAL}) byte[] dest,
+ @JniArg(cast="size_t") long destPos,
+ @JniArg(cast="size_t") long length);
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // The lmdb API
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ //====================================================//
+ // Version Info
+ //====================================================//
+ @JniField(flags = {CONSTANT})
+ static public int MDB_VERSION_MAJOR;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_VERSION_MINOR;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_VERSION_PATCH;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_VERSION_FULL;
+
+ @JniField(cast = "const char *", flags = {CONSTANT})
+ static long MDB_VERSION_DATE;
+ @JniField(cast = "const char *", flags = {CONSTANT})
+ static long MDB_VERSION_STRING;
+
+ //====================================================//
+ // Environment Flags
+ //====================================================//
+ @JniField(flags = {CONSTANT})
+ static public int MDB_FIXEDMAP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NOSUBDIR;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NOSYNC;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_RDONLY;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NOMETASYNC;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_WRITEMAP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_MAPASYNC;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NOTLS;
+
+ //====================================================//
+ // Database Flags
+ //====================================================//
+ @JniField(flags = {CONSTANT})
+ static public int MDB_REVERSEKEY;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_DUPSORT;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_INTEGERKEY;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_DUPFIXED;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_INTEGERDUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_REVERSEDUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_CREATE;
+
+ //====================================================//
+ // Write Flags
+ //====================================================//
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NOOVERWRITE;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NODUPDATA;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_CURRENT;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_RESERVE;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_APPEND;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_APPENDDUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_MULTIPLE;
+
+ //====================================================//
+ // enum MDB_cursor_op:
+ //====================================================//
+ @JniField(flags = {CONSTANT})
+ static public int MDB_FIRST;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_FIRST_DUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_GET_BOTH;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_GET_BOTH_RANGE;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_GET_CURRENT;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_GET_MULTIPLE;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_LAST;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_LAST_DUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NEXT;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NEXT_DUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NEXT_MULTIPLE;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NEXT_NODUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_PREV;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_PREV_DUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_PREV_NODUP;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_SET;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_SET_KEY;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_SET_RANGE;
+
+ //====================================================//
+ // Return Codes
+ //====================================================//
+ @JniField(flags = {CONSTANT})
+ static public int MDB_SUCCESS;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_KEYEXIST;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_NOTFOUND;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_PAGE_NOTFOUND;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_CORRUPTED;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_PANIC;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_VERSION_MISMATCH;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_INVALID;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_MAP_FULL;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_DBS_FULL;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_READERS_FULL;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_TLS_FULL;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_TXN_FULL;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_CURSOR_FULL;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_PAGE_FULL;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_MAP_RESIZED;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_INCOMPATIBLE;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_BAD_RSLOT;
+ @JniField(flags = {CONSTANT})
+ static public int MDB_LAST_ERRCODE;
+
+ /**
+ * details
+ */
+ @JniClass(flags = {STRUCT, TYPEDEF})
+ static public class MDB_envinfo {
+ @JniField(cast = "void *")
+ public long me_mapaddr;
+ @JniField(cast = "size_t")
+ public long me_mapsize;
+ @JniField(cast = "size_t")
+ public long me_last_pgno;
+ @JniField(cast = "size_t")
+ public long me_last_txnid;
+ @JniField(cast = "unsigned int")
+ public long me_maxreaders;
+ @JniField(cast = "unsigned int")
+ public long me_numreaders;
+ }
+
+ /**
+ * details
+ */
+ @JniClass(flags = {STRUCT, TYPEDEF})
+ public static class MDB_stat {
+ @JniField(cast = "unsigned int")
+ public long ms_psize;
+ @JniField(cast = "unsigned int")
+ public long ms_depth;
+ @JniField(cast = "size_t")
+ public long ms_branch_pages;
+ @JniField(cast = "size_t")
+ public long ms_leaf_pages;
+ @JniField(cast = "size_t")
+ public long ms_overflow_pages;
+ @JniField(cast = "size_t")
+ public long ms_entries;
+ }
+
+ /**
+ * details
+ */
+ @JniClass(flags = {STRUCT, TYPEDEF})
+ public static class MDB_val {
+ @JniField(cast = "size_t")
+ public long mv_size;
+ @JniField(cast = "void *")
+ public long mv_data;
+ }
+
+ /**
+ * details
+ */
+ @JniMethod(cast="char *")
+ public static final native long mdb_strerror(int err);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_create(
+ @JniArg(cast = "MDB_env **", flags={NO_IN}) long[] env);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_open(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "const char *") String path,
+ @JniArg(cast = "unsigned int") int flags,
+ @JniArg(cast = "mdb_mode_t") int mode
+ );
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_copy(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "const char *") String path);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_stat(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "MDB_stat *", flags = {NO_IN}) MDB_stat stat);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_info(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = " MDB_envinfo *", flags = {NO_IN}) MDB_envinfo stat);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_sync(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "int") int force);
+
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native void mdb_env_close(
+ @JniArg(cast = "MDB_env *") long env);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_set_flags(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "unsigned int") int flags,
+ @JniArg(cast = "int") int onoff);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_get_flags(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "unsigned int *") long[] flags);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_get_path(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "const char **", flags={NO_IN}) long[] path);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_set_mapsize(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "size_t") long size);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_set_maxreaders(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "unsigned int") long readers);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_get_maxreaders(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "unsigned int *") long[] readers);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_env_set_maxdbs(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "unsigned int") long dbs);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_txn_begin(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "MDB_txn *") long parent,
+ @JniArg(cast = "unsigned int") long flags,
+ @JniArg(cast = "MDB_txn **", flags={NO_IN}) long[] txn);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_txn_commit(
+ @JniArg(cast = "MDB_txn *") long txn);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native void mdb_txn_abort(
+ @JniArg(cast = "MDB_txn *") long txn);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native void mdb_txn_reset(
+ @JniArg(cast = "MDB_txn *") long txn);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_txn_renew(
+ @JniArg(cast = "MDB_txn *") long txn);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_dbi_open(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "const char *") String name,
+ @JniArg(cast = "unsigned int") long flags,
+ @JniArg(cast = "unsigned int *") long[] dbi);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_stat(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int ") long dbi,
+ @JniArg(cast = "MDB_stat *", flags = {NO_IN}) MDB_stat stat);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native void mdb_dbi_close(
+ @JniArg(cast = "MDB_env *") long env,
+ @JniArg(cast = "unsigned int ") long dbi);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_drop(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int ") long dbi,
+ int del);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_set_compare(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int ") long dbi,
+ @JniArg(cast = "MDB_cmp_func *") long cmp);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_set_dupsort(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int ") long dbi,
+ @JniArg(cast = "MDB_cmp_func *") long cmp);
+
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_get(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int ") long dbi,
+ @JniArg(cast = "MDB_val *", flags={NO_OUT}) MDB_val key,
+ @JniArg(cast = "MDB_val *", flags={NO_IN}) MDB_val data);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_put(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int ") long dbi,
+ @JniArg(cast = "MDB_val *", flags={NO_OUT}) MDB_val key,
+ @JniArg(cast = "MDB_val *") MDB_val data,
+ @JniArg(cast = "unsigned int") int flags);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_del(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int ") long dbi,
+ @JniArg(cast = "MDB_val *", flags={NO_OUT}) MDB_val key,
+ @JniArg(cast = "MDB_val *", flags={NO_OUT}) MDB_val data);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_cursor_open(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int") long dbi,
+ @JniArg(cast = "MDB_cursor **", flags={NO_IN}) long[] cursor);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native void mdb_cursor_close(
+ @JniArg(cast = "MDB_cursor *") long cursor);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_cursor_renew(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "MDB_cursor *") long cursor);
+
+ /**
+ * details
+ */
+ @JniMethod(cast = "MDB_txn *")
+ public static final native long mdb_cursor_txn(
+ @JniArg(cast = "MDB_cursor *") long cursor);
+
+ /**
+ * details
+ */
+ @JniMethod(cast = "unsigned int")
+ public static final native long mdb_cursor_dbi(
+ @JniArg(cast = "MDB_cursor *") long cursor);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_cursor_get(
+ @JniArg(cast = "MDB_cursor *") long cursor,
+ @JniArg(cast = "MDB_val *") MDB_val key,
+ @JniArg(cast = "MDB_val *") MDB_val data,
+ @JniArg(cast = "MDB_cursor_op") int op);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_cursor_put(
+ @JniArg(cast = "MDB_cursor *") long cursor,
+ @JniArg(cast = "MDB_val *", flags = {NO_OUT}) MDB_val key,
+ @JniArg(cast = "MDB_val *", flags = {NO_OUT}) MDB_val data,
+ @JniArg(cast = "unsigned int ") int flags);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_cursor_del(
+ @JniArg(cast = "MDB_cursor *") long cursor,
+ @JniArg(cast = "unsigned int ") int flags);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_cursor_count(
+ @JniArg(cast = "MDB_cursor *") long cursor,
+ @JniArg(cast = "size_t *") long[] countp);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_cmp(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int") long dbi,
+ @JniArg(cast = "MDB_val *", flags = {NO_OUT}) MDB_val a,
+ @JniArg(cast = "MDB_val *", flags = {NO_OUT}) MDB_val b);
+
+ /**
+ * details
+ */
+ @JniMethod
+ public static final native int mdb_dcmp(
+ @JniArg(cast = "MDB_txn *") long txn,
+ @JniArg(cast = "unsigned int") long dbi,
+ @JniArg(cast = "MDB_val *", flags = {NO_OUT}) MDB_val a,
+ @JniArg(cast = "MDB_val *", flags = {NO_OUT}) MDB_val b);
+
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/LMDBException.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/LMDBException.java
new file mode 100644
index 0000000..9c6b369
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/LMDBException.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+/**
+ * @author Hiram Chirino
+ */
+public class LMDBException extends RuntimeException {
+
+ int errorCode;
+
+ public LMDBException() {
+ }
+
+ public LMDBException(String message) {
+ super(message);
+ }
+
+ public LMDBException(String message, int errorCode) {
+ super(message);
+ this.errorCode = errorCode;
+ }
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeBuffer.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeBuffer.java
new file mode 100644
index 0000000..be8e928
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeBuffer.java
@@ -0,0 +1,230 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import org.fusesource.hawtjni.runtime.PointerMath;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A NativeBuffer allocates a native buffer on the heap. It supports
+ * creating sub slices/views of that buffer and manages reference tracking
+ * so that the the native buffer is freed once all NativeBuffer views
+ * are deleted.
+ *
+ * @author Hiram Chirino
+ */
+class NativeBuffer extends NativeObject {
+
+ private static class Allocation extends NativeObject {
+ private final AtomicInteger retained = new AtomicInteger(0);
+
+ private Allocation(long size) {
+ super(JNI.malloc(size));
+ }
+
+ void retain() {
+ checkAllocated();
+ retained.incrementAndGet();
+ }
+
+ void release() {
+ checkAllocated();
+ int r = retained.decrementAndGet();
+ if( r < 0 ) {
+ throw new Error("The object has already been deleted.");
+ } else if( r==0 ) {
+ JNI.free(self);
+ self = 0;
+ }
+ }
+ }
+
+ private static class Pool {
+ private final NativeBuffer.Pool prev;
+ Allocation allocation;
+ long pos;
+ long remaining;
+ int chunk;
+
+ public Pool(int chunk, Pool prev) {
+ this.chunk = chunk;
+ this.prev = prev;
+ }
+
+ NativeBuffer create(long size) {
+ if( size >= chunk ) {
+ Allocation allocation = new Allocation(size);
+ return new NativeBuffer(allocation, allocation.self, size);
+ }
+
+ if( remaining < size ) {
+ delete();
+ }
+
+ if( allocation == null ) {
+ allocate();
+ }
+
+ NativeBuffer rc = new NativeBuffer(allocation, pos, size);
+ pos = PointerMath.add(pos, size);
+ remaining -= size;
+ return rc;
+ }
+
+ private void allocate() {
+ allocation = new NativeBuffer.Allocation(chunk);
+ allocation.retain();
+ remaining = chunk;
+ pos = allocation.self;
+ }
+
+ public void delete() {
+ if( allocation!=null ) {
+ allocation.release();
+ allocation = null;
+ }
+ }
+ }
+
+ private final Allocation allocation;
+ private final long capacity;
+
+ static final private ThreadLocal CURRENT_POOL = new ThreadLocal();
+
+ static public NativeBuffer create(long capacity) {
+ Pool pool = CURRENT_POOL.get();
+ if( pool == null ) {
+ Allocation allocation = new Allocation(capacity);
+ return new NativeBuffer(allocation, allocation.self, capacity);
+ } else {
+ return pool.create(capacity);
+ }
+ }
+
+
+ public static void pushMemoryPool(int size) {
+ Pool original = CURRENT_POOL.get();
+ Pool next = new Pool(size, original);
+ CURRENT_POOL.set(next);
+ }
+
+ public static void popMemoryPool() {
+ Pool next = CURRENT_POOL.get();
+ next.delete();
+ if( next.prev == null ) {
+ CURRENT_POOL.remove();
+ } else {
+ CURRENT_POOL.set(next.prev);
+ }
+ }
+
+ static public NativeBuffer create(byte[] data) {
+ if( data == null ) {
+ return null;
+ } else {
+ return create(data, 0 , data.length);
+ }
+ }
+
+ static public NativeBuffer create(String data) {
+ return create(cbytes(data));
+ }
+
+ static public NativeBuffer create(byte[] data, int offset, int length) {
+ NativeBuffer rc = create(length);
+ rc.write(0, data, offset, length);
+ return rc;
+ }
+
+ static public NativeBuffer create(long pointer, int length) {
+ return new NativeBuffer(null, pointer, length);
+ }
+
+ private NativeBuffer(Allocation allocation, long self, long capacity) {
+ super(self);
+ this.capacity = capacity;
+ this.allocation = allocation;
+ if( allocation!=null ) {
+ allocation.retain();
+ }
+ }
+
+ public NativeBuffer slice(long offset, long length) {
+ checkAllocated();
+ if( length < 0 ) throw new IllegalArgumentException("length cannot be negative");
+ if( offset < 0 ) throw new IllegalArgumentException("offset cannot be negative");
+ if( offset+length >= capacity) throw new ArrayIndexOutOfBoundsException("offset + length exceed the length of this buffer");
+ return new NativeBuffer(allocation, PointerMath.add(self, offset), length);
+ }
+
+ static byte[] cbytes(String strvalue) {
+ byte[] value = strvalue.getBytes();
+ // expand by 1 so we get a null at the end.
+ byte[] rc = new byte[value.length+1];
+ System.arraycopy(value, 0, rc, 0, value.length);
+ return rc;
+ }
+
+ public NativeBuffer head(long length) {
+ return slice(0, length);
+ }
+
+ public NativeBuffer tail(long length) {
+ if( capacity-length < 0) throw new ArrayIndexOutOfBoundsException("capacity-length cannot be less than zero");
+ return slice(capacity-length, length);
+ }
+
+ public void delete() {
+ allocation.release();
+ }
+
+ public long capacity() {
+ return capacity;
+ }
+
+ public void write(long at, byte []source, int offset, int length) {
+ checkAllocated();
+ if( length < 0 ) throw new IllegalArgumentException("length cannot be negative");
+ if( offset < 0 ) throw new IllegalArgumentException("offset cannot be negative");
+ if( at < 0 ) throw new IllegalArgumentException("at cannot be negative");
+ if( at+length > capacity ) throw new ArrayIndexOutOfBoundsException("at + length exceeds the capacity of this object");
+ if( offset+length > source.length) throw new ArrayIndexOutOfBoundsException("offset + length exceed the length of the source buffer");
+ JNI.buffer_copy(source, offset, self, at, length);
+ }
+
+ public void read(long at, byte []target, int offset, int length) {
+ checkAllocated();
+ if( length < 0 ) throw new IllegalArgumentException("length cannot be negative");
+ if( offset < 0 ) throw new IllegalArgumentException("offset cannot be negative");
+ if( at < 0 ) throw new IllegalArgumentException("at cannot be negative");
+ if( at+length > capacity ) throw new ArrayIndexOutOfBoundsException("at + length exceeds the capacity of this object");
+ if( offset+length > target.length) throw new ArrayIndexOutOfBoundsException("offset + length exceed the length of the target buffer");
+ JNI.buffer_copy(self, at, target, offset, length);
+ }
+
+ public byte[] toByteArray() {
+ if( capacity > Integer.MAX_VALUE ) {
+ throw new OutOfMemoryError("Native buffer larger than the largest allowed Java byte[]");
+ }
+ byte [] rc = new byte[(int) capacity];
+ read(0, rc, 0, rc.length);
+ return rc;
+ }
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeObject.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeObject.java
new file mode 100644
index 0000000..16e4ca4
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeObject.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import org.fusesource.lmdbjni.LMDBException;
+
+/**
+ * A helper base class which is used to track a pointer to a native
+ * structure or class.
+ *
+ * @author Hiram Chirino
+ */
+class NativeObject {
+
+ protected long self;
+
+ protected NativeObject(long self) {
+ this.self = self;
+ if( self ==0 ) {
+ throw new OutOfMemoryError("Failure allocating native heap memory");
+ }
+ }
+
+ long pointer() {
+ checkAllocated();
+ return self;
+ }
+
+ public boolean isAllocated() {
+ return self !=0;
+ }
+
+ protected void checkAllocated() {
+ if( !isAllocated() ) {
+ throw new LMDBException("Native object has been freed.");
+ }
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Transaction.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Transaction.java
new file mode 100644
index 0000000..cd508ad
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Transaction.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import static org.fusesource.lmdbjni.JNI.*;
+import static org.fusesource.lmdbjni.Util.checkErrorCode;
+
+/**
+ * @author Hiram Chirino
+ */
+public class Transaction extends NativeObject {
+
+ private final Env env;
+
+ Transaction(Env env, long self) {
+ super(self);
+ this.env = env;
+ }
+
+ public void renew() {
+ checkErrorCode(mdb_txn_renew(pointer()));
+ }
+
+ public void commit() {
+ if( self != 0 ) {
+ checkErrorCode(mdb_txn_commit(self));
+ self = 0;
+ }
+ }
+
+ public void reset() {
+ checkAllocated();
+ mdb_txn_reset(pointer());
+ }
+
+ public void abort() {
+ if( self != 0 ) {
+ mdb_txn_abort(self);
+ self = 0;
+ }
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Util.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Util.java
new file mode 100644
index 0000000..eae8355
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Util.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+import static org.fusesource.lmdbjni.JNI.mdb_strerror;
+import static org.fusesource.lmdbjni.JNI.strlen;
+
+/**
+ * Some miscellaneous utility functions.
+ *
+ * @author Hiram Chirino
+ */
+class Util {
+
+ public static int errno() {
+ return errno();
+ }
+
+ public static String strerror() {
+ return string(JNI.strerror(errno()));
+ }
+
+ public static String string(long ptr) {
+ if( ptr == 0 )
+ return null;
+ return new String(NativeBuffer.create(ptr, strlen(ptr)).toByteArray());
+ }
+
+ public static void checkErrorCode(int rc) {
+ if( rc != 0 ) {
+ String msg = string(mdb_strerror(rc));
+ throw new LMDBException(msg, rc);
+ }
+ }
+
+ public static void checkArgNotNull(Object value, String name) {
+ if(value==null) {
+ throw new IllegalArgumentException("The "+name+" argument cannot be null");
+ }
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/Value.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Value.java
new file mode 100644
index 0000000..36ca2a5
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/Value.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni;
+
+/**
+ * @author Hiram Chirino
+ */
+class Value extends JNI.MDB_val {
+
+ public Value() {
+ }
+
+ public Value(long data, long length) {
+ this.mv_data = data;
+ this.mv_size = length;
+ }
+
+ public Value(NativeBuffer buffer) {
+ this(buffer.pointer(), buffer.capacity());
+ }
+
+ public static Value create(NativeBuffer buffer) {
+ if(buffer == null ) {
+ return null;
+ } else {
+ return new Value(buffer);
+ }
+ }
+
+ public byte[] toByteArray() {
+ if( mv_data == 0 ) {
+ return null;
+ }
+ if( mv_size > Integer.MAX_VALUE ) {
+ throw new ArrayIndexOutOfBoundsException("Native slice is larger than the maximum Java array");
+ }
+ byte []rc = new byte[(int) mv_size];
+ JNI.buffer_copy(mv_data, 0, rc, 0, rc.length);
+ return rc;
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDB.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDB.java
new file mode 100644
index 0000000..1041dbe
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDB.java
@@ -0,0 +1,375 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni.leveldb;
+
+import org.fusesource.lmdbjni.*;
+import org.iq80.leveldb.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Implements the LevelDB API using LMDB.
+ */
+public class LMDB implements DB {
+
+ final Env env;
+ final Database db;
+ final AtomicBoolean closed = new AtomicBoolean(false);
+
+ public LMDB(File path, Options options) throws IOException {
+ try {
+ env = new Env();
+ env.setMapSize(1024*1024*1024*1024);
+ if (options instanceof LMDBOptions) {
+ LMDBOptions o = ((LMDBOptions) options);
+ env.setMaxReaders(o.maxReaders());
+ env.setMapSize(o.mapSize());
+ env.addFlags(o.openFlags);
+ }
+ env.open(path.getCanonicalPath());
+ db = env.openDatabase("x");
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public void close() throws IOException {
+ try {
+ if (closed.compareAndSet(false, true)) {
+ db.close();
+ env.close();
+ }
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public byte[] get(byte[] key) throws DBException {
+ try {
+ return db.get(key);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public byte[] get(byte[] key, ReadOptions readOptions) throws DBException {
+ try {
+ if (readOptions.snapshot() == null) {
+ return db.get(key);
+ } else {
+ Transaction tx = ((LMDBSnapshot) readOptions.snapshot()).tx;
+ return db.get(tx, key);
+ }
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public DBIterator iterator() {
+ try {
+ Transaction tx = env.createTransaction(true);
+ return new LMDBIterator(tx, db.openCursor(tx));
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public DBIterator iterator(ReadOptions readOptions) {
+ try {
+ if (readOptions.snapshot() == null) {
+ return iterator();
+ } else {
+ Transaction tx = ((LMDBSnapshot) readOptions.snapshot()).tx;
+ return new LMDBIterator(null, db.openCursor(tx));
+ }
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+
+ public void put(byte[] bytes, byte[] value) throws DBException {
+ try {
+ db.put(bytes, value);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public Snapshot put(byte[] key, byte[] value, WriteOptions writeOptions) throws DBException {
+ try {
+ put(key, value);
+ return processWriteOptions(writeOptions);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ private Snapshot processWriteOptions(WriteOptions writeOptions) {
+ if (writeOptions.sync()) {
+ env.sync(true);
+ }
+ if (writeOptions.snapshot()) {
+ return getSnapshot();
+ } else {
+ return null;
+ }
+ }
+
+ public void delete(byte[] key) throws DBException {
+ try {
+ db.delete(key);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public Snapshot delete(byte[] key, WriteOptions writeOptions) throws DBException {
+ try {
+ delete(key);
+ return processWriteOptions(writeOptions);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ class LMDBSnapshot implements Snapshot {
+ private final Transaction tx;
+
+ public LMDBSnapshot(Transaction tx) {
+ this.tx = tx;
+ }
+
+ public void close() throws IOException {
+ try {
+ tx.commit();
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+ }
+
+ public Snapshot getSnapshot() {
+ try {
+ return new LMDBSnapshot(env.createTransaction(true));
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+
+ static class LMDBWriteBatch implements WriteBatch {
+
+ static abstract class Op {
+ abstract public void apply(Database db, Transaction tx);
+ }
+
+ static class PutOp extends Op {
+ private final byte[] key;
+ private final byte[] value;
+
+ public PutOp(byte[] key, byte[] value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public void apply(Database db, Transaction tx) {
+ db.put(tx, key, value);
+ }
+ }
+
+ static class DeleteOp extends Op {
+ private final byte[] key;
+
+ public DeleteOp(byte[] key) {
+ this.key = key;
+ }
+
+ public void apply(Database db, Transaction tx) {
+ db.delete(tx, key);
+ }
+ }
+
+ private ArrayList ops = new ArrayList();
+
+ public void apply(Database db, Transaction tx) {
+ for (Op op : ops) {
+ op.apply(db, tx);
+ }
+ }
+
+ public void close() throws IOException {
+ ops = null;
+ }
+
+ public WriteBatch put(byte[] key, byte[] value) {
+ ops.add(new PutOp(key, value));
+ return this;
+ }
+
+ public WriteBatch delete(byte[] key) {
+ ops.add(new DeleteOp(key));
+ return this;
+ }
+ }
+
+ public WriteBatch createWriteBatch() {
+ return new LMDBWriteBatch();
+ }
+
+ public void write(WriteBatch writeBatch) throws DBException {
+ try {
+ Transaction tx = env.createTransaction(false);
+ try {
+ ((LMDBWriteBatch) writeBatch).apply(db, tx);
+ } finally {
+ tx.commit();
+ }
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public Snapshot write(WriteBatch writeBatch, WriteOptions writeOptions) throws DBException {
+ try {
+ write(writeBatch);
+ return processWriteOptions(writeOptions);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ static class LMDBIterator implements DBIterator {
+
+ private final Transaction tx;
+ private final Cursor cursor;
+ Entry next;
+ Entry prev;
+
+ public LMDBIterator(Transaction tx, Cursor cursor) {
+ this.tx = tx;
+ this.cursor = cursor;
+ }
+
+ public void close() throws IOException {
+ cursor.close();
+ if (tx != null) {
+ tx.commit();
+ }
+ }
+
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ public boolean hasPrev() {
+ return prev != null;
+ }
+
+ public Map.Entry peekNext() {
+ return next;
+ }
+
+ public Map.Entry peekPrev() {
+ return prev;
+ }
+
+ public void seekToFirst() {
+ try {
+ prev = null;
+ next = cursor.get(CursorOp.FIRST);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public void seekToLast() {
+ try {
+ next = null;
+ prev = cursor.get(CursorOp.LAST);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public void seek(byte[] bytes) {
+ try {
+ next = cursor.seek(bytes, CursorOp.SET_RANGE);
+ prev = cursor.seek(bytes, CursorOp.PREV);
+ cursor.seek(bytes, CursorOp.NEXT);
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public Map.Entry prev() {
+ if (!hasPrev()) {
+ throw new NoSuchElementException();
+ }
+ try {
+ Entry rc = prev;
+ next = prev;
+ prev = cursor.get(CursorOp.PREV);
+ return rc;
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+
+ }
+
+ public Map.Entry next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ try {
+ Entry rc = next;
+ prev = next;
+ next = cursor.get(CursorOp.NEXT);
+ return rc;
+ } catch (LMDBException e) {
+ throw new DBException(e.getMessage(), e);
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public long[] getApproximateSizes(Range... ranges) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getProperty(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void suspendCompactions() throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void resumeCompactions() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBFactory.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBFactory.java
new file mode 100644
index 0000000..1a25584
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBFactory.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni.leveldb;
+
+import org.fusesource.lmdbjni.Env;
+import org.iq80.leveldb.DB;
+import org.iq80.leveldb.DBFactory;
+import org.iq80.leveldb.Options;
+
+import java.io.*;
+
+/**
+ * Factory class for the LevelDB API.
+ *
+ * @author Hiram Chirino
+ */
+public class LMDBFactory implements DBFactory {
+
+ public static final LMDBFactory factory = new LMDBFactory();
+
+ private static final String LIBLMDB_VERSION;
+ static {
+ LIBLMDB_VERSION = Env.version();
+ }
+
+ public static final String VERSION;
+ static {
+ String v="unknown";
+ InputStream is = Env.class.getResourceAsStream("version.txt");
+ try {
+ v = new BufferedReader(new InputStreamReader(is, "UTF-8")).readLine();
+ } catch (Throwable e) {
+ } finally {
+ try {
+ is.close();
+ } catch (Throwable e) {
+ }
+ }
+ VERSION = v;
+ }
+
+ public static byte[] bytes(String value) {
+ if( value == null) {
+ return null;
+ }
+ try {
+ return value.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String asString(byte value[]) {
+ if( value == null) {
+ return null;
+ }
+ try {
+ return new String(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ public DB open(File path, Options options) throws IOException {
+ checkArgNotNull(path, "path");
+ checkArgNotNull(options, "options");
+ File datafile = new File(path, "data.mdb");
+ if(options.errorIfExists() && datafile.exists() ) {
+ throw new IOException("Database already exists.");
+ }
+ if(!options.createIfMissing() && !datafile.exists() ) {
+ throw new IOException("Database does not exist.");
+ }
+ return new LMDB(path, options);
+ }
+
+ public void destroy(File path, Options options) throws IOException {
+ File datafile = new File(path, "data.mdb");
+ datafile.delete();
+ File lockfile = new File(path, "lock.mdb");
+ lockfile.delete();
+ }
+
+ public void repair(File path, Options options) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("lmdbjni version %s", VERSION);
+ }
+
+ public static void pushMemoryPool(int size) {
+ Env.pushMemoryPool(size);
+ }
+
+ public static void popMemoryPool() {
+ Env.popMemoryPool();
+ }
+
+ public static void checkArgNotNull(Object value, String name) {
+ if(value==null) {
+ throw new IllegalArgumentException("The "+name+" argument cannot be null");
+ }
+ }
+
+}
diff --git a/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBOptions.java b/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBOptions.java
new file mode 100644
index 0000000..fda5cd3
--- /dev/null
+++ b/lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBOptions.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni.leveldb;
+
+import org.iq80.leveldb.Options;
+
+/**
+ * Additional options which you can use with the LMDB based databases.
+ *
+ * @author Hiram Chirino
+ */
+public class LMDBOptions extends Options {
+ long maxReaders;
+ long mapSize;
+ int openFlags;
+
+ public long mapSize() {
+ return mapSize;
+ }
+
+ public LMDBOptions mapSize(long mapSize) {
+ this.mapSize = mapSize;
+ return this;
+ }
+
+ public long maxReaders() {
+ return maxReaders;
+ }
+
+ public LMDBOptions maxReaders(long maxReaders) {
+ this.maxReaders = maxReaders;
+ return this;
+ }
+
+ public int openFlags() {
+ return openFlags;
+ }
+
+ public LMDBOptions openFlags(int openFlags) {
+ this.openFlags = openFlags;
+ return this;
+ }
+}
diff --git a/lmdbjni/src/main/native-package/license.txt b/lmdbjni/src/main/native-package/license.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/lmdbjni/src/main/native-package/license.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lmdbjni/src/main/native-package/m4/custom.m4 b/lmdbjni/src/main/native-package/m4/custom.m4
new file mode 100644
index 0000000..e8c3223
--- /dev/null
+++ b/lmdbjni/src/main/native-package/m4/custom.m4
@@ -0,0 +1,36 @@
+dnl ---------------------------------------------------------------------------
+dnl Copyright (C) 2013, RedHat, Inc.
+dnl
+dnl http://www.redhat.com/
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([CUSTOM_M4_SETUP],
+[
+ AC_CHECK_HEADER([pthread.h],[AC_DEFINE([HAVE_PTHREAD_H], [1], [Define to 1 if you have the header file.])])
+
+ AC_ARG_WITH([lmdb],
+ [AS_HELP_STRING([--with-lmdb@<:@=PATH@:>@], [Directory where lmdb was built. Example: --with-lmdb=/opt/lmdb])],
+ [
+ CFLAGS="$CFLAGS -I${withval}"
+ CXXFLAGS="$CXXFLAGS -I${withval}"
+ AC_SUBST(CXXFLAGS)
+ LDFLAGS="$LDFLAGS -llmdb -L${withval}"
+ AC_SUBST(LDFLAGS)
+ ]
+ )
+
+ AC_CHECK_HEADER([lmdb.h],,AC_MSG_ERROR([cannot find headers for lmdb]))
+ AC_CHECK_HEADER([sys/errno.h],[AC_DEFINE([HAVE_SYS_ERRNO_H], [1], [Define to 1 if you have the header file.])])
+])
\ No newline at end of file
diff --git a/lmdbjni/src/main/native-package/src/buffer.c b/lmdbjni/src/main/native-package/src/buffer.c
new file mode 100644
index 0000000..594a669
--- /dev/null
+++ b/lmdbjni/src/main/native-package/src/buffer.c
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "lmdbjni.h"
+
+void buffer_copy(const void *source, size_t source_pos, void *dest, size_t dest_pos, size_t length) {
+ memmove(((char *)dest)+dest_pos, ((const char *)source)+source_pos, length);
+}
diff --git a/lmdbjni/src/main/native-package/src/lmdbjni.h b/lmdbjni/src/main/native-package/src/lmdbjni.h
new file mode 100755
index 0000000..543aa26
--- /dev/null
+++ b/lmdbjni/src/main/native-package/src/lmdbjni.h
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LMDBJNI_H
+#define LMDBJNI_H
+
+#ifdef HAVE_CONFIG_H
+ /* configure based build.. we will use what it discovered about the platform */
+ #include "config.h"
+#endif
+#if defined(_WIN32) || defined(_WIN64)
+ /* Windows based build */
+ #define _WIN32_WINNT 0x0501
+ #include
+#endif
+#if !defined(HAVE_CONFIG_H) && (defined(_WIN32) || defined(_WIN64))
+ #define HAVE_STDLIB_H 1
+ #define HAVE_STRINGS_H 1
+#endif
+
+#ifdef HAVE_UNISTD_H
+ #include
+#endif
+
+#ifdef HAVE_STDLIB_H
+ #include
+#endif
+
+#ifdef HAVE_STRINGS_H
+ #include
+#endif
+
+#ifdef HAVE_SYS_ERRNO_H
+ #include
+#endif
+
+#include "hawtjni.h"
+#include
+#include
+#include "lmdb.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void buffer_copy(const void *source, size_t source_pos, void *dest, size_t dest_pos, size_t length);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif /* LMDBJNI_H */
diff --git a/lmdbjni/src/main/resources/org/fusesource/lmdbjni/version.txt b/lmdbjni/src/main/resources/org/fusesource/lmdbjni/version.txt
new file mode 100644
index 0000000..f2ab45c
--- /dev/null
+++ b/lmdbjni/src/main/resources/org/fusesource/lmdbjni/version.txt
@@ -0,0 +1 @@
+${project.version}
\ No newline at end of file
diff --git a/lmdbjni/src/test/java/org/fusesource/lmdbjni/test/EnvTest.java b/lmdbjni/src/test/java/org/fusesource/lmdbjni/test/EnvTest.java
new file mode 100644
index 0000000..4eab150
--- /dev/null
+++ b/lmdbjni/src/test/java/org/fusesource/lmdbjni/test/EnvTest.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni.test;
+
+import junit.framework.TestCase;
+import org.fusesource.lmdbjni.Database;
+import org.fusesource.lmdbjni.Env;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import static org.fusesource.lmdbjni.leveldb.LMDBFactory.bytes;
+
+/**
+ * Unit tests for the LMDB API.
+ *
+ * @author Hiram Chirino
+ */
+public class EnvTest extends TestCase {
+
+ static public void assertEquals(byte[] arg1, byte[] arg2) {
+ assertTrue(Arrays.equals(arg1, arg2));
+ }
+
+ static File getTestDirectory(String name) throws IOException {
+ File rc = new File(new File("test-data"), name);
+ rc.mkdirs();
+ return rc;
+ }
+
+ @Test
+ public void testCRUD() throws IOException {
+
+ String path = getTestDirectory(getName()).getCanonicalPath();
+ Env env = new Env();
+ env.open(path);
+ Database db = env.openDatabase("foo");
+
+ db.put(bytes("Tampa"), bytes("green"));
+ db.put(bytes("London"), bytes("red"));
+ db.put(bytes("New York"), bytes("blue"));
+
+ assertEquals(db.get(bytes("Tampa")), bytes("green"));
+ assertEquals(db.get(bytes("London")), bytes("red"));
+ assertEquals(db.get(bytes("New York")), bytes("blue"));
+
+ assertTrue(db.delete(bytes("New York")));
+ assertNull(db.get(bytes("New York")));
+
+ // We should not be able to delete it again.
+ assertFalse(db.delete(bytes("New York")));
+
+ db.close();
+ env.close();
+ }
+
+
+}
diff --git a/lmdbjni/src/test/java/org/fusesource/lmdbjni/test/LevelDBTest.java b/lmdbjni/src/test/java/org/fusesource/lmdbjni/test/LevelDBTest.java
new file mode 100644
index 0000000..a563621
--- /dev/null
+++ b/lmdbjni/src/test/java/org/fusesource/lmdbjni/test/LevelDBTest.java
@@ -0,0 +1,292 @@
+/**
+ * Copyright (C) 2013, RedHat, Inc.
+ *
+ * http://www.redhat.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fusesource.lmdbjni.test;
+
+import junit.framework.TestCase;
+import org.fusesource.lmdbjni.Database;
+import org.fusesource.lmdbjni.Env;
+import org.fusesource.lmdbjni.leveldb.LMDBFactory;
+import org.iq80.leveldb.DB;
+import org.iq80.leveldb.DBException;
+import org.iq80.leveldb.DBFactory;
+import org.iq80.leveldb.Options;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.iq80.leveldb.*;
+
+import java.nio.ByteBuffer;
+import java.util.*;
+
+
+import static org.fusesource.lmdbjni.leveldb.LMDBFactory.*;
+
+/**
+ * A Unit test for the LevelDB API interface to LMDB.
+ *
+ * @author Hiram Chirino
+ */
+public class LevelDBTest extends TestCase {
+
+
+ DBFactory factory = LMDBFactory.factory;
+
+ static public void assertEquals(byte[] arg1, byte[] arg2) {
+ assertTrue(Arrays.equals(arg1, arg2));
+ }
+
+ static File getTestDirectory(String name) throws IOException {
+ File rc = new File(new File("test-data"), name);
+ rc.mkdirs();
+ return rc;
+ }
+
+ @Test
+ public void testCRUDx() throws IOException {
+
+ String path = getTestDirectory(getName()).getCanonicalPath();
+ Env env = new Env();
+ env.open(path);
+ Database db = env.openDatabase("foo");
+
+ db.put(bytes("Tampa"), bytes("green"));
+ db.put(bytes("London"), bytes("red"));
+ db.put(bytes("New York"), bytes("blue"));
+
+ assertEquals(db.get(bytes("Tampa")), bytes("green"));
+ assertEquals(db.get(bytes("London")), bytes("red"));
+ assertEquals(db.get(bytes("New York")), bytes("blue"));
+
+ assertTrue(db.delete(bytes("New York")));
+ assertNull(db.get(bytes("New York")));
+
+ // We should not be able to delete it again.
+ assertFalse(db.delete(bytes("New York")));
+
+ db.close();
+ env.close();
+ }
+
+ @Test
+ public void testOpen() throws IOException {
+
+ Options options = new Options().createIfMissing(true);
+
+ File path = getTestDirectory(getName());
+ DB db = factory.open(path, options);
+
+ db.close();
+
+ // Try again.. this time we expect a failure since it exists.
+ options = new Options().errorIfExists(true);
+ try {
+ factory.open(path, options);
+ fail("Expected exception.");
+ } catch (IOException e) {
+ }
+
+ }
+
+ @Test
+ public void testCRUD() throws IOException, DBException {
+
+ Options options = new Options().createIfMissing(true);
+
+ File path = getTestDirectory(getName());
+ DB db = factory.open(path, options);
+
+ WriteOptions wo = new WriteOptions().sync(false);
+ ReadOptions ro = new ReadOptions().fillCache(true).verifyChecksums(true);
+
+ db.put(bytes("Tampa"), bytes("green"));
+ db.put(bytes("London"), bytes("red"));
+ db.put(bytes("New York"), bytes("blue"));
+
+ assertEquals(db.get(bytes("Tampa"), ro), bytes("green"));
+ assertEquals(db.get(bytes("London"), ro), bytes("red"));
+ assertEquals(db.get(bytes("New York"), ro), bytes("blue"));
+
+ db.delete(bytes("New York"), wo);
+ assertNull(db.get(bytes("New York"), ro));
+
+ // leveldb does not consider deleting something that does not exist an error.
+ db.delete(bytes("New York"), wo);
+
+ db.close();
+ }
+
+ @Test
+ public void testIterator() throws IOException, DBException {
+
+ Options options = new Options().createIfMissing(true);
+
+ File path = getTestDirectory(getName());
+ DB db = factory.open(path, options);
+
+ db.put(bytes("a"), bytes("av"));
+ db.put(bytes("c"), bytes("cv"));
+ db.put(bytes("e"), bytes("ev"));
+
+ ArrayList expecting = new ArrayList();
+ expecting.add("av");
+ expecting.add("cv");
+ expecting.add("ev");
+
+ ArrayList actual = new ArrayList();
+
+ DBIterator iterator = db.iterator();
+ for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
+ actual.add(asString(iterator.peekNext().getValue()));
+ }
+ iterator.close();
+
+ assertEquals(expecting, actual);
+
+ expecting = new ArrayList();
+ expecting.add("cv");
+ expecting.add("ev");
+
+ actual = new ArrayList();
+
+ iterator = db.iterator();
+ for (iterator.seek(bytes("b")); iterator.hasNext(); iterator.next()) {
+ actual.add(asString(iterator.peekNext().getValue()));
+ }
+ iterator.close();
+
+ iterator = db.iterator();
+ for (iterator.seek(bytes("b")); iterator.hasPrev(); iterator.prev()) {
+ actual.add(asString(iterator.peekPrev().getValue()));
+ }
+ iterator.close();
+
+ db.close();
+ }
+
+ @Test
+ public void testSnapshot() throws IOException, DBException {
+
+ Options options = new Options().createIfMissing(true);
+
+ File path = getTestDirectory(getName());
+ DB db = factory.open(path, options);
+
+ db.put(bytes("Tampa"), bytes("green"));
+ db.put(bytes("London"), bytes("red"));
+ db.delete(bytes("New York"));
+
+ ReadOptions ro = new ReadOptions().snapshot(db.getSnapshot());
+
+ db.put(bytes("New York"), bytes("blue"));
+
+ assertEquals(db.get(bytes("Tampa"), ro), bytes("green"));
+ assertEquals(db.get(bytes("London"), ro), bytes("red"));
+
+ // Should not be able to get "New York" since it was added
+ // after the snapshot
+ assertNull(db.get(bytes("New York"), ro));
+
+ ro.snapshot().close();
+
+ // Now try again without the snapshot..
+ ro.snapshot(null);
+ assertEquals(db.get(bytes("New York"), ro), bytes("blue"));
+
+ db.close();
+ }
+
+ @Test
+ public void testWriteBatch() throws IOException, DBException {
+
+ Options options = new Options().createIfMissing(true);
+
+ File path = getTestDirectory(getName());
+ DB db = factory.open(path, options);
+
+ db.put(bytes("NA"), bytes("Na"));
+
+ WriteBatch batch = db.createWriteBatch();
+ batch.delete(bytes("NA"));
+ batch.put(bytes("Tampa"), bytes("green"));
+ batch.put(bytes("London"), bytes("red"));
+ batch.put(bytes("New York"), bytes("blue"));
+ db.write(batch);
+ batch.close();
+
+ ArrayList expecting = new ArrayList();
+ expecting.add("London");
+ expecting.add("New York");
+ expecting.add("Tampa");
+
+ ArrayList actual = new ArrayList();
+
+ DBIterator iterator = db.iterator();
+ for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
+ actual.add(asString(iterator.peekNext().getKey()));
+ }
+ iterator.close();
+ assertEquals(expecting, actual);
+
+ db.close();
+ }
+
+// @Ignore
+// public void testIssue26() throws IOException {
+//
+// LMDBFactory.pushMemoryPool(1024 * 512);
+// try {
+// Options options = new Options();
+// options.createIfMissing(true);
+//
+// DB db = factory.open(getTestDirectory(getName()), options);
+//
+// for (int i = 0; i < 1024 * 1024; i++) {
+// byte[] key = ByteBuffer.allocate(4).putInt(i).array();
+// byte[] value = ByteBuffer.allocate(4).putInt(-i).array();
+// db.put(key, value);
+// assertTrue(Arrays.equals(db.get(key), value));
+// }
+// db.close();
+// } finally {
+// LMDBFactory.popMemoryPool();
+// }
+//
+// }
+
+ @Test
+ public void testIssue27() throws IOException {
+
+ Options options = new Options();
+ options.createIfMissing(true);
+ DB db = factory.open(getTestDirectory(getName()), options);
+ db.close();
+
+ try {
+ db.iterator();
+ fail("Expected a DBException");
+ } catch(DBException e) {
+ }
+
+ }
+
+}
diff --git a/pom.xml b/pom.xml
new file mode 100755
index 0000000..a7bdde0
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,347 @@
+
+
+
+
+ 4.0.0
+
+ org.fusesource
+ fusesource-pom
+ 1.9
+
+
+ org.fusesource.lmdbjni
+ lmdbjni-project
+ 99-master-SNAPSHOT
+ pom
+
+ ${project.artifactId}
+ lmdbjni is a jni library for accessing leveldb.
+
+
+ lmdbjni
+ LMDBJNI
+ UTF-8
+ 1.6
+ 0.5
+
+
+
+ lmdbjni
+
+
+ http://${forge-project-id}.fusesource.org
+ 2009
+
+
+ github
+ https://github.com/fusesource/lmdbjni/issues
+
+
+
+
+ ${forge-project-id} dev
+ ${forge-project-id}-dev@fusesource.org
+ ${forge-project-id}-dev-subscribe@fusesource.org
+
+
+ ${forge-project-id} commits
+ ${forge-project-id}-commits@fusesource.org
+ ${forge-project-id}-commits-subscribe@fusesource.org
+
+
+
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+ scm:git:git://github.com/fusesource/lmdbjni.git
+ scm:git:git@github.com:fusesource/lmdbjni.git
+ https://github.com/fusesource/lmdbjni
+
+
+
+
+ website.fusesource.org
+ website
+ dav:http://fusesource.com/forge/dav/${forge-project-id}/maven/${project.version}
+
+
+
+
+
+ chirino
+ Hiram Chirino
+ hiram@hiramchirino.com
+ http://hiramchirino.com
+ GMT-5
+
+
+
+
+
+ junit
+ junit
+ 4.7
+ test
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+ 2.3
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.5
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.4.3
+
+ true
+ once
+ -ea
+ false
+ ${project.build.directory}
+
+ **/*Test.java
+
+
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ jxr-maven-plugin
+ 2.0-beta-1
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.6
+
+ *.internal
+ true
+
+ http://java.sun.com/j2se/1.5.0/docs/api
+
+
+
+
+ org.apache.maven.plugins
+ maven-project-info-reports-plugin
+ 2.1.1
+
+
+
+ index
+ sumary
+ plugins
+ dependencies
+ mailing-list
+ issue-tracking
+ license
+ scm
+
+
+
+
+
+ org.codehaus.mojo
+ surefire-report-maven-plugin
+ 2.0-beta-1
+
+
+ org.apache.maven.plugins
+ maven-plugin-plugin
+ 2.5
+
+
+
+
+
+
+
+ download
+
+
+ fusesource.nexus.snapshot
+ FuseSource Community Snapshot Repository
+ http://repo.fusesource.com/nexus/content/groups/public-snapshots
+
+
+ sonatype-nexus
+ Sonatype Nexus
+ https://oss.sonatype.org/content/repositories/public
+ true
+ true
+
+
+
+
+ fusesource.nexus.snapshot
+ FuseSource Community Snapshot Repository
+ http://repo.fusesource.com/nexus/content/groups/public-snapshots
+
+
+
+
+
+ full
+
+ lmdbjni-osx
+ lmdbjni-linux32
+ lmdbjni-linux64
+ lmdbjni-win32
+ lmdbjni-win64
+ lmdbjni-all
+
+
+
+
+ all
+
+ lmdbjni-all
+
+
+
+ osx
+
+ lmdbjni-osx
+
+
+
+
+ linux32
+
+ lmdbjni-linux32
+
+
+
+
+ linux64
+
+ lmdbjni-linux64
+
+
+
+
+ win32
+
+ true
+
+
+ lmdbjni-win32
+
+
+
+
+ win64
+
+ true
+
+
+ lmdbjni-win64
+
+
+
+
+
+ license
+
+
+
+ com.mycila.maven-license-plugin
+ maven-license-plugin
+ 1.6.0
+
+ false
+ src/main/resources/license-header.txt
+ true
+
+ src/**
+ **/pom.xml
+
+
+ **/version.txt
+ **/license.txt
+ **/LICENSE.txt
+ **/LICENSE
+ **/.svn/**
+ **/.git/**
+
+
+ **/target/**
+
+
+ **/*.jpg
+ **/*.png
+ **/*.gif
+ **/*.ico
+ **/*.keystore
+
+
+ false
+
+ JAVADOC_STYLE
+ DOUBLESLASH_STYLE
+ SCRIPT_STYLE
+
+
+
+
+
+ check
+
+
+
+
+
+
+
+
+
+
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..4727b29
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,11 @@
+# LMDB JNI
+
+## Description
+
+LMDB JNI gives you a Java interface to the
+[OpenLDAP Lightning Memory-Mapped Database](http://symas.com/mdb/) library
+which is a fast key-value storage library written for OpenLDAP project
+that provides an ordered mapping from string keys to string values.
+
+
+
diff --git a/src/main/resources/license-header.txt b/src/main/resources/license-header.txt
new file mode 100644
index 0000000..e850e4d
--- /dev/null
+++ b/src/main/resources/license-header.txt
@@ -0,0 +1,15 @@
+Copyright (C) 2013, RedHat, Inc.
+
+ http://www.redhat.com/
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file