• No results found

4.2 Managing Nested Transactions

4.2.4 Child Session Management

The execution of a child session begins whenever a thread detects that it has called a nested transaction (i.e the argument to the CallTx function is a nested transaction invocation). Each child session is then comprised of the following activities:

1. The thread invokes the ExecuteNested function, which contains the logic necessary to execute a child session. The ExecuteNested function first attempts to acquire a resource.

2. If a resource is acquired, the RegisterNested function is invoked to pre- pare the necessary data structures for the execution of a child session. 3. Once registered, the thread executes a nested Speculative Phase and Com-

mit Phase (in the same manner as described in Section 4.1.4). The Vali- dateNested function is then called, which terminates the child session. A modification to the CallTx function is required to identify whether the argument supplied to CallTx is a nested or non-nested transaction (see Al- gorithm 11). All threads possess a private variable to hold their current state. When a thread is first initialised, the variable is assigned the value ready. After a thread has called the CallTx function, the variable is set to registered (see line 7), and once validation has been performed, the variable is reset to the value ready (line 18). If the CallTx function is invoked while the state variable holds the value registered then the thread knows that the argument to CallTx is a nested transaction and the ExecuteNested function is invoked (lines 2 and 3). Algorithm 10 The Table Mask Get Algorithm

1: function Get(mask, slot) 2: if slot = maskSLOT then

3: return maskT XACT ION

4: end if

5: return Get(maskP AREN T, slot)

Whenever a thread invokes the ExecuteNested function (see Algorithm 12), it first attempts to acquire a resource (line 2). If there are no resources available then the thread simply executes the transaction as a flattened transaction (line 15). Alternatively, if the thread acquires a resource then it gains exclusive access to the Table Mask and Binary Tree referenced by that resource. The Table Mask is used during the thread’s Speculative Phase to retrieve transaction invocations. The Binary Tree is used during the thread’s Commit Phase (lines 8-9).

Algorithm 11 The New Execute Algorithm

1: function CallTx(txaction)

2: if LocalST AT E = registered then

3: return executeNested(txaction) 4: end if 5: while true do 6: if Register(txaction) then 7: LocalST AT E ← registered 8: initialise timer

9: while time remaining do

10: call expansion function

11: decrement time remaining

12: end while

13: synchronize(T Mbintree)

14: while ¬(session expired) do

15: await session results

16: end while

17: if transaction validated then

18: LocalST AT E ← done

19: reset cache and return

20: end if

21: end if

22: reset cache and handle abort

23: end while

Nested Registration The RegisterNested function allows a thread to be- gin its nested Speculative Phase once a resource has been acquired (see Algo- rithm 13). Firstly, the thread retrieves the Table Mask structure from its acquired resource (line 2), and the Table Mask ’s parent entry is set to the thread’s cur- rent table (line 3). Next, the thread creates a checkpoint of its Ticket structure (line 4) by invoking the CheckPoint function. This allows the thread to make changes to its Ticket within the child session, which can be undone if the child session cannot commit. The thread then resets its slot and session variables before setting up its table references to point to the Table Mask (lines 7-10).

The remaining statements of the RegisterNested function (lines 11-13) are required to support the addition of Pseudo Threads, which are explained in Section 4.3.2.

Algorithm 12 The Nested-Execute Algorithm

1: function ExecuteNested(txaction) 2: if resource ← pop(NMCST ACK) then

3: RegisterNested(resource, txaction) 4: while time remaining do

5: call expansion function

6: decrement time remaining

7: end while

8: bintree ← get(NMT REES, resource)

9: synchronize(bintree) 10: while ¬(session expired) do

11: await session results

12: end while 13: return ValidateNested(resource) 14: else 15: return call(txaction) 16: end if 17: end function

Child Session Validation Once a thread has executed a nested Speculative Phase and Commit Phase, it invokes the ValidateNested function (Algo- rithm 14). The ValidateNested function begins with the thread invoking the RollBack function to store the head of its Ticket stack in a thread-private vari- able called Head (line 2). Next, the thread relinquishes its resource by pushing it back onto the concurrent stack of the NM. The resource may now be used by any other threads wishing to conduct nested transactions (line 3).

