Tuning for Concurrency

Concurrent process execution is mainly governed by the concurrency restrictions of the data accessed in a process - independent from whether Infinity Process Platform manages these data by reference or by value. If two concurrent workflow threads are accessing the same process data either directly via data mappings or indirectly via applications performed in the process activities - concurrency conflicts may occur. These conflicts are either handled by the application logic or by explicitly modeled exception handling in the corresponding process models.

To reduce the possibility of conflicts when accessing internal persistent data concurrently (e.g. the state of a process), Infinity Process Platform provides sophisticated concurrency tuning mechanisms as described in the following sections.

Proxy Lock Tables

The Infinity Process Engine relies on pessimistic locking of database rows to guarantee correctness of process execution. While all database systems supported by the Infinity Process Engine provide means to implement such row locking behavior, current experience proves the chosen implementation to have scalability and robustness problems on database systems using the classical two-phase locking approach to row lock management (basically any DBMS but Oracle). A major weakness in such environments is even readers being blocked from accessing locked rows, thus causing unneeded delays or even deadlocks.

The feature Proxy Lock Tables is the introduction of a runtime option to separate logically and physically locked database rows. This change will introduce optional proxy tables exclusively used for applying exclusive row locks. Thus, even while original rows are logically locked for update by one thread of execution (which is done by obtaining a physical lock on the associated row in the proxy table), any parallel read access is able to obtain the original row content without causing a conflict.

If applied, the locking table extension will add for each of the tables ACTIVITY_INSTANCE, DATA_VALUE, PROCESS_INSTANCE and TRANSITION_TOKEN, a proxy table containing just the primary key column from the original table. The engine then maintains a row in the associated proxy table, consisting of exactly the original row's PK value for every row in original tables. Additionally, any pessimistic lock operation on a row from original tables with proxy will obtain an exclusive DB lock from the according row in the associated proxy table.

Disadvantages of using Proxy Lock Tables are a minimal database size overhead.

The Proxy Locking Table feature is activated with the session property UseLockTables:

AuditTrail.UseLockTables = false/true

Proxy lock tables are administrated with the corresponding options in the sysconsole command.

Tuning JDBC Exception Handling

Exactly one data value can be created per process instance and per data, but in a process instance more than one activity instance could try to access the same data value. If this data value does not already exist at that time, it will be created. This can happen at the same time in more than one threads of a process instance. In that case a database exception is thrown.

There are two possibilities how this can be handled:

  1. The rollback mechanism provided by Infinity will come into action and the activity thread will be restarted. This can happen several times until the exception is propagated. Please refer to the chapter Exceptions in the Programming Guide for detailed information on exception handling in Infinity Process Platform .
  2. If you set the property AuditTrail.InterceptJdbcCalls in your server-side carnot.properties to true, the exception will directly be caught during the creation of the data value bean in the engine. It will be tried to load the instance of the already existing data value bean, which has been created meanwhile from a parallel thread. This will be tried up to three times before an ObjectNotFoundException is thrown.

Tracing of Transactions, Method Calls or Requests

To trace the duration of database calls, use the tuning property Carnot.Engine.Tuning.ServiceCallTracingThreshold. Set this property in your server-side carnot.properties file to a threshold in milliseconds. If this threshold is exceeded, a log is written. This log could look like in the following example, where a threshold of 100 was used:

14:24:44 INFO - [main  ] DebugInterceptor - --> closeSession
14:24:44 INFO - [main  ] Security         - Partition: default, Domain: default.
....
14:24:44 INFO - [main  ] Performance      - Service call: 188 ms for 'org.eclipse.stardust.engine.api.runtime.UserService.closeSession'. (total SQL: 0 ms)
14:24:44 INFO - [main  ] Performance      - List of recorded SQL statements for this service call:
14:24:44 INFO - [main  ] Performance      -     0 ms: SELECT dd.oid, dd.model, dd.id, dd.name, dd.description FROM data dd INNER JOIN model m ON (dd.model = m.oid AND m.partition = 1)
14:24:44 INFO - [main  ] Performance      -     0 ms: SELECT sd.oid, sd.xpath, sd.data, sd.model FROM structured_data sd INNER JOIN model m ON (sd.model = m.oid AND m.partition = 1)
14:24:44 INFO - [main  ] Performance      -     0 ms: SELECT mpd.oid, mpd.model, mpd.id, mpd.name, mpd.type, mpd.description FROM participant mpd INNER JOIN model m ON (mpd.model = m.oid AND m.partition = 1)
14:24:44 INFO - [main  ] Performance      -     0 ms: SELECT pd.oid, pd.model, pd.id, pd.name, pd.description FROM process_definition pd INNER JOIN model m ON (pd.model = m.oid AND m.partition = 1)
14:24:44 INFO - [main  ] Performance      -     0 ms: SELECT pt.oid, pt.model, pt.id, pt.name, pt.processDefinition FROM process_trigger pt INNER JOIN model m ON (pt.model = m.oid AND m.partition = 1)
14:24:44 INFO - [main  ] Performance      -     0 ms: SELECT ad.oid, ad.model, ad.id, ad.name, ad.processDefinition, ad.description FROM activity ad INNER JOIN model m ON (ad.model = m.oid AND m.partition = 1)
....
14:24:44 INFO - [main  ] DebugInterceptor - >-- closeSession

The lines with category Performance have the following format:

The list of recorded SQL statements contains all SQL statements performed during this service method call.

The dependencies between the values XXX, YYY and yyy are the following:

The logging is performed by log4j. So the logging can be configured by a file name log4j.properties. The following example writes any line to any.log excluding the lines for the category Performance, which are written to perf.log:

log4j.rootCategory = INFO, default
log4j.appender.default = org.apache.log4j.FileAppender
log4j.appender.default.File = any.log
log4j.appender.default.layout = org.apache.log4j.PatternLayout
log4j.appender.default.layout.ConversionPattern = %d{HH:mm:ss} %-5.5p- [%-15.15t] %-20.20c{1} - %m%n
log4j.appender.default.Threshold = INFO

log4j.logger.org.eclipse.stardust.engine.api.runtime.logging.Performance = INFO, perf
log4j.appender.perf = org.apache.log4j.FileAppender
log4j.appender.perf.File = perf.log
log4j.appender.perf.layout = org.apache.log4j.PatternLayout
log4j.appender.perf.layout.ConversionPattern = %d{HH:mm:ss} %-5.5p- [%-15.15t] %-20.20c{1} - %m%n
log4j.appender.perf.Threshold = INFO
log4j.additivity.org.eclipse.stardust.engine.api.runtime.logging.Performance=false