Marking versus Locking

Most RDBMS control access to shared data objects by using locks. One operation at a time can hold the lock, all other operations requesting access are blocked, and sit idle until the lock is released. At that point, one of the waiting operations acquires the lock and the others continue to wait. Most RDBMS hold locks until a transaction is completed. A mark never causes an operation to block, instead, if the mark is already held, the requesting operation receives an immediate error.

The TIBCO Patterns server uses a combination of locks and marks to control access to data objects. Within a specific command, all data objects are locked by blocking locks for the duration of the command. This is regardless of whether it is associated with an explicit transaction or an implicit transaction. Marks are also placed on the data objects. The locks are released when the command completes and the marks are released when the transaction is committed or aborted. As implicit transactions are committed or aborted automatically before the locks are released, the marks are cleared before the locks are released and thus are not normally seen by the user. So the discussion of marks, with just a few exceptions, pertains only to explicit transactions and how data objects are treated between commands within an explicit transaction. The exceptions are when using joined tables or when accessing a cluster through a gateway.

Some implications:

A command that attempts to access an object being updated by another command blocks until the first command completes. But it blocks only until the individual command completes, not until the transaction is closed.
Deadlocking on data object locks does not happen when using TIBCO Patterns. By isolating locks within a single command, TIBCO Patterns can ensure that these locks are acquired in a deadlock safe manner (a hierarchical allocation scheme is used). This means that the mechanisms provided by RDBMS to prevent deadlocks, such as timeouts on locks and deadlock detection algorithms, are not needed.

It might seem that this method of using marks instead of locks puts a burden on the application. Although it might appear the application must implement a check and retry mechanism to handle transaction conflict errors, in nearly all cases it is not necessary. A properly functioning application should never get a transaction conflict error. A conflict error is generated only when two or more transactions attempt to make conflicting changes to the same object at the same time. The final state of the object becomes unpredictable as it depends on which transaction happened to get in first. Leaving data in an unpredictable state is not desirable. Thus, receiving a transaction conflict error from TIBCO Patterns indicates a problem in the application that should be corrected. If applications simply ignore all transaction conflict errors, the effective results are the same as if blocking locks had been used. (The one exception is if using a clustered arrangement where both commands might fail instead of one or the other. If you use blocking locks, this situation is likely to result in a deadlock situation, which the application would need to handle, so there is still no net gain in simplicity for the application.)

Marking and Access Rules

Marks on an object are not necessarily mutually exclusive. In some situations, it is safe to allow two or more transactions to perform certain operations on the same data object at the same time. The main example is updating records in a table. Two or more transactions might update records in a table at the same time, as long as they are different records. The general rule is that commands that modify an object as a whole are mutually exclusive, whereas commands that modify only some portion of an object are not. Currently, all operations on Thesauri, Character Maps, Learn Models and Records operate on the associated object as a whole, and are thus exclusive. Commands that operate on the table as a whole and are thus mutually exclusive are: add (that is, create or load), delete, rename (that is, move), checkpoint, restore and bulk (that is, fast) loads of records. (The bulk (or fast) load of large batches of records is considered to change the table as a whole for performance reasons.) The other record operations are exclusive at the record level, but not at the table level. However, they are exclusive at the table level with operations that modify the table as a whole. Thus, two different transactions can update records on the same table at the same time (as long as they are different records), but one transaction is not allowed to delete a table when another transaction is updating records in that table.

The rules of marking mentioned before pertain to two or more different transactions. The same transaction can act on the same object multiple times. Thus, the same transaction might add a new table, load it with records and then rename the table. These marks do not restrict actions performed by the same transaction.

Marks are retained until the transaction that created them is closed. This is true even for objects that are deleted. When a table is deleted, it is no longer visible, even before the transaction is closed. So in the following sequence:

1. Transaction 1 deletes table A.

2. Transaction 2 adds table A.

3. Transaction 1 is committed.

Transaction 2 receives a transaction conflict error at step 2. This is necessary to maintain the integrity of the data objects. If the application aborts the first transaction, it must be able to restore the deleted table. If another transaction were allowed to add a new table with the same name, the restore would either fail or be forced to delete the new table.

When dealing with joined tables, there is one other kind of mark that is placed on a parent table. When a child table is added to the parent table, it is marked as held. Although no change is being made to it, the parent table is necessary for the existence of the new child table. So actions on that table are blocked until the transaction is closed.

Unlike the marks discussed previously, marks indicating a data object are held block actions by all transactions, even the transaction that created the mark. Adding a new child table and then deleting its parent is invalid even when performed in the same transaction. Held marks are not mutually exclusive, however, two or more transactions might hold the same parent table at the same time. The same transaction might also place multiple held marks on the same parent table.