semantic concurrency control in linear hash

2 downloads 0 Views 169KB Size Report
In our model, linear hash operations such as find, insert, delete, split, and merge are implemented as ..... Lock management on the root variable and on pages is done using ..... An object will be deleted to free memory space, only if both the.
SEMANTIC CONCURRENCY CONTROL IN LINEAR HASH STRUCTURE USING MULTI-LEVEL TRANSACTIONS IN AN OBJECT ORIENTED ENVIRONMENT Sanjay Kumar Madria Centre for Advanced Information Systems School of Applied Science Nanyang Technological University, Singapore [email protected]

Malik Ayed Tubaishat School of Computer Sciences Universiti Sains Malaysia 11800 Penang, Malaysia [email protected]

ABSTRACT In this paper, we present a version of the linear hash structure algorithm to increase concurrency using multi-level transaction model. We exploit the semantics of the linear hash operations at each level of nesting to allow more concurrency. We consider locks at both vertex (page) and key level (tuple) to further increase concurrency. As undo based recovery is not possible with multi-level transactions and therefore, we have used compensating based undo to achieve atomicity. We have also implemented our model using object-oriented technology using multithreading paradigm. In our model, linear hash operations such as find, insert, delete, split, and merge are implemented as methods and correspond to multi-level transactions. Keywords: linear hash structure, concurrency, multi-level transactions, object-oriented, multithreading.

1. INTRODUCTION To exploit layer specific semantics at each level of operation nesting, Weikum presented a multi-level transaction model [1,18]. The model has received considerable attention for designing high performance transaction processing and concurrency control algorithms [2,15,16,]. The multi-level transaction model takes into account the commutative properties of the semantics of operations at each level of data abstraction to achieve a high degree of concurrency. If two operations at the same high level commute then their conflicting descendants at the same lower level will be allowed to execute since they will not introduce any inconsistencies. A multi-level transaction is a balanced tree of actions in which all nodes at the same depth correspond to operations of the same level of abstraction. Edges in a transaction tree present the implementation of an operation by a sequens of operations at the same lower level. In this model, a subtransaction is allowed to release a lock on finishing before the commit of high level transactions. In case a subtransaction aborts, the aborted subtransaction’s effect is to be undone by a compensatory transaction. Two actions at the lower level of abstraction conflict if there is a state in which the corresponding actions do not commute. Multi-level transaction models enhance advanced DBMS applications by providing better support for long-lived activities, capture more semantics about the operations, and enhance parallelism. Attention is being given to the designing of concurrency control algorithms which take advantage of the knowledge of particular data structures and the semantics of operations such as insert, delete, find, etc. to improve availability and expedite accesses. Data structures that have been studied with above in mind are B-trees [9,17] and hashing techniques [3, 4, 6, 7, 8, 13]. Hashing is one of many addressing techniques used to find a record based on its unique key value. When a record is to be updated, the system takes the value of the key and performs some type of calculations to derive a target address for the record. Among various hashing techniques, Linear Hashing [3,6] is interested because of its simplicity, ability to handle large amount of data with increased concurrency, and very fast in retrieving data. Current database applications are increasingly using object-oriented techniques that necessitate the revaluation of the traditional concurrency control methods that are in use for more efficiency. When combining database

1

functionality with object-oriented concepts, object-oriented databases become the ideal repository of the information that is shared by multiple users and multiple applications on different platforms. In object-oriented databases, if the execution of methods is seen as a transaction then the execution of methods generates a hierarchy that correspond to nested transactions. Nested transaction [14] processing and concurrency control issues play a major role in providing higher concurrency and better handling of transaction’s abort and hence have been an important area of research in database systems. In [5], B-tree algorithm in nested transaction environment has been presented to show its correctness but no implementation issues have been discussed. In [12], linear hashing using nested transactions has been studied only with the aim of formalizing and proving the correctness of the algorithm using I/O automaton model [11]. While it is

essential that object-oriented database systems must support multiple concurrent users, to our knowledge, no implementation of multi-level transactions accessing linear hash structure has been available in literature. In this paper, we exploit the semantics of multi-level transactions at each level of nesting in a linear hash structure environment. We allow various multi-level transactions to execute in parallel and make the effects of the subtransactions persistent before the commit of top-level transaction. However, we execute a compensating transaction [18] in case the parent transaction of a previously committed subtransaction aborts. Thus, we also handle transaction aborts in our model. We consider the granularity of data at two levels; one at the bucket level and the other at the key level. Thus, we manage the locking at two levels, which result in providing more concurrency. We have also realized while implementing that in case of aborts of restructuring operations either split or merge, there is no need of executing any compensated transaction. The reason being these operations only affect the structure of the data, but do not change the key values stored therein. These types of operations are usually referred as nested topactions [13]. We have implemented a multi-level transaction version of the linear hash structure algorithm [3] using object-

oriented concepts and multithreading paradigm. In our implementation, we model buckets as objects and linear hash operations find, insert, delete, split, and merge as methods. These methods correspond to multi-level transactions and are implemented as multithreads. Multithreading is a programming paradigm that allows the application processes to run concurrently. When the process performs multiple tasks at the same time, multithreading split themselves into separate threads that run concurrently and independently. Each thread performs one atomic action. The threads execute individually and are unaware of the other threads in a process. Thus, multithreading can be used very efficiently to implement the behaviors of multi-level transactions. Finally, we have designed and implemented our system using layered system architecture in a client/server environment, which allows more flexibility in term of decomposing of application programs whose modules may be designed and implemented independently. Rest of the paper is organized as follows. Section 2 outlines some preliminary discussion on multi-level transactions and a background on linear hash structure, concurrency control, and locking. Section 3 discusses the linear hash structure model in multi-level transaction environment. Section 4 discusses various scenarios of multilevel transactions in linear hash structure environment. In section 5, we discuss the layered system architecture for the implementation of our model. Section 6 explains the object-oriented design of our model. Section 7 describes the implementation of nested transactions using multithreading. We give a snapshot of our model in section 8. We conclude in section 9.

2

2. PRELIMANERIES 2.1 Principles Of Multi-Level Transactions The main features of multi-level transaction models [1, 18] are the following. First, semantic properties of operations can be exploited to relax the isolation of concurrent transactions; second, as a consequence, atomicity is achieved by compensation rather than state-based undo; and third, subtransactions can be made persistent independently of their commit state, that is, global visibility of their updates.

