[LON-CAPA-cvs] cvs: rat / lonuserstate.pm
raeburn
raeburn@source.lon-capa.org
Sun, 15 Nov 2009 14:08:53 -0000
This is a MIME encoded message
--raeburn1258294133
Content-Type: text/plain
raeburn Sun Nov 15 14:08:53 2009 EDT
Modified files:
/rat lonuserstate.pm
Log:
Users occasionally prevented from initializing couse by missing .state file and corrupted $user_$course.db in /home/httpd/perl/tmp.
- Move code used to populate tied hashes for $user_$course.db and $user_$course_parms.db in /home/httpd/perl/tmp to subroutine - &build_tmp_hashes().
- Move code used to unlink old $user_$course.db and $user_$course_parms.db and $user_$course.state in /home/httpd/perl/tmp to subroutine - &unlink_tmpfiles().
- More detailed logging to lonnet.log for failed operations.
- Additional check for existence of $user_$course.state after hash population and/or busy wait to get lock and read of existing files.
--raeburn1258294133
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20091115140853.txt"
Index: rat/lonuserstate.pm
diff -u rat/lonuserstate.pm:1.131 rat/lonuserstate.pm:1.132
--- rat/lonuserstate.pm:1.131 Wed Feb 18 07:06:19 2009
+++ rat/lonuserstate.pm Sun Nov 15 14:08:53 2009
@@ -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.131 2009/02/18 07:06:19 raeburn Exp $
+# $Id: lonuserstate.pm,v 1.132 2009/11/15 14:08:53 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -653,84 +653,41 @@
open(LOCKFILE,">$fn.db.lock");
my $lock=0;
+ my $gotstate=0;
if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) {
$lock=1;
- unlink($fn.'.db');
- unlink($fn.'_symb.db');
- unlink($fn.'.state');
- unlink($fn.'parms.db');
+ &unlink_tmpfiles($fn);
}
undef %randompick;
undef %hiddenurl;
undef %encurl;
$retfrid='';
- 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("<font color=blue>WARNING: ".
- "Could not untie coursemap $fn for $uri.</font>");
- }
-# ---------------------------------------------------- Store away initial state
- {
- my $cfh;
- if (open($cfh,">$fn.state")) {
- print $cfh join("\n",@cond);
- } else {
- &Apache::lonnet::logthis("<font color=blue>WARNING: ".
- "Could not write statemap $fn for $uri.</font>");
- }
- }
+ 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.'.</font>');
+ }
+ $untiedparmhash = untie(%parmhash);
+ unless ($untiedparmhash) {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not untie coursemap parmhash '.$fn.' for '.$uri.'.</font>');
+ }
+ }
+ $untiedhash = untie(%hash);
+ unless ($untiedhash) {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not untie coursemap hash '.$fn.' for '.$uri.'.</font>');
+ }
+ }
flock(LOCKFILE,LOCK_UN);
close(LOCKFILE);
- } else {
+ }
+ unless ($lock && $tiedhash && $tiedparmhash) {
# 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
@@ -739,34 +696,115 @@
if ($lock) {
# Got the lock but not the DB files
flock(LOCKFILE,LOCK_UN);
+ $lock = 0;
}
- untie(%hash);
- untie(%parmhash);
+ if ($tiedhash) {
+ unless($untiedhash) {
+ untie(%hash);
+ }
+ }
+ if ($tiedparmhash) {
+ unless($untiedparmhash) {
+ untie(%parmhash);
+ }
+ }
&Apache::lonnet::logthis("<font color=blue>WARNING: ".
- "Could not tie coursemap $fn for $uri.</font>");
+ "Could not tie coursemap $fn for $uri.</font>");
+ $tiedhash = '';
+ $tiedparmhash = '';
my $i=0;
while($i<90) {
$i++;
sleep(1);
- 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 (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);
+ }
+ }
}
- flock(LOCKFILE,LOCK_UN);
- close(LOCKFILE);
+ if ($lock) {
+ flock(LOCKFILE,LOCK_UN);
+ if ($tiedparmhash) {
+ unless ($untiedparmhash) {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not untie coursemap parmhash '.$fn.' for '.$uri.'.</font>');
+ }
+ }
+ if ($tiedparmhash) {
+ unless ($untiedhash) {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not untie coursemap hash '.$fn.' for '.$uri.'.</font>');
+ }
+ }
+ }
+ }
+ unless ($gotstate) {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not read statemap '.$fn.' for '.$uri.'.</font>');
+ &unlink_tmpfiles($fn);
+ if (open(LOCKFILE,">$fn.db.lock")) {
+ my $lock=0;
+ if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) {
+ $lock=1;
+ &unlink_tmpfiles($fn);
+ }
+ 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('<font color="blue">WARNING: '.
+ 'Failed to write statemap at second attempt '.$fn.' for '.$uri.'.</font>');
+ }
+ unless (untie(%parmhash)) {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not untie coursemap parmhash '.$fn.'.db for '.$uri.'.</font>');
+ }
+ } else {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not tie coursemap '.$fn.'__parms.db for '.$uri.'.</font>');
+ }
+ unless (untie(%hash)) {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not untie coursemap hash '.$fn.'.db for '.$uri.'.</font>');
+ }
+ } else {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not tie coursemap '.$fn.'.db for '.$uri.'.</font>');
+ }
+ flock(LOCKFILE,LOCK_UN);
+ close(LOCKFILE);
+ } else {
+ &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+ 'Could not obtain lock to tie coursemap hash '.$fn.'.db for '.$uri.'.</font>');
+ }
+ close(LOCKFILE);
+ }
+ }
+ unless (($errtext eq '') || ($env{'request.course.uri'} =~ m{^/uploaded/})) {
+ &Apache::lonmsg::author_res_msg($env{'request.course.uri'},
+ $errtext);
}
- &Apache::lonmsg::author_res_msg($env{'request.course.uri'},$errtext);
# ------------------------------------------------- Check for critical messages
my @what=&Apache::lonnet::dump('critical',$env{'user.domain'},
@@ -779,6 +817,91 @@
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("<font color=blue>WARNING: ".
+ "Could not write statemap $fn for $uri.</font>");
+ }
+ }
+ 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("<font color=blue>WARNING: ".
+ "Could not unlink ".$fn.$file."</font>");
+ }
+ }
+ }
+ }
+ return;
+}
+
# ------------------------------------------------------- Evaluate state string
sub evalstate {
--raeburn1258294133--