• No results found

Guarantees ensuring weak isolation

2.4 Transaction semantics

2.4.4 Correctness guarantees

2.4.4.1 Guarantees ensuring weak isolation

As explained in Section2.4.1weak isolation allows transactional data races. This is equiv- alent to saying that the ACI properties of transactions are valid only among transactions and not between transactional and non-transactional code. There are a number of different guarantees that ensure this requirement. In general, the basic rationale of these guarantees is equivalence of the current transactional execution to a sequential history, i.e., an ex- ecution where transactions execute one after the other without interruption. A sequential history trivially ensures the ACI properties and so does a history equivalent to a sequential history.

Below, we present a series of weak isolation guarantees that are based on equivalence to a sequential history. For the sake of simplicity, we consider in the remainder only read/write objects and we assume that all executions respect the sequential specification of these objects meaning that a read to an object must return the last written value or the default one in case no previous write exists.

Ensuring correctness of committed transactions: We start with guarantees that con- sider correctness only for committed transactions. Although these guarantees are not suit- able for TM systems, we start by introducing them since they form the foundations of correctness guarantees specific to TMs.

ˆ Serializability [146] is a correctness guarantee that has been extensively used to characterize transactional database systems. Serializability accepts an execution as being correct if it is equivalent to a sequential history.

ˆ Strict serializability can be considered as linearizability [100] defined for transactions. As such, it is the same as serializability with an additional constraint: the occurrence order of non-concurrent transactions must be preserved in the equivalent sequential history (we say that two transactions are non-concurrent if there is no common point in time where the two transactions have started and none of them have terminated yet). In other words, strict serializability takes the occurrence times of start and commit operations of a transaction into account and provides the illusion that a transaction takes effect instantaneously at some point in time between its start and commit operations (and does not allow any transaction ordering that would violate this illusion). As strict serializability restricts the set of possible equivalent sequential histories, it is strictly stronger than serializability.

Ensuring correctness of all transactions: Ensuring correctness of only committed trans- actions is a valid approach in database systems since the user of the system is not effected

by the execution of the transaction, but rather sees the committed result. So a database system can allow aborted transactions to execute based on inconsistent states. However, in TM-based programs a transaction is a part of the program logic, so any fault that could occur in the execution of a transaction (even if the transaction would abort) can lead to anomalies such as infinite loops, access violation exceptions, divide-by-zero errors [79]. For a multi-threaded program such anomalies should be avoided even for aborted transactions to ensure the correctness of the program. Transactions that have observed inconsistent values but that have not yet aborted (and hence can cause anomalies) have been named doomed transaction [171] (or zombie transaction [42]). In the following, we analyze correctness guarantees that forbid the execution of doomed transactions (while still ensuring correctness of committed transactions):

ˆ Opacity [79] requires that strict serializability is ensured for all transactions (both committed or aborted) and that all transactions including aborted ones access only consistent system states at any time.

ˆ Virtual world consistency (VWC) [104] is the same as opacity except that strict serializability is ensured for all committed transactions rather than all transactions (both committed and aborted). It should be noted that VWC still ensures the execu- tion of aborted transactions on consistent state, as in opacity. This is made possible by enforcing aborted transactions to execute based on some possible set and/or order of committed transactions. The set and/or order of committed transactions observed by aborted transactions may disagree with the one finally observed by all threads. The rationale behind this guarantee is that since the aborted transaction’s execution is consistent with a possible set and/or order of committed transactions (does not matter if it is the finally observed one), this execution should not result in any anoma- lies; the transaction should be executing correctly as if the set and/or order accepted by the aborted transaction were correct. With its restriction on aborted transactions, VWC is stronger than strict serializability but weaker than opacity.

ˆ Weakest Reasonable Condition (WRC) [44] shares the same rationale as VWC for the consistency of aborted transactions. However, it also allows any transaction to pretend as a commit-pending transaction that has committed, even though it may ul- timately abort (a transaction is said to be commit-pending if it has invoked commit, but has not yet committed or aborted). This allows WRC to include some uncom- mitted transactions to be included in the order of committed transactions. Another difference between WRC and VWC is that VWC allows an aborted transaction T to ignore committed transactions that precede T in the order of real-time occurrence while WRC takes this real-time occurrence into account. With such properties, WRC

Figure 2.5: Two operations with same accesses and differing semantics.

is stronger than neither opacity nor VWC [44]. But it is obviously stronger than strict serializability.

Relaxing correctness requirements when not needed: In a concurrent environment, two operations may look very similar even though they do not share the same semantics. For example, this is the case for a contains(z) operation traversing an ordered linked list data structure and failing in finding element z and another operation size() capturing an atomic snapshot of the number of elements of this data structure. Both operations have the same sequence of read/write accesses, yet they have distinct semantics. Figure 2.5 depicts the reads r(*) and writes w(*) of these operations.

The contains(z) is consistent even though y is concurrently inserted after r(u) oc- curs. Conversely, the size() requires for example that u and y, which are both counted, were both present in the linked list at the same time. Hence, contains(z) enables theoret- ically more concurrency than size() as it allows a weaker guarantee than size() requires. Below, we describe the guarantees that exploit the high-level application level semantics of operations such as the contains(z) and that improve the performance of the TM for executions including these operations:

ˆ Elastic-opacity [58] assumes a model with two types of transactions, elastic and regular, and requires that if we cut elastic transactions into smaller sub-transactions, then the resulting execution is an opaque execution composed of regular transactions and sub-transactions. A programmer can choose to associate elastic-opacity to a transaction if the transaction as a whole does not need to appear as atomic, whereas all couples of consecutive operations or the operations delimited by write operations in this transaction need to appear as atomic. As long as these requirements are satisfied by the transaction code, elastic opacity provides fast and safe execution of the transaction among other elastic and regular transactions.

ˆ View transactions [15] uses multi-versions [22] which allow accessing older versions of an accessed memory location. Having the possibility to access older versions (rather than only the current version) a read operation can return a value based on a consistent snapshot, which does not need to be the same as the snapshot used at commit-time. It is sufficient for program correctness that only a subset of the actual snapshot encountered at the commit-time is the same as the subset of the snapshot constructed during execution (the snapshot constructed during execution can point to older versions of several objects compared to the commit-time snapshot). The subset that needs to be the same is determined by the program level correctness criteria, e.g., for the contains(z) example above, it would be last consecutive two reads. This subset that needs to be valid should be identified by the programmer as a critical view. As with VWC and WRC, aborted view transactions execute on some consistent state of the system, since a transaction executes based on a possible snapshot that does not need to be the same as the actual one. This way, inconsistency anomalies that could occur are avoided. Note that this is not the case with elastic opacity.