How do I get best custom application performance when employing user-initiated transactions?
The IBM FileNet P8 Content Engine has numerous caches related to security, some associated with the object store and others associated with server security configuration. These caches are updated whenever objects are accessed by an application outside of a user transaction. Three of the primary security caches are the Security Descriptor (SD) cache, the Object Security (SO) cache, and the Marking Set (MS) cache.
You may want to use transactions in a custom application to facilitate data integrity across both P8 Content Engine and an outside database or action handler.
Transactions are supported over the EJB transport through Java API calls. (The CEWS transport and the .NET API do not support client-initiated transactions.) Transaction processing is implemented using standard J2EE transaction mechanisms through the Java Transaction API (JTA). An application can perform multiple operations within a transaction. Should the transaction fail (for example, one of the operations fails), the JTA would handle the roll back of the entire transaction. To set up transaction support for your Java client application, use the standard J2EE UserTransaction calls (on the javax.transaction.UserTransaction interface). You must also enable transactions on the Connection object you are using by setting the CONNECTION_PARTICIPATES_IN_TRANSACTION parameter to true.
When your custom application makes an EJB call within a transaction, and the query does not find the security object in the main global cache, the Content Engine loads the security object into a transient cache instead of the main cache. This transient cache is per request, and is only in existence during the EJB call. This transient cache is meant for use when updating, creating, or deleting one or more objects within a transaction.
Due to this transient cache behavior, any security object required during the transaction is not loaded into the main cache. The Content Engine does this because the security object might have been created on another cluster server and might not yet be committed. Since that server cannot tell if the security object was just created in a transaction that might be rolled back, the object cannot be added to the main cache. The Content Engine is not aware of which security objects participated in, or were queried during the transaction after it is committed, and these objects are therefore not added to the main global cache.
The main global cache is updated with security objects only when outside of a user-initiated transaction.
If you are running multiple Content Engine servers in a cluster, this behavior is multiplied since these separate server caches are updated only when the security object is requested outside of a transaction on that specific server.
Therefore if your custom application must incorporate user-initiated transaction, you must design the application so that transactions are only used during update, create, and delete actions. All other actions must be outside of a transaction so that your application updates the main cache as much as possible.
Suggestions to maximize cache effectiveness when using transactions:
There are three suggested approaches for limiting transactions within your custom application to update, create, and delete actions only. Approach #3 is the least trouble to implement.
1. If your custom code, which is already EJB-based, is using application-managed transactions, then you can either be in a transaction (TX) or not in a TX, when appropriate. There are a couple of reasons this may not work. First, if you are using container-managed transactions, there might not be a way for your code to not be in a TX. We do not recommend suspending the TX in this case, due to the added complexity of this action. Second, it may be inconvenient for your application logic to have periods of not being in a TX while you call Content Engine.
2. You could use two Connection objects, one with and one without the participation parameter. This is not as convenient as it sounds because a reference to the Connection object tends to get embedded into many Content Engine objects. Keeping the objects sorted out by flavor of Connection is an awkward solution.
3. You can toggle the CONNECTION_PARTICIPATES_IN_TRANSACTION participation parameter. Our recommendation would be to leave it off by default and explicitly set it for any RPC that requires it (update, create, or delete actions only). Further, we recommend putting such RPCs inside a try/finally block so that the participation parameter gets toggled back off in all cases when the RPC is concluded.
Our recommendation is to carefully examine when you really need a user transaction versus not, and do not use a transaction for operations which do not need one. Simply put: for best performance you must perform queries and actions outside of a user-initiated transaction in order to see and update the main global cache.