diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..164e526 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/build.sh=UTF-8 diff --git a/mdbxjni/src/main/java/com/castortech/mdbxjni/Cursor.java b/mdbxjni/src/main/java/com/castortech/mdbxjni/Cursor.java index 7c5f4e0..04da18a 100644 --- a/mdbxjni/src/main/java/com/castortech/mdbxjni/Cursor.java +++ b/mdbxjni/src/main/java/com/castortech/mdbxjni/Cursor.java @@ -72,7 +72,7 @@ public void close() { * transaction handle */ public void renew(Transaction tx) { - checkErrorCode(env, mdbx_cursor_renew(tx.pointer(), pointer())); + checkErrorCode(env, tx, mdbx_cursor_renew(tx.pointer(), pointer())); } /** @@ -96,7 +96,7 @@ public Entry get(CursorOp op) { if (rc == MDBX_NOTFOUND) { return null; } - checkErrorCode(env, rc); + checkErrorCode(env, tx, rc); return new Entry(key.toByteArray(), value.toByteArray()); } @@ -110,7 +110,7 @@ public Entry get(CursorOp op, byte[] key) { if (rc == MDBX_NOTFOUND) { return null; } - checkErrorCode(env, rc); + checkErrorCode(env, tx, rc); return new Entry(keyValue.toByteArray(), value.toByteArray()); } finally { @@ -131,7 +131,7 @@ public Entry get(CursorOp op, byte[] key, byte[] value) { if (rc == MDBX_NOTFOUND) { return null; } - checkErrorCode(env, rc); + checkErrorCode(env, tx, rc); return new Entry(keyValue.toByteArray(), valValue.toByteArray()); } finally { @@ -154,7 +154,7 @@ public OperationStatus get(CursorOp op, DatabaseEntry key, DatabaseEntry value) if (rc == MDBX_NOTFOUND) { return OperationStatus.NOTFOUND; } - checkErrorCode(env, rc); + checkErrorCode(env, tx, rc); key.setData(keyValue.toByteArray()); value.setData(valValue.toByteArray()); return OperationStatus.SUCCESS; @@ -262,7 +262,7 @@ private byte[] put(Value keySlice, Value valueSlice, int flags) { } else { // If the put failed, throw an exception.. - checkErrorCode(env, rc); + checkErrorCode(env, tx, rc); if (!valueSlices.isEmpty()) { db.deleteSecondaries(tx, keySlice, valueSlices); @@ -289,7 +289,7 @@ public void delete() { } int rc = mdbx_cursor_del(pointer(), 0); - checkErrorCode(env, rc); + checkErrorCode(env, tx, rc); if (hasSec) { for (SecondaryDatabase secDb : db.getSecondaries()) { @@ -311,7 +311,7 @@ public void delete() { * May only be called if the database was opened with {@link com.castortech.mdbxjni.Constants#DUPSORT}. */ public void deleteIncludingDups() { - checkErrorCode(env, mdbx_cursor_del(pointer(), MDBX_NODUPDATA)); + checkErrorCode(env, tx, mdbx_cursor_del(pointer(), MDBX_NODUPDATA)); } /** @@ -326,7 +326,7 @@ public void deleteIncludingDups() { */ public long count() { long[] rc = new long[1]; - checkErrorCode(env, mdbx_cursor_count(pointer(), rc)); + checkErrorCode(env, tx, mdbx_cursor_count(pointer(), rc)); return rc[0]; } diff --git a/mdbxjni/src/main/java/com/castortech/mdbxjni/EnvInfo.java b/mdbxjni/src/main/java/com/castortech/mdbxjni/EnvInfo.java index 5f99806..c616d55 100644 --- a/mdbxjni/src/main/java/com/castortech/mdbxjni/EnvInfo.java +++ b/mdbxjni/src/main/java/com/castortech/mdbxjni/EnvInfo.java @@ -61,7 +61,8 @@ public class EnvInfo { pgopStat = new PgopStat(rc.mi_pgop_stat_newly, rc.mi_pgop_stat_cow, rc.mi_pgop_stat_clone, rc.mi_pgop_stat_split, rc.mi_pgop_stat_merge, rc.mi_pgop_stat_spill, rc.mi_pgop_stat_unspill, - rc.mi_pgop_stat_wops); + rc.mi_pgop_stat_wops, rc.mi_pgop_stat_prefault, rc.mi_pgop_stat_mincore, rc.mi_pgop_stat_msync, + rc.mi_pgop_stat_fsync); } public Geo getGeo() { @@ -338,9 +339,13 @@ public class PgopStat { private final long spill; private final long unspill; private final long wops; + private final long prefault; + private final long mincore; + private final long msync; + private final long fsync; public PgopStat(long newly, long cow, long clone, long split, long merge, long spill, long unspill, - long wops) { + long wops, long prefault, long mincore, long msync, long fsync) { super(); this.newly = newly; this.cow = cow; @@ -350,6 +355,10 @@ public PgopStat(long newly, long cow, long clone, long split, long merge, long s this.spill = spill; this.unspill = unspill; this.wops = wops; + this.prefault = prefault; + this.mincore = mincore; + this.msync = msync; + this.fsync = fsync; } public long getNewly() { @@ -384,6 +393,22 @@ public long getWops() { return wops; } + public long getPrefault() { + return prefault; + } + + public long getMincore() { + return mincore; + } + + public long getMsync() { + return msync; + } + + public long getFsync() { + return fsync; + } + @SuppressWarnings("nls") @Override public String toString() { @@ -396,6 +421,10 @@ public String toString() { ", spill=" + spill + ", unspill=" + unspill + ", wops=" + wops + + ", prefault=" + prefault + + ", mincore=" + mincore + + ", msync=" + msync + + ", fsync=" + fsync + "}"; } } diff --git a/mdbxjni/src/main/java/com/castortech/mdbxjni/MDBXException.java b/mdbxjni/src/main/java/com/castortech/mdbxjni/MDBXException.java index f864629..bf3a7cf 100644 --- a/mdbxjni/src/main/java/com/castortech/mdbxjni/MDBXException.java +++ b/mdbxjni/src/main/java/com/castortech/mdbxjni/MDBXException.java @@ -29,16 +29,21 @@ public class MDBXException extends RuntimeException { @SuppressWarnings("nls") public enum Status { OK(0, "OK"), + ENODATA(JNI.MDBX_ENODATA, "Handle EOF"), EINVAL(JNI.MDBX_EINVAL, "Invalid Parameter"), EACCES(JNI.MDBX_EACCESS, "Access Denied"), - ENODATA(JNI.MDBX_ENODATA, "Handle EOF"), ENOMEM(JNI.MDBX_ENOMEM, "Out of Memory"), EROFS(JNI.MDBX_EROFS, "File Read Only"), ENOSYS(JNI.MDBX_ENOSYS, "Not Supported"), EIO(JNI.MDBX_EIO, "Write Fault"), EPERM(JNI.MDBX_EPERM, "Invalid Function"), EINTR(JNI.MDBX_EINTR, "Cancelled"), + ENOFILE(JNI.MDBX_ENOFILE, "File not found"), + EREMOTE(JNI.MDBX_EREMOTE, "Remote storage media error"), + RESULT_FALSE(JNI.MDBX_RESULT_FALSE, "Alias for Successful result"), + RESULT_TRUE(JNI.MDBX_RESULT_TRUE, "Successful result with special meaning or a flag"), KEYEXIST(JNI.MDBX_KEYEXIST, "key/data pair already exists"), + FIRST_LMDB_ERRCODE(JNI.MDBX_FIRST_LMDB_ERRCODE, "The first LMDB-compatible defined error code"), NOTFOUND(JNI.MDBX_NOTFOUND, "key/data pair not found (EOF)"), PAGE_NOTFOUND(JNI.MDBX_PAGE_NOTFOUND, "Requested page not found - this usually indicates corruption"), CORRUPTED(JNI.MDBX_CORRUPTED, "Located page was wrong type"), @@ -51,29 +56,24 @@ public enum Status { TXN_FULL(JNI.MDBX_TXN_FULL, "Transaction has too many dirty pages"), CURSOR_FULL(JNI.MDBX_CURSOR_FULL, "Cursor stack too deep - internal error"), PAGE_FULL(JNI.MDBX_PAGE_FULL, "Page has not enough space - internal error"), + UNABLE_EXTEND_MAPSIZE(JNI.MDBX_UNABLE_EXTEND_MAPSIZE, "Database engine was unable to extend mapping, e.g. since address space is unavailable or busy"), INCOMPATIBLE(JNI.MDBX_INCOMPATIBLE, "Operation and DB incompatible, or DB type changed."), BAD_RSLOT(JNI.MDBX_BAD_RSLOT, "Invalid reuse of reader locktable slot"), BAD_TXN(JNI.MDBX_BAD_TXN, "Transaction must abort, has a child, or is invalid"), BAD_VALSIZE(JNI.MDBX_BAD_VALSIZE, "Unsupported size of key/DB name/data, or wrong DUPFIXED size"), BAD_DBI(JNI.MDBX_BAD_DBI, "The specified DBI was changed unexpectedly"), PROBLEM(JNI.MDBX_PROBLEM, "Unexpected problem - Transaction should abort"), + LAST_LMDB_ERRCODE(JNI.MDBX_LAST_LMDB_ERRCODE, "The last LMDB-compatible defined error code"), BUSY(JNI.MDBX_BUSY, "Another write transaction is running"), + FIRST_ADDED_ERRCODE(JNI.MDBX_FIRST_ADDED_ERRCODE, "The first of MDBX-added error codes"), EMULTIVAL(JNI.MDBX_EMULTIVAL, "The mdbx_put() or mdbx_replace() was called for key, that has more that one associated value."), BAD_SIGNATGURE(JNI.MDBX_EBADSIGN, "Bad signature of a runtime object(s), this can mean: - memory corruption or double-free; - ABI version mismatch (rare case)"), WANNA_RECOVERY(JNI.MDBX_WANNA_RECOVERY, "Database should be recovered, but this could NOT be done automatically right now (e.g. in readonly mode and so forth)."), KE_YMISMATCH(JNI.MDBX_EKEYMISMATCH, "The given key value is mismatched to the current cursor position, when mdbx_cursor_put() called with MDBX_CURRENT option."), TOO_LARGE(JNI.MDBX_TOO_LARGE, "Database is too large for current system, e.g. could NOT be mapped into RAM."), THREAD_MISMATCH(JNI.MDBX_THREAD_MISMATCH, "A thread has attempted to use a not owned object, e.g. a transaction that started by another thread."), - RESULT_FALSE(JNI.MDBX_RESULT_FALSE, "Alias for Successful result"), - RESULT_TRUE(JNI.MDBX_RESULT_TRUE, "Successful result with special meaning or a flag"), - FIRST_LMDB_ERRCODE(JNI.MDBX_FIRST_LMDB_ERRCODE, "The first LMDB-compatible defined error code"), - UNABLE_EXTEND_MAPSIZE(JNI.MDBX_UNABLE_EXTEND_MAPSIZE, "Database engine was unable to extend mapping, e.g. since address space is unavailable or busy"), - LAST_LMDB_ERRCODE(JNI.MDBX_LAST_LMDB_ERRCODE, "The last LMDB-compatible defined error code"), - FIRST_ADDED_ERRCODE(JNI.MDBX_FIRST_ADDED_ERRCODE, "The first of MDBX-added error codes"), TXN_OVERLAPPING(JNI.MDBX_TXN_OVERLAPPING, "Overlapping read and write transactions for the current thread"), LAST_ADDED_ERRCODE(JNI.MDBX_LAST_ADDED_ERRCODE, "The last added error code"), - ENOFILE(JNI.MDBX_ENOFILE, "?? no description"), - EREMOTE(JNI.MDBX_EREMOTE, "?? no description"), ; private final int code; diff --git a/mdbxjni/src/main/java/com/castortech/mdbxjni/Transaction.java b/mdbxjni/src/main/java/com/castortech/mdbxjni/Transaction.java index a1163e0..28a8980 100644 --- a/mdbxjni/src/main/java/com/castortech/mdbxjni/Transaction.java +++ b/mdbxjni/src/main/java/com/castortech/mdbxjni/Transaction.java @@ -61,7 +61,7 @@ public long getId() { * must be called before a reset transaction may be used again. */ public void renew() { - checkErrorCode(env, mdbx_txn_renew(pointer())); + checkErrorCode(env, this, mdbx_txn_renew(pointer())); } /** @@ -78,7 +78,7 @@ public void renew() { */ public void commit() { if (self != 0) { - checkErrorCode(env, mdbx_txn_commit(self)); + checkErrorCode(env, this, mdbx_txn_commit(self)); self = 0; } } @@ -86,7 +86,7 @@ public void commit() { public CommitLatency commitWithLatency() { if (self != 0) { MDBX_commit_latency rc = new MDBX_commit_latency(); - checkErrorCode(env, mdbx_txn_commit_ex(self, rc)); + checkErrorCode(env, this, mdbx_txn_commit_ex(self, rc)); self = 0; return new CommitLatency(rc); } @@ -132,12 +132,12 @@ public void abort() { } public void broken() { - checkErrorCode(env, mdbx_txn_break(pointer())); + checkErrorCode(env, this, mdbx_txn_break(pointer())); } public TxnInfo info(boolean scanRlt) { MDBX_txn_info rc = new MDBX_txn_info(); - checkErrorCode(env, mdbx_txn_info(pointer(), rc, scanRlt ? 1 : 0)); + checkErrorCode(env, this, mdbx_txn_info(pointer(), rc, scanRlt ? 1 : 0)); return new TxnInfo(rc); } diff --git a/mdbxjni/src/main/java/com/castortech/mdbxjni/Util.java b/mdbxjni/src/main/java/com/castortech/mdbxjni/Util.java index c9ba9fa..9d8725e 100644 --- a/mdbxjni/src/main/java/com/castortech/mdbxjni/Util.java +++ b/mdbxjni/src/main/java/com/castortech/mdbxjni/Util.java @@ -28,6 +28,7 @@ * * @author Hiram Chirino */ +@SuppressWarnings("nls") class Util { public static final boolean isAndroid = isAndroid(); @@ -57,6 +58,16 @@ public static void checkErrorCode(Env env, int rc) { } } + public static void checkErrorCode(Env env, Transaction txn, int rc) { + if (rc != JNI.MDBX_SUCCESS && rc != JNI.MDBX_RESULT_TRUE) { + String msg = string(mdbx_strerror(rc)); + if (env != null) { + System.err.println("MDBX Exception. Msg:" + msg + ", Env:" + env.info(txn).toString()); + } + throw new MDBXException(msg, rc); + } + } + public static void checkSize(final Env env, final Value val) { long size = val.getOffendingSize(env.getMaxKeySize()); diff --git a/readme.md b/readme.md index fb41a7b..ab49f28 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ ## Description MDBX JNI gives you a Java interface to the -[libmdbx](https://github.com/leo-yuriev/libmdbx) library +[libmdbx](https://gitflic.ru/project/leo-yuriev/libmdbx) library which is a fast key-value storage library written for ReOpenLDAP project that provides an ordered mapping from string keys to string values.