In multi-level transaction model, transaction management takes place on a fixed set of levels simultaneously. It is particularly suited to the design and description of transaction management in complex systems. In the layered system, transaction management is distributed among the levels. Multi-level transactions are a variant of open-nested transactions in which the subtransactions correspond to operations at different levels of layered system architecture. They allow the exploitation of semantics of high-level operations to increase concurrency. As a consequence, undoing a transaction requires compensation of completed subtransactions. In addition, multi-level recovery methods must take into consideration that high-level operations are necessarily atomic if multiple pages are updated in a single subtransaction. Open nested transactions gain concurrency, that is, reduce the number of lock conflicts, by exploiting the semantics of operations at all levels of the transaction trees, and by committing subtransactions early. The consequence of the early commit is that transaction aborts (and the undo phase of crash recovery) can no longer implemented by restoring the pre-transaction state of the modified storage-level objects (i.e., objects modified by the leaves of a transaction tree). Simply restoring before-image to undo a transaction may result in illegal effects such as unintentionally backing out updates of a record, possibly already committed transaction, as well. Therefore, in this model, committed subtransactions need to be compensated by means of appropriate "inverse" operations. The necessary compensating subtransactions are again subject to the semantic concurrency control protocol. The locks of the actions in a subtransaction are released upon the completion of the subtransaction, rather than being passed to the subtransaction’s parent as in the conventional model of "closed nested transaction" [14]. Only the transaction root holds semantic locks for its children (i.e., top-level actions) until the end of the transaction. This means that subtransactions commit, that is, expose their effects, independently of the commit of their ancestors. However, because the parent of a committed subtransaction holds a higher-level semantic lock, the effects of the subtransaction are visible only to such actions that commute with the root of the subtransaction. This locking protocol ensures semantic serializability, that is, equivalence to a serial execution as viewed by the top-level actions of the executed transactions. In principle, one may adopt a uniform approach to concurrency control in a multi-level system - a single scheduler is applied to all (sub-) transactions. A more flexible and modular approach that offers better support for structured system design is the layer-oriented approach -a different scheduler is used for controlling concurrency at each layer. Concurrency control for a layered architecture can be implemented on several levels. Doing so on the page level to ensure serializability of top-level transactions seems to be the most common practice. An example of a multi-level transaction is shown in figure 1, where two transactions are updating the database concurrently. The execution order of bottom-level L0 actions is from left to right. Each action at the bottom level is designated by two numbers. The first number is to show to which transaction this action belongs. The second number is to show the sequence of operations within the transaction. For actions on a higher level, we say that a precedes b if and only if all L0 subtransactions of a have terminated before b’s first L0 subaction starts. If neither a precedes b nor

3

vice versa, both actions are considered concurrent. So, in a multi-level schedule, concurrency potentially exists on each level of the underlying architecture. Principles of how to realize transaction aborts in a layered database system architecture: •

To abort an Li+1 transaction T (0 ≤ i < n). undo its Li actions,



Where undoing an Li action a means performing an inverse Li action a ,



Which, for i > 0, spawns a subtransaction in order to compensate the effects of the successfully terminated

-1

subtransaction issued by a.

R11(rv, r)

T1

T2

Insert1(x)

Delete2(y)

R21(rv, r)

Update12(p, -, s)

R13(-, k, r)

Update22(p, -, s)

R23(-, k, r)

W14(-, k, w)

L1

W24(-, k, w)

L0

Figure 1. Example of a two-level schedule To determine the inverse operation of an Li action a, it is not sufficient to know which operation a has performed on which object. For example, undoing a Delete(x) operation requires information on the value of x to construct the appropriate Insert(x) action. Transaction aborts here can no longer be implemented by restoring the pre-transaction state of modified L0 objects, since low-level modifications become visible to concurrent transactions at the end of each subtransaction. The solution to this problem is to perform transaction aborts by means of inverse high-level operations that compensate complete subtransactions rather than backing them out.

2.2 Background On Linear Hash Structure In a linear hash structure [2], there are primary buckets where each holds some constant number b of records. The function h0 : k È {0, 1, ..., N -1} is initially used to load the file. There exists a sequence of functions h1, h2, ..., hi, ..., i-1

such that for any key value k, either hi(k) = hi-1(k) or hi(k) = hi-1(k) + 2 N, where N is the number of buckets. The hash functions change as the hash structure grows or shrinks. The operations defined on a linear hash structure are find, insert, delete, split, and merge. A variable level is used to determine the appropriate hash function for find, insert, or delete operations. A pointer called next is used to point to the bucket to be split or points to the bucket involved in the merge operation. Level and next are both initially set to 0, and together they referred to as root variable. Each bucket keeps an additional field local-level that specifies the hash function appropriate to that bucket. The private variable lev keeps the value of level at the time root variable is read. To access a bucket, the process checks whether lev value matches that bucket’s local-level, and if not, it increments lev value and recalculates the address hlev(key) until a match is found. This operation is called rehashing. A process in its search phase behaves as follows: the root variable is read and its value determines the hash function to be used initially. The bucket and hash function are updated as follows: lev = level

4

bucket no. Ç hlev(key) if bucket no. < next then {

lev Ç lev + 1 bucket no. Ç hlev(key)

} lev where hlev(key) = key mod (2 * N) Attempting to insert into a full primary bucket leads to collision. The problem of collision is handled by creating a chain of overflow bucket associated with that particular bucket address. If any bucket overflows, the bucket pointed by the pointer next will be split by moving some keys from its original bucket to a new primary bucket to be appended at the end of the hash file. The split operation is applied cyclically. Split operation increases the address space of primary buckets in order to reduce the accumulation of overflow chains. All bucket chains with address less level

than the value of next, and buckets with addresses greater than or equal to 2 N have local-level values equal to level + 1. All of the buckets in between have local-level = level, which indicates that they have not efficiently been split in the current round of restructuring. j-1

The next pointer travels from 0 to 2 *N with hash function hj. After the split, the next is updated as follows: next Ç (next + 1) mod (2

level

* N)

if next = 0 then level Ç level + 1

When a primary bucket becomes empty, a merge operation is called. Here, the next bucket will be merged with its level

partner (where partner = next + 2

* N). That is, keys will be moved from the partner bucket to the next bucket.

