LWJGL Forum

Programming => Bug Reports / RFE => Topic started by: joshua tang on November 28, 2017, 04:21:25

Title: How do I switch to the latest version of LMDB
Post by: joshua tang on November 28, 2017, 04:21:25
Hi Guys:
    when I using lwgjl 3.1.3 lmdb api to write certain data item to the database, sometimes I get SIGSEGV error. when switched to another LMDB java binding (lmdbjni), all works fine.

    the reason I believe is that lmdbjni using a more recent branch of native lmdb library.

   So my question is How can I customized the lwgjl library to use the latest native lmdb library (is it possible that I replace the native code in my local git repository to achieve that?)


Best regards,
Title: Re: How do I switch to the latest version of LMDB
Post by: spasi on November 28, 2017, 09:29:02
LWJGL 3.1.3 includes lmdb 0.9.21.

The lmdb build that comes with LWJGL 3.1.5 is based on the latest commit (https://github.com/LMDB/lmdb/commit/4d5e2d2a2ac38b9d56b6ba73187c325024718167) of the master branch, plus a custom patch (https://github.com/LWJGL/lwjgl3/commit/1aba8cf8607c0711b0104c05f88cf9c55954077b) that improves incremental file growth performance on Windows.

Afaict, lmdbjni is still at 0.9.19 (https://github.com/deephacks/lmdbjni/commits/master/lmdbjni/src/main/native-package/src/mdb.c).

Please try again with LWJGL 3.1.5 or 3.1.6-SNAPSHOT. If the problem persists, please prepare an MCVE (https://stackoverflow.com/help/mcve) and I'll gladly have a look and maybe help identify what's causing the crash.
Title: Re: How do I switch to the latest version of LMDB
Post by: joshua tang on November 29, 2017, 06:47:43
Hi :

   Thanks for your quick response. I will switch to 3.15 to see what is the result. If still get the same problem I will give you detailed information about the issue I encountered.

Thanks again.
Title: Re: How do I switch to the latest version of LMDB
Post by: joshua tang on November 29, 2017, 10:48:21
Hi Guy:

    I have attached the file dumped when the JVM crash. 

    I am writing a DUP_SORT mode database, using mdb_cursor_put. 

    there have been a lot of records successfully written. I found the problematic record that cause the issue, write it to the database again, the issue happens again.
    But when clean all the db, then write the problematic record, it can be successfully written. That is strange.
Title: Re: How do I switch to the latest version of LMDB
Post by: spasi on November 29, 2017, 11:25:46
It would help if you could reproduce the crash in a simple program. Share it here and I'll try to debug it.
Title: Re: How do I switch to the latest version of LMDB
Post by: joshua tang on November 29, 2017, 17:20:05
import org.lwjgl.PointerBuffer;
import org.lwjgl.util.lmdb.LMDB;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.util.lmdb.MDBVal;

import java.io.*;
import java.nio.IntBuffer;


public class CrashLmdb {
    static long env;
    static int db;

    public static void main(String[] args) throws IOException {
        try (MemoryStack stack = MemoryStack.stackPush()) {
            File dir = new File("/home/joshua/Data1");
            PointerBuffer envPointer = stack.mallocPointer(1);
            LMDB.mdb_env_create(envPointer);
            env = envPointer.get(0);
            LMDB.mdb_env_set_mapsize(env, 1024 * 1024 * 1024);
            LMDB.mdb_env_set_maxreaders(env, 512);
            LMDB.mdb_env_set_maxdbs(env, 512);
            LMDB.mdb_env_open(env, dir.getPath(), 0, 0644);
        }

        try (MemoryStack stack = MemoryStack.stackPush()) {
            IntBuffer dbPointer = stack.mallocInt(1);
            PointerBuffer txnPointer = stack.mallocPointer(1);
            LMDB.mdb_txn_begin(env, MemoryUtil.NULL, 0, txnPointer);
            long txn = txnPointer.get(0);
            LMDB.mdb_dbi_open(txn, "mydb", LMDB.MDB_CREATE|LMDB.MDB_DUPSORT, dbPointer);
            LMDB.mdb_txn_commit(txn);
            db = dbPointer.get(0);
        }

        try (MemoryStack stack = MemoryStack.stackPush()) {
            PointerBuffer txnPointer = stack.mallocPointer(1);
            LMDB.mdb_txn_begin(env, MemoryUtil.NULL, 0, txnPointer);
            long txn = txnPointer.get(0);
            PointerBuffer cursorPointer = stack.mallocPointer(1);
            long cursor = cursorPointer.get(0);
            LMDB.mdb_cursor_open(txn, db,cursorPointer);
            MDBVal key = MDBVal.callocStack(stack);
            MDBVal value = MDBVal.callocStack(stack);
            key.mv_data(stack.ASCII("AA ABE  AMS  ", false));
            value.mv_data(stack.ASCII("001AA ABE  AMS  KMZ     00100009", false));
            LMDB.mdb_cursor_put(cursor, key, value, 0);
            LMDB.mdb_cursor_close(cursor);
            LMDB.mdb_txn_commit(txn);
        }

    }
}


just run the above code will cause a  JVM crash, please point the db directory to a clean directory. Hope this could help you help me. :)
Title: Re: How do I switch to the latest version of LMDB
Post by: spasi on November 29, 2017, 17:52:28
The bug is in these 3 lines:

PointerBuffer cursorPointer = stack.mallocPointer(1);
long cursor = cursorPointer.get(0);
LMDB.mdb_cursor_open(txn, db,cursorPointer);


You're dereferencing the cursor pointer before calling mdb_cursor_open. It's trivially fixed by doing:

PointerBuffer cursorPointer = stack.mallocPointer(1);
LMDB.mdb_cursor_open(txn, db,cursorPointer);
long cursor = cursorPointer.get(0);
Title: Re: How do I switch to the latest version of LMDB
Post by: joshua tang on November 30, 2017, 02:52:58
Hi Guy:
 
     I made a mistake in the previous program. you are right about it.  this time I give you the right code, and a data.txt file.  I try to load all data.txt file into db, the last record seems cause the SIGSEGV error.

     please run the following code against the attached data.txt file.  Appreciate your help.

import org.lwjgl.PointerBuffer;
import org.lwjgl.util.lmdb.LMDB;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.util.lmdb.MDBVal;

import java.io.*;
import java.nio.IntBuffer;


public class CrashLmdb {
    static long env;
    static int db;

    public static void main(String[] args) throws IOException {
        try (MemoryStack stack = MemoryStack.stackPush()) {
            File dir = new File("/home/joshua/Data1");
            PointerBuffer envPointer = stack.mallocPointer(1);
            LMDB.mdb_env_create(envPointer);
            env = envPointer.get(0);
            LMDB.mdb_env_set_mapsize(env, 1024 * 1024 * 1024);
            LMDB.mdb_env_set_maxreaders(env, 512);
            LMDB.mdb_env_set_maxdbs(env, 512);
            LMDB.mdb_env_open(env, dir.getPath(), 0, 0644);
        }

        try (MemoryStack stack = MemoryStack.stackPush()) {
            IntBuffer dbPointer = stack.mallocInt(1);
            PointerBuffer txnPointer = stack.mallocPointer(1);
            LMDB.mdb_txn_begin(env, MemoryUtil.NULL, 0, txnPointer);
            long txn = txnPointer.get(0);
            LMDB.mdb_dbi_open(txn, "mydb", LMDB.MDB_CREATE|LMDB.MDB_DUPSORT, dbPointer);
            LMDB.mdb_txn_commit(txn);
            db = dbPointer.get(0);
        }

        FileReader input = new FileReader("/home/joshua/Desktop/data.txt");
        BufferedReader reader = new BufferedReader(input);
        String strKey = reader.readLine();
        String strValue = reader.readLine();
        while (null != strKey & null != strValue) {
            try (MemoryStack stack = MemoryStack.stackPush()) {
                PointerBuffer txnPointer = stack.mallocPointer(1);
                LMDB.mdb_txn_begin(env, MemoryUtil.NULL, 0, txnPointer);
                long txn = txnPointer.get(0);
                PointerBuffer cursorPointer = stack.mallocPointer(1);
                LMDB.mdb_cursor_open(txn, db,cursorPointer);
                long cursor = cursorPointer.get(0);
                MDBVal key = MDBVal.callocStack(stack);
                MDBVal value = MDBVal.callocStack(stack);
                key.mv_data(stack.ASCII(strKey, false));
                value.mv_data(stack.ASCII(strValue, false));
                LMDB.mdb_cursor_put(cursor, key, value, 0);
                LMDB.mdb_cursor_close(cursor);
                LMDB.mdb_txn_commit(txn);
            }
            strKey = reader.readLine();
            strValue = reader.readLine();
        }
        LMDB.mdb_dbi_close(env, db);
        LMDB.mdb_env_close(env);
    }
}
Title: Re: How do I switch to the latest version of LMDB
Post by: joshua tang on November 30, 2017, 06:24:21
Hi :

   New findings.

   if these lines in the previous program:
         key.mv_data(stack.ASCII(strKey, false));
         value.mv_data(stack.ASCII(strValue, false));
   changed to:
        key.mv_data(stack.ASCII(strKey, true));
        value.mv_data(stack.ASCII(strValue, true));

  for the attached dataset there are no SIGSEGV error happens anymore.   But when I try to load more data, I sitll get SIGSEGV at some point,  always on mdb_cursor_put method.
Title: Re: How do I switch to the latest version of LMDB
Post by: spasi on November 30, 2017, 10:20:13
I was able to reproduce this. It only happens on the Linux build which is compiled with GCC. Debugging showed that you're hitting this issue (http://www.openldap.org/lists/openldap-bugs/201604/msg00003.html), which I believe is caused by GCC vectorizing a loop doing misaligned memory access (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58039).

The issue is fixed by:

- Changing optimization level from -O3 to -O2.
- Using -O3 and -fno-strict-aliasing.
- Using -O3 and -fno-tree-vectorize.
- Changing the offending loop from:

Quotefor (i=0; i<NUMKEYS(fp); i++)
    mp->mp_ptrs[ i ] = fp->mp_ptrs[ i ] + offset; // fp->mp_ptrs[ i ] is misaligned

to

Quotememcpy(mp->mp_ptrs, fp->mp_ptrs, NUMKEYS(fp) * sizeof(indx_t));
for (i=0; i<NUMKEYS(fp); i++)
    mp->mp_ptrs[ i ] += offset;

The next LWJGL 3.1.6 snapshot will incorporate the last option. Thank you for reporting this!
Title: Re: How do I switch to the latest version of LMDB
Post by: joshua tang on November 30, 2017, 10:37:23
what time will  the next LWJGL 3.1.6 snapshot be ready?
Title: Re: How do I switch to the latest version of LMDB
Post by: spasi on November 30, 2017, 10:39:25
In 30-60'.
Title: Re: How do I switch to the latest version of LMDB
Post by: joshua tang on December 01, 2017, 03:11:51
Seems the issue never happened when using the latest 3.1.6 snapshot.

Great job, thanks guy.