From TradeDesign perspective there are some important basic information to be setup for locking to work properly.
Defining one or multiple fields defining the lock key for each table where locking will be needed. Typically, the INR is defined as single lock field. In table where the entries are not identified by their own INR a group of fields identifying the entities which shall be jointly locked shall be specified as lock key. As sample case the DOKA table ETAUIL might be seen, where die language specific fields of an entity address are stored. The table ETAUIL uses as lock fields the field ETAINR, which links the ETAUIL to the owning ETA, and UIL which holds the language.
When setting up a new table definition, the lock field must be defined. The definition is done in the properties of the table module. If the table uses an INR to identify each entry, the lock key is typically exactly the INR of that table.
Sample:
For low level technical reasons any acquiring or releasing a lock (e.g. SdbReadLock, DbLock, DbFree, DbFreeAll) implicitly issues a database commit. Therefore, long-term locks should only be raised in the initialization phase of a transaction, or in separate events, which are executed during a transaction and which should add another entry to the long-term locked entries.
When an entry to be updated is read with a short-term lock which is technically a DbReadHold and the entry to be updated is currently not accessible due to being locked or held by another process, TradeDesign automatically internally retries to get hold of the entry multiple times with some fractions of a second delay before returning record not accessible to the application.
To be able to detect wrongly issued commits there is a pair of rules in SYSMOD which helps to detect unwanted commits. The two functions DbCommitStateSave and DbCommitStateCheck might be called at the beginning of a database transaction and at the end of the database transaction. The purpose of these routines is to detect intermediate database commits, which might lead to only half completed database transactions and in the end might lead to incomplete updates in the database with a most probably inconsistent database content. These two functions are typically not needed to be called from application rules. They are called in the generic rule frameset provided in MTABUT, MDxBUT etc..
Another aspect is, that it is essential first to lock and then to read the data of an entry and only then process / use / update the data. If data is used, which is read from the database before a lock is placed, this data might not be the data valid at the point in time, when the update is executed. The typical solution is to use the rule SdbReadLock to access the database, which provides the associated logic.
To be able to share the long-term locks with other processes TradeDesign stores all locks in a central lock table (LCK) in the database. Short term locks are implemented differently depending on the used database system. TradeDesign uses the database side provided update procedures (e.g. select for update).
Each TradeDesign process keeps a process internal hash table of open locks which might be retrieved for debugging purpose. It is part of the output stored in the dump files to provide an overview of the currently locked entries. It is important to know, that the list is not sorted and therefore does not reflect the locking hierarchy or the lock sequence. The shown lock key is made up by the issuing table and the concatenated content of the defined lock fields.
Below a sample taken from a dump which occurred during the update of ETA in DBEETA. In this sample the different lock states and a combined lock definition (in ETAUIL the INR plus the language are used as lock definition) can be seen.
Locked Records:
Flag | Table | Lock Key |
---|---|---|
L | SSN | 00000362 |
B | ETA | 00000010 |
H | ETAUIL | 00000010DE |
I | SLG | 00003999 |