I. Problem Statement:
Your project's run time environment consists of a main thread that handles the input,
initializes the necessary data structures and a pool of mutex and condition variables to
ensure that operations belonging to the same transaction are executed in proper order
(zgt_test.C). The main thread creates a transaction manager object (there is only one Tx
mgr object) and the associated hash table that acts as a lock table. As the input is read
from a file, a separate thread is created and started for carrying out each operation (in
a real DBMS one thread or process will handle all the operations of a Tx) requested by
that transaction (zgt_tm.C). The reason for using threads is to allow concurrent execution
of multiple threads, where possible, by the Tx mgr logic. The thread is terminated at the
end of the operation using a pthread_exit call. The main thread reads transactions
(instructions from the input- see below) and invokes a method on the created
transaction manager object. This method will create a new thread to perform each
operation.
The thread created for each operation will execute a function (not a method, as we are
using C) for that operation in zgt_tx.C. For example, the function begintx does the
operation of starting a transaction. All the functions for a transaction execution (begintx,
readtx, writetx, committx, and aborttx) need to be implemented or completed as part of/nCSE 4331/5331 - Fall 2023 (All Sections)
this project. The thread has to make sure that a previous operation by the same
transaction has been completed before starting the current operation (otherwise, as
you know, it is not a legal schedule). In order to do that, it uses a condition wait on a
mutex. Each transaction has a mutex associated with it for this purpose. This is
accomplished by using the SEQNUM array and condset array defined in class zgt_tm. They
are initialized to zero. Each operation is assigned its position using the count variable
before a thread is created. SEQNUM is used to keep track of the order of operations for
each Tx. The count variable in each thread holds the current operation number. They are
compared with the condset[tid] value to decide whether to wait (using cond_wait on the
thread) for an operation or proceed. This allows the operations to be executed
sequentially within a Tx. Use the cond_wait and cond_broadcast functions. The working
of these functions is described in the supplementary material. If the operation is
successfully completed (i.e., transaction gets a shared or exclusive lock for that
operation), the appropriate parameters should be inserted in the log file. Do a flush on
the logfile write operation to force write it. If there are no threads available, an error
should be written in the log. You make sure all threads complete before exiting the test
program.
Since each operation of each transaction is done in a separate thread, all errors and the
log output need to be printed (or transmitted) at the point of occurrence. These threads
cannot return any error status.
A transaction abort operation should release locks held on all objects by that transaction
(not necessarily in any particular order). In addition, the abort operation should release
all transactions waiting on objects held by the aborted transaction so that one of them
can proceed.
A transaction commit will also release locks held on all objects by that transaction and the
transactions waiting on those objects (not necessarily in any particular order). This is done
by doing as many p operations associated with the semaphore for that tx. In a real DBMS,
the data durability (or persistence) will be handled by the buffer manager and the log is
written for recovery which we are not addressing in this project. However, in this
simplified project, values of the data items reflect the work accomplished by a
transaction.