Weird error while using ODatabaseObjectPool in webapp

729 views
Skip to first unread message

Jack Singleton

unread,
Sep 16, 2011, 8:53:00 AM9/16/11
to OrientDB
I've been experimenting with using OrientDB (specifically, the object
database) in a JSF2/Spring web application (working on an
OrientDBTemplate at the same time). I had everything worked out great
and was about to start developing my app with OrientDB, but then came
across this weird error.

On my test page, everything works fine until I start rapidly
refreshing the page (tap ctrl-r as fast as possible). I then get an
ODatabaseException stating "Database instance has been released to the
pool...".

I have to restart the server to make the app functional again (It
keeps throwing the same exception once it comes up once).

I created a simple JSP page and entity class to illustrate this
problem. If needed I can upload the maven project for the example, and
for my JSF/Spring prototype. Let me know if it would help.

I've been working all day on this with no luck - it's looking like I'm
not going to be able to use OrientDB but I thought I'd try asking here
first.

Any help would be much appreciated!

INDEX.JSP
==========

<%@page import="java.util.List"%>
<%@page
import="com.orientechnologies.orient.core.sql.query.OSQLSynchQuery"%>
<%@page import="java.util.ArrayList"%>
<%@page import="com.jacksingleton.orientdbwebtest.Item"%>
<%@page
import="com.orientechnologies.orient.core.db.object.ODatabaseObject"%>
<%@page
import="com.orientechnologies.orient.core.db.object.ODatabaseObjectTx"%>
<%@page
import="com.orientechnologies.orient.core.db.object.ODatabaseObjectPool"%>
<html>
<body>
<%

String connectionString = "memory:dddprototypedb";
String username = "admin";
String password = "admin";
String entityPackage = "com.jacksingleton.orientdbwebtest";

ArrayList<Item> items = null;

ODatabaseObjectTx db = null;

try {
// If DB does not exist, cannot use pool, so create it first.
// --> i had to do this hack to get the pool to work, comments?
ODatabaseObject createDb = null;
try {
db = new ODatabaseObjectTx(connectionString);
if (!db.exists()) {
db.create();
}
} finally {
db.close();
}

db = ODatabaseObjectPool.global().acquire(connectionString, username,
password);

db.getEntityManager().registerEntityClasses(entityPackage);

db.save(new Item("item", new Item("subitem"), new Item("subitem")));

items = new ArrayList<Item>();

List<Item> orientItems = db.query(new OSQLSynchQuery<Item>("select
from Item where subItems.size() > 0"));
for (Item i : orientItems) {
items.add(i);
}
} finally {
db.close();
}

for (Item i : items) {
out.println(i.getText());
out.println("<br/>");
out.println(i.renderSubItems());
out.println("<hr/>");
}

%>
</body>
</html>
==========

ITEM.JAVA
==========
package com.jacksingleton.orientdbwebtest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.persistence.Id;

import com.orientechnologies.orient.core.db.object.ODatabaseObject;
import
com.orientechnologies.orient.core.db.object.ODatabaseObjectPool;
import com.orientechnologies.orient.core.db.object.ODatabaseObjectTx;

public class Item {

private @Id String id;
private String text;
private List<Item> subItems;

public Item() {
// Default constructor
}

public Item(String text, Item ... items) {
this.text = text;
subItems = new ArrayList<Item>();
subItems.addAll(Arrays.asList(items));
}

public String renderSubItems() {
String connectionString = "memory:dddprototypedb";
String username = "admin";
String password = "admin";
String entityPackage = "com.jacksingleton.orientdbwebtest";

ArrayList<Item> items = null;

ODatabaseObjectTx db = null;

try {
db = ODatabaseObjectPool.global().acquire(connectionString,
username, password);

db.getEntityManager().registerEntityClasses(entityPackage);

items = new ArrayList<Item>();

for (Item i : subItems) {
items.add(i);
}
} finally {
db.close();
}

StringBuilder sb = new StringBuilder();
for (Item i : items) {
sb.append(i.getText() + " ");
}
return sb.toString();
}

public List<Item> getSubItems() {
return subItems;
}

public void setSubItems(List<Item> subItems) {
this.subItems = subItems;
}

public void setText(String text) {
this.text = text;
}

public String getText() {
return text;
}

public String getId() {
return id;
}
}
==========

Luca Garulli

unread,
Sep 16, 2011, 3:14:35 PM9/16/11
to orient-...@googlegroups.com
Hi,
seems that the connection pool is exhausted and returns the error. The problem is that the connection are never freed in case of error because you need to restart the app. 

Could you create a testcase with that code so I can reproduce?

By the way this line could be executed once: all the db should inherit it settings:

db.getEntityManager().registerEntityClasses(entityPackage);

Lvc@

Jack Singleton

unread,
Sep 16, 2011, 4:50:34 PM9/16/11
to OrientDB
Hey Luca,

I wasn't able to reproduce this in unit tests - part of the reason
I've been so stumped.

Here is a link to the maven project I made to isolate this problem. It
is only those two files, and I simplified it more since my post.

http://ubuntuone.com/3Ivw5sCzP7MWBUWUutxzJ7

To reproduce:

1. cd into project directory
2. 'mvn jetty:run'
3. Open in web browser
4. Refresh the page normally a few times; note everything works as
expected.
5. Start refreshing the page rapidly (hit ctrl-r as fast as you can).
6. Note the exception page, and that a server restart is required to
regain functionality

I wasn't able to find any documentation on pool management. How do I
increase the pool size?

Thanks for the tip on registerEntityClasses - I've been getting db
instances from a factory class that I have configured via spring. When
that factory creates the db instance, it doesn't know whether it is
the first instance created or not - thus does not know if
registerEntityClasses has been called before. Is there any downfalls
to calling it repeatedly?

Also, is it expected behavior to have to create a regular connection
to create the database and then get one from the pool? It seems quite
hackish but I was not able to find any other way.

Thanks for your time!

Jack Singleton

On Sep 16, 3:14 pm, Luca Garulli <l.garu...@gmail.com> wrote:
> Hi,
> seems that the connection pool is exhausted and returns the error. The
> problem is that the connection are never freed in case of error because you
> need to restart the app.
>
> Could you create a testcase with that code so I can reproduce?
>
> By the way this line could be executed once: all the db should inherit it
> settings:
>
> db.getEntityManager().registerEntityClasses(entityPackage);
>
> Lvc@
>

Jack Singleton

unread,
Sep 16, 2011, 6:57:30 PM9/16/11
to OrientDB
Update.. adding "ODatabaseObjectPool.global().release(db);" after the
"db.close()" statements makes the app able to recover after error,
however, rapid refreshes still cause exceptions to be thrown.

I've been looking through the source for a cause but haven't been able
to find anything yet.

Jack Singleton

unread,
Sep 18, 2011, 2:25:38 PM9/18/11
to OrientDB
Okay...

I've managed to fix the problem, I just don't understand why it works
yet :)

And I'm not sure if it has any side-effects... tests still pass (both
mine and yours).

