Hi,
I'm having trouble related to ODatabaseRecordThreadLocal in a 
*single-threaded* application, in particular: ODatabaseException: Database 
instance is not set in current thread.
I understand why it's happening (I'll explain in a moment) and I'm trying 
to find a way around it that it doesn't pollute my code.
Here's a really basic scenario:

private OrientGraphFactory factory;

public void someMethod() {
    ODatabaseDocumentTx database = factory.getDatabase();
    try {
        // work with the database
    } finally {
        database.close();
    }
}

This works fine. Problems start when I have something like this:

public void someMethod() {
(1) ODatabaseDocumentTx database = factory.getDatabase();
    try {
        // work with the database
(2)     someOtherMethod(); // <-- nested open/close
(5)     // work with the database
    } finally {
(6)     database.close();
    }
}

public void someOtherMethod() {
(3) ODatabaseDocumentTx database = factory.getDatabase();
    try {
        // work with the database
    } finally {
(4)     database.close();
    }
}

If I got it right, this is what happens:

   1. someMethod gets a database from the factory. This database is stored 
   in ODatabaseRecordThreadLocal.INSTANCE.
   2. someMethod invokes someOtherMethod.
   3. someOtherMethod gets a database from the factory. This database is 
   stored in ODatabaseRecordThreadLocal.INSTANCE, overwriting the one that 
   someMethod got before.
   4. someOtherMethod closes the database. 
   ODatabaseRecordThreadLocal.INSTANCE is cleared (set to null) as a result.
   5. someMethod tries to continue working with the database but the 
   ODatabaseRecordThreadLocal.INSTANCE is no longer valid and I get: 
ODatabaseException: 
   Database instance is not set in current thread.
   
I looked into it and read this 
<http://orientdb.com/docs/last/Java-Multi-Threading.html>:

> Since v2.1 OrientDB doesn't allow implicit usage of multiple database 
> instances from the same thread. Any attempt to manage multiple instances in 
> the same thread must explicitly call the method 
> db.activateOnCurrentThread() against the database instance BEFORE you use it
> .
>

I couldn't find method activateOnCurrentThread() (was it removed?) but I 
guess I can just do:

ODatabaseRecordThreadLocal.INSTANCE.set(database);

However, since I saw this warning about using multiple database instances 
in the same thread, I thought that rather than doing this I would simply 
reuse the same ODatabaseDocumentTx by storing it locally rather than 
getting one from the factory every time. Since I'm working in a 
single-threaded scenario there's no problem sharing this one instance 
between methods. I added a bit of logic to make sure that the database 
doesn't get closed by someOtherMethod if someMethod still wants to use it 
-- this is hidden from the methods in a DBHandler (written by myself) that 
keeps track of this stuff:

public void someMethod() {
    ODatabaseDocumentTx database = dbHandler.getDatabase();
    try {
        // work with the database
        someOtherMethod(); // <-- nested open/close
        // work with the database
    } finally {
        dbHandler.closeDatabase();
    }
}

public void someOtherMethod() {
    ODatabaseDocumentTx database = dbHandler.getDatabase();
    try {
        // work with the database
    } finally {
        dbHandler.closeDatabase();
    }
}

Everything works fine. There's only one instance of ODatabaseDocumentTx in 
the thread.
However, trouble starts when I want to get a graph. I invoke this method in 
OrientGraphFactory:

  /**
   * Gets transactional graph with the database from pool if pool is 
configured. Otherwise creates a graph with new db instance. The
   * Graph instance inherits the factory's configuration.
   *
   * @return transactional graph
   */
  public OrientGraph getTx() {
    final OrientGraph g;
    if (pool == null) {
(1)   g = new OrientGraph(getDatabase(), user, password, settings);
    } else {
      // USE THE POOL
(2)   g = new OrientGraph(pool, settings);
    }
    initGraph(g);
    return g;
  }

...which will either instantiate a new database (1) or get one from the 
pool (2). Since I want to always use the same database in the same thread, 
I set up the pool in the factory:

factory.setupPool(1, 10);

...so I guess graphs are ok like that (they don't trigger more database 
instantiation). However, I cannot find a way to put my database, initially 
obtained like this...

ODatabaseDocumentTx database = factory.getDatabase();

...into the pool so that it gets picked up by the factory when I invoke:

factory.getTx();

So I will have 2 database instances: the one I got with 
factory.getDatabase() and the the one that is in the pool and will be used 
in factory.getTx().
What am I supposed to do? IMO this solution...

ODatabaseRecordThreadLocal.INSTANCE.set(database);

...isn't good because there are still several database instances floating 
around in the same thread, which (if I understand the documentation 
correctly) is not a good thing. Plus I don't want to pollute my code with 
ODatabaseRecordThreadLocal.INSTANCE.set(database) just to deal with the 
possibility that someone somewhere has changed the thread-local database. I 
want to use 1 single instance but it seems that OrientDB won't let me, 
since it will instantiate databases in code over which I have no control.
What can I do?

I hope this made sense. I'm kinda tired...
Thanks,
Alicia

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"OrientDB" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to