• No results found

6.2 Automatic transactification with Java

6.2.1 Transactification overview

6.4.2.3 Control flow

Below we detail the transformations performed both for regular, transactional and excep- tional control flow constructs described in Section 5.4.

Regular control flow: For regular control flow we consider only the control keywords return, continue and break. In the immediate scope of a transaction block (i.e., if the control flow keywords do not relate to a nested construct such as a loop), these keywords evoke the commit of the transaction. However, if the scope of these keywords is larger than the transaction, once committed the behavior expected from the keyword should be valid also out of the transaction. In order to provide this behavior we perform the following transformation:

ˆ A position pointer field (an integer) is added to the class where the transformation is performed. This position pointer is meant to store the position (in the transaction) of the regular control flow keyword that caused the transaction to commit. The position value is generated by enumerating the regular control flow keywords in the transaction in their order of appearance in the transaction block code.

ˆ The enumeration in the previous item causes a nested if-then-else statement to be added after the call to the Deuce function generated for the transaction block. In this nested if-then-else statement the conditions that are checked are the position values of the regular control statements (the position of the currently active control statement is held in the position pointer). The body corresponding to each position value in the nested if-then-else statement is the regular control statement for this position value.

ˆ Each regular control statement encountered in the transaction block is replaced with two statements: (i) assignment of the position value of the control statement to the generated position pointer, and (ii) a return statement.

An example of this transformation is shown Listings 6.3 and 6.4. The code to be transformed is similar to the code in Listing 6.1 except that there are two if statements before and after the line where the amount stored in the source account is obtained (lines 11 and 16 of Listing 6.3 respectively). The first if statement (line 11) checks whether access to the account is granted (using the credentials ok() method) and if access is denied quits the for loop using the break keyword in order to cease the transfers. The second if statement (line16) ensures that the source account has an amount higher than zero before before any transfer is done. If, however, amount is not a positive value, it skips the rest of the iteration using the continue keyword in order to read the next source account.

The transformed code for the example in Listing 6.3is illustrated in Listing 6.4. The code generated by the transformation is shown in red. The three transformation items previously explained are as follows:

1 2 3 4

5 public int transferAll(Account[] src, Account dst) 6 {

7 int total = 0;

8 for (Account acc : src) { 9

10 transaction{

11 if ( !acc.credentials ok() ) 12 break;

13

14 int amount = acc.balance(); 15 16 if ( amount <= 0 ) 17 continue; 18 19 acc.withdraw(amount); 20 dst.deposit(amount); 21 total += amount; 22 } 23 24 25 26 27 28 29 } 30 return total; 31 } 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

Listing 6.3: Code illustrating a transaction enclosing regular control keywords whose scopes exceed the transaction boundaries.

// Class has a new field; int commitPos transferAll ab1;

public int transferAll(Account[] src, Account dst) {

int total = 0;

for (Account acc : src) {

commitPos transferAll ab1=-1;

total = transferAll ab1(total, dst, acc);

if(commitPos transferAll ab1 >= 0){ if( commitPos transferAll ab1 == 0);

break; else

if( commitPos transferAll ab1 == 1) continue; } } return total; } @Atomic

private final int transferAll ab1(int total, Account dst, Account acc) {

if ( !acc.credentials ok() ){ commitPos transferAll ab1=0; return total;

}

int amount = acc.balance(); if ( amount <= 0 ){

commitPos transferAll ab1=1; return total; } acc.withdraw(amount); dst.deposit(amount); total += amount; return total; }

Listing 6.4: Code of Listing 6.3 trans- formed by TMJava for Deuce.

ˆ The position pointer field added to the class is seen at line 3. The name of the position pointer is constructed using the prefix commitPos and the name of the method corresponding to the transaction block (i.e., transferAll ab1). The range of values this field can store is {−1, 0, 1} in this example. The field is set to the value −1 in line10before the transferAll ab1 call and if this value stays unchanged after the transferAll ab1 method returns, this means that the method has completed normally without using any of the control keywords. If a condition in one of if statements of the transaction is true, the value of the position pointer will be 0 or 1 after the method returned. 0 indicates that the break caused the return while 1 corresponds to the case where continue keyword resulted in the return.