After merge the following changes will be made: if next = 0 then level Ç level - 1

next Ç (next - 1) mod (2

level

* N)

2.3 Concurrency and Locking in Linear Hashing In linear hashing algorithm [3], the find operation can be performed concurrently with find, insert, delete, and split operations. Insert and delete operations may operate in parallel if they are accessing different bucket chains. A split may be performed in parallel with insert and delete operations that are not accessing the particular chain being split. No concurrency is possible between a merge and processes doing find, insert, or delete operations. That is, these processes can neither access the two buckets being merged nor they can read the values of level and next while merging process is using them. At most one restructuring operation either merge or split is executable at a time.

Lock Request

Existing Locks read-lock

selective-lock

exclusive-lock

read-lock

yes

yes

no

selective-lock

yes

no

no

exclusive-lock

no

no

no

Table 1. The lock compatibility-matrix Locking protocol in [3] uses three types of locks as shown in Table 1. The primary bucket, and all its overflow buckets are locked as a unit. The find algorithm uses lock-coupled read-lock on the root variable and holds the lock until a read-lock is placed on the bucket. Lock-coupling provides the particular flow of locking in which next

5

component is locked before releasing the lock on the current component. The insert and delete processes hold readlock on root variable and selective-lock on buckets with lock-coupling. The split operation uses selective-lock on root variable as well as on the buckets. Exclusive-locks are used on root variable and on both the buckets involved in merge when old overflow buckets are deallocated. If rehashing is required, a lock is placed on the subsequent bucket before the lock is released on the current bucket. The read-lock on root variable held by the searching process prevents a merge from decreasing the size of the address space (by updating level and next) during the initial bucket access.

User Transaction

Agent

insert-TM

split-TM

find-TM

merge-TM

delete-TM

REQUEST-CREATE

REPORT-COMMIT

REQUEST-COMMIT

REPORT-ABORT L1

SCHEDULER

ABORT CREATE COMMIT

split-write

search-insert

search-read

search-delete

merge-write

REQUEST-COMMIT

REPORT-ABORT L0

SCHEDULER

ABORT CREATE COMMIT

BMs

Figure 2. Multi-level transaction tree with schedulers

3. LINEAR HASH STRUCTURE IN MULTI-LEVEL TRANSACTION ENVIRONMENT Our model of the linear hash structure algorithm [3] in multi-level transaction environment is as follows. The multilevel transaction tree of our model is shown in figure 2. In figure 2, user-transaction passes the request to perform an operation (i.e., find, insert, or delete) to the agent. In the multi-level transaction tree, next to the agent, we have a level of transaction managers (TM). The agent sends the user-transaction’s request to the appropriate TM. Each TM handles transaction-related processing requests like when transactions are created, when they are to be committed or

6

aborted. In our model, we have five TMs, these TMs are find-TM, insert-TM, delete-TM, split-TM, and merge-TM. Find-TM creates a transaction search-read to find a key. Insert-TM creates a transaction search-insert to insert a key. If insert-TM receives an “overflow” message after the insert operation, it will pass the message to the agent, which in turn will initiate split-TM. Split-TM will create a split-write transaction to perform the split operation. Delete-TM creates a transaction search-delete to delete a key. If delete-TM receives an “underflow” message after the delete operation, it will pass the message to the agent, which in turn will initiate merge-TM. Merge-TM will create a mergewrite transaction to perform the merge operation. The schedulers as shown in figure 2 determine the order in which subtransactions are to be executed. In [12] scheduler receives two types of request; to create a transaction (REQUEST-CREATE) or request for committing a transaction (REQUEST-COMMIT). In return, scheduler responds by creating, committing, or aborting the transaction as shown in figure 2. The scheduler will control operations of the subtransactions, makes a decision about the completion of subtransaction and reports back to their parent (a REPORT-COMMIT or REPORT-ABORT), and informs objects the fate of transactions. Our model contains two levels of data abstraction, these levels are page level and key level. Scheduler at page level (L1 level) will synchronize the transactions that are accessing the pages (buckets in our case). This is done by granting a lock to the root variable and to the page(s) to be accessed. The other scheduler at the key level (L0 level) will synchronize the transactions accessing the keys. Before accessing the key, the transaction will acquire an appropriate lock on the key. Lock management on the root variable and on pages is done using Moss’s two phase locking algorithm [14] and locking algorithm using lock-coupling protocols given in [3]. Further, lock management on the key is done using read/write lock. The lock-compatibility matrix is shown in Table 2. Compared to a global scheduler, the level-by-level scheduling approach avoids overhead at the expense of concurrency. It restricts concurrency in that a total order is imposed on the conflicting actions of each level. That is, no concurrency is allowed among conflicting actions. A nice property of level-by-level scheduling is the modularity that is achieved by treating each layer separately. The point of the level-by-level scheduling strategy is that each scheduler needs to know only the Li+1 transactions and Li actions of a single layer Li, and can employ a conventional concurrency control algorithm between the pair (Li+1, Li) of adjacent levels. Furthermore, notice that, in a practical implementation, an Li scheduler could actually be integrated into the layer Li rather than operating on top of the level Li.

Linear Hash

root

Operations

variable

accessed page

next page

partner page

new page

Find

read

read

-

-

-

read

Insert/Delete

read

selective

-

-

-

write

Split

selective

-

selective

-

selective

read

Merge

exclusive

-

exclusive

exclusive

-

-

Locked pages

key

Table 2. Linear hash operations’ locks In our model, we have bucket managers (BMs) as shown in figure 2. Each BM manages a bucket, in a linear hash file, and its overflow buckets. Each BM also maintains the keys and their associated values in a bucket and in its overflow buckets. As in [12] we consider keys as the user-visible objects and buckets as user-invisible objects.

7

4. LINEAR HASH STRUCTURE OPERATIONS AS MULTI-LEVEL TRANSACTIONS In our model, we use multi-level transactions to implement the linear hash operations within multi-user environment. We will discuss how the five operations (find, insert, delete, split, and merge) of the linear hash structure will work concurrently in the multi-level transactions environment. Each transaction in multi-level transaction model is a tree of actions, where the edges represent the caller-callee relationship between operations of adjacent levels. The following are the assumptions of our algorithm: •

The primary buckets and all its overflow buckets are considered as a unit.



Each bucket is occupied by a single page. Its overflow buckets will be stored in the different bucket (page). However, a bucket and all its overflow buckets are locked as a unit.



