--- rat/lonuserstate.pm 2009/11/16 20:26:04 1.128.2.3 +++ rat/lonuserstate.pm 2008/12/19 03:58:24 1.130 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Construct and maintain state and binary representation of course for user # -# $Id: lonuserstate.pm,v 1.128.2.3 2009/11/16 20:26:04 raeburn Exp $ +# $Id: lonuserstate.pm,v 1.130 2008/12/19 03:58:24 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -573,8 +573,7 @@ sub accinit { $acchash{'acc.res.'.$short.'.'}='&:0&'; my $courseuri=$uri; $courseuri=~s/^\/res\///; - my $regexp = 1; - &Apache::lonnet::delenv('(acc\.|httpref\.)',$regexp); + &Apache::lonnet::delenv('(acc\.|httpref\.)'); &Apache::lonnet::appenv(\%acchash); } @@ -645,52 +644,92 @@ sub readmap { my $uri; $short=~s/\//\_/g; unless ($uri=$cenv{'url'}) { - &Apache::lonnet::logthis('WARNING: '. + &Apache::lonnet::logthis("WARNING: ". "Could not load course $short."); return ('',&mt('No course data available.'));; } @cond=('true:normal'); - unless (open(LOCKFILE,">$fn.db.lock")) { - $errtext.='
'.&mt('Map not loaded - Lock file could not be opened when reading map:').' '.$fn.'.'; - $retfurl = ''; - return ($retfurl,$errtext); - } + open(LOCKFILE,">$fn.db.lock"); my $lock=0; - my $gotstate=0; if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) { $lock=1; - &unlink_tmpfiles($fn); + unlink($fn.'.db'); + unlink($fn.'_symb.db'); + unlink($fn.'.state'); + unlink($fn.'parms.db'); } undef %randompick; undef %hiddenurl; undef %encurl; $retfrid=''; - my ($untiedhash,$untiedparmhash,$tiedhash,$tiedparmhash); - if ($lock) { - if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_WRCREAT(),0640)) { - $tiedhash = 1; - if (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_WRCREAT(),0640)) { - $tiedparmhash = 1; - $gotstate = &build_tmp_hashes($uri,$fn,$short,\%cenv); - unless ($gotstate) { - &Apache::lonnet::logthis('Failed to write statemap at first attempt '.$fn.' for '.$uri.'.
'); - } - $untiedparmhash = untie(%parmhash); - unless ($untiedparmhash) { - &Apache::lonnet::logthis('WARNING: '. - 'Could not untie coursemap parmhash '.$fn.' for '.$uri.'.'); - } - } - $untiedhash = untie(%hash); - unless ($untiedhash) { - &Apache::lonnet::logthis('WARNING: '. - 'Could not untie coursemap hash '.$fn.' for '.$uri.'.'); - } - } - flock(LOCKFILE,LOCK_UN); - } - unless ($lock && $tiedhash && $tiedparmhash) { + if ($lock && (tie(%hash,'GDBM_File',"$fn.db",&GDBM_WRCREAT(),0640)) && + (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_WRCREAT(),0640))) { + %hash=(); + %parmhash=(); + $errtext=''; + $pc=0; + &clear_mapalias_count(); + &processversionfile(%cenv); + my $furi=&Apache::lonnet::clutter($uri); + $hash{'src_0.0'}=&versiontrack($furi); + $hash{'title_0.0'}=&Apache::lonnet::metadata($uri,'title'); + $hash{'ids_'.$furi}='0.0'; + $hash{'is_map_0.0'}=1; + loadmap($uri,'0.0'); + if (defined($hash{'map_start_'.$uri})) { + &Apache::lonnet::appenv({"request.course.id" => $short, + "request.course.fn" => $fn, + "request.course.uri" => $uri}); + $env{'request.course.id'}=$short; + &traceroute('0',$hash{'map_start_'.$uri},'&'); + &accinit($uri,$short,$fn); + &hiddenurls(); + } + $errtext .= &get_mapalias_errors(); +# ------------------------------------------------------- Put versions into src + foreach my $key (keys(%hash)) { + if ($key=~/^src_/) { + $hash{$key}=&putinversion($hash{$key}); + } elsif ($key =~ /^(map_(?:start|finish|pc)_)(.*)/) { + my ($type, $url) = ($1,$2); + my $value = $hash{$key}; + $hash{$type.&putinversion($url)}=$value; + } + } +# ---------------------------------------------------------------- Encrypt URLs + foreach my $id (keys(%encurl)) { +# $hash{'src_'.$id}=&Apache::lonenc::encrypted($hash{'src_'.$id}); + $hash{'encrypted_'.$id}=1; + } +# ----------------------------------------------- Close hashes to finally store +# --------------------------------- Routine must pass this point, no early outs + $hash{'first_rid'}=$retfrid; + my ($mapid,$resid)=split(/\./,$retfrid); + $hash{'first_mapurl'}=$hash{'map_id_'.$mapid}; + my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$hash{'src_'.$retfrid}); + $retfurl=&add_get_param($hash{'src_'.$retfrid},{ 'symb' => $symb }); + if ($hash{'encrypted_'.$retfrid}) { + $retfurl=&Apache::lonenc::encrypted($retfurl,(&Apache::lonnet::allowed('adv') ne 'F')); + } + $hash{'first_url'}=$retfurl; + unless ((untie(%hash)) && (untie(%parmhash))) { + &Apache::lonnet::logthis("WARNING: ". + "Could not untie coursemap $fn for $uri."); + } +# ---------------------------------------------------- Store away initial state + { + my $cfh; + if (open($cfh,">$fn.state")) { + print $cfh join("\n",@cond); + } else { + &Apache::lonnet::logthis("WARNING: ". + "Could not write statemap $fn for $uri."); + } + } + flock(LOCKFILE,LOCK_UN); + close(LOCKFILE); + } else { # if we are here it is likely because we are already trying to # initialize the course in another child, busy wait trying to # tie the hashes for the next 90 seconds, if we succeed forward @@ -699,113 +738,34 @@ sub readmap { if ($lock) { # Got the lock but not the DB files flock(LOCKFILE,LOCK_UN); - $lock = 0; } - if ($tiedhash) { - unless($untiedhash) { - untie(%hash); - } - } - if ($tiedparmhash) { - unless($untiedparmhash) { - untie(%parmhash); - } - } - &Apache::lonnet::logthis('WARNING: '. - "Could not tie coursemap $fn for $uri."); - $tiedhash = ''; - $tiedparmhash = ''; + untie(%hash); + untie(%parmhash); + &Apache::lonnet::logthis("WARNING: ". + "Could not tie coursemap $fn for $uri."); my $i=0; while($i<90) { $i++; sleep(1); - if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) { - $lock = 1; - if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER(),0640)) { - $tiedhash = 1; - if (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_READER(),0640)) { - $tiedparmhash = 1; - if (-e "$fn.state") { - $retfurl='/adm/navmaps'; - &Apache::lonnet::appenv({"request.course.id" => $short, - "request.course.fn" => $fn, - "request.course.uri" => $uri}); - $untiedhash = untie(%hash); - $untiedparmhash = untie(%parmhash); - $gotstate = 1; - last; - } - $untiedparmhash = untie(%parmhash); - } - $untiedhash = untie(%hash); + if (flock(LOCKFILE,LOCK_EX|LOCK_NB) && + (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER(),0640))) { + if (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_READER(),0640)) { + $retfurl='/adm/navmaps'; + &Apache::lonnet::appenv({"request.course.id" => $short, + "request.course.fn" => $fn, + "request.course.uri" => $uri}); + untie(%hash); + untie(%parmhash); + last; } } + untie(%hash); + untie(%parmhash); } - if ($lock) { - flock(LOCKFILE,LOCK_UN); - $lock = 0; - if ($tiedparmhash) { - unless ($untiedparmhash) { - &Apache::lonnet::logthis('WARNING: '. - 'Could not untie coursemap parmhash '.$fn.' for '.$uri.'.'); - } - } - if ($tiedparmhash) { - unless ($untiedhash) { - &Apache::lonnet::logthis('WARNING: '. - 'Could not untie coursemap hash '.$fn.' for '.$uri.'.'); - } - } - } - } - unless ($gotstate) { - $lock = 0; - &Apache::lonnet::logthis('WARNING: '. - 'Could not read statemap '.$fn.' for '.$uri.'.'); - &unlink_tmpfiles($fn); - if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) { - $lock=1; - } - undef %randompick; - undef %hiddenurl; - undef %encurl; - $retfrid=''; - if ($lock) { - if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_WRCREAT(),0640)) { - if (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_WRCREAT(),0640)) { - $gotstate = &build_tmp_hashes($uri,$fn,$short,\%cenv); - unless ($gotstate) { - &Apache::lonnet::logthis('WARNING: '. - 'Failed to write statemap at second attempt '.$fn.' for '.$uri.'.'); - } - unless (untie(%parmhash)) { - &Apache::lonnet::logthis('WARNING: '. - 'Could not untie coursemap parmhash '.$fn.'.db for '.$uri.'.'); - } - } else { - &Apache::lonnet::logthis('WARNING: '. - 'Could not tie coursemap '.$fn.'__parms.db for '.$uri.'.'); - } - unless (untie(%hash)) { - &Apache::lonnet::logthis('WARNING: '. - 'Could not untie coursemap hash '.$fn.'.db for '.$uri.'.'); - } - } else { - &Apache::lonnet::logthis('WARNING: '. - 'Could not tie coursemap '.$fn.'.db for '.$uri.'.'); - } - flock(LOCKFILE,LOCK_UN); - $lock = 0; - } else { - &Apache::lonnet::logthis('WARNING: '. - 'Could not obtain lock to tie coursemap hash '.$fn.'.db for '.$uri.'.'); - } - } - close(LOCKFILE); - unless (($errtext eq '') || ($env{'request.course.uri'} =~ m{^/uploaded/})) { - &Apache::lonmsg::author_res_msg($env{'request.course.uri'}, - $errtext); + flock(LOCKFILE,LOCK_UN); + close(LOCKFILE); } + &Apache::lonmsg::author_res_msg($env{'request.course.uri'},$errtext); # ------------------------------------------------- Check for critical messages my @what=&Apache::lonnet::dump('critical',$env{'user.domain'}, @@ -818,91 +778,6 @@ sub readmap { return ($retfurl,$errtext); } -sub build_tmp_hashes { - my ($uri,$fn,$short,$cenvref) = @_; - unless(ref($cenvref) eq 'HASH') { - return; - } - my %cenv = %{$cenvref}; - my $gotstate = 0; - %hash=(); - %parmhash=(); - $errtext=''; - $pc=0; - &clear_mapalias_count(); - &processversionfile(%cenv); - my $furi=&Apache::lonnet::clutter($uri); - $hash{'src_0.0'}=&versiontrack($furi); - $hash{'title_0.0'}=&Apache::lonnet::metadata($uri,'title'); - $hash{'ids_'.$furi}='0.0'; - $hash{'is_map_0.0'}=1; - &loadmap($uri,'0.0'); - if (defined($hash{'map_start_'.$uri})) { - &Apache::lonnet::appenv({"request.course.id" => $short, - "request.course.fn" => $fn, - "request.course.uri" => $uri}); - $env{'request.course.id'}=$short; - &traceroute('0',$hash{'map_start_'.$uri},'&'); - &accinit($uri,$short,$fn); - &hiddenurls(); - } - $errtext .= &get_mapalias_errors(); -# ------------------------------------------------------- Put versions into src - foreach my $key (keys(%hash)) { - if ($key=~/^src_/) { - $hash{$key}=&putinversion($hash{$key}); - } elsif ($key =~ /^(map_(?:start|finish|pc)_)(.*)/) { - my ($type, $url) = ($1,$2); - my $value = $hash{$key}; - $hash{$type.&putinversion($url)}=$value; - } - } -# ---------------------------------------------------------------- Encrypt URLs - foreach my $id (keys(%encurl)) { -# $hash{'src_'.$id}=&Apache::lonenc::encrypted($hash{'src_'.$id}); - $hash{'encrypted_'.$id}=1; - } -# ----------------------------------------------- Close hashes to finally store -# --------------------------------- Routine must pass this point, no early outs - $hash{'first_rid'}=$retfrid; - my ($mapid,$resid)=split(/\./,$retfrid); - $hash{'first_mapurl'}=$hash{'map_id_'.$mapid}; - my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$hash{'src_'.$retfrid}); - $retfurl=&add_get_param($hash{'src_'.$retfrid},{ 'symb' => $symb }); - if ($hash{'encrypted_'.$retfrid}) { - $retfurl=&Apache::lonenc::encrypted($retfurl,(&Apache::lonnet::allowed('adv') ne 'F')); - } - $hash{'first_url'}=$retfurl; -# ---------------------------------------------------- Store away initial state - { - my $cfh; - if (open($cfh,">$fn.state")) { - print $cfh join("\n",@cond); - $gotstate = 1; - } else { - &Apache::lonnet::logthis("WARNING: ". - "Could not write statemap $fn for $uri."); - } - } - return $gotstate; -} - -sub unlink_tmpfiles { - my ($fn) = @_; - if ($fn =~ m{^\Q$Apache::lonnet::perlvar{'lonUsersDir'}\E/tmp/}) { - my @files = qw (.db _symb.db .state _parms.db); - foreach my $file (@files) { - if (-e $fn.$file) { - unless (unlink($fn.$file)) { - &Apache::lonnet::logthis("WARNING: ". - "Could not unlink ".$fn.$file.""); - } - } - } - } - return; -} - # ------------------------------------------------------- Evaluate state string sub evalstate { @@ -1002,37 +877,33 @@ of course for user. This is part of the LearningOnline Network with CAPA project described at http://www.lon-capa.org. -=head1 HANDLER SUBROUTINE - -There is no handler subroutine. - -=head1 OTHER SUBROUTINES +=head1 SUBROUTINES -=over 4 +=over -=item * +=item loadmap() -loadmap() : Loads map from disk +Loads map from disk -=item * +=item simplify() -simplify() : Simplify expression +Simplify expression -=item * +=item traceroute() -traceroute() : Build condition hash +Build condition hash -=item * +=item accinit() -accinit() : Cascading conditions, quick access, parameters +Cascading conditions, quick access, parameters -=item * +=item readmap() -readmap() : Read map and all submaps +Read map and all submaps -=item * +=item evalstate() -evalstate() : Evaluate state string +Evaluate state string =back