PSE/PSE Pro for Java API User Guide
This chapter provides information about how to manage the threads in your application. Sample code that uses threads is in demo\threads.
Relationship Between Threads and Sessions
Which Threads Can Access Which Persistent Objects?
Allowing Threads to Use PSE/PSE Pro
Understanding Concurrency
The concept of a session is important to understand when you are working with threads.
A session is the software component that allows the use of the PSE/PSE Pro API. For a thread to use the PSE/PSE Pro API, it must issue a call that associates it with a session. Any number of threads can be serviced by a session.
An active session is a session that has been initialized by a call to ObjectStore.initialize(host, properties) and not yet shut down. A Java virtual machine that is running a PSE Pro application can have multiple active sessions at the same time. A Java virtual machine that is running a PSE application can run only one session at a time.
A session defines an isolated namespace. The namespace defines unique names (and consequently identities) for databases, segments, transactions, and persistent objects. A session can oversee
Cooperating Threads
All threads associated with a particular session cooperate. That is, they
For example, suppose thread A and thread B are cooperating threads, that is, they belong to the same session. A and B are running along asynchronously. Each thread is issuing a sequence of operations and these sequences are interleaved in an unpredictable fashion.
For PSE/PSE Pro, these operations are all coming from the same place. It does not matter which operation comes from A and which operation comes from B. PSE/PSE Pro views the operations as being in a single sequence, because they are issued from cooperating threads.
If A or B starts a transaction, it does not matter which thread issues the call. The transaction begins for both threads regardless of which thread actually starts the transaction. Any changes performed by A or B during the transaction are visible to both threads and can be acted on by either thread. Similarly, if A commits the transaction, it is just as if B commits the transaction. So B must be in a state where it is okay to commit the transaction. A and B must cooperate.
Threads that do not belong to the same session canonot share transactions, persistent objects, locks on PSE/PSE Pro data, and the view of the state of the database. Threads that belong to different sessions are noncooperating threads.
PSE Pro allows multiple active sessions.
With PSE, there cannot be more than one session that is active at the same time in a single Java Virtual Machine. A PSE application can shut down one session and start another session.
One reason you might want to shut down a session is to release the Java objects associated with the session.
Each persistent object is tied to exactly one session. Any modification to the state of a persistent object must be done by a thread that cooperates in the session to which the persistent object belongs.
For example, suppose you have
In thread TA, you read the contents of a persistent object called OA. Since TA cooperates in session A, OA belongs to session A. Then in thread TB, which is in a transaction, you try to
Effects of Committing a Transaction
When a thread commits a transaction, it affects only those persistent objects that belong to the same session that the thread belongs to.
You must ensure that an object never refers to an object that belongs to a different session. This is crucial because transitive persistence (performed when commiting a transaction) must never reach an object that belongs to another session.
When you have multiple sessions, it is possible to have multiple persistent objects that represent the same object in the database. For example, a thread belonging to session A accesses object X. Then a thread belonging to session B accesses object X. There are two persistent objects named X. Each one is a representation of the same object in the database. If you use the == operator on session A's X and session B's X, the result is that they are not identical; they are not the same object. Within a session, PSE/PSE Pro preserves object identity.
It is the responsibility of the application to ensure that noncooperating threads act on persistent objects only in the ways allowed when a transaction is not in progress.
Noncooperating threads can simultaneously have read-only transactions against the same database. So, in a sense, noncooperating threads can share a database even though they are not cooperating.
Also, noncooperating threads can simultaneously have update transactions against different databases; each noncooperating thread must update a different database. However, noncooperating threads cannot simultaneously open the same database for update. It is as if they are distinct processes; if one thread has a database open for update and a noncooperating thread tries to open that database then the second thread waits. The system property COM.odi.useDatabaseLocking enforces this when it is set to true.
Each metaobject is is related to exactly one session. These metaobjects include
If you open the same database from two different transactions, each session has its own Database object to represent the database. Using the == operator on the two Database objects gives the result that they are not identical.
The first time a thread tries to use PSE/PSE Pro, PSE/PSE Pro determines if an ObjectStore.initialize() method has been executed for that thread. If ObjectStore.initialize() has been executed, the program continues. If it has not been executed, PSE/PSE Pro throws ObjectStoreException.
Each thread must invoke the ObjectStore.initialize() method to use PSE/PSE Pro. This method has two overloadings. The first overloading starts a session. The second overloading joins a thread to an existing session.
In a session, the first thread that needs to use PSE/PSE Pro must initialize the session. This thread calls the overloading of ObjectStore.initialize() that takes two arguments. The method signature is
public static boolean initialize(String host, Properties properties)
PSE/PSE Pro ignores the host parameter. For the properties parameter you can specify null or any combination of the following properties:
Adding Threads to a Session
After a session has one thread, each additional thread that needs to use PSE/PSE Pro in that session must join that session. A thread does this by calling the overloading of ObjectStore.initialize() that takes one argument. The method signature is
public static boolean initialize(Thread targetThread)
The targetThread is any thread that already belongs to the session that the thread is joining.
The initialize() method returns a Boolean value. A value of true indicates that the thread joined the session. A value of false indicates that the action was not performed. For intialize(targetThread), this means that the thread that is calling the method already belongs to the session.
If you want to use PSE/PSE Pro with applets then it is likely that you will use cooperating threads. Typically, one thread initializes things and another thread runs the applet's body.
The PSE/PSE Pro concurrency feature allows
Turning On Database Locking
The COM.odi.useDatabaseLocking property allows you to turn database locking on. By default, database locking is turned off. When database locking is turned off, multiuser access to a database is not safe. You can turn database locking on when you invoke the ObjectStore.initialize(host, properties) method.
When database locking is turned off, it is the application's responsibility to ensure that there are no concurrent updates and that there is no attempt to modify a database while some other application is attempting to read the database.
If all applications are running with database locking turned on, an application need not be concerned about concurrent updates. PSE/PSE Pro provides database locking against multiple updates as described in the next section. However, if even one application is using PSE/PSE Pro without database locking turned on, all applications, whether or not they have database locking turned on, must guard against concurrent updates.
When database locking is turned on, PSE/PSE Pro maintains a lock entry file for each open database. You need not be concerned with these files except that in some situations you might need to delete them.
A lock entry file is a readable text file that lists the lock holders and lock waiters for the associated database. The name of the lock entry file is the name of the database file with the extension .odl. So for the foo.odb database, there is the foo.odl lock entry file.
A sample lock entry file appears below.
# Locker's-ipaddress locker's-lockID Read/Write # locktime
198.3.17.60 1 Read # Thu Apr 24 11:03:04 EDT 1997
198.3.17.60 2 Read # Thu Apr 24 11:03:10 EDT 1997
198.3.17.60 3 Write # Thu Apr 24 11:03:10 EDT 1997
The first line is a comment header that describes the various fields in the file. There are entries for the locker's IP address, the locker's lock ID (which is used by PSE/PSE Pro), whether it is a read lock or a write lock, and the date and time the lock was acquired.
There are situations when you might need to delete lock entry files to release locks on databases. This can happen if database locking is turned on, that is, COM.odi.useDatabaseLocking is set to true, and a Java process exits without closing a database. For example, if the machine crashes or if you press Control-C to exit the Java VM.
When a Java process exits without closing a database, PSE/PSE Pro cannot clean up the lock entry file. Consequently, PSE/PSE Pro continues to operate as though the locks are held even though their holders are no longer active. In this situation you must delete the
This allows PSE/PSE Pro to correctly grant locks. However, before you delete lock entry files or database directories, you must be absolutely certain that there are no users of the database. Use the IP addresses in the lock entry file to confirm this. If you delete the lock entry file or database directory when there are still users, those users might get inconsistent results.
When database locking is turned on (not the default), PSE and PSE Pro for Java allow multiple readers or one writer of a database at any given time. The term one writer implies one session in any process. Two cooperating threads that are both updating a database count as one writer. Two noncooperating threads in the same process that are both writing count as two writers. So they cannot be writing to the same database. Two threads from different processes also count as two writers.
This means that a write lock on a database is exclusive. If a session has a write lock on a database, no other session can read or update that database. If a session requests a write lock and any other session has any kind of lock on that database, PSE/PSE Pro does not grant the requested write lock. The thread requesting the write lock waits until the lock on the database is available.
If a session has a read lock on a database and another session requests a read lock for the same database, PSE/PSE Pro grants the read lock if no other session is waiting for a write lock on the database. If another session is waiting for a write lock, the session requesting the read lock waits until the current read lock or locks are released, the write lock is granted, and the write lock is released.
PSE/PSE Pro grants and releases database locks upon invocation of the Database.open() and Database.close() methods.
PSE permits several Java VMs to read the same PSE database at the same time. PSE does not permit multiple threads in the same Java VM to run in independent transactions against the same or different databases.
PSE permits multiple threads within a Java VM to cooperate in the same transaction and read or write a single database.
In addition to the features provided by PSE, PSE Pro permits threads that belong to different sessions in the same Java VM to start their own independent transactions and use them to access the same or different databases.
Neither PSE nor PSE Pro permit different threads or different Java VMs to read and write the same database at the same time.
When a session requests a lock on a database and that lock is not available, you might prefer that the thread receive an exception instead of waiting until the lock is released. You can do this by specifying nonblocking open modes when you invoke the Database.open() method. When PSE/PSE Pro throws an exception instead of having the session wait for the lock, it does not put an entry in the lock entry file.
[previous] [next]
doc@odi.com
Copyright © 1997 Object Design, Inc. All rights
reserved.
Updated: 05/13/97 12:17:16