# --------------------------------------------------------------- #
# -- Copyright (c) 1994, 1995 Computer Sciences Department,    -- #
# -- University of Wisconsin-Madison, subject to the terms     -- #
# -- and conditions given in the file COPYRIGHT.  All Rights   -- #
# -- Reserved.                                                 -- #
# --------------------------------------------------------------- #

#
#  This script tests 5x5 (IS, IX, SH, SIX, and EX) lock compatibility
#  on file. 
#
#  The operations to set an IS lock on a file are
#  (through hierarchical locking)
#	sm read_rec
#	sm read_rec_body
#	sm print_rec
#
#  The operations to set an IX lock on a file are
#  (through hierarchical locking)
#	sm append_rec
#	sm truncate_rec
#	sm update_rec
#	sm update_rec_hdr
#
#  The operations to set a SH lock on a file are
#	sm scan_recs
#
#  The operations to set a SIX lock on a file are
#	sm scan_recs, sm append_rec
#	sm scan_recs, sm truncate_rec
#	sm scan_recs, sm update_rec
#	sm scan_recs, sm update_rec_hdr
#
#  The operations to set an EX lock on a file are
#	sm destroy_file  (this is not yet implemented)
#

proc req_lock { fid rid lock op } {
    sm begin_xct

    case $lock in {

	IS {  case $op in {
		read 		{ verbose [sm read_rec $rid 0 0] }
		read_body 	{ verbose [sm read_rec_body $rid 0 0] }
		print 		{ verbose [sm print_rec $rid 0 0] }
	      }
	   }

	IX {  case $op in {
		update 		{ sm update_rec $rid 1 b }
		update_hdr 	{ sm update_rec_hdr $rid 1 h }
		append 		{ sm append_rec $rid z }
		truncate 	{ sm truncate_rec $rid 1 }
	      }
	   }

	SH {  case $op in {
		scan 		{ verbose [sm scan_recs $fid] }
	      }
	   }

	SIX {  
	      verbose [sm scan_recs $fid]
	      case $op in {
		update 		{ sm update_rec $rid 1 b }
		update_hdr 	{ sm update_rec_hdr $rid 1 h }
		append 		{ sm append_rec $rid z }
		truncate 	{ sm truncate_rec $rid 1 }
	      }
	   }

	EX {  case $op in {
		destroy 	{ sm destroy_file $fid }
	      }
	   }
    }
}

proc rel_lock { args } {
    sm commit_xct
}

proc holder { fid rid type op me } {
    global verbose_flag
    sync

    echo "$me: $type ($op) requesting lock on $fid"
    req_lock $fid $rid $type $op
    echo "$me: $type ($op) lock on $fid granted"
#    if { $verbose_flag } { sm dump_locks }

    sync
    sync

    echo "$me: $type ($op) releasing lock on $fid"
    rel_lock
#    echo "$me: $type ($op) lock on $fid released"
}

proc requester { fid rid type op me } {
    global verbose_flag
    sync
    sync

    echo "$me: $type ($op) requesting lock on $fid"
    req_lock $fid $rid $type $op
    echo "$me: $type ($op) lock on $fid granted"
#    if { $verbose_flag } { sm dump_locks }

    sync

    echo "$me: $type ($op) releasing lock on $fid"
    rel_lock
#    echo "$me: $type ($op) lock on $fid released"
}

proc testit { fid r1 r2 lock1 lock2 } {
    global ops
    foreach i $ops($lock1) { 
    	foreach j $ops($lock2) { 
	    set x [ fork_thread holder $fid $r1 $lock1 $i 1 ]
	    set y [ fork_thread requester $fid $r2 $lock2 $j 2 ]

	    sync_thread $x $y
	    sync_thread $x $y
	    sync_thread $x $y
	    join_thread $x $y
	    echo "----------------"
	}
    }
}

####  global variables ####

set ops(IS) { read read_body print }
set ops(IX) { append truncate update update_hdr }
set ops(SH) { scan }
set ops(SIX) { append truncate update update_hdr }
set ops(EX) { destroy }

##########  main  ########## 


source $script_dir/vol.init

sm begin_xct
set fid [ sm create_file $volid ]
set r1 [ sm create_rec $fid "hdr1" 0 "body1" ]
set r2 [ sm create_rec $fid "hdr2" 0 "body2" ]
sm commit_xct

echo volid = $volid
echo fid = $fid
echo r1 = $r1
echo r2 = $r2

echo "TEST:\tFile Locking with SM Rec/File Operations"

foreach i { IS IX SH SIX } {
    foreach j { IS IX SH SIX } {

	echo "==================   $i  $j  ====================="
	testit $fid $r1 $r2 $i $j
    }
}

unset i j ops fid r1 r2