Each key is of fixed length.



Ordering of keys within a bucket is not mandatory.



Each page is updated in a transaction’s own workspace.

Next, we will study the various scenarios where different subtransactions are running concurrently within multilevel transactions environment. In each scenario, we will consider types of transactions at different levels and the lock types they used for each action. Notations : For simplicity, we will abbreviate the locks type names as following: read-lock: r, write-lock: w,

selective-lock: s, exclusive-lock: x. In the following figures, reading the root variable is represented by R(rv, locktype) where rv is the root variable and lock-type is the lock acquired on the root variable depending on each linear hash operation. Operations on pages will be represented as operation_name(page, key, lock-type). Reading the page without updating it is represented by Select(page, -, s) where page is the page being accessed, key here is substituted by a dash as it is a page level operation (i.e., key will not be accessed here), and s represents the selective-lock. Select(page, -, s) is used by find operation before accessing any page. Updating a page is represented by Update(page, -, lock-type). Key is also substitute by a dash as it is a page level operation and lock-type will be changed according to the linear hash operation that updates the page. For a split operation, writing the keys in the new page created is represented by New(-, key, lock-type). Since the locks concern here is not the page, page is substitute by a dash. Reading and writing the keys are represented by R(-, key, lock-type) and W(-, key, lock-type) respectively. Actions are numbered hierarchically to identify their ancestors on higher levels.

À INSERT-INSERT/DELETE

In figure 3.a, we have two transactions T1 and T2 running serially as T1’s actions on L0 level finish before T2’s actions start. Next, we will discuss various cases of insert operations running concurrently. Case 1: The scenario in figure 3.b shows the concurrent execution of two transactions, involving actions at different levels of abstraction. The transaction T1 is created to insert a key x whereas, T2 is created to insert a key y where x≠y. At level (L1), each transaction acquires a read-lock on the root variable represented as R(rv, r). As the locks granted on the root variable are compatible, both the insert transactions T1 and T2 acquires a selective-lock on page p represented as Update(p, -, s) where p represents the page, and s represents the page's selective-lock. As the locks are not compatible (see Table 2) on page p, BM of page p will suspend T2. After T1 locks the key at next lower level, it releases the page level lock. This technique, releasing the page’s lock before the commit of the transaction will increase the concurrency as more transactions can access the same page concurrently. Each update operation at L1

8

level will perform two actions. These actions are R(-, k, r) and W(-, k, w) for reading and writing the keys, respectively. While reading the key, a read-lock is granted to the key k and while writing the key, a write-lock is granted to the key. T1

T2

Insert1(x)

Insert2(y)

R11(rv)

Update12(p)

R13(k)

R21(rv)

W14(k)

Update22(p)

R23(k)

L1

W24(k)

L0

Figure 3.a Now, in case T1 aborts, we can not use before-image of the page as before-image will undo the effect of the other transaction T2 as it has started its execution before T1 has committed. The solution is to performing an inverse action to compensate the aborted transaction. In this case, the inverse action is a delete operation Delete(x). In case T2 aborts, the inverse action will be Delete(y).

R11(rv, r)

T1

T2

Insert1(x)

Insert2(y) / Delete2(y)

R21(rv, r)

Update12(p, -, s)

R13(-, k, r)

Update22(p, -, s)

R23(-, k, r)

L1

W14(-, k, w)

W24(-, k, w)

L0

Figure 3.b Similar scenario is shown in figure 3.b if the transaction T1 inserts a key and T2 deletes another key on the same page concurrently. In this case if T2 aborts, the inverse action is an insert operation. Case 2:

R11(rv, r)

T1

T2

Insert1(x)

Insert2(y)

R21(rv, r)

Update12(p, -, s)

R13(-, k, r)

Update22(q, -, s)

R23(-, k, r)

W14(-, k, w)

L1

W24(-, k, w)

L0

Figure 3.c The scenario of figure 3.c is the same as the previous one but here two different pages are considered. First transaction T1 will insert a key x to the page p whereas, T2 will insert a key y probaly to an overflow page q. If both the transactions commit, no problem occurs. However, insert-insert do not commute if the page p becomes full.

9

Suppose T1 inserts a key x to page p and T2 inserts a key y to the overflow page q as page p becomes full after inserting key x. A problem will occur if T1 aborts. When T1 aborts, a compensating subtransaction Delete(x) will be initiated and hence, an empty space will exist in page p. However, T2 had already inserted a key y to the overflow page q whereas there exists an empty space in page p. In any serial execution, the key y will appear in page p only. The solution to this problem is to force T2 to wait until T1 commits, that is, the top-level transaction. If T2 aborts, no problem occurs and its effect is compensated by a Delete(y) operation. Case 3: In figure 3.d, both the transactions T1 and T2 are inserting the same key. After T 1 inserts key x, it will unlock the key and when T2 try to insert the same key it can not do that as the keys are unique (we assume no duplicate key exists). Hence, T2 will report back to its TM a message "keyalready exists" and will not insert the key. But a problem will occur if T1 aborts in which case an inverse action Delete(x) will delete the key x. Thus, T2 had reported a wrong message that x already exists in the page but it is not true after T1’s abort.

R11(rv, r)

T1

T2

Insert1(x)

Insert2(x)

R21(rv, r)

Update12(p, -, s)

R13(-, k, r)

À

Update22(p, -, s)

R23(-, k, r)

W14(-, k, w)

L1

W24(-, k, w)

L0

Figure 3.d

INSERT/DELETE FIND T1

T2

Insert1(x) / Delete(x)

Find2(x)

R11(rv, r)

R21(rv, r)

Update12(p, -, s)

R13(-, k, r)

R23(-, k, r)

Select22(p, -, r)

L1

W14(-, k, w)

L0

Figure 4 In figure 4, insert-TM creates a transaction T 1 to insert the key x and find-TM creates transaction T2 to find the key x. Both the transactions will acquire a read-lock on the root variable. Transaction T1 will acquire a selective-lock on page p whereas, transaction T2 will acquire a read-lock on page p. Both the transactions will work concurrently at this level as there is no lock conflict between the read and selective locks (see Table 2). At level L1, the operation Select(p, -, r) is initiated by the find operation. We use this operation to differentiate between the update operations that will perform a read/write actions and the read operations like find operation that will just read the page. Insert-