In ODatabaseObjectTxPooled::close(), I removed the line "ownerPool =
null;".

Ideas? Any pointers to find a proper solution?

Jack Singleton

Jack Singleton

unread,
Sep 18, 2011, 4:50:16 PM9/18/11
to OrientDB
Also, as a workaround in my application right now I'm just calling
"ODatabaseObjectPool.global().release(db);" instead of "db.close();"

This appears to work, does it have any downsides I'm missing?

Thanks again for all the help.

Jack Singleton

Luca Garulli

unread,
Sep 19, 2011, 8:49:54 AM9/19/11
to orient-...@googlegroups.com
Hi,
the problem was in the collections that needed the database open to work. I've also fixed a bug on it available as SVN r3835.

Below the slightly changed code:

<body>
<%!static String connectionString = "memory:dddprototypedb";
static String username = "admin";
static String password = "admin";
static String entityPackage = "com.jacksingleton.orientdbwebtest";

static {
ODatabaseObject createDb = new ODatabaseObjectTx(connectionString);
if (createDb.exists())
createDb.open(username, password);
else
createDb.create();

createDb.getEntityManager().registerEntityClasses(entityPackage);
createDb.close();
}%>
<%
ArrayList<Item> items = null;

ODatabaseObjectTx db = ODatabaseObjectPool.global().acquire(connectionString, username, password);
try {

db.save(new Item("item", new Item("subitem"), new Item("subitem")));

items = new ArrayList<Item>();

List<Item> orientItems = db.query(new OSQLSynchQuery<Item>("select from Item where subItems.size() > 0"));
for (Item i : orientItems) {
items.add(i);
}
} finally {
db.close();
}

try {
db = ODatabaseObjectPool.global().acquire(connectionString, username, password);
for (Item i : items) {
i.setSubItems(new ArrayList<Item>(i.getSubItems()));

out.println(i.getText());
out.println("<br/>");
out.println(i.renderSubItems());
out.println("<hr/>");
}
} finally {
db.close();
}
%>
</body>

The static part contains the db creation/opening + class registration. Then the try{} begins AFTER the db is acquired.

Lvc@

Stefan