ˆ The nested if-then-else statement (lines 22-28) is generated after the call to transferAll ab1 method. The outermost if statement checks whether the method transferAll ab1 has returned using a control keyword. If this is the case, then it checks the value of the position pointer field (the commitPos transferAll ab1 variable) in lines 23 and26 and executes the corresponding control keyword, i.e., it executes a break if position pointer field is 0 (line24) and a continue if the field is 1 (line27).

ˆ The control keywords used in the transaction block are replaced with code storing the position of the keyword in the position pointer field and returning from the method. The break keyword under the access grant condition is replaced by lines38-39where the position pointer field is set to 0 with a following return statement. The code replacement for the continue keyword is the same (lines 45-46) with the exception that the position pointer field is set to the value 1 to indicate the difference in the keyword used and its position in the transaction block.

Alternative execution paths: An alternative execution path corresponds to one of the either, or or blocks given to define the alternative paths. Since the execution of all of these blocks is done according to transactional behavior the content of these blocks need to be executed in the Deuce function that corresponds to the original transaction block. The either-or structure of a transaction is transformed into a switch-case statement, where each of either and or blocks become a case of the switch-case statement. The mapping of the blocks to the cases is done as follows: either and or blocks are enumerated in order of their appearance and the number that corresponds to each block becomes the case value which enables the execution of the corresponding either or or block.

Transactional control flow: The transactional control flow is provided by the 3 keywords transaction retry, transaction next and transaction cancel. The transfor- mation required for these keywords is composed of the following modifications:

ˆ An object that counts the number of retries and that is excluded from transactifica- tion. This object is instantiated before the Deuce function that corresponds to the transaction is called and it is passed as a parameter to the Deuce function. The fact that it is excluded from transactification allows to follow the status of the control flow between transaction re-executions.

ˆ A condition check at the very beginning of the Deuce function. This check executes each time the transaction executes and compares the current retry number to the maximum possible retry number (the maximum possible retry number is any value bigger than the number of alternative execution paths in the transaction). If the retry number is at the maximum possible value or bigger the Deuce function returns immediately. This allows the transaction cancel behavior, i.e., it implements the rollback and passing of the control flow to the statement that follows the transaction. If the retry number is smaller than the maximum possible value, then the transaction is executed. The retry number in this case corresponds to the case statement value of an alternative execution path that should be executed for the current transaction execution.

ˆ Each of the encountered keywords is replaced with a piece of code as follows: – transaction retry: It is simply replaced with a transaction abort. It does

not change the retry number stored so that the transaction can be re-executed exactly with the same retry number (hence exactly with the same alternative execution path).

– transaction next: It is replaced with two statements: (i) a statement in- crementing the stored retry number (ii) a transaction abort. This way the retry number is modified for the next transaction execution. If the transaction is to be re-executed, it will be executed with another alternative execution path that corresponds to the new retry number (because the switch statement will use the value of this retry number).

– transaction cancel: The replacement is the same as transaction next except that instead of incrementing, the retry number is set to its maximum value. This way, the re-execution of the transaction is prevented after the abort. Exceptional control flow: For the exceptional control flow, two behaviors need to be provided: commit-and-throw and abort-and-throw (see Section 5.4.2.3). Since Deuce in-

strumentation provides the commit-and-throw behavior by design, no changes are necessary for this behavior. However, the abort-and-throw behavior requires modifications. Since the abort-and-throw behavior is equivalent to the behavior of a transaction cancel upon an exception, all the modifications necessary for the transaction cancel keyword needs to be performed also for abort-and-throw. Additional modifications required are as follows: ˆ A CancelException object is instantiated before the call to the Deuce function that replaces the original transaction block and the same object is passed as a parameter to the Deuce function. The object is also excluded from transactification, since it will need to carry the type of raised exception out of the transaction.

ˆ The throw statement that performs the abort-and-throw is replaced with a state- ment that stores the exception class given to the abort-and-throw statement in the CancelException object (see Section 5.4.2.3 for the abort-and-throw statement syntax). Of course, this store statement is followed by some code that replaces a

transaction cancel statement so that the transaction is not executed again. ˆ Right after the call to the Deuce function that replaces the original transaction block

the CancelException object is checked to see if it has stored an exception, and if it is the case the CancelException object is thrown to propagate the exception.