10

find commute as there is no conflict between them if both transactions commit and so no problem occurs. Similarly, this is true for delete-find.

À INSERT–SPLIT

The scenario in figure 5 shows an insert and split operations working concurrently. The insert transaction T1 will acquire a read-lock on the root variable whereas, the split transaction T 2 will acquire a selective-lock on the root variable. T1 and T2 both will initiate Update(p, -, s), to acquire a selective-lock to page p. For split, we lock all the keys in the page while splitting. After split transaction T2 updates the page p, it will access the new page represented in the figure as New(q, -, s). It first acquires a selective-lock before accessing the new page q. Insert-split commutes as the two transactions do not affect each other.

R11(rv, r)

T1

T2

Insert1(x) / Delete1(x)

Split2

R21(rv, s)

Update12(p, -, s) R13(-, k, r)

Update22(p, -, s)

R23(-, ks, r)

W14(-, k, w)

W24(-, ks, w)

New25(q, -, s)

L1

W26(-, ks, w)

L0

Figure 5

À INSERT/DELETE-MERGE T1

T2

Insert1(x) / Delete(x)

Merge2

R11(rv, r)

Update12(p, -, s) R13(-, k, r)

W14(-, k, w)

R21(rv, x)

Update22(p, -, x) R23(-, k, -)

W24(-, k, -)

Update25(q, -, x) R26(-, k, -)

W27(-, k, -)

L1 L0

Figure 6 In figure 6, insert-TM creates a transaction T 1 to insert the key x whereas, merge-TM creates a transaction T 2 to merge page p (next page) with page q (partner page). At the L1 level, insert transaction T1 will acquire a read-lock on the root variable. As merge transaction T 2 needs an exclusive-lock on the root variable, it will be suspended. Once T1 acquires a selective-lock on page p, it will unlock the root variable as in lock-coupling protocol. Hence, T2 can get its lock on the root variable and can continue execution. Merge transaction T2 will perform two update operations; one on page p and the other one on page q. At L1 level, T2 will acquire an exclusive-lock on both pages p and q, and so, there is no need to lock the keys as they are is not accessible to any transaction. The same scenario will work for the delete-merge transactions.

À SPLIT-FIND

11

In figure 7, we have a split and find operations working concurrently. Both the transactions will acquire a read-lock on the root variable. Split transaction T1 will acquire a selective-lock before updating the page p whereas, find transaction T2 will acquire a read-lock on the same page by initiating the operation Select(p, -, r). Both the transactions will work concurrently at the two levels as there is no lock-conflict between them. After updating the page p, transaction T2 will acquire a selective-lock on the new page q created after split. Split-find commute as they do not affect each other.

R11(rv, r)

R21(rv, r)

T1

T2

Split1

Find(x)2

Update12(p, -, s)

Select22(p, -, r)

R13(-, ks, r)

R23(-, k, r)

W14(-, ks, w)

New15(q, -, s)

L1

W16(-, ks, w)

L0

Figure 7

5. LAYERED SYSTEM ARCHITECTURE In this section, we will discuss the layered system architecture of our model. Our system design is based on client/server model as shown in figure 10. Each module in the layered system is designed and implemented separately. The communications among various components in our system are done via messages. The architecture of our model consists of five layers distributed between the clients and the server. Each client site has one layer called user interface (UI) layer. The other layers are implemented at the server site. These layers are ordered as transaction manager (TM) layer, schedulers layer, bucket manager (BM) layer, and finally file manager (FM) layer respectively. All layers at the client and server site work in chronological order to achieve the transaction’s computation. At each level, subtransactions can operate concurrently without leading to an inconsistency and hence a higher concurrency can be achieved in our system. A very important feature of our layered system architecture is that if a subtransaction fails at any level; the parent at a higher layer level can compensate another subtransaction without aborting the entire transaction.

À User Interface (UI) Layer

This is the only layer that has been implemented at the client site. It works as an interface between users and the server. UI layer’s task is to receive an operation request from the user and pass it to the server. In UI layer, two components exist. They are user interface operations (i.e., find, insert, and delete) and the agent. When the user initiates one of the operations, the agent will pass the message to the appropriate TM at the server site. This message contains the target page no. and the key to handle the operation. At the end of computations at the server site, the agent will receive a message from the TM, which could be either " key is found", " key does not exist", or confirmation messages. In addition to these messages, agent may also receive “overflow” or “underflow” messages to do the restructuring operations as a result of insert or delete. These messages call for split or merge to be initiated. In case of “overflow” message, agent initiates a split-TM and if the message is “underflow”, it initiates a merge-TM. Different agents at different client sites will work concurrently, and no agent communicates to other agents.

12

Server

Over Flow

FM

DB File

FM Layer

Page

BM

BM

BM

L0

BM

BM

BM Layer

BM

SCHEDULER SCHEDULERS Layer

L1

SCHEDULER

find-TM

insert-TM

delete-TM

merge-TM

split-TM

Agent

Agent

Agent

Find Insert Delete

Find Insert Delete

Find Insert Delete

TM Layer

UI Layer

Client

Client

....

Client

Figure 8. Layered architecture for client/server model

À Transaction Manager (TM) Layer This is the first layer at the server site. It receives messages from the UI layer. TM layer contains the five TMs; findTM, insert-TM, delete-TM, split-TM, and merge-TM explained before. Each TM creates subtransactions to complete the required operation. TMs will work concurrently and independently. After a TM completes its execution, it reports back to the agent the result of the operation. Transactions created at this layer will be passed to the schedulers at the next layer to synchronize various subtransactions created by TMs. Subtransactions created by TMs can also work concurrently and only leaf level subtransactions will access the keys directly.

À Scheduler Layer

At this layer we have two schedulers that synchronize all transactions. Scheduler will determine when to create, commit, and abort a transaction. The scheduler at L1 level will synchronize transactions before they access the pages whereas, the scheduler at L0 level will synchronize transactions before they access the keys. Scheduler will send the synchronized subtransactions to the BM layer to access the pages. When a transaction completes, the scheduler will report back to the TMs the state of each transaction; whether it is successfully created, committed or aborted.

À Bucket Manager (BM) Layer

At this layer, each BM handles a page and all its overflow pages. Before a transaction accesses any page, the corresponding BM will determine whether to permit the transaction to access the page or suspend it with the help of the lock compatibility-matrix shown in Table 2. If two transactions accessing the same page interfere with each other,

