int READ_REQ (TM_ID, DM_ID, variable/object, TS)
{
int i;
int SUCCESS=TRUE;
/* Checks to see if another WRITE is scheduled to happen earlier in time. In that
case, it buffers the request to avoid the potential conflict */
for (i=1; i<=N; i++) {
if (NonEmpty(*Write_Queue[i]) && ( Head(Write_Queue[i]->TS) ) > TS) ;
else {
/* If test fails, procedure enqueues the request in a read queue. */
Enqueue(Read_Queue(TM_ID, TS));
SUCCESS=FALSE;
return(0);
}
} /* End for */
/* If succeeds, request is executed */
if (SUCCESS) {
READ(variable/object, DM_ID);
return(SUCCESS);
}
} /* End READ_REQ */
WRITE_REQ (TM_ID, DM_ID, variable/object, value, TS)
{
int i;
int SUCCESS=TRUE;
for (i=1, i<=N; i++) {
/* Checks to see if any read requests are scheduled to happen earlier in time. In that case, it buffers the
request to avoid potential conflicts */
if (NonEmpty(*Read_Queue[i]) && NonEmpty(*Write_Queue[i]) && (Head(Read_Queue)->TS > TS) );
else {
Enqueue(Write_queue(TM_ID, TS));
SUCCESS=FALSE;
return(0);
}
if (SUCCESS) {
WRITE(variable/object, value, DM_ID);
return (SUCCESS);
}
} /* End WRITE_REQ */
1st to arrive, w/ TS=1 : REQ_READ (TM_1, DM_1, x, 1); 2nd to arrive, w/ TS=2 : REQ_READ (TM_2, DM_1, x, 2); 3rd to arrive, w/ TS=3 : REQ_READ (TM_2, DM_1, y, 3); 4th to arrive, w/ TS=4 : REQ_WRITE(TM_1, DM_1, y, 4);These operations are clearly serializable, for it represents the execution of transaction 2 before transaction 1. One can see, however, that all the requests are buffered because of empty queues in the system, and because the final write request has a timestamp greater than the ones in the system. This example also illustrates a very undesirable situation that may occur when using CTO algorithms: the system can be blocked , even though it has no conflicting actions.
It should be clear also from the simple example above, that with only two transactions and one write request, every possible ordering of actions is valid and serializable, and there is no reason for blocking. The write request of transaction 1 could, for example, be executed in any order.
However, in the case of large number of requests arriving from a large number of transactions, or when the possibility of conflict among requests is big, the conservative algorithm does its job fairly well. By making sure that all the requests are processed in timestamp order, it guarantees a consistant and serializable execution of events.
To handle those blocking situations, where termination is not guaranteed, it is recommended that "dummy" requests be sent regularly to the scheduler.
1. Bernstein, P. and N. Goodman, "Timestamp Based Algorithms for Concurrency Control in Distributed Database Systems," Proceedings of 6th Int Conf. on Very Large Databases, Oct. 1980
2. Singhal, M. and N. Shivaratri, "Advanced Concepts in Operating Systems,"McGraw-Hill, Inc. 1994