2
votes

I am trying to use an orientdb in-memory instance in a multi-threaded app. I've looked at lots of code examples but none of the seem to cover this case. Here's my test code:

DbTest.java

public class DbTest {
    public static void main(String [] args) {
        ODatabaseDocumentTx db = new ODatabaseDocumentTx("memory:MyDb").create();

        Runnable myRunnable = new MyRunnable(db);

        Thread thread = new Thread(myRunnable);
        thread.start();
    }  
}  

MyRunnable.java

public class MyRunnable implements Runnable {
    private ODatabaseDocumentTx db;

    MyRunnable(ODatabaseDocumentTx db) {
        this.db = db;
    }

    public void run() {
        ODocument animal = new ODocument("Animal");
        animal.field( "name", "Gaudi" );
        animal.field( "location", "Madrid" );
        animal.save();
    }
}

This gives the error

Exception in thread "Thread-3" com.orientechnologies.orient.core.exception.ODatabaseException: Database instance is not set in current thread. Assure to set it with: ODatabaseRecordThreadLocal.INSTANCE.set(db);

I read that I should try to use the connection pool, but the connection pool does not seem to work with memory databases

ODatabaseDocumentTx db = ODatabaseDocumentPool.global().acquire("memory:MyDb", "admin", "admin");

Exception in thread "main" com.orientechnologies.orient.core.exception.OStorageException: Cannot open local storage 'MyDb' with mode=rw

Any ideas how this is actually supposed to work?

2

2 Answers

4
votes

An ODatabaseDocumentPool instance is thread-safe and can be reused. An ODatabaseDocumentTx is not thread-safe and should only be used by a single Thread. The OrientDB API is a little ugly here, the memory database must be created first which is not possible using the default API. However, when using a memory database, pooling does not make any sense.

So in your example, the most efficient way to do it is:

public class OrientTest {

static class MyRunnable implements Runnable {

    @Override
    public void run() {
        // If using Java7+, use try-with-resources!
        try (ODatabaseDocumentTx tx = getDatabase("memory:Test", "admin", "admin")) {
            ODocument animal = tx.newInstance("Animal")
                .field("name", "Gaudi")
                .field("location", "Madrid");
            tx.save(animal);
        }
    }

    private ODatabaseDocumentTx getDatabase(String url, String userName, String password) {
        ODatabaseDocumentTx tx = new ODatabaseDocumentTx(url);
        // database is not open yet!
        if (!tx.exists()) {
            // this will create AND open the database! 
            // Default credentials are "admin"/"admin"
            tx.create();
            return tx;
        }
        return tx.open(userName, password);
    }

}

public static void main(String[] args) {
    new Thread(new MyRunnable()).start();
}
}
2
votes

Try to create the database before

ODatabaseDocumentTx db = new ODatabaseDocumentTx("memory:MyDb").create();

and then use the pool in your thread

ODatabaseDocumentTx db = ODatabaseDocumentPool.global().acquire("memory:MyDb", "admin", "admin");