13

BM will permit one of the transactions to access the page while suspending the other until previous transaction finishes. Thus, BMs will restrict accesses to the pages that lead to an inconsistent database state. The subtransactions, which access the BMs, are called decisive subtransactions as they are the only subtransactions that access the pages directly and any interference between transactions at this layer will lead to an inconsistency. BMs work independently of each other.

À

File Manager (FM) Layer

This is the last layer in our system. FM layer will insure the durability of the transaction. Any updates on the pages will be stored in the database file (i.e., DB File in figure 8) which resides on a permanent disk space. Updating of the database file will be performed after the commit of a top-level transaction to insure the consistency of our database file. FM is also responsible for loading the keys from the database file to the memory pages (i.e., pages). It can also restore the current database state in case of a system crash.

6. OBJECT-ORIENTED DESIGN We have implemented our system using object-oriented methodology since it provides the way for objects to communicate among themselves via methods. Each method invocation corresponds to the initiation of a subtransaction. Each time a method is called, a message is created either to be sent to other object or used by the same object. Our object-oriented design consists of four components, namely, the agent, linear hash (LH) structure, page manager (BM), and file manager (FM) and are implemented as classes as shown in figure 9. Each class contains a private section and a public section. Private section will be accessed within its own class and will handle the implementation of the class. Public section contains the public methods; these methods will communicate with their classes and with the other methods at different objects.

A variable of the class type is called an object. Any object can be created from a class, and an object is said to be an instance of a class. The main program and the subprograms that oversee the interaction among objects handle the accesses. The control code directs an object to access its data by using one of its methods or operations. A sender passes a message to a receiving object and asks the object to perform a task; the receiving object may return the information to the sender (output data) or pass messages to other objects requesting the execution of additional tasks.

Each object is designated by an id, called object id (OID), to distinguish from other objects. In our design, we have the following classes:

À AGENT Class

Agent is implemented as a class to facilitate the communication with other classes. In our implementation, the agent class is the core class, as it is needed to create instances of other classes (i.e., LH and BM classes) and to start sending messages to them. In the private section, we have FindPage&Object( ) method, which will be called for each operation of the public methods. This method will find the target page depending on the key given and the object where this page resides. In the public section, three methods are implemented. These are Find( ), Insert( ), and Delete( ) methods. When the user requests an operation, one of these methods will be initiated. The initiated public method will send a message, containing the key, to FindPage&Object( ) method to find the page no. and the OID (in the next section we will see how OID will be found). FindPage&Object( ) method will reply to the requested method with a message that contains the information needed (i.e., page no. and OID). The requested method will send a message to the appropriate method at the target LH object to handle the request. If the object does not exist, agent

14

class will create a new one. Furthermore, agent class is responsible for deleting deserted object that contains empty pages. FM class

BM class

Private: Private:

Public:

Cfile f; CfileException fileException;

Void UnLockPage( );

Void Store(int& key); LH class

Public:

Void Load(int& key);

Void LockPage( ); Private: CArray Page[NoOfPages]; CList Overflow[NoOfPages]; int local_level[NoOfPages]; Void InsertTM( );

Public:

Void Update(int& key);

Void MergeTM( ); Void SplitTM( );

Void DeleteTM( ); Void FindTM( ); AGENT class Private: FindPage&Object( );

Public:

Void Insert( );

Void Delete( );

Void Find( );

Figure 9. Object-oriented design

À LH Class TMs are implemented using methods, which are declared, in the public section of this class. FindTM( ) method will search for a key in the page. WriteTM( ) method will either insert a key or delete a key depends on the message received. SplitTM( ) method will split the next page and will send a message to the agent class to create a new object if needed for the new page. MergeTM( ) method will merge the two pages involved in the merge operation (next and partner pages), and will send a message to the agent class to delete the object if it has empty pages. When one of these public methods is initiated, it will send a message to the BM class to get the appropriate lock before it proceeds with computation. When the methods finishes its computation, it will send another method to the BM class to unlock the page. TMs’s methods will communicate with the FM class to load or store keys and to update file after a write operation. Pages and all its overflow pages are declared in the private section of this class. The implementation of pages are 1

done by using a built in class named CArray in visual C++ language, which has a number of methods for insert, delete, or search for a key, and other related methods to handle the array. The overflow chain is implemented using a 2

built in class named CList that has a number of methods, which deals with the linked list. CArray and CList classes 1 2

CArray is a built in class in Microsoft Foundation Classes (MFC). CList is a built in class in MFC.

15

contain the operation related to insert, delete, or search for a key. Pages and overflow chains are private instance in the LH class because there is no need for the client to know the details of the implementation. Local-level variable is also declared in the private section of this class. In our model, each LH object contains two pages. We have considered two pages in each object rather than one to reduce the system’s overhead during split and merge operations. This is due to the fact that when the first page of any object say O1 needs to be split, a new object say O2 will be created with two pages. However, when the second page from the object O1 splits, no new object (page) has to be created as the keys from this page can move to the second page of the object O2. Similarly, no object needs to be deleted when one of the pages becomes empty after a merge operation as the other page may contain some data. An object will be deleted to free memory space, only if both the pages become empty. On the other hand, having more pages in each object will waste memory space. Thus, having two pages in an object is a compromise between speediness and space utilization. Whenever split operation is called, the agent will read the local-level of the last page of the last object. If the local-level is 0 (which indicates that this page has not been accessed yet), the keys of the split page will move to this page. Otherwise, a new object will be created and the keys will move to the first page of this object in this object. At level

each level of the hash function, we have a maximum of 2

page no. = key mod (2

level

objects. We find an object id (OID) using the following:

* N)

OID = page no. / N.

À BM Class

Where N is the number of pages contained in each LH object (In our model, N = 2).

The read-lock and write-lock variables are declared in this class. Before TMs methods access any page, it will send a message to the LockPage( ) method to set a specific lock. After accessing the page, TMs methods will send another message to the UnLockPage( ) method to reset its lock. OODBMS may provide locking at the object and/or page level. We choose a physical page; a page in our design. As each LH object has two pages, holding lock on the object level will decrease the concurrency among transactions that access the pages.

À FM Class