unread,
Sep 28, 2011, 3:30:43 AM9/28/11
to orient-...@googlegroups.com
Hi,

What a coincidence! I am doing the same. I am using 1.0r5.
However when I restart the webapp and the code I am getting warnings like this:

28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:245 WARN [ODataLocal] Segment file default.0.oda was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:247 WARN [ODataLocal] OK
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:248 WARN [ODataLocalHole] File C:\Users\user\Desktop\yacht.odb\default.odh was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:256 WARN [OClusterLocal] Segment file internal.0.ocl was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:257 WARN [OClusterLocal] OK
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:257 WARN [OClusterLocalHole] File C:\Users\user\Desktop\yacht.odb\internal.och was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:261 WARN [OSingleFileSegment] File C:\Users\user\Desktop\yacht.odb\database.ocf was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:263 WARN [OClusterLocal] Segment file index.0.ocl was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:263 WARN [OClusterLocal] OK
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:264 WARN [OClusterLocalHole] File C:\Users\user\Desktop\yacht.odb\index.och was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:264 WARN [OClusterLocal] Segment file default.0.ocl was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:265 WARN [OClusterLocal] OK
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:265 WARN [OClusterLocalHole] File C:\Users\user\Desktop\yacht.odb\default.och was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:279 WARN [OClusterLocal] Segment file orole.0.ocl was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:279 WARN [OClusterLocal] OK
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:280 WARN [OClusterLocalHole] File C:\Users\user\Desktop\yacht.odb\orole.och was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:281 WARN [OClusterLocal] Segment file ouser.0.ocl was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:281 WARN [OClusterLocal] OK
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:281 WARN [OClusterLocalHole] File C:\Users\user\Desktop\yacht.odb\ouser.och was not closed correctly last time. Checking segments...
28.09.2011 09:20:19 com.orientechnologies.common.log.OLogManager log
WARNUNG: 
2011-09-28 09:20:19:282 WARN [OTxSegment] File C:\Users\user\Desktop\yacht.odb\txlog.otx was not closed correctly last time. Checking segments...

It seems that the database does not get closed properly. How do I do this?

Stefan

Luca Garulli

unread,
Sep 28, 2011, 4:27:39 AM9/28/11
to orient-...@googlegroups.com
Assure that:
  • all the databases are correctly closed
  • the JVM is soft shutdowned, not with a "kill -9".
Lvc@

Luca Molino

unread,
Sep 28, 2011, 4:28:35 AM9/28/11
to orient-...@googlegroups.com

Hi stefan,

How do you shutdown the server? Anyway that doesn't cause any problem. I have an application in poduction that uses orient as an embedded server using tomcat and i always get this warning after a shutdown but data's still there whithout any kind of error.

Stefan

unread,
Sep 28, 2011, 4:43:54 AM9/28/11
to orient-...@googlegroups.com
1. With "databases" you mean instances of ODatabaseObjectTx?
2. Well, the webapp runs inside an OSGi container and it is not supposed to shutdown the whole jvm but only stops certain bundles (e.g. the bundle offering a database service, which is a wrapper for accessing orintdb ).

Luca Garulli

unread,
Sep 28, 2011, 4:54:44 AM9/28/11
to orient-...@googlegroups.com
Hi,
1) yes
2) try to set -Dstorage.keepOpen=false in JVM arguments or via code set this: OGlobalConfiguration.STORAGE_KEEP_OPEN.setValue(false);

Lvc@

Stefan

unread,
Sep 28, 2011, 5:04:14 AM9/28/11
to orient-...@googlegroups.com
Hi,

1. yes, I close them always after usage
2. Nice, that did it!  Does this have any "bad" implications", e.g. performance,.. ?

Stefan

Stefan

unread,
Sep 28, 2011, 5:12:33 AM9/28/11
to orient-...@googlegroups.com
Hi Luca,

Currently, while developing the JVM (jetty, Eqinox ServletBridge) will be "killed". However, when run under a OSGi container it should not be neccessary to shutdown the server - it shold be sufficent to stop and start bundles on the go.
I also recognised that "killing" does not harm :-)

Stefan

Luca Garulli

unread,
Sep 28, 2011, 5:21:39 AM9/28/11
to orient-...@googlegroups.com
2. In this case, for the same URL, when all the database are closed the underlying storage is closed as well. It's slower if you have 1 thread that open and close the database.

Lvc@

Stefan

unread,
Sep 28, 2011, 5:25:32 AM9/28/11
to orient-...@googlegroups.com
Hi Lvc@,

Ok, I was hoping that it worked that way :-)

Thanks,
Stefan

Reply all
Reply to author
Forward
0 new messages