From 79f087dae06d408a8a4c342e7a01b0a626ba26cf Mon Sep 17 00:00:00 2001 From: Hiram Chirino Date: Mon, 6 May 2013 22:06:07 -0400 Subject: [PATCH] Initial lmdb jni port spike. --- changelog.md | 5 + license.txt | 202 ++++++ lmdbjni-all/pom.xml | 113 ++++ .../java/org/fusesource/leveldbjni/All.java | 4 + lmdbjni-linux32/pom.xml | 88 +++ lmdbjni-linux64/pom.xml | 87 +++ lmdbjni-osx/pom.xml | 98 +++ lmdbjni-win32/pom.xml | 86 +++ lmdbjni-win64/pom.xml | 85 +++ lmdbjni/pom.xml | 181 +++++ .../java/org/fusesource/lmdbjni/Cursor.java | 124 ++++ .../java/org/fusesource/lmdbjni/CursorOp.java | 57 ++ .../java/org/fusesource/lmdbjni/Database.java | 218 ++++++ .../java/org/fusesource/lmdbjni/Entry.java | 48 ++ .../main/java/org/fusesource/lmdbjni/Env.java | 167 +++++ .../java/org/fusesource/lmdbjni/Flags.java | 78 +++ .../main/java/org/fusesource/lmdbjni/JNI.java | 639 ++++++++++++++++++ .../org/fusesource/lmdbjni/LMDBException.java | 39 ++ .../org/fusesource/lmdbjni/NativeBuffer.java | 230 +++++++ .../org/fusesource/lmdbjni/NativeObject.java | 55 ++ .../org/fusesource/lmdbjni/Transaction.java | 59 ++ .../java/org/fusesource/lmdbjni/Util.java | 58 ++ .../java/org/fusesource/lmdbjni/Value.java | 58 ++ .../org/fusesource/lmdbjni/leveldb/LMDB.java | 375 ++++++++++ .../lmdbjni/leveldb/LMDBFactory.java | 124 ++++ .../lmdbjni/leveldb/LMDBOptions.java | 59 ++ lmdbjni/src/main/native-package/license.txt | 202 ++++++ lmdbjni/src/main/native-package/m4/custom.m4 | 36 + lmdbjni/src/main/native-package/src/buffer.c | 23 + lmdbjni/src/main/native-package/src/lmdbjni.h | 68 ++ .../org/fusesource/lmdbjni/version.txt | 1 + .../org/fusesource/lmdbjni/test/EnvTest.java | 76 +++ .../fusesource/lmdbjni/test/LevelDBTest.java | 292 ++++++++ pom.xml | 347 ++++++++++ readme.md | 11 + src/main/resources/license-header.txt | 15 + 36 files changed, 4408 insertions(+) create mode 100644 changelog.md create mode 100644 license.txt create mode 100755 lmdbjni-all/pom.xml create mode 100644 lmdbjni-all/src/main/java/org/fusesource/leveldbjni/All.java create mode 100755 lmdbjni-linux32/pom.xml create mode 100755 lmdbjni-linux64/pom.xml create mode 100755 lmdbjni-osx/pom.xml create mode 100755 lmdbjni-win32/pom.xml create mode 100755 lmdbjni-win64/pom.xml create mode 100755 lmdbjni/pom.xml create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Cursor.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/CursorOp.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Database.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Entry.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Env.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Flags.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/JNI.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/LMDBException.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeBuffer.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/NativeObject.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Transaction.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Util.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/Value.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDB.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBFactory.java create mode 100644 lmdbjni/src/main/java/org/fusesource/lmdbjni/leveldb/LMDBOptions.java create mode 100644 lmdbjni/src/main/native-package/license.txt create mode 100644 lmdbjni/src/main/native-package/m4/custom.m4 create mode 100644 lmdbjni/src/main/native-package/src/buffer.c create mode 100755 lmdbjni/src/main/native-package/src/lmdbjni.h create mode 100644 lmdbjni/src/main/resources/org/fusesource/lmdbjni/version.txt create mode 100644 lmdbjni/src/test/java/org/fusesource/lmdbjni/test/EnvTest.java create mode 100644 lmdbjni/src/test/java/org/fusesource/lmdbjni/test/LevelDBTest.java create mode 100755 pom.xml create mode 100644 readme.md create mode 100644 src/main/resources/license-header.txt 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 + 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 + 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