For this class we will have only one object which is the DB file in figure 3. In the public section, three methods are declared. Store( ) method will store a key from the memory to the database file, load( ) method will fetch a key from the database file to the memory, and Update( ) method is called whenever an update is occurred to the DB file. Agent class is responsible for instantiating an object from this class. The first object created will load the database file into the memory.

7. Implementation of Multi-level Transaction Using Multithreading In the previous section we have seen how messages have been used to communicate among various methods and objects. In this section, we will see how the multithreads have been used to implement nested transactions in our system. In our system, multithreads are managed in such a way that they can not interfere with each other. Life cycle of the thread is hidden from clients. During a thread’s life cycle, many multithreads may be created. A thread may be halted, or an inconsistency may occur, however, these situations will not affect clients. For the clients, a creation and a commit of the top-level thread is important.

16

As clients operate concurrently, many multithreads will be created. To control these threads from interfering, a locking scheme explained earlier is implemented. The operations in our model will require multithreads to complete their jobs such as searching for the object, inserting, deleting, etc.

7.1 User Interface Operations In this section, we will see how each user operation is processed and implemented.

À Find

Find operation searches for a record in the database file. This operation is handled by read-TM. When a user initiates the find operation, a request for creating a thread to search for a key will be sent to the read-TM. Read-TM will create a search-read thread to perform a search for the key. Search-read’s thread will acquire a read-lock on root variable and on the page being accessed. Holding a read-lock permits other multithreads to perform simultaneously a search, insert, delete, or split operations. When the search process finishes, a report "transaction-commit" will be issued to inform read-TM that the thread is committed along with a message which is either "key is found" or "key does not exists".

À Insert Insert operation inserts a record into the DB file. This operation is handled by insert-TM. insert-TM will create a search thread to search for the requested key. If the key does not exist, another subthread write will be created to insert the key into its appropriate page. In the searching phase, the search thread will be granted a read-lock on the root variable so that other threads can also execute concurrently. After finding the page, a new write thread will be created and will be granted a write-lock on this page, so that no other operations can access the same page. If an overflow occurs after insertion, agent will send a message to the split-TM to create a subthread split-write that will perform the split operation. Split-write thread will hold a read-lock on the root variable and write-lock on the page to be split so other operations can work concurrently with split but on different pages.

À Delete

Delete operation is called to delete a record from the DB file. It is handled by delete-TM. As before, delete-TM will create a search thread to search for the requested key. If the key exists, another write thread will be created to delete the key from the page. In the searching phase, the subthread search will grant a read-lock to the root variable so that other threads can work concurrently. In the second phase, the write thread will hold a write on the page being accessed so no other insert and delete operations can access the same page. If the page becomes empty after deletion, the agent will send a message to the merge-TM to create a subthread that will perform the merge operation. Merge-write thread will hold a write-lock on the root variable and on both pages to be merged. No other operations can work concurrently with merge operation.

8. Snapshot of Our Model Here we give a working example of our model. The example explains when the pages/objects are created and deleted. Locking scheme is also taken into consideration. In the example (figure 10.a, 10.b, 10.c, and 10.d), we consider three operations that are running concurrently. These operations are search for key 32, insert key 16, and delete key 15. Each page is handled by a BM, which contains a list of all transactions accessing the page with their lock types and the status of the transaction as shown in figure 10.a. The root variable resides at the L1’s scheduler and will be read by each transaction before accessing the page. The variables level and next are shown in the example to specify

17

when their values are changed. Transactions created by search-read, search-insert, search-delete, split-write, and merge-write will read the root variable’s lock. If the lock is exclusive, L1’s scheduler will suspend other transactions until the root variable’s lock becomes unlocked. In other cases where the root’s lock type is read, selective, or unlock, a concurrency between transactions can occur (see Table 2). Before accessing the page, BM of the accessed page will check the transaction’s lock to decide whether to suspend it until the appropriate time or to permit it to access the page. TB5: Find key 32 TC5: Insert key 16 TD5: Delete key 15

search-read search-insert

Split-write

search-delete

TB5

TC5

delete-write

scheduler

L1

TB6: Find key 32 TC6: Insert key 16 TD6: Delete key 15

TD5

search-read search-delete

search-insert

level = 1 next = 0 Split-write L0

level = 1 next = 0

scheduler L0

BM

BM

BM

delete-write

scheduler

L1

scheduler

TC5

BM

TD5

TB5 LL=1

LL=1

LL=1

LL=1

4 20 32

25 33 13

18

15

BM

BM

BM

BM

LL=1

LL=1

LL=1

LL=1

4 20 32

25 33 13

18

Object1

Object0

16

Transaction’s ID TA5 TB5, TC5 TD9

Lock Type unlock read, selective exclusive

Object1

Object0

Bucket Manager (BM) Profile No 1) 2) 3)

Status finished running concurrently idle

Figure 10.b Figure 10.a In figure 10.a, two objects have been created and each contains two pages with local-level = 1. Consider that search-read has created a transaction TB5 to find key 32, search-insert has created a transaction TC5 to insert key 16 and search-delete has created a transaction TD5 to delete key 15. Initially, all the three transactions will acquire a read-lock on the root variable. The scheduler at L1 level will permit the three transactions to proceed since there is no lock-conflict. Transactions TB5 and TC5 will access page 0 whereas, transaction TD5 will access page 3. Find transaction TB5 will acquire a read-lock on the page whereas, insert transaction TC5 will acquire a selective-lock on the same page. At the same level (L1), delete transaction TD5 will acquire a selective-lock on page 3. The three transactions will work concurrently at level L1 because insert (TC5) and delete (TD5) transactions acquire selectivelock on different pages. At the next level (L0), find transaction TB5 will acquire a read-lock on key 32, insert transaction TC5 will acquire a write-lock on key 16, and delete transactionTD5 will acquire a write-lock on key 15. BM of page 0 will permit the both transactions TB5 and TC5 to access the page, as there is no lock-conflict between the keys. At the same time, transaction TD5 accesses page 3. At the moment the three transactions lock their keys, they will unlock their accessing page for another working transactions. When transaction TB5 finds key 32, it will report back a message "found" and then commits. When TC5 inserts key 16, an overflow occurs which will call for split operation (see figure 10.b). At the same time, an underflow occurs, as page 3 becomes empty after deleting key 15. As a result for the overflow and underflow, split-write will create transaction TC6 to perform the split operation

18

