Program guide > Access data with client applications > Programming for transactions > Use locking



Map entry locks with query and indexes

This topic describes how eXtreme Scale Query APIs and the MapRangeIndex indexing plug-in interact with locks and some best practices to increase concurrency and decrease deadlocks when using the pessimistic locking strategy for maps.


Overview

The ObjectGrid Query API allows SELECT queries over ObjectMap cache objects and entities. When a query is run, the query engine uses a MapRangeIndex when possible to find matching keys that match values in the query's WHERE clause or to bridge relationships. When an index isn't available, the query engine will scan each entry in one or more maps to find the appropriate entries. Both the query engine and index plugins will acquire locks to verify consistent data, depending on the locking strategy, transaction isolation level, and transaction state.


Locking with the HashIndex plug-in

The eXtreme Scale HashIndex plug-in allows finding keys based on a single attribute stored in the cache entry value. The index stores the indexed value in a separate data structure from the cache map. The index validates the keys against map entries before returning to the user to try to achieve an accurate result set. When the pessimistic lock strategy is used and the index is used against a local ObjectMap instance (versus a client/server ObjectMap), the index will acquire locks for each matching entry. When using optimistic locking or a remote ObjectMap, the locks are always immediately released.

The type of lock that is acquired depends upon the forUpdate argument passed to the ObjectMap.getIndex method. The forUpdate argument specifies the type of lock that the index should acquire. If false, a shareable (S) lock is acquired and if true, an upgradeable (U) lock is acquired.

If the lock type is shareable, the transaction isolation setting for the session is applied and affects the duration of the lock. See the transaction isolation topic for details on how transaction isolation is used to add concurrency to applications.


Shared locks with query

The eXtreme Scale query engine acquires S locks when needed to introspect the cache entries to discover if they satisfy the query's filter criteria. When using repeatable read transaction isolation with pessimistic locking, the S locks are only retained for the elements that are included in the query result and are released for any entries that are not included in the result. If using a lower transaction isolation level or optimistic locking, the S locks are not retained.


Shared locks with client to server query

When using the eXtreme Scale query from a client, the query typically runs on the server unless all of the maps or entities referenced in the query are local to the client (for example: a client-replicated map or a query result entity). All queries that run in a read/write transaction will retain S locks as described in the previous section. If the transaction is not a read/write transaction, then a session is not retained on the server and the S locks are released.

A read/write transaction is only routed to a primary partition and a session is maintained on the server for the client session. A transaction can be promoted to read/write under the following conditions:

  1. Any map configured to use pessimistic locking is accessed using the ObjectMap get and getAll API methods or the EntityManager.find methods.

  2. The transaction is flushed, causing updates to be sent to the server.

  3. Any map configured to use optimistic locking is accessed using the ObjectMap.getForUpdate or EntityManager.findForUpdate method.


Upgradeable locks with query

Shareable locks are useful when concurrency and consistency is important. It guarantees that an entry's value does not change for the life of the transaction. No other transaction can change the value while any other S locks are held, and only one other transaction can establish an intent to update the entry. See the Pessimistic Locking Mode topic for details on the S, U and X locking modes.

Upgradeable locks are used to identify the intent to update a cache entry when using the pessimistic lock strategy. It allows synchronization between transactions that want to modify a cache entry. Transactions can still view the entry using an S lock, but other transactions are prevented from acquiring a U lock or an X lock. In many scenarios, acquiring a U lock without first acquiring an S lock is necessary to avoid deadlocks. See the Pessimistic Locking Mode topic for common deadlock examples.

The ObjectQuery and EntityManager Query interfaces provide the setForUpdate method to identify the intended use for the query result. Specifically, the query engine acquires U locks instead of S locks for each map entry involved in the query result:

ObjectMap orderMap = session.getMap("Order");
ObjectQuery q = session.createQuery("SELECT o FROM Order o WHERE o.orderDate=?1");
q.setParameter(1, "20080101");
q.setForUpdate(true);
session.begin();
// Run the query.  Each order has  U lock
Iterator result = q.getResultIterator();
// For each order, update the status.
while(result.hasNext()) {
    Order o = (Order) result.next();
    o.status = "shipped";
    orderMap.update(o.getId(), o);
}
// When committed, the 
session.commit();

Query q = em.createQuery("SELECT o FROM Order o WHERE o.orderDate=?1");
q.setParameter(1, "20080101");
q.setForUpdate(true);
emTran.begin();
// Run the query.  Each order has  U lock
Iterator result = q.getResultIterator();
// For each order, update the status.
while(result.hasNext()) {
    Order o = (Order) result.next();
    o.status = "shipped";
}
tmTran.commit();

When the setForUpdate attribute is enabled, the transaction is automatically converted to a read/write transaction and the locks are held on the server as expected. If the query cannot use any indexes, then the map must be scanned which will result in temporary U locks for map entries that do not satisfy the query result, and hold U locks for entries that are included in the result.


Parent topic:

Use locking


Related concepts

Locks

Locking performance best practices


Related tasks

Implement exception handling in locking scenarios

Configure a locking strategy

Configure the lock timeout value