On Tue, Jul 24, 2012 at 9:40 AM, Christian Grün <christian.gruen@gmail.com> wrote:
> Any insights on the issue with BaseX randomly locking databases and then
> failing CREATE DB/ALTER DB operations?

I noticed your mail, but it's difficult to give a general assumption
on what might be the problem. I'm aware of many existing use cases in
which databases are created and dropped, and queries are sent.

As databass are implicitly locked if they are accessed by a client
[1], you may need to explicitly close sessions in order to avoid that
opened databases will not be properly closed.


I am very confused.  I never explicitly "open" a database. I use sessions that issue a series of queries & commands, such as 'XQUERY', 'CREATE DB', and the like.  I don't issue any 'OPEN' or 'CLOSE' commands.

I note that we are using the client/server architecture. A single server, with multiple client sessions. Each client session issues 'XQUERY', etc. commands via the org.basex.  Closing a session simply disconnects - why should it have any effect on the db state?

Let me look at the code to illustrate the failure...

The message we're talking about is
org.basex.core.BaseXException: Database 'PUB_feed_libx_dot_editions_at_gmail_dot_com_core' is currently opened by another client.

That's 'db_pinned_%' in your code...
DB_PINNED_X in Text.java...

Happens during createDB:

./src/main/java/org/basex/core/cmd/CreateDB.java:92:        if(context.pinned(name)) return error(DB_PINNED_X, name);
./src/main/java/org/basex/core/cmd/CreateDB.java:152:    if(ctx.pinned(name)) throw new BaseXException(DB_PINNED_X, name);
another client.

I'm guessing it's line 92.... Looking at context.pinned:

  public boolean pinned(final String db) {
    return datas.pinned(db) || TableDiskAccess.locked(db, this);
  }

Leads to Datas.java.... and TableDiskAccess.java
Datas.java simply records in memory which dbs are 'pinned' and how often.
TableDiskAccess.java does physical file locking.

Looking for calls to 'unpin' ... finds one in Close.java:

/**
 * Evaluates the 'close' command and closes the current database.
 *

So it appears that BaseX expects database accesses to be wrapped in a OPEN...CLOSE brace.  We don't issue neither OPEN nor CLOSE... so I'm guessing it's done internally as part of XQUERY?

Suppose one client run an XQUERY against a db, which involves (internally) one or more 'OPEN' calls, then accesses, then 'CLOSE' commands --- how do you synchronize this client with others?  Do you have a master lock so that the server processes only one query/command at a time?  

If so, that would be bad for performance... if not, your assumption that you can throw an error in CreateDB.run if the db is pinned is wrong.  Instead, you'll need a 'wait_until_unpinned' method that CreateDB calls until the db it's trying to create is no longer pinned. It would need to wait on a signaling device that's signaled in unpin(). (Note that we are recreating a database with the same name over and over, even while some clients perform XQUERY on the then-current version of that database.)  This mode of failure would, in essence, be a race condition that would manifest itself if there happened to be a read access to the db by one client while another is trying to create a db with the same name.

I actually don't think that's the failure we're seeing, based on the fact that restarting the server allows the operation to succeed. The latter would point to not calling 'close()' on some path in a previous db operation, leading to a stale entry in the datas. list.

 - Godmar

If you should manage to create a test case, that would be great.
Christian

[1] http://docs.basex.org/wiki/Transaction_Management#Locking