(see figure 7.c) and merge-write will create transaction TD6 to perform the merge operation. Split transaction TC6 will acquire a selective-lock on the root variable and merge transaction TD6 will acquire an exclusive-lock on the root variable. As selective and exclusive locks are incompatible, transaction TD6 will be suspended whereas transaction TC6 will continue its work. After locking the root variable, split transaction TC6 will acquire a selective-lock on the page. As for lock-coupling protocol, root variable will be unlocked after split transaction TC6 locks page 0. In turn, merge transaction TD6 grants an exclusive-lock to the root variable. Lock-coupling in this case is very efficient because if we keep the root variable locked with selective-lock, merge transaction may stay suspended while other find transactions are executing the objects. Split transaction TC6 will rehash page 0 using h2 function (see section 2.2). As a result, some of the keys will be moved to page 4, as shown in figure 10.c, which will also be locked by a selective-lock. A new object (object 3) will be created and will contain page 4, which is appended at the end of the hash file. After the split operation, next will be incremented by 1. Merge transaction TD6 will acquire an exclusivelock on both the pages 0 and 4 and will decrement next by 1. Transaction TD6 will merge the next page and its partner, here page 0 and 4, and then will unlock page 0 and the root variable respectively. Object 3 will be deleted (figure 10.d) to save memory space, as no keys are left in the page.

TC7: Split thread TD7: merge thread

search-read

search-read search-insert Split-write

scheduler TC6

L1

TD6

level = 1 next = 1

scheduler

Split-write

delete-write

L1

search-delete

search-insert

search-delete

delete-write

scheduler level = 1 next = 0

L0

L0

scheduler

TC6 BM

BM

BM

BM

BM

BM

LL=2

LL=1

LL=1

LL=1

LL=2

LL=0

4 32 16

25 33 13

18

20

BM

BM

BM

BM

LL=1

LL=1

LL=1

LL=0

4 32 16

25 33 13

18

20 Object1

Object1

Object1 Object1

Object0

Figure 10.c

Figure 10.d

9. CONCLUSION In this paper, we have exploited semantics of multi-level transactions in the environment of linear hash structures to increase concurrency. We have also presented an object-oriented client/server model for the implementation of multilevel transactions accessing linear hash structures. Multi-level transactions in concurrent linear hash structure robust the concurrency and handle transaction aborts. We have used object-oriented technology, which is suitable for client/server systems for its speediness in accessing data at the server site, and the property to encapsulate communications from the user. In our model, pages are modeled as objects whereas linear hash operations find, insert, delete, split, and merge are considered as methods. These methods correspond to multi-level transactions in their behavior and are implemented as threads and multithreads. As a future work, we would like to do the

19

performance evaluation of our algorithm to examine our claim of increase in concurrency and to measure the overheads associated with our system. Another direction of research is to study the model in a distributed environment [10] where a linear hash structure can be spread over a number of machines.

References st

[1] Beeri, C., Schek, H-J, Weikum, G., Multi-Level Transaction Management, Theoretical Art or Practical Need?, 1 Int. Conference on Extending Database Technology, Venice, LNCS 303, Springer-Verlag, 1988.

[2] Chrysanthis P. K., Transaction Processing in a Mobile Computing Environment, in Proceedings of IEEE Workshop on Advances in Parallel and Distributed Systems, pp. 77-82,1993. [3] Ellis, C. S., Concurrency in Linear Hashing, ACM Transactions on Database Systems, 12(2), 195-217, June 1987. [4] Enbody, R. J., Du, H. C., Dynamic Hashing Schemes, ACM Computing Surveys, 20(2), pp. 85-113, June 1988. th

[5] Fu, A. and Kameda, T., Concurrency control of Nested Transactions Accessing B-Trees, in proceedings of the 8 ACM symposium on principles of database systems, pp. 270-285, 1989.

[6] Hsu, M., Tung, S. S., Yang, W.P., Concurrent Operations on Linear Hashing, Information Sciences, Vol. 2, July 1990. [7] Kumar, V., Concurrency Control on Extendible Hashing, Information, Information Processing Letters, Vol. 31, pp. 35-41, April 1989. [8] Larson, P. A., Linear Hashing with Separator: A Dynamic Hashing Scheme Achieving One-Access Retrieval, ACM Transaction on Database Systems, Vol. 13, No. 3, Sept. 1988.

[9] Lechman, P. L., Yao, S. B., Efficient Locking for Concurrent Operations on B-trees, ACM Transaction on Database Systems, Vol. 6, No. 4, pp. 650-670, Dec. 1981. [10] Litwin, W., Neimat, N. Schneider, LH* - A Scalable, distributed Data Structure, ACM Transactions on Database Systems, 21(4), pp. 480-525, Dec. 1996. [11] Lynch, N., Merrit, M., Weihl, W., Fekete, A., Atomic Transactions, Morgan Kaufman Publishers, San Mateo, California, 1994.

[12] Madria, S. K., Maheshwari, S. N., Chandra, B., Formalization of a Concurrent Linear Hash Structure Algorithm Using nested Transactions and I/O Automation Model, accepted for IADT’98, Berlin, Germany, July, 1998. [13] Mohan, C., Aries/LHS: A Concurrency Control and Recovery Method Using Write-Ahead logging for Hashing th

With Separators, in proceedings of the 9 IEEE International Conference on Data Engineering, April 1993. [14] Moss, J. E., Nested Transactions: An Approach to Reliable Distributed Computing. MIT Press Cambridge, Massachusetts, 1985.

[15] Muth, P., Rakow, T.C., Weikum, G., Brossler, P., Hasse, C., Semantic Concurrency Control in Object-Oriented Database Systems, in Proceedings of the 9th IEEE International Conference on Data Engineering, pp. 233-242, 1993. [16] Rys, M., Norrie M. C. and Schek H. J., Intra-Transaction Parallelism in the Mapping of an Object Model to a Relational Multi-Processor System, in Proceedings of the 22nd VLDB conference, Mumbai, India, 1996. rd

[17] Sagiv, Y., Concurrent Operations on B*-trees with Overtaking, in proceeding of the 3 ACM SIGACTSIGMOD symposium on principles of Database Systems, Waterloo, Ontario, Canada, pp. 28-37, April 1985. [18] Weikum, G., Principles and Realization Strategies of Multi-level Transaction Management, ACM Transactions on Database Systems, 16(1), 132-180, March 1991.

20