[LON-CAPA-cvs] cvs: rat(version_2_8_X) / lonuserstate.pm

raeburn raeburn@source.lon-capa.org
Mon, 16 Nov 2009 20:26:04 -0000


This is a MIME encoded message

--raeburn1258403164
Content-Type: text/plain

raeburn		Mon Nov 16 20:26:04 2009 EDT

  Modified files:              (Branch: version_2_8_X)
    /rat	lonuserstate.pm 
  Log:
  - Backport 1.132, 1.133.
  
  
--raeburn1258403164
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20091116202604.txt"

Index: rat/lonuserstate.pm
diff -u rat/lonuserstate.pm:1.128.2.2 rat/lonuserstate.pm:1.128.2.3
--- rat/lonuserstate.pm:1.128.2.2	Sat Mar 21 06:12:05 2009
+++ rat/lonuserstate.pm	Mon Nov 16 20:26:04 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.128.2.2 2009/03/21 06:12:05 raeburn Exp $
+# $Id: lonuserstate.pm,v 1.128.2.3 2009/11/16 20:26:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -645,92 +645,52 @@
     my $uri;
     $short=~s/\//\_/g;
     unless ($uri=$cenv{'url'}) { 
-	&Apache::lonnet::logthis("<font color=blue>WARNING: ".
+	&Apache::lonnet::logthis('<font color="blue">WARNING: '.
 				 "Could not load course $short.</font>"); 
 	return ('',&mt('No course data available.'));;
     }
     @cond=('true:normal');
 
-    open(LOCKFILE,">$fn.db.lock");
+    unless (open(LOCKFILE,">$fn.db.lock")) {
+        $errtext.='<br />'.&mt('Map not loaded - Lock file could not be opened when reading map:').' <tt>'.$fn.'</tt>.';
+        $retfurl = '';
+        return ($retfurl,$errtext);
+    }
     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>"); 
-	    }
-	}
-	flock(LOCKFILE,LOCK_UN);
-	close(LOCKFILE);
-    } else {
+    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);
+    }
+    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 +699,113 @@
 	if ($lock) {
 	    # Got the lock but not the DB files
 	    flock(LOCKFILE,LOCK_UN);
+            $lock = 0;
 	}
-	untie(%hash);
-	untie(%parmhash);
-	&Apache::lonnet::logthis("<font color=blue>WARNING: ".
-				 "Could not tie coursemap $fn for $uri.</font>"); 
+        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>");
+        $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;
+	    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);
 		}
 	    }
-	    untie(%hash);
-	    untie(%parmhash);
 	}
-	flock(LOCKFILE,LOCK_UN);
-	close(LOCKFILE);
+        if ($lock) {
+            flock(LOCKFILE,LOCK_UN);
+            $lock = 0;
+            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) {
+        $lock = 0;
+        &Apache::lonnet::logthis('<font color="blue">WARNING: '.
+                     'Could not read statemap '.$fn.' for '.$uri.'.</font>');
+        &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('<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);
+            $lock = 0;
+        } 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 +818,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 {

--raeburn1258403164--