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.