Loading...
 

Transactions

Transactions

InstantView® automatically manages database transactions.
The InstantView® interpreter tries to start a transaction as late as possible: The first statement, which can only operate within a transaction, starts the database transaction.
At the end of the statement sequence it is automatically terminated (commit), and thus modified or newly created objects are written to the database.
If an error occurs, the transaction is aborted. Changed objects remain in the (old) state before the change, newly created objects no longer exist.
InstantView® reflects this undoing of changes in the database by managing logical transactions in parallel to the database transactions.
For example, this prevents an InstantView® variable from referring to a persistent object that no longer exists.
Consistency between the database and InstantView® is achieved by ensuring that when a transaction is aborted

  • all module variables and global variables are reset to the value at the beginning of the transaction,
    Local variables are not reset!
  • transient collections again contain exactly those objects as elements to which they were referred at the beginning of the transaction,
  • the SetLayer, SetDomain and SetPattern commands executed within the transaction are reset to the value at the beginning of the transaction,
  • the following system parameters to be set using SystemObject - if they have been changed within a transaction - are reset when the transaction is terminated:
    Parameters SystemObject method
    Validity date SetValidityDate
    Check-Mask for validity (of objects) SetCheckMask
    session date SetSessionDate
    Switching the timestamp for update operations on or off SetTimeStamp
    Upper limit for a date - CX_DATE SetDateLimit
    Preset Unit of measurement for CX_VALUE SetDefaultUnit
    Default Currency SetDefaultCurrency
    current locale SetLocaleByName, SetLocaleByObject
    Message for variable query for CX_FORMULA (bind message) SetBindMessage
    Conversion tables for units (or currencies) SetRate, RegisterRate, DeregisterRate, AddOverwriteRate
  • Changes to the PlugSpace can be undone - PlugSpace, PlugSpacePush, PlugSpacePop
  • the set language index is reset - Language
  • Windows opened within the transaction just aborted can be closed again,
  • the window objects ObjectList, ObjectComboBox, ListView and ObjectTree are reset to the state at the beginning of the transaction (if they have displayed new or other persistent objects within the transaction)
  • modules initialised within the transaction are considered as not initialised. INITIALIZE is implicitly called again at the next message they receive.

Attention: Changes of transient objects are not reversed!
Examples for the behaviour of the above mentioned elements of the ClassiX® system can be found here.

To reduce locking conflicts it may be useful to control transactions explicitly (the InstantView® interpreter knows the latest possible time to start a transaction, but not the earliest time to end it!)

Note:
- If a transaction is explicitly controlled with EndTXN / BeginTXN, this also affects the logical transaction handling of InstantView®.
For a transaction switch with the purpose of releasing address space, the method FreeAddressSpace of the object manager should be used!

- Transaction change is not allowed everywhere - see instruction iterate - and is then ignored. A warning appears in the log file.

Furthermore, databases can be opened in MVCC mode (Multi Version Concurrency Control - see ObjectStore documentation): Locking conflicts are largely avoided, because the objects read in MVCC mode can be changed by other clients. In MVCC mode a client does not always see the latest version of an object, but all objects are in a state that is consistent in itself.

Lock timeouts

Lock timeouts can occur at any time during a write transaction if a client has to wait too long for a database lock. To ensure that each client has a consistent view of the database, the database ensures that at any given time either any number of clients can read a page at the same time (n read locks), or a single client can write to the page (1 write lock).

When attempting to write/read a page, a client may not yet be allowed to read/write because another client is still holding a lock that prevents this. If the client waits too long for the lock, a lock timeout error occurs.

Reduce/avoid lock timeouts:

  1. Keep write transactions as short as possible. No long calculations should be carried out during a write transaction or user interaction should be required in between. As far as possible, calculations should be carried out beforehand in a read transaction in the transient space and then the changes transferred to the persistent space in a short write transaction.
  2. Perform read transactions in MVCC mode (BeginTXN(READ)). A client in MVCC mode cannot block other clients. However, clients that need to read and write frequently must reopen the database when changing transactions, which costs more time depending on the size of the database, and the entire cache is lost.
  3. Another approach would be to restructure the application so that there is only one client that performs all write operations (a kind of database worker) and the remaining clients read the database in MVCC mode. However, this approach only works for very specific applications and if two clients want to write to the same object, a lost update is very likely, which can lead to inconsistent data.
  4. Automatically repeat transaction using RetryTXN. This is one way of hiding lock timeouts from the user, but this approach can potentially make the problem worse as it does not solve the underlying problem and the user now potentially has to wait longer for the error message to appear. In addition, the client that repeats the transaction itself holds database locks, which in turn can block other clients more, as the locks persist for a longer period of time due to the repetition.

Deadlocks

A deadlock occurs when two clients request the same 2 locks in different order and both have already received their first lock. In this case, neither client can continue its transaction unless the other client releases the lock it has already received. ObjectStore detects such a situation and randomly decides which of the two clients may continue the transaction, while the transaction of the other client is automatically aborted.

Reduce/avoid deadlocks:

  1. Investigate deadlock situations and adapt the application flow so that objects are always touched in the same order if possible (in the sense of lock-ordering). This is by far the best solution for deadlocks, as it prevents deadlocks completely.
  2. Perform read transactions in MVCC mode (BeginTXN(READ)). A client in MVCC mode cannot block other clients. However, clients that have to read and write frequently have to reopen the database when changing transactions, which takes more time depending on the size of the database, and the entire cache is lost.
  3. Investigate deadlock situations and use BeginLock(WRITE) to lock a synchronisation object in both use cases, which represents the entry point into the use case, so to speak, and ensures that only one client has access to the affected objects at any time. However, this approach has the disadvantage that clients that are not affected (same use case but different objects) are potentially slowed down unnecessarily and transactions remain open longer than necessary, which in turn can lead to lock timeouts.
  4. Automatically retry the failed transaction using RetryTXN . The client whose transaction was aborted by the deadlock can automatically repeat its transaction with this, but this approach does not solve the underlying problem and can lead to the deadlock occurring again in the repeated transaction with another client for many active clients. In extreme cases, this can lead to deadlocks continuing to be reported just as frequently and only increasing waiting times. The repeated transaction causes locks to be held for a longer period of time, which in turn can lead to increased lock timeouts.
  5. Keeping write transactions as short as possible can also reduce deadlocks, but this potentially only postpones the problem, as deadlocks can reoccur as soon as the number of clients is increased.
  6. Using BeginLock(WRITE, DATABASE) or CX_TRANSACTION_MANAGER։։SetDefaultLockMode, the entire database can be locked for each transaction in extreme cases. The database then works in single-user mode and transactions are no longer carried out in parallel. A client must wait with its transaction until all preceding clients have completed their transaction. This approach makes deadlocks impossible, but it also causes very long waiting times and can increase the number of lock timeouts (especially with many clients). This approach should only be chosen for extremely short write transactions and is more of an emergency solution. The performance of the application suffers extremely from this approach.

statements:

Note: The ClassiX® system carries out self-tests to monitor the automatisms described above. The errors that can be detected are summarised in this table.