The thread must now determine whether the speculative changes it made to any atomic objects during its child session will be kept or discarded. Retaining those changes depends on whether the thread’s child transaction was able to commit during the execution of the child session. This can be determined from the Permutation saved in the Head variable, specifically:

• If the child transaction was not committed then the thread immediately returns from the ValidateNested function with the value abort (line 10). • Otherwise, the thread’s cache of atomic object modifications is updated with the modifications made during the child session. The state of the NM Algorithm 13 Commencing Nested Execution

1: function RegisterNested(resource, txaction) 2: mask ← get(NMM ASKS, resource)

3: maskP AREN T ← (LocalT ICKET)T XT ABLE

4: CheckPoint(LocalT ICKET)

5: ticket ← LocalT ICKET

6: depth ← (ticketP ERM)DEP T H

7: maskSLOT ← Get(ticketP ERM, depth)

8: ticketSLOT ← ticketSESSION ← 0

9: ticketT XT ABLE ← ticketLOG← mask

10: maskT XACT ION ← txaction

11: maskCACHE ← Copy(ticketCACHE)

12: maskP ERM ← Copy(ticketP ERM)

13: Cas(maskN EXT, 0, 1)

is set to validated, and the value commit is returned from the ValidateN- ested function (lines 6-8).

The return value of the ValidateNested function will, in turn, determine the status of the parent transaction (and may cause the parent to abort). If a nested transaction aborts then aborting the parent transaction ensures that the atomicity property is maintained.

Algorithm 14 Ending Nested Execution

1: function ValidateNested(resource) 2: LocalHEAD ← RollBack(LocalT ICKET)

3: push(N MCST ACK, resource)

4: new cache ← ((LocalHEAD)T ICKET)CACHE

5: if child transaction committed then

6: (LocalT ICKET)CACHE ← new cache

7: LocalN M ST AT E ← validated

8: return commit

9: end if

10: return abort

11: end function

Once the nested transaction has executed, thread execution returns to the speculative algorithm (i.e. the Greedy Algorithm) in the parent session context. If the remainder of the parent transaction is not aborted then the PermCommit function will be called. The PermCommit function must now be able to handle cases when a nested transaction has successfully committed, so that the thread’s Permutation is updated correctly (see Algorithm 15, lines 1-9). Specifically, the PermCommit function reads the state of the NM, and if this is validated then the CommitNested function is invoked (recall that the ValidateNested func- tion sets the status of the NM to validated if a nested transaction successfully commits). If this extra functionality was not present then a thread may sub- sequently execute transactions in its parent session, which have already been executed during a previous child session.

The CommitNested function is shown in Algorithm 15 (lines 10-17). In the CommitNested function, the thread updates its own Permutation structure

with the Permutation saved in the Head variable. This comprises overwriting the thread’s current Permutation with the Permutation from the previously executed child session (line 14). In addition, the commit count is adjusted to include the number of transactions committed during the execution of the child session (line 12). The final required action is to reset the state of the NM to ready, so that further calls of PermCommit do not erroneously call CommitNested without first executing a new child session (line 16).

Algorithm 15 The New Permutation Commit Algorithm

1: function permCommit(perm)

2: if LocalN M ST AT E = validated then

3: CommitNested(perm)

4: else

5: permCOM M IT S ← permCOM M IT S + 1

6: permDEP T H ← permDEP T H + 1

7: permOF F SET ← 1

8: end if

9: end function

10: function CommitNested(perm) 11: newperm ← (LocalHEAD)P ERM

12: newpermCOM M IT S ← newpermCOM M IT S + permCOM M IT S

13: newpermOF F SET ← 1

14: perm ← newperm

15: (LocalT ICKET)CACHE ← (LocalHEAD)CACHE

16: LocalN M ST AT E ← ready

17: end function