diff --git a/java/leveldbjni/.gitignore b/java/leveldbjni/.gitignore new file mode 100644 index 000000000..0f7766ed7 --- /dev/null +++ b/java/leveldbjni/.gitignore @@ -0,0 +1,13 @@ +*~ +*.swp +.idea +.idea/* +*.iml +*.ipr +*.iws +target +.DS_Store +.project +.classpath +.settings +eclipse-classes diff --git a/java/leveldbjni/changelog.md b/java/leveldbjni/changelog.md new file mode 100644 index 000000000..a99093b17 --- /dev/null +++ b/java/leveldbjni/changelog.md @@ -0,0 +1,42 @@ +# [LevelDBJNI](https://github.com/fusesource/leveldbjni) + +## [leveldbjni 1.3][1_3], released 2012-09-24 +[1_3]: http://repo.fusesource.com/nexus/content/groups/public/org/fusesource/leveldbjni/leveldbjni/1.3 + +* Make Util.link work on windows too. +* Expose the CreateHardLinkW windows API call. +* Added Windows LevelDB Support +* Update to hawtjni 1.6. +* Support the db.compactRange method to force compaction of the leveldb files. +* Fixed bug need to get leveldbjni workin on the Zing JVM + +## [leveldbjni 1.2][1_2], released 2012-02-27 +[1_2]: http://repo.fusesource.com/nexus/content/groups/public/org/fusesource/leveldbjni/leveldbjni/1.2 + +* Document how to use the memory pools. +* Fixes issue #6 Support using a memory pool to reduce native memory allocation overhead. +* Update leveldb, hawtjni, and leveldb-api versions. +* Store the version in the factory class. +* Added a release guide. + +## [leveldbjni 1.1][1_1], released 2011-09-29 +[1_1]: http://repo.fusesource.com/nexus/content/groups/public/org/fusesource/leveldbjni/leveldbjni/1.1 + +* the all module needs at least one java file so that it produces a javadoc and src.zip +* Try to load the native lib when the JniDBFactory class is loaded. +* Fixes issue #1 : Bug on NativeBuffer offset +* Switch the license from CDDL to the New BSD license to match the license used in the leveldb project. +* Add the sonatype snapshot repo since that's where the leveldb-api is at currently. +* Pickup updates in the api module. +* Updating build instructions. +* implement repair and destroy. +* api updated +* Cleaner java package structure. We only need to expose one public class now since we are using the org.iq80.leveldb abstract api. +* Refactored so that the main user API is the abstract API defined in 'org.iq80.leveldb.api' package. + +## [leveldbjni 1.0][1_0], released 2011-08-08 +[1_0]: http://repo.fusesource.com/nexus/content/groups/public/org/fusesource/leveldbjni/leveldbjni/1.0 + +* Initial Release +* OS X Intel 32 and 64 bit support +* Linux Intel 32 and 64 bit support diff --git a/java/leveldbjni/leveldb.patch b/java/leveldbjni/leveldb.patch new file mode 100644 index 000000000..bc075c85e --- /dev/null +++ b/java/leveldbjni/leveldb.patch @@ -0,0 +1,29 @@ +diff --git a/build_detect_platform b/build_detect_platform +index 959a7d6..388d225 100755 +--- a/build_detect_platform ++++ b/build_detect_platform +@@ -171,9 +171,9 @@ echo "CC=$CC" >> $OUTPUT + echo "CXX=$CXX" >> $OUTPUT + echo "PLATFORM=$PLATFORM" >> $OUTPUT + echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT +-echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT +-echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT +-echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT ++echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS $PLATFORM_SHARED_CFLAGS" >> $OUTPUT ++echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS $PLATFORM_SHARED_CFLAGS" >> $OUTPUT ++echo "PLATFORM_SHARED_CFLAGS=" >> $OUTPUT + echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT + echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT + echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT +diff --git a/include/leveldb/slice.h b/include/leveldb/slice.h +index 74ea8fa..135bbd7 100644 +--- a/include/leveldb/slice.h ++++ b/include/leveldb/slice.h +@@ -77,7 +77,6 @@ class Slice { + (memcmp(data_, x.data_, x.size_) == 0)); + } + +- private: + const char* data_; + size_t size_; + diff --git a/java/leveldbjni/leveldbjni-all/pom.xml b/java/leveldbjni/leveldbjni-all/pom.xml new file mode 100755 index 000000000..e5b3f8e06 --- /dev/null +++ b/java/leveldbjni/leveldbjni-all/pom.xml @@ -0,0 +1,95 @@ + + + + + 4.0.0 + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-all + 99-master-SNAPSHOT + + ${project.artifactId} + An uber jar which contains all the leveldbjni platform libraries and dependencies + + + + org.fusesource.leveldbjni + leveldbjni-osx + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-linux32 + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-linux64 + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-win32 + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-win64 + 99-master-SNAPSHOT + + + + + + + + + org.fusesource.mvnplugins + maven-uberize-plugin + 1.15 + + + package + uberize + + + + + + + diff --git a/java/leveldbjni/leveldbjni-all/src/main/java/org/fusesource/leveldbjni/All.java b/java/leveldbjni/leveldbjni-all/src/main/java/org/fusesource/leveldbjni/All.java new file mode 100644 index 000000000..a2ca0c7c4 --- /dev/null +++ b/java/leveldbjni/leveldbjni-all/src/main/java/org/fusesource/leveldbjni/All.java @@ -0,0 +1,4 @@ +package org.fusesource.leveldbjni; + +public class All { +} \ No newline at end of file diff --git a/java/leveldbjni/leveldbjni-linux32/pom.xml b/java/leveldbjni/leveldbjni-linux32/pom.xml new file mode 100755 index 000000000..366cf696c --- /dev/null +++ b/java/leveldbjni/leveldbjni-linux32/pom.xml @@ -0,0 +1,100 @@ + + + + + 4.0.0 + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-linux32 + 99-master-SNAPSHOT + + ${project.artifactId} + The leveldbjni linux 32 native libraries + + + + org.fusesource.leveldbjni + leveldbjni + 99-master-SNAPSHOT + + + + + ${basedir}/../leveldbjni/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 + + + + leveldbjni + false + + org.fusesource.leveldbjni + leveldbjni + ${project.version} + native-src + zip + + + --with-leveldb=${env.LEVELDB_HOME} + --with-snappy=${env.SNAPPY_HOME} + + + + + + + diff --git a/java/leveldbjni/leveldbjni-linux64/pom.xml b/java/leveldbjni/leveldbjni-linux64/pom.xml new file mode 100755 index 000000000..e63d6f87f --- /dev/null +++ b/java/leveldbjni/leveldbjni-linux64/pom.xml @@ -0,0 +1,99 @@ + + + + + 4.0.0 + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-linux64 + 99-master-SNAPSHOT + + ${project.artifactId} + The leveldbjni linux 64 native libraries + + + + org.fusesource.leveldbjni + leveldbjni + 99-master-SNAPSHOT + + + + + ${basedir}/../leveldbjni/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 + + + + + leveldbjni + false + + org.fusesource.leveldbjni + leveldbjni + ${project.version} + native-src + zip + + + --with-leveldb=${env.LEVELDB_HOME} + --with-snappy=${env.SNAPPY_HOME} + + + + + + + diff --git a/java/leveldbjni/leveldbjni-osx/pom.xml b/java/leveldbjni/leveldbjni-osx/pom.xml new file mode 100755 index 000000000..cf31b8be5 --- /dev/null +++ b/java/leveldbjni/leveldbjni-osx/pom.xml @@ -0,0 +1,110 @@ + + + + + 4.0.0 + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-osx + 99-master-SNAPSHOT + + ${project.artifactId} + The leveldbjni OS X universal native libraries + + + + org.fusesource.leveldbjni + leveldbjni + 99-master-SNAPSHOT + + + + org.fusesource.leveldbjni + leveldbjni + 99-master-SNAPSHOT + test-jar + test + + + + + ${basedir}/../leveldbjni/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 + + + + + leveldbjni + false + + org.fusesource.leveldbjni + leveldbjni + ${project.version} + native-src + zip + + osx + + --with-leveldb=${env.LEVELDB_HOME} + --with-snappy=${env.SNAPPY_HOME} + --with-universal + + + + + + + diff --git a/java/leveldbjni/leveldbjni-win32/pom.xml b/java/leveldbjni/leveldbjni-win32/pom.xml new file mode 100755 index 000000000..1defb4667 --- /dev/null +++ b/java/leveldbjni/leveldbjni-win32/pom.xml @@ -0,0 +1,97 @@ + + + + + 4.0.0 + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-win32 + 99-master-SNAPSHOT + + ${project.artifactId} + The leveldbjni Windows 32 bit native libraries + + + + org.fusesource.leveldbjni + leveldbjni + 99-master-SNAPSHOT + + + + + ${basedir}/../leveldbjni/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 + + + + leveldbjni + false + + org.fusesource.leveldbjni + leveldbjni + ${project.version} + native-src + zip + + ${basedir}/../leveldbjni/target/generated-sources/hawtjni/native-package + + + + + + diff --git a/java/leveldbjni/leveldbjni-win64/pom.xml b/java/leveldbjni/leveldbjni-win64/pom.xml new file mode 100755 index 000000000..7f3aa6bc2 --- /dev/null +++ b/java/leveldbjni/leveldbjni-win64/pom.xml @@ -0,0 +1,96 @@ + + + + + 4.0.0 + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni-win64 + 99-master-SNAPSHOT + + ${project.artifactId} + The leveldbjni Windows 64 bit native libraries + + + + org.fusesource.leveldbjni + leveldbjni + 99-master-SNAPSHOT + + + + + ${basedir}/../leveldbjni/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 + + + + + leveldbjni + false + + org.fusesource.leveldbjni + leveldbjni + ${project.version} + native-src + zip + + ${basedir}/../leveldbjni/target/generated-sources/hawtjni/native-package + + + + + + diff --git a/java/leveldbjni/leveldbjni/pom.xml b/java/leveldbjni/leveldbjni/pom.xml new file mode 100755 index 000000000..28cf17e61 --- /dev/null +++ b/java/leveldbjni/leveldbjni/pom.xml @@ -0,0 +1,180 @@ + + + + + 4.0.0 + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + + + org.fusesource.leveldbjni + leveldbjni + 99-master-SNAPSHOT + jar + + ${project.artifactId} + leveldbjni 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} + leveldbjni + true + + + + + + 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.leveldbjni*,!org.fusesource.hawtjni*,sun.reflect;resolution:=optional,* + + + + + + + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + + + diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/JniDBFactory.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/JniDBFactory.java new file mode 100644 index 000000000..02d82a4f8 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/JniDBFactory.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni; + +import org.fusesource.leveldbjni.internal.*; +import org.iq80.leveldb.*; + +import java.io.*; +import java.net.URL; +import java.util.concurrent.Callable; + +/** + * @author Hiram Chirino + */ +public class JniDBFactory implements DBFactory { + + public static final JniDBFactory factory = new JniDBFactory(); + static { + NativeDB.LIBRARY.load(); + } + + public static final String VERSION; + static { + String v="unknown"; + InputStream is = JniDBFactory.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); + } + } + + static private class OptionsResourceHolder { + + NativeCache cache = null; + NativeComparator comparator=null; + NativeLogger logger=null; + NativeOptions options; + + public void init(Options value) { + + options = new NativeOptions(); + options.blockRestartInterval(value.blockRestartInterval()); + options.blockSize(value.blockSize()); + options.createIfMissing(value.createIfMissing()); + options.errorIfExists(value.errorIfExists()); + options.maxOpenFiles(value.maxOpenFiles()); + options.paranoidChecks(value.paranoidChecks()); + options.writeBufferSize(value.writeBufferSize()); + + switch(value.compressionType()) { + case NONE: + options.compression(NativeCompressionType.kNoCompression); + break; + case SNAPPY: + options.compression(NativeCompressionType.kSnappyCompression); + break; + } + + + if(value.cacheSize()>0 ) { + cache = new NativeCache(value.cacheSize()); + options.cache(cache); + } + + final DBComparator userComparator = value.comparator(); + if(userComparator!=null) { + comparator = new NativeComparator() { + @Override + public int compare(byte[] key1, byte[] key2) { + return userComparator.compare(key1, key2); + } + + @Override + public String name() { + return userComparator.name(); + } + }; + options.comparator(comparator); + } + + final Logger userLogger = value.logger(); + if(userLogger!=null) { + logger = new NativeLogger() { + @Override + public void log(String message) { + userLogger.log(message); + } + }; + options.infoLog(logger); + } + + } + public void close() { + if(cache!=null) { + cache.delete(); + } + if(comparator!=null){ + comparator.delete(); + } + if(logger!=null) { + logger.delete(); + } + } + } + + public DB open(File path, Options options) throws IOException { + NativeDB db=null; + OptionsResourceHolder holder = new OptionsResourceHolder(); + try { + holder.init(options); + db = NativeDB.open(holder.options, path); + } finally { + // if we could not open up the DB, then clean up the + // other allocated native resouces.. + if(db==null) { + holder.close(); + } + } + return new JniDB(db, holder.cache, holder.comparator, holder.logger); + } + + public void destroy(File path, Options options) throws IOException { + OptionsResourceHolder holder = new OptionsResourceHolder(); + try { + holder.init(options); + NativeDB.destroy(path, holder.options); + } finally { + holder.close(); + } + } + + public void repair(File path, Options options) throws IOException { + OptionsResourceHolder holder = new OptionsResourceHolder(); + try { + holder.init(options); + NativeDB.repair(path, holder.options); + } finally { + holder.close(); + } + } + + @Override + public String toString() { + return String.format("leveldbjni version %s", VERSION); + } + + + public static void pushMemoryPool(int size) { + NativeBuffer.pushMemoryPool(size); + } + + public static void popMemoryPool() { + NativeBuffer.popMemoryPool(); + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniDB.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniDB.java new file mode 100644 index 000000000..fec478ccf --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniDB.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.Callback; +import org.iq80.leveldb.*; + +import java.util.concurrent.CountDownLatch; + +/** + * @author Hiram Chirino + */ +public class JniDB implements DB { + + private final NativeDB db; + private final NativeCache cache; + private final NativeComparator comparator; + private final NativeLogger logger; + + public JniDB(NativeDB db, NativeCache cache, NativeComparator comparator, NativeLogger logger) { + this.db = db; + this.cache = cache; + this.comparator = comparator; + this.logger = logger; + } + + public void close() { + db.delete(); + if(cache!=null) { + cache.delete(); + } + if(comparator!=null){ + comparator.delete(); + } + if(logger!=null) { + logger.delete(); + } + } + + + public byte[] get(byte[] key) throws DBException { + return get(key, new ReadOptions()); + } + + public byte[] get(byte[] key, ReadOptions options) throws DBException { + try { + return db.get(convert(options), key); + } catch (NativeDB.DBException e) { + if(e.isNotFound()) { + return null; + } + throw new DBException(e.getMessage(), e); + } + } + + public DBIterator iterator() { + return iterator(new ReadOptions()); + } + + public DBIterator iterator(ReadOptions options) { + return new JniDBIterator(db.iterator(convert(options))); + } + + public void put(byte[] key, byte[] value) throws DBException { + put(key, value, new WriteOptions()); + } + + public void delete(byte[] key) throws DBException { + delete(key, new WriteOptions()); + } + + public void write(WriteBatch updates) throws DBException { + write(updates, new WriteOptions()); + } + + public WriteBatch createWriteBatch() { + return new JniWriteBatch(new NativeWriteBatch()); + } + + public Snapshot put(byte[] key, byte[] value, WriteOptions options) throws DBException { + try { + db.put(convert(options), key, value); + return null; + } catch (NativeDB.DBException e) { + throw new DBException(e.getMessage(), e); + } + } + + public Snapshot delete(byte[] key, WriteOptions options) throws DBException { + try { + db.delete(convert(options), key); + return null; + } catch (NativeDB.DBException e) { + throw new DBException(e.getMessage(), e); + } + } + + public Snapshot write(WriteBatch updates, WriteOptions options) throws DBException { + try { + db.write(convert(options), ((JniWriteBatch) updates).writeBatch()); + return null; + } catch (NativeDB.DBException e) { + throw new DBException(e.getMessage(), e); + } + } + + public Snapshot getSnapshot() { + return new JniSnapshot(db, db.getSnapshot()); + } + + public long[] getApproximateSizes(Range... ranges) { + NativeRange args[] = new NativeRange[ranges.length]; + for (int i = 0; i < args.length; i++) { + args[i] = new NativeRange(ranges[i].start(), ranges[i].limit()); + } + return db.getApproximateSizes(args); + } + + public String getProperty(String name) { + return db.getProperty(name); + } + + private NativeReadOptions convert(ReadOptions options) { + if(options==null) { + return null; + } + NativeReadOptions rc = new NativeReadOptions(); + rc.fillCache(options.fillCache()); + rc.verifyChecksums(options.verifyChecksums()); + if(options.snapshot()!=null) { + rc.snapshot(((JniSnapshot) options.snapshot()).snapshot()); + } + return rc; + } + + private NativeWriteOptions convert(WriteOptions options) { + if(options==null) { + return null; + } + NativeWriteOptions rc = new NativeWriteOptions(); + rc.sync(options.sync()); + if(options.snapshot()) { + throw new UnsupportedOperationException("WriteOptions snapshot not supported"); + } + return rc; + } + + public void compactRange(byte[] begin, byte[] end) throws DBException { + db.compactRange(begin, end); + } + + + private static class Suspension { + static long env = Util.EnvJNI.Default(); + + CountDownLatch suspended = new CountDownLatch(1); + CountDownLatch resumed = new CountDownLatch(1); + Callback callback = new Callback(this, "suspended", 1); + + public Suspension() { + Util.EnvJNI.Schedule(env, callback.getAddress(), 0); + } + + private long suspended(long arg) { + suspended.countDown(); + try { + resumed.await(); + } catch (InterruptedException e) { + } finally { + callback.dispose(); + } + return 0; + } + } + + int suspendCounter = 0; + Suspension suspension = null; + + public void suspendCompactions() throws InterruptedException { + Suspension s = null; + synchronized (this) { + suspendCounter++; + if( suspendCounter==1 ) { + suspension = new Suspension(); + } + s = suspension; + } + // Don't return until the compactions have suspended. + s.suspended.await(); + } + + synchronized public void resumeCompactions() { + suspendCounter--; + if( suspendCounter==0 ) { + suspension.resumed.countDown(); + suspension = null; + } + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniDBIterator.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniDBIterator.java new file mode 100644 index 000000000..0bfd46f65 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniDBIterator.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.leveldbjni.internal.NativeDB; +import org.fusesource.leveldbjni.internal.NativeIterator; +import org.iq80.leveldb.DBIterator; + +import java.util.AbstractMap; +import java.util.Map; +import java.util.NoSuchElementException; + +/** + * @author Hiram Chirino + */ +public class JniDBIterator implements DBIterator { + + private final NativeIterator iterator; + + JniDBIterator(NativeIterator iterator) { + this.iterator = iterator; + } + + public void close() { + iterator.delete(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public void seek(byte[] key) { + try { + iterator.seek(key); + } catch (NativeDB.DBException e) { + if( e.isNotFound() ) { + throw new NoSuchElementException(); + } else { + throw new RuntimeException(e); + } + } + } + + public void seekToFirst() { + iterator.seekToFirst(); + } + + public void seekToLast() { + iterator.seekToLast(); + } + + + public Map.Entry peekNext() { + if(!iterator.isValid()) { + throw new NoSuchElementException(); + } + try { + return new AbstractMap.SimpleImmutableEntry(iterator.key(), iterator.value()); + } catch (NativeDB.DBException e) { + throw new RuntimeException(e); + } + } + + public boolean hasNext() { + return iterator.isValid(); + } + + public Map.Entry next() { + Map.Entry rc = peekNext(); + try { + iterator.next(); + } catch (NativeDB.DBException e) { + throw new RuntimeException(e); + } + return rc; + } + + public boolean hasPrev() { + if( !iterator.isValid() ) + return false; + try { + iterator.prev(); + try { + return iterator.isValid(); + } finally { + iterator.next(); + } + } catch (NativeDB.DBException e) { + throw new RuntimeException(e); + } + } + + public Map.Entry peekPrev() { + try { + iterator.prev(); + try { + return peekNext(); + } finally { + iterator.next(); + } + } catch (NativeDB.DBException e) { + throw new RuntimeException(e); + } + } + + public Map.Entry prev() { + Map.Entry rc = peekPrev(); + try { + iterator.prev(); + } catch (NativeDB.DBException e) { + throw new RuntimeException(e); + } + return rc; + } + + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniSnapshot.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniSnapshot.java new file mode 100644 index 000000000..827613f35 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniSnapshot.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.leveldbjni.internal.*; +import org.iq80.leveldb.Snapshot; + +/** + * @author Hiram Chirino + */ +public class JniSnapshot implements Snapshot { + + private final NativeDB db; + private final NativeSnapshot snapshot; + + JniSnapshot(NativeDB db, NativeSnapshot snapshot) { + this.db = db; + this.snapshot = snapshot; + } + + public void close() { + db.releaseSnapshot(snapshot); + } + + NativeSnapshot snapshot() { + return snapshot; + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniWriteBatch.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniWriteBatch.java new file mode 100644 index 000000000..27d86d6f1 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/JniWriteBatch.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.leveldbjni.internal.NativeWriteBatch; +import org.iq80.leveldb.WriteBatch; + +/** + * @author Hiram Chirino + */ +public class JniWriteBatch implements WriteBatch { + + private final NativeWriteBatch writeBatch; + + JniWriteBatch(NativeWriteBatch writeBatch) { + this.writeBatch = writeBatch; + } + + public void close() { + writeBatch.delete(); + } + + public WriteBatch put(byte[] key, byte[] value) { + writeBatch.put(key, value); + return this; + } + + public WriteBatch delete(byte[] key) { + writeBatch.delete(key); + return this; + } + + public NativeWriteBatch writeBatch() { + return writeBatch; + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeBuffer.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeBuffer.java new file mode 100644 index 000000000..6eeb06f2f --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeBuffer.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniArg; +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniMethod; +import org.fusesource.hawtjni.runtime.PointerMath; + +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.fusesource.hawtjni.runtime.ArgFlag.*; + +/** + * 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 + */ +public class NativeBuffer extends NativeObject { + + @JniClass + static class NativeBufferJNI { + static { + NativeDB.LIBRARY.load(); + } + + @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); + +// public static final native void buffer_copy ( +// @JniArg(cast="const void *") long 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 *", 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); + +// @JniMethod(cast="void *") +// public static final native long memset ( +// @JniArg(cast="void *") long buffer, +// int c, +// @JniArg(cast="size_t") long num); + + } + + private static class Allocation extends NativeObject { + private final AtomicInteger retained = new AtomicInteger(0); + + private Allocation(long size) { + super(NativeBufferJNI.malloc(size)); + } + + void retain() { + assertAllocated(); + retained.incrementAndGet(); + } + + void release() { + assertAllocated(); + int r = retained.decrementAndGet(); + if( r < 0 ) { + throw new Error("The object has already been deleted."); + } else if( r==0 ) { + NativeBufferJNI.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; + } + + private NativeBuffer(Allocation allocation, long self, long capacity) { + super(self); + this.capacity = capacity; + this.allocation = allocation; + this.allocation.retain(); + } + + public NativeBuffer slice(long offset, long length) { + assertAllocated(); + 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) { + assertAllocated(); + 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"); + NativeBufferJNI.buffer_copy(source, offset, self, at, length); + } + + public void read(long at, byte []target, int offset, int length) { + assertAllocated(); + 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"); + NativeBufferJNI.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/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeCache.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeCache.java new file mode 100644 index 000000000..056249760 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeCache.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniArg; +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniMethod; + +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.MethodFlag.CPP_DELETE; + +/** + * Provides a java interface to the C++ leveldb::Cache class. + * + * @author Hiram Chirino + */ +public class NativeCache extends NativeObject { + + @JniClass(name="leveldb::Cache", flags={CPP}) + private static class CacheJNI { + static { + NativeDB.LIBRARY.load(); + } + + @JniMethod(cast="leveldb::Cache *", accessor="leveldb::NewLRUCache") + public static final native long NewLRUCache( + @JniArg(cast="size_t") long capacity); + + @JniMethod(flags={CPP_DELETE}) + public static final native void delete(long self); + } + + public NativeCache(long capacity) { + super(CacheJNI.NewLRUCache(capacity)); + } + + public void delete() { + assertAllocated(); + CacheJNI.delete(self); + self = 0; + } + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeComparator.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeComparator.java new file mode 100644 index 000000000..f2f85853e --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeComparator.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.*; + +import static org.fusesource.hawtjni.runtime.FieldFlag.*; +import static org.fusesource.hawtjni.runtime.MethodFlag.*; +import static org.fusesource.hawtjni.runtime.ArgFlag.*; +import static org.fusesource.hawtjni.runtime.ClassFlag.*; + +/** + *

+ * Provides a java interface to the C++ leveldb::Comparator class. + *

+ * + * @author Hiram Chirino + */ +public abstract class NativeComparator extends NativeObject { + + @JniClass(name="JNIComparator", flags={STRUCT, CPP}) + static public class ComparatorJNI { + + static { + NativeDB.LIBRARY.load(); + init(); + } + + @JniMethod(flags={CPP_NEW}) + public static final native long create(); + @JniMethod(flags={CPP_DELETE}) + public static final native void delete(long ptr); + + public static final native void memmove ( + @JniArg(cast="void *") long dest, + @JniArg(cast="const void *", flags={NO_OUT, CRITICAL}) ComparatorJNI src, + @JniArg(cast="size_t") long size); + + public static final native void memmove ( + @JniArg(cast="void *", flags={NO_IN, CRITICAL}) ComparatorJNI dest, + @JniArg(cast="const void *") long src, + @JniArg(cast="size_t") long size); + + @JniField(cast="jobject", flags={POINTER_FIELD}) + long target; + + @JniField(cast="jmethodID", flags={POINTER_FIELD}) + long compare_method; + + @JniField(cast="const char *") + long name; + + @JniMethod(flags={CONSTANT_INITIALIZER}) + private static final native void init(); + + @JniField(flags={CONSTANT}, accessor="sizeof(struct JNIComparator)") + static int SIZEOF; + + @JniField(flags={CONSTANT}, cast="const Comparator*", accessor="leveldb::BytewiseComparator()") + private static long BYTEWISE_COMPARATOR; + + } + + private NativeBuffer name_buffer; + private long globalRef; + + public NativeComparator() { + super(ComparatorJNI.create()); + try { + name_buffer = NativeBuffer.create(name()); + globalRef = NativeDB.DBJNI.NewGlobalRef(this); + if( globalRef==0 ) { + throw new RuntimeException("jni call failed: NewGlobalRef"); + } + ComparatorJNI struct = new ComparatorJNI(); + struct.compare_method = NativeDB.DBJNI.GetMethodID(this.getClass(), "compare", "(JJ)I"); + if( struct.compare_method==0 ) { + throw new RuntimeException("jni call failed: GetMethodID"); + } + struct.target = globalRef; + struct.name = name_buffer.pointer(); + ComparatorJNI.memmove(self, struct, ComparatorJNI.SIZEOF); + + } catch (RuntimeException e) { + delete(); + throw e; + } + } + + public static final NativeComparator BYTEWISE_COMPARATOR = new NativeComparator(ComparatorJNI.BYTEWISE_COMPARATOR) { + @Override + public void delete() { + // we won't really delete this one since it's static. + } + @Override + public int compare(byte[] key1, byte[] key2) { + throw new UnsupportedOperationException(); + } + @Override + public String name() { + throw new UnsupportedOperationException(); + } + }; + + NativeComparator(long ptr) { + super(ptr); + } + + public void delete() { + if( name_buffer!=null ) { + name_buffer.delete(); + name_buffer = null; + } + if( globalRef!=0 ) { + NativeDB.DBJNI.DeleteGlobalRef(globalRef); + globalRef = 0; + } + } + + private int compare(long ptr1, long ptr2) { + NativeSlice s1 = new NativeSlice(); + s1.read(ptr1, 0); + NativeSlice s2 = new NativeSlice(); + s2.read(ptr2, 0); + return compare(s1.toByteArray(), s2.toByteArray()); + } + + public abstract int compare(byte[] key1, byte[] key2); + public abstract String name(); + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeCompressionType.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeCompressionType.java new file mode 100644 index 000000000..2c8b97b96 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeCompressionType.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +/** + * Provides a java interface to the C++ leveldb::CompressionType enum. + * + * @author Hiram Chirino + */ +public enum NativeCompressionType { + kNoCompression(0x0), kSnappyCompression(0x1); + + static final int t = kNoCompression.value; + final int value; + + NativeCompressionType(int value) { + this.value = value; + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeDB.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeDB.java new file mode 100644 index 000000000..f6afb4da9 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeDB.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniArg; +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniMethod; +import org.fusesource.hawtjni.runtime.Library; + +import java.io.File; +import java.io.IOException; + +import static org.fusesource.hawtjni.runtime.ArgFlag.*; +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.MethodFlag.*; + +/** + * The DB object provides the main interface to acessing LevelDB + * + * @author Hiram Chirino + */ +public class NativeDB extends NativeObject { + + public static final Library LIBRARY = new Library("leveldbjni", NativeDB.class); + + @JniClass(name="leveldb::DB", flags={CPP}) + static class DBJNI { + static { + NativeDB.LIBRARY.load(); + } + + @JniMethod(flags={JNI, POINTER_RETURN}, cast="jobject") + public static final native long NewGlobalRef( + Object target); + + @JniMethod(flags={JNI}, cast="jobject") + public static final native void DeleteGlobalRef( + @JniArg(cast="jobject", flags={POINTER_ARG}) + long target); + + @JniMethod(flags={JNI, POINTER_RETURN}, cast="jmethodID") + public static final native long GetMethodID( + @JniArg(cast="jclass", flags={POINTER_ARG}) + Class clazz, + String name, + String signature); + + @JniMethod(flags={CPP_DELETE}) + static final native void delete( + long self + ); + + @JniMethod(copy="leveldb::Status", accessor = "leveldb::DB::Open") + static final native long Open( + @JniArg(flags={BY_VALUE, NO_OUT}) NativeOptions options, + @JniArg(cast="const char*") String path, + @JniArg(cast="leveldb::DB**") long[] self); + + @JniMethod(copy="leveldb::Status", flags={CPP_METHOD}) + static final native long Put( + long self, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeWriteOptions options, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice key, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice value + ); + + @JniMethod(copy="leveldb::Status", flags={CPP_METHOD}) + static final native long Delete( + long self, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeWriteOptions options, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice key + ); + + @JniMethod(copy="leveldb::Status", flags={CPP_METHOD}) + static final native long Write( + long self, + @JniArg(flags={BY_VALUE}) NativeWriteOptions options, + @JniArg(cast="leveldb::WriteBatch *") long updates + ); + + @JniMethod(copy="leveldb::Status", flags={CPP_METHOD}) + static final native long Get( + long self, + @JniArg(flags={NO_OUT, BY_VALUE}) NativeReadOptions options, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice key, + @JniArg(cast="std::string *") long value + ); + + @JniMethod(cast="leveldb::Iterator *", flags={CPP_METHOD}) + static final native long NewIterator( + long self, + @JniArg(flags={NO_OUT, BY_VALUE}) NativeReadOptions options + ); + + @JniMethod(cast="leveldb::Snapshot *", flags={CPP_METHOD}) + static final native long GetSnapshot( + long self); + + @JniMethod(flags={CPP_METHOD}) + static final native void ReleaseSnapshot( + long self, + @JniArg(cast="const leveldb::Snapshot *") long snapshot + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void GetApproximateSizes( + long self, + @JniArg(cast="const leveldb::Range *") long range, + int n, + @JniArg(cast="uint64_t*") long[] sizes + ); + + @JniMethod(flags={CPP_METHOD}) + static final native boolean GetProperty( + long self, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice property, + @JniArg(cast="std::string *") long value + ); + + @JniMethod(copy="leveldb::Status", accessor = "leveldb::DestroyDB") + static final native long DestroyDB( + @JniArg(cast="const char*") String path, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeOptions options); + + @JniMethod(copy="leveldb::Status", accessor = "leveldb::RepairDB") + static final native long RepairDB( + @JniArg(cast="const char*") String path, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeOptions options); + + @JniMethod(flags={CPP_METHOD}) + static final native void CompactRange( + long self, + @JniArg(flags={NO_OUT}) NativeSlice begin, + @JniArg(flags={NO_OUT}) NativeSlice end + ); + + } + + public void delete() { + assertAllocated(); + DBJNI.delete(self); + self = 0; + } + + private NativeDB(long self) { + super(self); + } + + public static class DBException extends IOException { + private final boolean notFound; + + DBException(String s, boolean notFound) { + super(s); + this.notFound = notFound; + } + + public boolean isNotFound() { + return notFound; + } + } + + static void checkStatus(long s) throws DBException { + NativeStatus status = new NativeStatus(s); + try { + if( !status.isOk() ) { + throw new DBException(status.toString(), status.isNotFound()); + } + } finally { + status.delete(); + } + } + + static void checkArgNotNull(Object value, String name) { + if(value==null) { + throw new IllegalArgumentException("The "+name+" argument cannot be null"); + } + } + + public static NativeDB open(NativeOptions options, File path) throws IOException, DBException { + checkArgNotNull(options, "options"); + checkArgNotNull(path, "path"); + long rc[] = new long[1]; + try { + checkStatus(DBJNI.Open(options, path.getCanonicalPath(), rc)); + } catch (IOException e) { + if( rc[0]!=0 ) { + DBJNI.delete(rc[0]); + } + throw e; + } + return new NativeDB(rc[0]); + } + + public void put(NativeWriteOptions options, byte[] key, byte[] value) throws DBException { + checkArgNotNull(options, "options"); + checkArgNotNull(key, "key"); + checkArgNotNull(value, "value"); + NativeBuffer keyBuffer = NativeBuffer.create(key); + try { + NativeBuffer valueBuffer = NativeBuffer.create(value); + try { + put(options, keyBuffer, valueBuffer); + } finally { + valueBuffer.delete(); + } + } finally { + keyBuffer.delete(); + } + } + + private void put(NativeWriteOptions options, NativeBuffer keyBuffer, NativeBuffer valueBuffer) throws DBException { + put(options, new NativeSlice(keyBuffer), new NativeSlice(valueBuffer)); + } + + private void put(NativeWriteOptions options, NativeSlice keySlice, NativeSlice valueSlice) throws DBException { + assertAllocated(); + checkStatus(DBJNI.Put(self, options, keySlice, valueSlice)); + } + + public void delete(NativeWriteOptions options, byte[] key) throws DBException { + checkArgNotNull(options, "options"); + checkArgNotNull(key, "key"); + NativeBuffer keyBuffer = NativeBuffer.create(key); + try { + delete(options, keyBuffer); + } finally { + keyBuffer.delete(); + } + } + + private void delete(NativeWriteOptions options, NativeBuffer keyBuffer) throws DBException { + delete(options, new NativeSlice(keyBuffer)); + } + + private void delete(NativeWriteOptions options, NativeSlice keySlice) throws DBException { + assertAllocated(); + checkStatus(DBJNI.Delete(self, options, keySlice)); + } + + public void write(NativeWriteOptions options, NativeWriteBatch updates) throws DBException { + checkArgNotNull(options, "options"); + checkArgNotNull(updates, "updates"); + checkStatus(DBJNI.Write(self, options, updates.pointer())); + } + + public byte[] get(NativeReadOptions options, byte[] key) throws DBException { + checkArgNotNull(options, "options"); + checkArgNotNull(key, "key"); + NativeBuffer keyBuffer = NativeBuffer.create(key); + try { + return get(options, keyBuffer); + } finally { + keyBuffer.delete(); + } + } + + private byte[] get(NativeReadOptions options, NativeBuffer keyBuffer) throws DBException { + return get(options, new NativeSlice(keyBuffer)); + } + + private byte[] get(NativeReadOptions options, NativeSlice keySlice) throws DBException { + assertAllocated(); + NativeStdString result = new NativeStdString(); + try { + checkStatus(DBJNI.Get(self, options, keySlice, result.pointer())); + return result.toByteArray(); + } finally { + result.delete(); + } + } + + public NativeSnapshot getSnapshot() { + return new NativeSnapshot(DBJNI.GetSnapshot(self)); + } + + public void releaseSnapshot(NativeSnapshot snapshot) { + checkArgNotNull(snapshot, "snapshot"); + DBJNI.ReleaseSnapshot(self, snapshot.pointer()); + } + + public NativeIterator iterator(NativeReadOptions options) { + checkArgNotNull(options, "options"); + return new NativeIterator(DBJNI.NewIterator(self, options)); + } + + public long[] getApproximateSizes(NativeRange... ranges) { + if( ranges==null ) { + return null; + } + + long rc[] = new long[ranges.length]; + NativeRange.RangeJNI structs[] = new NativeRange.RangeJNI[ranges.length]; + if( rc.length> 0 ) { + NativeBuffer range_array = NativeRange.RangeJNI.arrayCreate(ranges.length); + try { + for(int i=0; i < ranges.length; i++) { + structs[i] = new NativeRange.RangeJNI(ranges[i]); + structs[i].arrayWrite(range_array.pointer(), i); + } + DBJNI.GetApproximateSizes(self,range_array.pointer(), ranges.length, rc); + } finally { + for(int i=0; i < ranges.length; i++) { + if( structs[i] != null ) { + structs[i].delete(); + } + } + range_array.delete(); + } + } + return rc; + } + + public String getProperty(String name) { + checkArgNotNull(name, "name"); + NativeBuffer keyBuffer = NativeBuffer.create(name.getBytes()); + try { + byte[] property = getProperty(keyBuffer); + if( property==null ) { + return null; + } else { + return new String(property); + } + } finally { + keyBuffer.delete(); + } + } + + private byte[] getProperty(NativeBuffer nameBuffer) { + return getProperty(new NativeSlice(nameBuffer)); + } + + private byte[] getProperty(NativeSlice nameSlice) { + assertAllocated(); + NativeStdString result = new NativeStdString(); + try { + if( DBJNI.GetProperty(self, nameSlice, result.pointer()) ) { + return result.toByteArray(); + } else { + return null; + } + } finally { + result.delete(); + } + } + + public void compactRange(byte[] begin, byte[] end) { + NativeBuffer keyBuffer = NativeBuffer.create(begin); + try { + NativeBuffer valueBuffer = NativeBuffer.create(end); + try { + compactRange(keyBuffer, valueBuffer); + } finally { + if( valueBuffer!=null ) { + valueBuffer.delete(); + } + } + } finally { + if( keyBuffer!=null ) { + keyBuffer.delete(); + } + } + } + + private void compactRange( NativeBuffer beginBuffer, NativeBuffer endBuffer) { + compactRange(NativeSlice.create(beginBuffer), NativeSlice.create(endBuffer)); + } + + private void compactRange( NativeSlice beginSlice, NativeSlice endSlice) { + assertAllocated(); + DBJNI.CompactRange(self, beginSlice, endSlice); + } + + + static public void destroy(File path, NativeOptions options) throws IOException, DBException { + checkArgNotNull(options, "options"); + checkArgNotNull(path, "path"); + checkStatus(DBJNI.DestroyDB(path.getCanonicalPath(), options)); + } + + static public void repair(File path, NativeOptions options) throws IOException, DBException { + checkArgNotNull(options, "options"); + checkArgNotNull(path, "path"); + checkStatus(DBJNI.RepairDB(path.getCanonicalPath(), options)); + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeIterator.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeIterator.java new file mode 100644 index 000000000..bf40b1901 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeIterator.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.*; + +import static org.fusesource.hawtjni.runtime.MethodFlag.*; +import static org.fusesource.hawtjni.runtime.ArgFlag.*; +import static org.fusesource.hawtjni.runtime.ClassFlag.*; + +/** + * Provides a java interface to the C++ leveldb::Iterator class. + * + * @author Hiram Chirino + */ +public class NativeIterator extends NativeObject { + + @JniClass(name="leveldb::Iterator", flags={CPP}) + private static class IteratorJNI { + static { + NativeDB.LIBRARY.load(); + } + + @JniMethod(flags={CPP_DELETE}) + public static final native void delete( + long self + ); + + @JniMethod(flags={CPP_METHOD}) + static final native boolean Valid( + long self + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void SeekToFirst( + long self + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void SeekToLast( + long self + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void Seek( + long self, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice target + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void Next( + long self + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void Prev( + long self + ); + + @JniMethod(copy="leveldb::Slice", flags={CPP_METHOD}) + static final native long key( + long self + ); + + @JniMethod(copy="leveldb::Slice", flags={CPP_METHOD}) + static final native long value( + long self + ); + + @JniMethod(copy="leveldb::Status", flags={CPP_METHOD}) + static final native long status( + long self + ); + } + + NativeIterator(long self) { + super(self); + } + + public void delete() { + assertAllocated(); + IteratorJNI.delete(self); + self = 0; + } + + public boolean isValid() { + assertAllocated(); + return IteratorJNI.Valid(self); + } + + private void checkStatus() throws NativeDB.DBException { + NativeDB.checkStatus(IteratorJNI.status(self)); + } + + public void seekToFirst() { + assertAllocated(); + IteratorJNI.SeekToFirst(self); + } + + public void seekToLast() { + assertAllocated(); + IteratorJNI.SeekToLast(self); + } + + public void seek(byte[] key) throws NativeDB.DBException { + NativeDB.checkArgNotNull(key, "key"); + NativeBuffer keyBuffer = NativeBuffer.create(key); + try { + seek(keyBuffer); + } finally { + keyBuffer.delete(); + } + } + + private void seek(NativeBuffer keyBuffer) throws NativeDB.DBException { + seek(new NativeSlice(keyBuffer)); + } + + private void seek(NativeSlice keySlice) throws NativeDB.DBException { + assertAllocated(); + IteratorJNI.Seek(self, keySlice); + checkStatus(); + } + + public void next() throws NativeDB.DBException { + assertAllocated(); + IteratorJNI.Next(self); + checkStatus(); + } + + public void prev() throws NativeDB.DBException { + assertAllocated(); + IteratorJNI.Prev(self); + checkStatus(); + } + + public byte[] key() throws NativeDB.DBException { + assertAllocated(); + long slice_ptr = IteratorJNI.key(self); + checkStatus(); + try { + NativeSlice slice = new NativeSlice(); + slice.read(slice_ptr, 0); + return slice.toByteArray(); + } finally { + NativeSlice.SliceJNI.delete(slice_ptr); + } + } + + public byte[] value() throws NativeDB.DBException { + assertAllocated(); + long slice_ptr = IteratorJNI.value(self); + checkStatus(); + try { + NativeSlice slice = new NativeSlice(); + slice.read(slice_ptr, 0); + return slice.toByteArray(); + } finally { + NativeSlice.SliceJNI.delete(slice_ptr); + } + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeLogger.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeLogger.java new file mode 100644 index 000000000..10f83e44a --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeLogger.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniArg; +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniField; +import org.fusesource.hawtjni.runtime.JniMethod; + +import static org.fusesource.hawtjni.runtime.ArgFlag.CRITICAL; +import static org.fusesource.hawtjni.runtime.ArgFlag.NO_OUT; +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.ClassFlag.STRUCT; +import static org.fusesource.hawtjni.runtime.FieldFlag.CONSTANT; +import static org.fusesource.hawtjni.runtime.FieldFlag.POINTER_FIELD; +import static org.fusesource.hawtjni.runtime.MethodFlag.*; + +/** + *

+ * Provides a java interface to the C++ leveldb::Logger class. + *

+ * + * @author Hiram Chirino + */ +public abstract class NativeLogger extends NativeObject { + + @JniClass(name="JNILogger", flags={STRUCT, CPP}) + static public class LoggerJNI { + + static { + NativeDB.LIBRARY.load(); + init(); + } + + @JniMethod(flags={CPP_NEW}) + public static final native long create(); + + @JniMethod(flags={CPP_DELETE}) + public static final native void delete( + long self + ); + + public static final native void memmove ( + @JniArg(cast="void *") long dest, + @JniArg(cast="const void *", flags={NO_OUT, CRITICAL}) LoggerJNI src, + @JniArg(cast="size_t") long size); + + @JniField(cast="jobject", flags={POINTER_FIELD}) + long target; + + @JniField(cast="jmethodID", flags={POINTER_FIELD}) + long log_method; + + @JniMethod(flags={CONSTANT_INITIALIZER}) + private static final native void init(); + + @JniField(flags={CONSTANT}, accessor="sizeof(struct JNILogger)") + static int SIZEOF; + } + + private long globalRef; + + public NativeLogger() { + super(LoggerJNI.create()); + try { + globalRef = NativeDB.DBJNI.NewGlobalRef(this); + if( globalRef==0 ) { + throw new RuntimeException("jni call failed: NewGlobalRef"); + } + LoggerJNI struct = new LoggerJNI(); + struct.log_method = NativeDB.DBJNI.GetMethodID(this.getClass(), "log", "(Ljava/lang/String;)V"); + if( struct.log_method ==0 ) { + throw new RuntimeException("jni call failed: GetMethodID"); + } + struct.target = globalRef; + LoggerJNI.memmove(self, struct, LoggerJNI.SIZEOF); + + } catch (RuntimeException e) { + delete(); + throw e; + } + } + + NativeLogger(long ptr) { + super(ptr); + } + + public void delete() { + if( globalRef!=0 ) { + NativeDB.DBJNI.DeleteGlobalRef(globalRef); + globalRef = 0; + } + } + + public abstract void log(String message); + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeObject.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeObject.java new file mode 100644 index 000000000..af2fb84ae --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeObject.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +/** + * 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() { + return self; + } + + public boolean isAllocated() { + return self !=0; + } + + protected void assertAllocated() { + assert isAllocated() : "This object has been deleted"; + } + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeOptions.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeOptions.java new file mode 100644 index 000000000..71ce0e29d --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeOptions.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniField; +import org.fusesource.hawtjni.runtime.JniMethod; + +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.ClassFlag.STRUCT; +import static org.fusesource.hawtjni.runtime.FieldFlag.CONSTANT; +import static org.fusesource.hawtjni.runtime.FieldFlag.FIELD_SKIP; +import static org.fusesource.hawtjni.runtime.MethodFlag.CONSTANT_INITIALIZER; + +/** + * Provides a java interface to the C++ leveldb::Options class. + * + * @author Hiram Chirino + */ +@JniClass(name="leveldb::Options", flags={STRUCT, CPP}) +public class NativeOptions { + + static { + NativeDB.LIBRARY.load(); + init(); + } + + @JniMethod(flags={CONSTANT_INITIALIZER}) + private static final native void init(); + + @JniField(flags={CONSTANT}, cast="Env*", accessor="leveldb::Env::Default()") + private static long DEFAULT_ENV; + + private boolean create_if_missing = false; + private boolean error_if_exists = false; + private boolean paranoid_checks = false; + @JniField(cast="size_t") + private long write_buffer_size = 4 << 20; + @JniField(cast="size_t") + private long block_size = 4086; + private int max_open_files = 1000; + private int block_restart_interval = 16; + + @JniField(flags={FIELD_SKIP}) + private NativeComparator comparatorObject = NativeComparator.BYTEWISE_COMPARATOR; + @JniField(cast="const leveldb::Comparator*") + private long comparator = comparatorObject.pointer(); + + @JniField(flags={FIELD_SKIP}) + private NativeLogger infoLogObject = null; + @JniField(cast="leveldb::Logger*") + private long info_log = 0; + + @JniField(cast="leveldb::Env*") + private long env = DEFAULT_ENV; + @JniField(cast="leveldb::Cache*") + private long block_cache = 0; + @JniField(flags={FIELD_SKIP}) + private NativeCache cache; + + @JniField(cast="leveldb::CompressionType") + private int compression = NativeCompressionType.kSnappyCompression.value; + + public NativeOptions createIfMissing(boolean value) { + this.create_if_missing = value; + return this; + } + public boolean createIfMissing() { + return create_if_missing; + } + + public NativeOptions errorIfExists(boolean value) { + this.error_if_exists = value; + return this; + } + public boolean errorIfExists() { + return error_if_exists; + } + + public NativeOptions paranoidChecks(boolean value) { + this.paranoid_checks = value; + return this; + } + public boolean paranoidChecks() { + return paranoid_checks; + } + + public NativeOptions writeBufferSize(long value) { + this.write_buffer_size = value; + return this; + } + public long writeBufferSize() { + return write_buffer_size; + } + + public NativeOptions maxOpenFiles(int value) { + this.max_open_files = value; + return this; + } + public int maxOpenFiles() { + return max_open_files; + } + + public NativeOptions blockRestartInterval(int value) { + this.block_restart_interval = value; + return this; + } + public int blockRestartInterval() { + return block_restart_interval; + } + + public NativeOptions blockSize(long value) { + this.block_size = value; + return this; + } + public long blockSize() { + return block_size; + } + +// @JniField(cast="Env*") +// private long env = DEFAULT_ENV; + + public NativeComparator comparator() { + return comparatorObject; + } + + public NativeOptions comparator(NativeComparator comparator) { + if( comparator==null ) { + throw new IllegalArgumentException("comparator cannot be null"); + } + this.comparatorObject = comparator; + this.comparator = comparator.pointer(); + return this; + } + + public NativeLogger infoLog() { + return infoLogObject; + } + + public NativeOptions infoLog(NativeLogger logger) { + this.infoLogObject = logger; + if( logger ==null ) { + this.info_log = 0; + } else { + this.info_log = logger.pointer(); + } + return this; + } + + public NativeCompressionType compression() { + if(compression == NativeCompressionType.kNoCompression.value) { + return NativeCompressionType.kNoCompression; + } else if(compression == NativeCompressionType.kSnappyCompression.value) { + return NativeCompressionType.kSnappyCompression; + } else { + return NativeCompressionType.kSnappyCompression; + } + } + + public NativeOptions compression(NativeCompressionType compression) { + this.compression = compression.value; + return this; + } + + public NativeCache cache() { + return cache; + } + + public NativeOptions cache(NativeCache cache) { + this.cache = cache; + if( cache!=null ) { + this.block_cache = cache.pointer(); + } else { + this.block_cache = 0; + } + return this; + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeRange.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeRange.java new file mode 100644 index 000000000..953d37e78 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeRange.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.*; + +import static org.fusesource.hawtjni.runtime.ArgFlag.*; +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.ClassFlag.STRUCT; +import static org.fusesource.hawtjni.runtime.FieldFlag.CONSTANT; +import static org.fusesource.hawtjni.runtime.FieldFlag.FIELD_SKIP; +import static org.fusesource.hawtjni.runtime.MethodFlag.CONSTANT_INITIALIZER; + +/** + * Provides a java interface to the C++ leveldb::ReadOptions class. + * + * @author Hiram Chirino + */ +public class NativeRange { + + @JniClass(name="leveldb::Range", flags={STRUCT, CPP}) + static public class RangeJNI { + + static { + NativeDB.LIBRARY.load(); + init(); + } + + public static final native void memmove ( + @JniArg(cast="void *") long dest, + @JniArg(cast="const void *", flags={NO_OUT, CRITICAL}) RangeJNI src, + @JniArg(cast="size_t") long size); + + public static final native void memmove ( + @JniArg(cast="void *", flags={NO_IN, CRITICAL}) RangeJNI dest, + @JniArg(cast="const void *") long src, + @JniArg(cast="size_t") long size); + + + @JniMethod(flags={CONSTANT_INITIALIZER}) + private static final native void init(); + + @JniField(flags={CONSTANT}, accessor="sizeof(struct leveldb::Range)") + static int SIZEOF; + + @JniField + NativeSlice start = new NativeSlice(); + @JniField(flags={FIELD_SKIP}) + NativeBuffer start_buffer; + + @JniField + NativeSlice limit = new NativeSlice(); + @JniField(flags={FIELD_SKIP}) + NativeBuffer limit_buffer; + + public RangeJNI(NativeRange range) { + start_buffer = NativeBuffer.create(range.start()); + start.set(start_buffer); + try { + limit_buffer = NativeBuffer.create(range.limit()); + } catch (OutOfMemoryError e) { + start_buffer.delete(); + throw e; + } + limit.set(limit_buffer); + } + + public void delete() { + start_buffer.delete(); + limit_buffer.delete(); + } + + static NativeBuffer arrayCreate(int dimension) { + return NativeBuffer.create(dimension*SIZEOF); + } + + void arrayWrite(long buffer, int index) { + RangeJNI.memmove(PointerMath.add(buffer, SIZEOF * index), this, SIZEOF); + } + + void arrayRead(long buffer, int index) { + RangeJNI.memmove(this, PointerMath.add(buffer, SIZEOF * index), SIZEOF); + } + + } + + final private byte[] start; + final private byte[] limit; + + public byte[] limit() { + return limit; + } + + public byte[] start() { + return start; + } + + public NativeRange(byte[] start, byte[] limit) { + NativeDB.checkArgNotNull(start, "start"); + NativeDB.checkArgNotNull(limit, "limit"); + this.limit = limit; + this.start = start; + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeReadOptions.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeReadOptions.java new file mode 100644 index 000000000..85e76a3dd --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeReadOptions.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniField; + +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.ClassFlag.STRUCT; + +/** + * Provides a java interface to the C++ leveldb::ReadOptions class. + * + * @author Hiram Chirino + */ +@JniClass(name="leveldb::ReadOptions", flags={STRUCT, CPP}) +public class NativeReadOptions { + + @JniField + private boolean verify_checksums = false; + + @JniField + private boolean fill_cache = true; + + @JniField(cast="const leveldb::Snapshot*") + private long snapshot=0; + + public boolean fillCache() { + return fill_cache; + } + + public NativeReadOptions fillCache(boolean fill_cache) { + this.fill_cache = fill_cache; + return this; + } + + public NativeSnapshot snapshot() { + if( snapshot == 0 ) { + return null; + } else { + return new NativeSnapshot(snapshot); + } + } + + public NativeReadOptions snapshot(NativeSnapshot snapshot) { + if( snapshot==null ) { + this.snapshot = 0; + } else { + this.snapshot = snapshot.pointer(); + } + return this; + } + + public boolean verifyChecksums() { + return verify_checksums; + } + + public NativeReadOptions verifyChecksums(boolean verify_checksums) { + this.verify_checksums = verify_checksums; + return this; + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeSlice.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeSlice.java new file mode 100644 index 000000000..a2e2d60b5 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeSlice.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.*; + +import static org.fusesource.hawtjni.runtime.ArgFlag.*; +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.ClassFlag.STRUCT; +import static org.fusesource.hawtjni.runtime.FieldFlag.CONSTANT; +import static org.fusesource.hawtjni.runtime.MethodFlag.CONSTANT_INITIALIZER; +import static org.fusesource.hawtjni.runtime.MethodFlag.CPP_DELETE; + +/** + * Provides a java interface to the C++ leveldb::Slice class. + * + * @author Hiram Chirino + */ +@JniClass(name="leveldb::Slice", flags={STRUCT, CPP}) +class NativeSlice { + + @JniClass(name="leveldb::Slice", flags={CPP}) + static class SliceJNI { + static { + NativeDB.LIBRARY.load(); + init(); + } + + @JniMethod(flags={CPP_DELETE}) + public static final native void delete( + long self + ); + + public static final native void memmove ( + @JniArg(cast="void *") long dest, + @JniArg(cast="const void *", flags={NO_OUT, CRITICAL}) NativeSlice src, + @JniArg(cast="size_t") long size); + + public static final native void memmove ( + @JniArg(cast="void *", flags={NO_IN, CRITICAL}) NativeSlice dest, + @JniArg(cast="const void *") long src, + @JniArg(cast="size_t") long size); + + + @JniMethod(flags={CONSTANT_INITIALIZER}) + private static final native void init(); + + @JniField(flags={CONSTANT}, accessor="sizeof(struct leveldb::Slice)") + static int SIZEOF; + + } + + + @JniField(cast="const char*") + private long data_; + @JniField(cast="size_t") + private long size_; + + public NativeSlice() { + } + + public NativeSlice(long data, long length) { + this.data_ = data; + this.size_ = length; + } + + public NativeSlice(NativeBuffer buffer) { + this(buffer.pointer(), buffer.capacity()); + } + + public static NativeSlice create(NativeBuffer buffer) { + if(buffer == null ) { + return null; + } else { + return new NativeSlice(buffer); + } + } + + public long data() { + return data_; + } + + public NativeSlice data(long data) { + this.data_ = data; + return this; + } + + public long size() { + return size_; + } + + public NativeSlice size(long size) { + this.size_ = size; + return this; + } + + public NativeSlice set(NativeSlice buffer) { + this.size_ = buffer.size_; + this.data_ = buffer.data_; + return this; + } + + public NativeSlice set(NativeBuffer buffer) { + this.size_ = buffer.capacity(); + this.data_ = buffer.pointer(); + return this; + } + + public byte[] toByteArray() { + if( size_ > Integer.MAX_VALUE ) { + throw new ArrayIndexOutOfBoundsException("Native slice is larger than the maximum Java array"); + } + byte []rc = new byte[(int) size_]; + NativeBuffer.NativeBufferJNI.buffer_copy(data_, 0, rc, 0, rc.length); + return rc; + } + + static NativeBuffer arrayCreate(int dimension) { + return NativeBuffer.create(dimension*SliceJNI.SIZEOF); + } + + void write(long buffer, int index) { + SliceJNI.memmove(PointerMath.add(buffer, SliceJNI.SIZEOF*index), this, SliceJNI.SIZEOF); + } + + void read(long buffer, int index) { + SliceJNI.memmove(this, PointerMath.add(buffer, SliceJNI.SIZEOF*index), SliceJNI.SIZEOF); + } + + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeSnapshot.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeSnapshot.java new file mode 100644 index 000000000..69403e198 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeSnapshot.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +/** + * Provides a java interface to the C++ leveldb::Snapshot class. + * + * @author Hiram Chirino + */ +public class NativeSnapshot extends NativeObject { + + NativeSnapshot(long self) { + super(self); + } + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeStatus.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeStatus.java new file mode 100644 index 000000000..2950066b9 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeStatus.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniMethod; + +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.MethodFlag.CPP_DELETE; +import static org.fusesource.hawtjni.runtime.MethodFlag.CPP_METHOD; + +/** + * Provides a java interface to the C++ leveldb::Status class. + * + * @author Hiram Chirino + */ +class NativeStatus extends NativeObject{ + + @JniClass(name="leveldb::Status", flags={CPP}) + static class StatusJNI { + static { + NativeDB.LIBRARY.load(); + } + + @JniMethod(flags={CPP_DELETE}) + public static final native void delete( + long self); + + @JniMethod(flags={CPP_METHOD}) + public static final native boolean ok( + long self); + + @JniMethod(flags={CPP_METHOD}) + public static final native boolean IsNotFound( + long self); + + @JniMethod(copy="std::string", flags={CPP_METHOD}) + public static final native long ToString( + long self); + } + + public NativeStatus(long self) { + super(self); + } + + public void delete() { + assertAllocated(); + StatusJNI.delete(self); + self = 0; + } + + public boolean isOk() { + assertAllocated(); + return StatusJNI.ok(self); + } + + public boolean isNotFound() { + assertAllocated(); + return StatusJNI.IsNotFound(self); + } + + public String toString() { + assertAllocated(); + long strptr = StatusJNI.ToString(self); + if( strptr==0 ) { + return null; + } else { + NativeStdString rc = new NativeStdString(strptr); + try { + return rc.toString(); + } finally { + rc.delete(); + } + } + } + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeStdString.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeStdString.java new file mode 100644 index 000000000..85a51c2b2 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeStdString.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniMethod; + +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.MethodFlag.*; + +/** + * Provides a java interface to the C++ std::string class. + * + * @author Hiram Chirino + */ +class NativeStdString extends NativeObject { + + @JniClass(name="std::string", flags={CPP}) + private static class StdStringJNI { + static { + NativeDB.LIBRARY.load(); + } + + @JniMethod(flags={CPP_NEW}) + public static final native long create(); + + @JniMethod(flags={CPP_NEW}) + public static final native long create(String value); + + @JniMethod(flags={CPP_DELETE}) + static final native void delete( + long self); + + @JniMethod(flags={CPP_METHOD}, accessor = "c_str", cast="const char*") + public static final native long c_str_ptr ( + long self); + + @JniMethod(flags={CPP_METHOD},cast = "size_t") + public static final native long length ( + long self); + + } + + public NativeStdString(long self) { + super(self); + } + + public NativeStdString() { + super(StdStringJNI.create()); + } + + public void delete() { + assertAllocated(); + StdStringJNI.delete(self); + self = 0; + } + + public String toString() { + return new String(toByteArray()); + } + + public long length() { + assertAllocated(); + return StdStringJNI.length(self); + } + + public byte[] toByteArray() { + long l = length(); + if( l > Integer.MAX_VALUE ) { + throw new ArrayIndexOutOfBoundsException("Native string is larger than the maximum Java array"); + } + byte []rc = new byte[(int) l]; + NativeBuffer.NativeBufferJNI.buffer_copy(StdStringJNI.c_str_ptr(self), 0, rc, 0, rc.length); + return rc; + } +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeWriteBatch.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeWriteBatch.java new file mode 100644 index 000000000..bac8f21f3 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeWriteBatch.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniArg; +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniMethod; + +import static org.fusesource.hawtjni.runtime.ArgFlag.BY_VALUE; +import static org.fusesource.hawtjni.runtime.ArgFlag.NO_OUT; +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.MethodFlag.*; + +/** + * Provides a java interface to the C++ leveldb::WriteBatch class. + * + * @author Hiram Chirino + */ +public class NativeWriteBatch extends NativeObject { + + @JniClass(name="leveldb::WriteBatch", flags={CPP}) + private static class WriteBatchJNI { + static { + NativeDB.LIBRARY.load(); + } + + @JniMethod(flags={CPP_NEW}) + public static final native long create(); + @JniMethod(flags={CPP_DELETE}) + public static final native void delete( + long self); + + @JniMethod(flags={CPP_METHOD}) + static final native void Put( + long self, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice key, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice value + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void Delete( + long self, + @JniArg(flags={BY_VALUE, NO_OUT}) NativeSlice key + ); + + @JniMethod(flags={CPP_METHOD}) + static final native void Clear( + long self + ); + + } + + public NativeWriteBatch() { + super(WriteBatchJNI.create()); + } + + public void delete() { + assertAllocated(); + WriteBatchJNI.delete(self); + self = 0; + } + + public void put(byte[] key, byte[] value) { + NativeDB.checkArgNotNull(key, "key"); + NativeDB.checkArgNotNull(value, "value"); + NativeBuffer keyBuffer = NativeBuffer.create(key); + try { + NativeBuffer valueBuffer = NativeBuffer.create(value); + try { + put(keyBuffer, valueBuffer); + } finally { + valueBuffer.delete(); + } + } finally { + keyBuffer.delete(); + } + } + + private void put(NativeBuffer keyBuffer, NativeBuffer valueBuffer) { + put(new NativeSlice(keyBuffer), new NativeSlice(valueBuffer)); + } + + private void put(NativeSlice keySlice, NativeSlice valueSlice) { + assertAllocated(); + WriteBatchJNI.Put(self, keySlice, valueSlice); + } + + + public void delete(byte[] key) { + NativeDB.checkArgNotNull(key, "key"); + NativeBuffer keyBuffer = NativeBuffer.create(key); + try { + delete(keyBuffer); + } finally { + keyBuffer.delete(); + } + } + + private void delete(NativeBuffer keyBuffer) { + delete(new NativeSlice(keyBuffer)); + } + + private void delete(NativeSlice keySlice) { + assertAllocated(); + WriteBatchJNI.Delete(self, keySlice); + } + + public void clear() { + assertAllocated(); + WriteBatchJNI.Clear(self); + } + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeWriteOptions.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeWriteOptions.java new file mode 100644 index 000000000..81c76fea1 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/NativeWriteOptions.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniField; + +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.ClassFlag.STRUCT; + +/** + * Provides a java interface to the C++ leveldb::WriteOptions class. + * + * @author Hiram Chirino + */ +@JniClass(name="leveldb::WriteOptions", flags={STRUCT, CPP}) +public class NativeWriteOptions { + + @JniField + boolean sync; + + public boolean sync() { + return sync; + } + + public NativeWriteOptions sync(boolean sync) { + this.sync = sync; + return this; + } + +} diff --git a/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/Util.java b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/Util.java new file mode 100644 index 000000000..55258ad4f --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/java/org/fusesource/leveldbjni/internal/Util.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.internal; + +import org.fusesource.hawtjni.runtime.JniArg; +import org.fusesource.hawtjni.runtime.JniClass; +import org.fusesource.hawtjni.runtime.JniField; +import org.fusesource.hawtjni.runtime.JniMethod; + +import java.io.File; +import java.io.IOException; + +import static org.fusesource.hawtjni.runtime.ClassFlag.CPP; +import static org.fusesource.hawtjni.runtime.FieldFlag.CONSTANT; +import static org.fusesource.hawtjni.runtime.MethodFlag.*; +import static org.fusesource.hawtjni.runtime.ArgFlag.*; + +/** + * Some miscellaneous utility functions. + * + * @author Hiram Chirino + */ +public class Util { + + @JniClass(name="leveldb::Env", flags={CPP}) + static class EnvJNI { + + static { + NativeDB.LIBRARY.load(); + } + + @JniMethod(cast = "leveldb::Env *", accessor = "leveldb::Env::Default") + public static final native long Default(); + + @JniMethod(flags = {CPP_METHOD}) + public static final native void Schedule( + long self, + @JniArg(cast = "void (*)(void*)") long fp, + @JniArg(cast = "void *") long arg); + + } + + @JniClass(flags={CPP}) + static class UtilJNI { + + static { + NativeDB.LIBRARY.load(); + init(); + } + + @JniMethod(flags={CONSTANT_INITIALIZER}) + private static final native void init(); + + @JniField(flags={CONSTANT}, accessor="1", conditional="defined(_WIN32) || defined(_WIN64)") + static int ON_WINDOWS; + + + @JniMethod(conditional="!defined(_WIN32) && !defined(_WIN64)") + static final native int link( + @JniArg(cast="const char*") String source, + @JniArg(cast="const char*") String target); + + @JniMethod(conditional="defined(_WIN32) || defined(_WIN64)") + static final native int CreateHardLinkW( + @JniArg(cast="LPCTSTR", flags={POINTER_ARG, UNICODE}) String target, + @JniArg(cast="LPCTSTR", flags={POINTER_ARG, UNICODE}) String source, + @JniArg(cast="LPSECURITY_ATTRIBUTES", flags={POINTER_ARG}) long lpSecurityAttributes); + + @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); + + } + + /** + * Creates a hard link from source to target. + * @param source + * @param target + * @return + */ + public static void link(File source, File target) throws IOException { + if( UtilJNI.ON_WINDOWS == 1 ) { + if( UtilJNI.CreateHardLinkW(target.getCanonicalPath(), source.getCanonicalPath(), 0) == 0) { + throw new IOException("link failed"); + } + } else { + if( UtilJNI.link(source.getCanonicalPath(), target.getCanonicalPath()) != 0 ) { + throw new IOException("link failed: "+strerror()); + } + } + } + + static int errno() { + return UtilJNI.errno(); + } + + static String strerror() { + return string(UtilJNI.strerror(errno())); + } + + static String string(long ptr) { + if( ptr == 0 ) + return null; + return new String(new NativeSlice(ptr, UtilJNI.strlen(ptr)).toByteArray()); + } + +} diff --git a/java/leveldbjni/leveldbjni/src/main/native-package/license.txt b/java/leveldbjni/leveldbjni/src/main/native-package/license.txt new file mode 100644 index 000000000..8edd37590 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/native-package/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2011 FuseSource Corp. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of FuseSource Corp. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/java/leveldbjni/leveldbjni/src/main/native-package/m4/custom.m4 b/java/leveldbjni/leveldbjni/src/main/native-package/m4/custom.m4 new file mode 100644 index 000000000..f29e5805c --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/native-package/m4/custom.m4 @@ -0,0 +1,63 @@ +dnl --------------------------------------------------------------------------- +dnl Copyright (C) 2011, FuseSource Corp. All rights reserved. +dnl +dnl http://fusesource.com +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that the following conditions are +dnl met: +dnl +dnl * Redistributions of source code must retain the above copyright +dnl notice, this list of conditions and the following disclaimer. +dnl * Redistributions in binary form must reproduce the above +dnl copyright notice, this list of conditions and the following disclaimer +dnl in the documentation and/or other materials provided with the +dnl distribution. +dnl * Neither the name of FuseSource Corp. nor the names of its +dnl contributors may be used to endorse or promote products derived from +dnl this software without specific prior written permission. +dnl +dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +dnl "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +dnl OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +dnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +dnl LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +dnl DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +dnl THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +dnl (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +dnl OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +dnl --------------------------------------------------------------------------- + +AC_DEFUN([CUSTOM_M4_SETUP], +[ + AC_LANG_PUSH(C++) + + AC_CHECK_HEADER([pthread.h],[AC_DEFINE([HAVE_PTHREAD_H], [1], [Define to 1 if you have the header file.])]) + + AC_ARG_WITH([leveldb], + [AS_HELP_STRING([--with-leveldb@<:@=PATH@:>@], + [Directory where leveldb was built. Example: --with-leveldb=/opt/leveldb])], + [ + CFLAGS="$CFLAGS -I${withval}/include" + CXXFLAGS="$CXXFLAGS -I${withval}/include" + AC_SUBST(CXXFLAGS) + LDFLAGS="$LDFLAGS -lleveldb -L${withval}" + AC_SUBST(LDFLAGS) + ]) + + AC_CHECK_HEADER([leveldb/db.h],,AC_MSG_ERROR([cannot find headers for leveldb])) + + AC_ARG_WITH([snappy], + [AS_HELP_STRING([--with-snappy@<:@=PATH@:>@], + [Directory where snappy was built. Example: --with-snappy=/opt/snappy])], + [ + LDFLAGS="$LDFLAGS -lsnappy -L${withval}" + AC_SUBST(LDFLAGS) + ]) + + AC_CHECK_HEADER([sys/errno.h],[AC_DEFINE([HAVE_SYS_ERRNO_H], [1], [Define to 1 if you have the header file.])]) + + AC_LANG_POP() +]) \ No newline at end of file diff --git a/java/leveldbjni/leveldbjni/src/main/native-package/src/buffer.c b/java/leveldbjni/leveldbjni/src/main/native-package/src/buffer.c new file mode 100644 index 000000000..c2beaf288 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/native-package/src/buffer.c @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *******************************************************************************/ +#include "leveldbjni.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/java/leveldbjni/leveldbjni/src/main/native-package/src/leveldbjni.h b/java/leveldbjni/leveldbjni/src/main/native-package/src/leveldbjni.h new file mode 100755 index 000000000..977405125 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/native-package/src/leveldbjni.h @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *******************************************************************************/ +#ifndef LEVELDBJNI_H +#define LEVELDBJNI_H + +#ifdef HAVE_CONFIG_H + /* configure based build.. we will use what it discovered about the platform */ + #include "config.h" +#else + #if defined(_WIN32) || defined(_WIN64) + /* Windows based build */ + #define HAVE_STDLIB_H 1 + #define HAVE_STRINGS_H 1 + #include + #endif +#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 + +#ifdef __cplusplus + +#include "leveldb/db.h" +#include "leveldb/options.h" +#include "leveldb/write_batch.h" +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/slice.h" + +struct JNIComparator : public leveldb::Comparator { + jobject target; + jmethodID compare_method; + const char *name; + + int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const { + JNIEnv *env; + if ( hawtjni_attach_thread(&env, "leveldb") ) { + return 0; + } + int rc = env->CallIntMethod(target, compare_method, (jlong)(intptr_t)&a, (jlong)(intptr_t)&b); + hawtjni_detach_thread(); + return rc; + } + + const char* Name() const { + return name; + } + + void FindShortestSeparator(std::string*, const leveldb::Slice&) const { } + void FindShortSuccessor(std::string*) const { } +}; + +struct JNILogger : public leveldb::Logger { + jobject target; + jmethodID log_method; + + void Logv(const char* format, va_list ap) { + JNIEnv *env; + if ( hawtjni_attach_thread(&env, "leveldb") ) { + return; + } + + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), format, ap); + + jstring message = env->NewStringUTF(buffer); + if( message ) { + env->CallVoidMethod(target, log_method, message); + env->DeleteLocalRef(message); + } + + if (env->ExceptionOccurred() ) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + hawtjni_detach_thread(); + } + +}; + +#endif + + +#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 /* LEVELDBJNI_H */ diff --git a/java/leveldbjni/leveldbjni/src/main/native-package/vs2010.vcxproj b/java/leveldbjni/leveldbjni/src/main/native-package/vs2010.vcxproj new file mode 100755 index 000000000..3c59b4a8e --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/native-package/vs2010.vcxproj @@ -0,0 +1,194 @@ + + + + + + debug + Win32 + + + debug + x64 + + + release + Win32 + + + release + x64 + + + + leveldbjni + leveldbjni + + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(ProjectDir)/target/$(Platform)-$(Configuration)/lib\ + $(ProjectDir)/target/$(Platform)-$(Configuration)/obj\ + false + $(ProjectDir)/target/$(Platform)-$(Configuration)/lib\ + $(ProjectDir)/target/$(Platform)-$(Configuration)/obj\ + false + $(ProjectDir)/target/$(Platform)-$(Configuration)/lib\ + $(ProjectDir)/target/$(Platform)-$(Configuration)/obj\ + true + $(ProjectDir)/target/$(Platform)-$(Configuration)/lib\ + $(ProjectDir)/target/$(Platform)-$(Configuration)/obj\ + true + + + + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\src\windows;%(AdditionalIncludeDirectories) + MaxSpeed + true + Speed + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + MultiThreadedDLL + true + false + + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\src\windows;%(AdditionalIncludeDirectories) + MaxSpeed + true + Speed + WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + MultiThreadedDLL + true + false + + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX64 + + + + + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\src\windows;%(AdditionalIncludeDirectories) + Disabled + Speed + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + MultiThreadedDebugDLL + false + + + Level3 + EditAndContinue + + + true + Windows + MachineX86 + + + + + $(JAVA_HOME)\include;$(JAVA_HOME)\include\win32;$(ProjectDir)\src\windows;%(AdditionalIncludeDirectories) + Disabled + Speed + WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + MultiThreadedDebugDLL + false + + + Level3 + EditAndContinue + + + true + Windows + MachineX64 + + + + + + + + + + + + SNAPPY;LEVELDB_PLATFORM_WINDOWS;OS_WIN;%(PreprocessorDefinitions) + $(LEVELDB_HOME);$(LEVELDB_HOME)\include;$(LEVELDB_HOME)\port\win;$(SNAPPY_HOME);%(AdditionalIncludeDirectories) + + + + + shlwapi.lib;$(LEVELDB_HOME)\Release\leveldb.lib;%(AdditionalDependencies) + + + + + shlwapi.lib;$(LEVELDB_HOME)\x64\Release\leveldb.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/java/leveldbjni/leveldbjni/src/main/resources/org/fusesource/leveldbjni/version.txt b/java/leveldbjni/leveldbjni/src/main/resources/org/fusesource/leveldbjni/version.txt new file mode 100644 index 000000000..f2ab45c3b --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/main/resources/org/fusesource/leveldbjni/version.txt @@ -0,0 +1 @@ +${project.version} \ No newline at end of file diff --git a/java/leveldbjni/leveldbjni/src/test/java/org/fusesource/leveldbjni/test/DBTest.java b/java/leveldbjni/leveldbjni/src/test/java/org/fusesource/leveldbjni/test/DBTest.java new file mode 100644 index 000000000..dd6bd1d56 --- /dev/null +++ b/java/leveldbjni/leveldbjni/src/test/java/org/fusesource/leveldbjni/test/DBTest.java @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2011, FuseSource Corp. All rights reserved. + * + * http://fusesource.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of FuseSource Corp. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.fusesource.leveldbjni.test; + +import junit.framework.TestCase; +import org.fusesource.leveldbjni.JniDBFactory; +import org.fusesource.leveldbjni.internal.JniDB; +import org.iq80.leveldb.*; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +import static org.fusesource.leveldbjni.JniDBFactory.asString; +import static org.fusesource.leveldbjni.JniDBFactory.bytes; + +/** + * A Unit test for the DB class implementation. + * + * @author Hiram Chirino + */ +public class DBTest extends TestCase { + DBFactory factory = JniDBFactory.factory; + + File getTestDirectory(String name) throws IOException { + File rc = new File(new File("test-data"), name); + factory.destroy(rc, new Options().createIfMissing(true)); + rc.mkdirs(); + return rc; + } + + @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 testRepair() throws IOException, DBException { + testCRUD(); + factory.repair(new File(new File("test-data"), getName()), new Options()); + } + + @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("Tampa"), bytes("green")); + db.put(bytes("London"), bytes("red")); + db.put(bytes("New York"), bytes("blue")); + + 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(); + } + + @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(); + } + + @Test + public void testApproximateSizes() throws IOException, DBException { + Options options = new Options().createIfMissing(true); + + File path = getTestDirectory(getName()); + DB db = factory.open(path, options); + + Random r = new Random(0); + String data=""; + for(int i=0; i < 1024; i++) { + data+= 'a'+r.nextInt(26); + } + for(int i=0; i < 5*1024; i++) { + db.put(bytes("row"+i), bytes(data)); + } + + long[] approximateSizes = db.getApproximateSizes(new Range(bytes("row"), bytes("s"))); + assertNotNull(approximateSizes); + assertEquals(1, approximateSizes.length); + assertTrue("Wrong size", approximateSizes[0] > 0); + + db.close(); + } + + @Test + public void testGetProperty() throws IOException, DBException { + Options options = new Options().createIfMissing(true); + + File path = getTestDirectory(getName()); + DB db = factory.open(path, options); + + Random r = new Random(0); + String data=""; + for(int i=0; i < 1024; i++) { + data+= 'a'+r.nextInt(26); + } + for(int i=0; i < 5*1024; i++) { + db.put(bytes("row"+i), bytes(data)); + } + + String stats = db.getProperty("leveldb.stats"); + assertNotNull(stats); + assertTrue(stats.contains("Compactions")); + + db.close(); + } + + @Test + public void testCustomComparator1() throws IOException, DBException { + Options options = new Options().createIfMissing(true); + options.comparator(new DBComparator() { + + public int compare(byte[] key1, byte[] key2) { + return new String(key1).compareTo(new String(key2)); + } + + public String name() { + return getName(); + } + + public byte[] findShortestSeparator(byte[] start, byte[] limit) { + return start; + } + + public byte[] findShortSuccessor(byte[] key) { + return key; + } + }); + + File path = getTestDirectory(getName()); + DB db = factory.open(path, options); + + ArrayList expecting = new ArrayList(); + for(int i=0; i < 26; i++) { + String t = ""+ ((char) ('a' + i)); + expecting.add(t); + db.put(bytes(t), bytes(t)); + } + + 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(); + } + + @Test + public void testCustomComparator2() throws IOException, DBException { + Options options = new Options().createIfMissing(true); + options.comparator(new DBComparator() { + + public int compare(byte[] key1, byte[] key2) { + return new String(key1).compareTo(new String(key2)) * -1; + } + + public String name() { + return getName(); + } + + public byte[] findShortestSeparator(byte[] start, byte[] limit) { + return start; + } + + public byte[] findShortSuccessor(byte[] key) { + return key; + } + }); + + File path = getTestDirectory(getName()); + DB db = factory.open(path, options); + + ArrayList expecting = new ArrayList(); + for(int i=0; i < 26; i++) { + String t = ""+ ((char) ('a' + i)); + expecting.add(t); + db.put(bytes(t), bytes(t)); + } + Collections.reverse(expecting); + + 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(); + } + + @Test + public void testLogger() throws IOException, InterruptedException, DBException { + final List messages = Collections.synchronizedList(new ArrayList()); + + Options options = new Options().createIfMissing(true); + options.logger(new Logger() { + public void log(String message) { + messages.add(message); + } + }); + + File path = getTestDirectory(getName()); + DB db = factory.open(path, options); + + for( int j=0; j < 5; j++) { + Random r = new Random(0); + String data=""; + for(int i=0; i < 1024; i++) { + data+= 'a'+r.nextInt(26); + } + for(int i=0; i < 5*1024; i++) { + db.put(bytes("row"+i), bytes(data)); + } + Thread.sleep(100); + } + + db.close(); + + assertFalse(messages.isEmpty()); + + } + + @Test + public void testCompactRanges() throws IOException, InterruptedException, DBException { + Options options = new Options().createIfMissing(true); + File path = getTestDirectory(getName()); + DB db = factory.open(path, options); + if( db instanceof JniDB) { + Random r = new Random(0); + String data=""; + for(int i=0; i < 1024; i++) { + data+= 'a'+r.nextInt(26); + } + for(int i=0; i < 5*1024; i++) { + db.put(bytes("row"+i), bytes(data)); + } + for(int i=0; i < 5*1024; i++) { + db.delete(bytes("row" + i)); + } + + String stats = db.getProperty("leveldb.stats"); + System.out.println(stats); + + // Compactions + // Level Files Size(MB) Time(sec) Read(MB) Write(MB) + // -------------------------------------------------- + assertFalse(stats.contains("1 0 0 0")); + assertFalse(stats.contains("2 0 0 0")); + + // After the compaction, level 1 and 2 should not have any files in it.. + ((JniDB) db).compactRange(null, null); + + stats = db.getProperty("leveldb.stats"); + System.out.println(stats); + assertTrue(stats.contains("1 0 0 0")); + assertTrue(stats.contains("2 0 0 0")); + + } + db.close(); + } + + public void assertEquals(byte[] arg1, byte[] arg2) { + assertTrue(Arrays.equals(arg1, arg2)); + } +} diff --git a/java/leveldbjni/license.txt b/java/leveldbjni/license.txt new file mode 100644 index 000000000..8edd37590 --- /dev/null +++ b/java/leveldbjni/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2011 FuseSource Corp. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of FuseSource Corp. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/java/leveldbjni/pom.xml b/java/leveldbjni/pom.xml new file mode 100755 index 000000000..a88f3c5b9 --- /dev/null +++ b/java/leveldbjni/pom.xml @@ -0,0 +1,303 @@ + + + + + 4.0.0 + + org.fusesource + fusesource-pom + 1.9 + + + org.fusesource.leveldbjni + leveldbjni-project + 99-master-SNAPSHOT + pom + + ${project.artifactId} + leveldbjni is a jni library for accessing leveldb. + + + leveldbjni + LEVELDBJNI + UTF-8 + 1.6 + 0.2 + + + + leveldbjni + + + http://${forge-project-id}.fusesource.org + 2009 + + + github + https://github.com/fusesource/leveldbjni/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 BSD 3-Clause License + http://www.opensource.org/licenses/BSD-3-Clause + repo + + + + + scm:git:git://github.com/fusesource/leveldbjni.git + scm:git:git@github.com:fusesource/leveldbjni.git + https://github.com/fusesource/leveldbjni + + + + + 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 + + leveldbjni-osx + leveldbjni-linux32 + leveldbjni-linux64 + leveldbjni-win32 + leveldbjni-win64 + leveldbjni-all + + + + + all + + leveldbjni-all + + + + osx + + leveldbjni-osx + + + + + linux32 + + leveldbjni-linux32 + + + + + linux64 + + leveldbjni-linux64 + + + + + win32 + + true + + + leveldbjni-win32 + + + + + win64 + + true + + + leveldbjni-win64 + + + + + diff --git a/java/leveldbjni/readme.md b/java/leveldbjni/readme.md new file mode 100644 index 000000000..b79d4911b --- /dev/null +++ b/java/leveldbjni/readme.md @@ -0,0 +1,242 @@ +# LevelDB JNI + +## Description + +LevelDB JNI gives you a Java interface to the +[LevelDB](http://code.google.com/p/leveldb/) C++ library +which is a fast key-value storage library written at Google +that provides an ordered mapping from string keys to string values.. + + +## Using as a Maven Dependency + +You just nee to add the following repositories and dependencies to your Maven pom. + + + + fusesource.nexus.snapshot + FuseSource Community Snapshot Repository + http://repo.fusesource.com/nexus/content/groups/public-snapshots + + + + + + org.fusesource.leveldbjni + leveldbjni-all + 1.1 + + + +## API Usage: + +Recommended Package imports: + + import org.iq80.leveldb.*; + import static org.fusesource.leveldbjni.JniDBFactory.*; + import java.io.*; + +Opening and closing the database. + + Options options = new Options(); + options.createIfMissing(true); + DB db = factory.open(new File("example"), options); + try { + // Use the db in here.... + } finally { + // Make sure you close the db to shutdown the + // database and avoid resource leaks. + db.close(); + } + +Putting, Getting, and Deleting key/values. + + db.put(bytes("Tampa"), bytes("rocks")); + String value = asString(db.get(bytes("Tampa"))); + db.delete(wo, bytes("Tampa")); + +Performing Batch/Bulk/Atomic Updates. + + WriteBatch batch = db.createWriteBatch(); + try { + batch.delete(bytes("Denver")); + batch.put(bytes("Tampa"), bytes("green")); + batch.put(bytes("London"), bytes("red")); + + db.write(batch); + } finally { + // Make sure you close the batch to avoid resource leaks. + batch.close(); + } + +Iterating key/values. + + DBIterator iterator = db.iterator(); + try { + for(iterator.seekToFirst(); iterator.hasNext(); iterator.next()) { + String key = asString(iterator.peekNext().getKey()); + String value = asString(iterator.peekNext().getValue()); + System.out.println(key+" = "+value); + } + } finally { + // Make sure you close the iterator to avoid resource leaks. + iterator.close(); + } + +Working against a Snapshot view of the Database. + + ReadOptions ro = new ReadOptions(); + ro.snapshot(db.getSnapshot()); + try { + + // All read operations will now use the same + // consistent view of the data. + ... = db.iterator(ro); + ... = db.get(bytes("Tampa"), ro); + + } finally { + // Make sure you close the snapshot to avoid resource leaks. + ro.snapshot().close(); + } + +Using a custom Comparator. + + DBComparator comparator = new DBComparator(){ + public int compare(byte[] key1, byte[] key2) { + return new String(key1).compareTo(new String(key2)); + } + public String name() { + return "simple"; + } + public byte[] findShortestSeparator(byte[] start, byte[] limit) { + return start; + } + public byte[] findShortSuccessor(byte[] key) { + return key; + } + }; + Options options = new Options(); + options.comparator(comparator); + DB db = factory.open(new File("example"), options); + +Disabling Compression + + Options options = new Options(); + options.compressionType(CompressionType.NONE); + DB db = factory.open(new File("example"), options); + +Configuring the Cache + + Options options = new Options(); + options.cacheSize(100 * 1048576); // 100MB cache + DB db = factory.open(new File("example"), options); + +Getting approximate sizes. + + long[] sizes = db.getApproximateSizes(new Range(bytes("a"), bytes("k")), new Range(bytes("k"), bytes("z"))); + System.out.println("Size: "+sizes[0]+", "+sizes[1]); + +Getting database status. + + String stats = db.getProperty("leveldb.stats"); + System.out.println(stats); + +Getting informational log messages. + + Logger logger = new Logger() { + public void log(String message) { + System.out.println(message); + } + }; + Options options = new Options(); + options.logger(logger); + DB db = factory.open(new File("example"), options); + +Destroying a database. + + Options options = new Options(); + factory.destroy(new File("example"), options); + +Repairing a database. + + Options options = new Options(); + factory.repair(new File("example"), options); + +Using a memory pool to make native memory allocations more efficient: + + JniDBFactory.pushMemoryPool(1024 * 512); + try { + // .. work with the DB in here, + } finally { + JniDBFactory.popMemoryPool(); + } + +## Building + +### Prerequisites + +* GNU compiler toolchain +* [Maven 3](http://maven.apache.org/download.html) + +### Supported Platforms + +The following worked for me on: + + * OS X Lion with X Code 4 + * CentOS 5.6 (32 and 64 bit) + * Ubuntu 12.04 (32 and 64 bit) + * apt-get install autoconf libtool + +### Build Procedure + +Then download the snappy, leveldb, and leveldbjni project source code: + + wget http://snappy.googlecode.com/files/snappy-1.0.5.tar.gz + tar -zxvf snappy-1.0.5.tar.gz + git clone git://github.com/chirino/leveldb.git + git clone git://github.com/fusesource/leveldbjni.git + export SNAPPY_HOME=`cd snappy-1.0.5; pwd` + export LEVELDB_HOME=`cd leveldb; pwd` + export LEVELDBJNI_HOME=`cd leveldbjni; pwd` + +Compile the snappy project. This produces a static library. + + cd ${SNAPPY_HOME} + ./configure --disable-shared --with-pic + make + +Patch and Compile the leveldb project. This produces a static library. + + cd ${LEVELDB_HOME} + export LIBRARY_PATH=${SNAPPY_HOME} + export C_INCLUDE_PATH=${LIBRARY_PATH} + export CPLUS_INCLUDE_PATH=${LIBRARY_PATH} + git apply ../leveldbjni/leveldb.patch + make libleveldb.a + +Now use maven to build the leveldbjni project. + + cd ${LEVELDBJNI_HOME} + mvn clean install -P download -P ${platform} + +Replace ${platform} with one of the following platform identifiers (depending on the platform your building on): + +* osx +* linux32 +* linux64 +* win32 +* win64 + +If your platform does not have the right auto-tools levels available +just copy the `leveldbjni-${version}-SNAPSHOT-native-src.zip` artifact +from a platform the does have the tools available then add the +following argument to your maven build: + + -Dnative-src-url=file:leveldbjni-${verision}-SNAPSHOT-native-src.zip + +### Build Results + +* `leveldbjni/target/leveldbjni-${version}.jar` : The java class file to the library. +* `leveldbjni/target/leveldbjni-${version}-native-src.zip` : A GNU style source project which you can use to build the native library on other systems. +* `leveldbjni-${platform}/target/leveldbjni-${platform}-${version}.jar` : A jar file containing the built native library using your currently platform. + diff --git a/java/leveldbjni/releasing.md b/java/leveldbjni/releasing.md new file mode 100644 index 000000000..1cc797ebe --- /dev/null +++ b/java/leveldbjni/releasing.md @@ -0,0 +1,30 @@ +# How To Release + +Since levedbjni has to be build against multiple platforms, the standard maven release plugin will not work to do the release. + +Once you ready to do the release, create a branch for the release using: + + git co -b ${version}.x + +Update the version number in the poms using: + + mvn -P all org.codehaus.mojo:versions-maven-plugin:1.2:set org.codehaus.mojo:versions-maven-plugin:1.2:commit -DnewVersion="${version}" + git commit -am "Preping for a the ${version} release" + git tag "leveldbjni-${version}" + git push origin "leveldbjni-${version}" + +Now release the non-platform specific artifacts using: + + mvn clean deploy -P release -P download + +Then for each platform, shell into the box check out the "leveldbjni-${version}" tag and then: + + cd $platform + mvn clean deploy -Dleveldb=`cd ../../leveldb; pwd` -Dsnappy=`cd ../../snappy-1.0.3; pwd` -P release -P download + +Finally release the `leveldbjni-all` which uber jars all the previously released artifacts. + + cd leveldbjni-all + mvn clean deploy -P release -P download + +Congrats your done. Make sure your releasing the artifacts in Nexus after each step. \ No newline at end of file