--- loncom/lond 2006/01/31 15:56:46 1.312 +++ loncom/lond 2006/01/31 16:12:12 1.313 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.312 2006/01/31 15:56:46 albertel Exp $ +# $Id: lond,v 1.313 2006/01/31 16:12:12 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -53,13 +53,15 @@ use LONCAPA::ConfigFileEdit; use LONCAPA::lonlocal; use LONCAPA::lonssl; use Fcntl qw(:flock); +use Symbol; my $DEBUG = 0; # Non zero to enable debug log entries. my $status=''; my $lastlog=''; +my $lond_max_wait_time = 13; -my $VERSION='$Revision: 1.312 $'; #' stupid emacs +my $VERSION='$Revision: 1.313 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; @@ -972,11 +974,11 @@ sub tie_domain_hash { my $user_top_dir = $perlvar{'lonUsersDir'}; my $domain_dir = $user_top_dir."/$domain"; my $resource_file = $domain_dir."/$namespace"; - return &_do_hash_tie($resource_file,$namespace,$how,$loghead,$logtail); + return &_locking_hash_tie($resource_file,$namespace,$how,$loghead,$logtail); } sub untie_domain_hash { - return &_do_hash_untie(@_); + return &_locking_hash_untie(@_); } # # Ties a user's resource file to a hash. @@ -1005,11 +1007,11 @@ sub tie_user_hash { my $proname = propath($domain, $user); my $file_prefix="$proname/$namespace"; - return &_do_hash_tie($file_prefix,$namespace,$how,$loghead,$what); + return &_locking_hash_tie($file_prefix,$namespace,$how,$loghead,$what); } sub untie_user_hash { - return &_do_hash_untie(@_); + return &_locking_hash_untie(@_); } # internal routines that handle the actual tieing and untieing process @@ -1041,6 +1043,71 @@ sub _do_hash_untie { my $result = untie(%$hashref); return $result; } + +{ + my $sym; + + sub _locking_hash_tie { + my ($file_prefix,$namespace,$how,$loghead,$what) = @_; + + my ($lock); + + if ($how eq &GDBM_READER()) { + $lock=LOCK_SH; + $how=$how|&GDBM_NOLOCK(); + #if the db doesn't exist we can't read from it + if (! -e "$file_prefix.db") { + $! = 2; + return undef; + } + } elsif ($how eq &GDBM_WRCREAT()) { + $lock=LOCK_EX; + $how=$how|&GDBM_NOLOCK(); + if (! -e "$file_prefix.db") { + # doesn't exist but we need it to in order to successfully + # lock it so bring it into existance + open(TOUCH,">>$file_prefix.db"); + close(TOUCH); + } + } else { + &logthis("Unknown method $how for $file_prefix"); + die(); + } + + &logthis("$$ for $namespace"); + $sym=&Symbol::gensym(); + open($sym,"$file_prefix.db"); + &logthis("$$ for $namespace attempt lock"); + my $failed=0; + eval { + local $SIG{__DIE__}='DEFAULT'; + local $SIG{ALRM}=sub { + $failed=1; + die("failed lock"); + }; + alarm($lond_max_wait_time); + flock($sym,$lock); + alarm(0); + }; + if ($failed) { + &logthis("$$ for $namespace got failed lock"); + $! = 100; # throwing error # 100 + return undef; + } + &logthis("$$ for $file_prefix.db got lock"); + return &_do_hash_tie($file_prefix,$namespace,$how,$loghead,$what); + } + + sub _locking_hash_untie { + my ($hashref) = @_; + my $result = untie(%$hashref); + flock($sym,LOCK_UN); + close($sym); + undef($sym); + return $result; + } +} + # read_profile # # Returns a set of specific entries from a user's profile file.