Tuesday, November 24, 2015

OrientDB - Using plocal Embedded Storage from Two Processes

OrientDB has this nice feature of creating and using database in embedded mode. We can programatically create and accesses OrientDB database for CRUD operations without the server. We can create a plocal storage (Paginated Local Storage) with this. plocal is a disk based storage which works with data using page model. This storage is very fast because of we can assess the database directly with local mode.

But, plocal storage has a limitation; it can only be accessed by one process at a time. When a process accesses the database, it locks the database so that no other program or process can access that. This lock will not be released until the program terminates. It avoids updating the database from several processes.
If you are going to accesses the plocal db while another process has acquired the lock, you will have the following error message.

com.orientechnologies.orient.core.exception.OStorageException: Cannot open local storage 'C:/MyOrientDb/dbs/myPlocal' with mode=rw
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.open(OAbstractPaginatedStorage.java:217)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.open(ODatabaseDocumentTx.java:243)
at com.lakj.comspace.orientdb.PlocalTest.readDb(PlocalTest.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)...
Caused by: com.orientechnologies.orient.core.exception.OSerializationException: Cannot load database's configuration. The database seems to be corrupted.
at com.orientechnologies.orient.core.storage.impl.local.OStorageConfigurationSegment.load(OStorageConfigurationSegment.java:86)
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.open(OAbstractPaginatedStorage.java:164)
... 28 more
Caused by: java.io.IOException: The process cannot access the file because another process has locked a portion of the file
at java.io.RandomAccessFile.read0(Native Method)
at java.io.RandomAccessFile.read(Unknown Source)
at com.orientechnologies.orient.core.storage.fs.OAbstractFile.openChannel(OAbstractFile.java:641)
at com.orientechnologies.orient.core.storage.fs.OAbstractFile.open(OAbstractFile.java:144)
at com.orientechnologies.orient.core.storage.impl.local.OSingleFileSegment.open(OSingleFileSegment.java:57)
at com.orientechnologies.orient.core.storage.impl.local.OStorageConfigurationSegment.load(OStorageConfigurationSegment.java:65)
... 29 more

 I found a solution to this problem!

When you want to share a plocal database among two (or more) processes, you can follow the following procedure.

Let's take a sample scenario. Two processes called Process-A and Process-B are going to access the same plocal storage named 'myPlocal'. Process-A reads the database. Then Process-B update the database and terminates. Then again Process-A reads the database.

Step 1:
Create the db connection from Process-A read the relevant data.
When the Process-A creates the db connection, it locks the db so that any other process cannot read or update the db.
ODatabaseDocumentTx dbProsA = new ODatabaseDocumentTx("plocal:/db/myPlocal");
dbProsA .open("admin", "admin");
Step 2:
Freeze the db from the Process-A.

Freeze method is used to create 'live' database backups. It flushes all cached content to the disk storage and allows to perform only read commands for current process. Here when the Process-A calls freeze method, no any thread from Process-A can write on db. But any thread from Process-A can read from db. More importantly, another process can acquire the db lock and update it. Here the Process-B will do it.
dbProsA .freeze();
Step 3:
Create the db connection from Process-B and read or update data. Then the Process-B terminates.
Because of Process-A has freezed it's connection Process-B can create a new connection and update the db. Here the Process-B should terminate and release the db so that the Process-A can get it back.
ODatabaseDocumentTx dbProsB = new ODatabaseDocumentTx("plocal:/db/myPlocal");
dbProsB.open("admin", "admin");
// Do whatever you want here 
dbProsB.close();
Step 4:
Process-A release the db.
If you freeze the db connection, you should call release method to enable it for write operations.
dbProsA .release();
Step 5:
Process-A restarts the db engine.

This is the most important step. Though you have release the db connection from Process-A, it won't be able to read the updates which has been done by Process-B. You may still read the data which you had at the point you freeze it.
To read the updated values from the Process-B you should re-start the db engine from Process-A. It's just two method calls; shutdown() and start().
OOrient instance = Orient.instance();
instance.shutdown();
instance.startup();
You are done..!
Now you have shared your plocal db between Process-A and Process-B.