Diff for /loncom/lonsql between versions 1.51 and 1.57

version 1.51, 2002/08/06 13:48:47 version 1.57, 2003/07/30 16:49:27
Line 39  lonsql - LON TCP-MySQL-Server Daemon for Line 39  lonsql - LON TCP-MySQL-Server Daemon for
 This script should be run as user=www.    This script should be run as user=www.  
 Note that a lonsql.pid file contains the pid of the parent process.  Note that a lonsql.pid file contains the pid of the parent process.
   
 =head1 DESCRIPTION  =head1 OVERVIEW
   
 lonsql is many things to many people.  To me, it is a source file in need  The SQL database in LON-CAPA is used for catalog searches against
 of documentation.  resource metadata only. The authoritative version of the resource
   metadata is an XML-file on the normal file system (same file name as
   resource plus ".meta"). The SQL-database is a cache of these files,
   and can be reconstructed from the XML files at any time.
   
   The current database is implemented assuming a non-adjustable
   architecture involving these data fields (specific to each version of
   a resource).
   
   =over 4
   
   =item * title
   
   =item * author
   
   =item * subject
   
   =item * notes
   
   =item * abstract
   
   =item * mime
   
   =item * language
   
   =item * creationdate
   
   =item * lastrevisiondate
   
   =item * owner
   
   =item * copyright 
   
   =back 
   
   =head2 Purpose within LON-CAPA
   
   LON-CAPA is meant to distribute A LOT of educational content to A LOT
   of people. It is ineffective to directly rely on contents within the
   ext2 filesystem to be speedily scanned for on-the-fly searches of
   content descriptions. (Simply put, it takes a cumbersome amount of
   time to open, read, analyze, and close thousands of files.)
   
   The solution is to index various data fields that are descriptive of
   the educational resources on a LON-CAPA server machine in a
   database. Descriptive data fields are referred to as "metadata". The
   question then arises as to how this metadata is handled in terms of
   the rest of the LON-CAPA network without burdening client and daemon
   processes.
   
   The obvious solution, using lonc to send a query to a lond process,
   doesn't work so well in general as you can see in the following
   example:
   
       lonc= loncapa client process    A-lonc= a lonc process on Server A
       lond= loncapa daemon process
   
                    database command
       A-lonc  --------TCP/IP----------------> B-lond
   
   The problem emerges that A-lonc and B-lond are kept waiting for the
   MySQL server to "do its stuff", or in other words, perform the
   conceivably sophisticated, data-intensive, time-sucking database
   transaction.  By tying up a lonc and lond process, this significantly
   cripples the capabilities of LON-CAPA servers.
   
   The solution is to offload the work onto another process, and use
   lonc and lond just for requests and notifications of completed
   processing:
   
                   database command
   
     A-lonc  ---------TCP/IP-----------------> B-lond =====> B-lonsql
            <---------------------------------/                |
              "ok, I'll get back to you..."                    |
                                                               |
                                                               /
     A-lond  <-------------------------------  B-lonc   <======
              "Guess what? I have the result!"
   
   Of course, depending on success or failure, the messages may vary, but
   the principle remains the same where a separate pool of children
   processes (lonsql's) handle the MySQL database manipulations.
   
   Thus, lonc and lond spend effectively no time waiting on results from
   the database.
   
 =head1 Internals  =head1 Internals
   
Line 116  my $MAX_CLIENTS_PER_CHILD  = 5;   # numb Line 201  my $MAX_CLIENTS_PER_CHILD  = 5;   # numb
 my %children               = ();  # keys are current child process IDs  my %children               = ();  # keys are current child process IDs
 my $children               = 0;   # current number of children  my $children               = 0;   # current number of children
                                                                 
 ########################################################  
 ########################################################  
   
 =pod  
   
 =item Functions required for forking  
   
 =over 4  
   
 =item REAPER  
   
 REAPER takes care of dead children.  
   
 =item HUNTSMAN  
   
 Signal handler for SIGINT.  
   
 =item HUPSMAN  
   
 Signal handler for SIGHUP  
   
 =item DISCONNECT  
   
 Disconnects from database.  
   
 =back  
   
 =cut  
   
 ########################################################  
 ########################################################  
 sub REAPER {                   # takes care of dead children  
     $SIG{CHLD} = \&REAPER;  
     my $pid = wait;  
     $children --;  
     &logthis("Child $pid died");  
     delete $children{$pid};  
 }  
   
 sub HUNTSMAN {                      # signal handler for SIGINT  
     local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children  
     kill 'INT' => keys %children;  
     my $execdir=$perlvar{'lonDaemons'};  
     unlink("$execdir/logs/lonsql.pid");  
     &logthis("<font color=red>CRITICAL: Shutting down</font>");  
     $unixsock = "mysqlsock";  
     my $port="$perlvar{'lonSockDir'}/$unixsock";  
     unlink($port);  
     exit;                           # clean up with dignity  
 }  
   
 sub HUPSMAN {                      # signal handler for SIGHUP  
     local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children  
     kill 'INT' => keys %children;  
     close($server);                # free up socket  
     &logthis("<font color=red>CRITICAL: Restarting</font>");  
     my $execdir=$perlvar{'lonDaemons'};  
     $unixsock = "mysqlsock";  
     my $port="$perlvar{'lonSockDir'}/$unixsock";  
     unlink($port);  
     exec("$execdir/lonsql");         # here we go again  
 }  
   
 sub DISCONNECT {  
     $dbh->disconnect or   
     &logthis("<font color=blue>WARNING: Couldn't disconnect from database ".  
              " $DBI::errstr : $@</font>");  
     exit;  
 }  
   
 ###################################################################  ###################################################################
 ###################################################################  ###################################################################
   
Line 222  my $run =0;              # running count Line 237  my $run =0;              # running count
 #  #
 # Read loncapa_apache.conf and loncapa.conf  # Read loncapa_apache.conf and loncapa.conf
 #  #
 my $perlvarref=LONCAPA::Configuration::read_conf('loncapa_apache.conf',  my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');
                                                  'loncapa.conf');  
 my %perlvar=%{$perlvarref};  my %perlvar=%{$perlvarref};
 #  #
 # Make sure that database can be accessed  # Make sure that database can be accessed
Line 237  unless ($dbh = DBI->connect("DBI:mysql:l Line 251  unless ($dbh = DBI->connect("DBI:mysql:l
     my $subj="LON: $perlvar{'lonHostID'} Cannot connect to database!";      my $subj="LON: $perlvar{'lonHostID'} Cannot connect to database!";
     system("echo 'Cannot connect to MySQL database!' |".      system("echo 'Cannot connect to MySQL database!' |".
            " mailto $emailto -s '$subj' > /dev/null");             " mailto $emailto -s '$subj' > /dev/null");
   
       open(SMP,'>/home/httpd/html/lon-status/mysql.txt');
       print SMP 'time='.time.'&mysql=defunct'."\n";
       close(SMP);
   
     exit 1;      exit 1;
 } else {  } else {
     $dbh->disconnect;      $dbh->disconnect;
 }  }
   
 #  #
 # Check if other instance running  # Check if other instance running
 #  #
Line 251  if (-e $pidfile) { Line 271  if (-e $pidfile) {
    chomp($pide);     chomp($pide);
    if (kill 0 => $pide) { die "already running"; }     if (kill 0 => $pide) { die "already running"; }
 }  }
   
 #  #
 # Read hosts file  # Read hosts file
 #  #
Line 268  while (my $configline=<CONFIG>) { Line 289  while (my $configline=<CONFIG>) {
 close(CONFIG);  close(CONFIG);
 #  #
 $PREFORK=int($PREFORK/4);  $PREFORK=int($PREFORK/4);
   
 #  #
 # Create a socket to talk to lond  # Create a socket to talk to lond
 #  #
Line 280  unless ($server=IO::Socket::UNIX->new(Lo Line 302  unless ($server=IO::Socket::UNIX->new(Lo
                                       Listen => 10)) {                                        Listen => 10)) {
     print "in socket error:$@\n";      print "in socket error:$@\n";
 }  }
 ########################################################  
 ########################################################  
 #  #
 # Fork once and dissociate  # Fork once and dissociate
   #
 my $fpid=fork;  my $fpid=fork;
 exit if $fpid;  exit if $fpid;
 die "Couldn't fork: $!" unless defined ($fpid);  die "Couldn't fork: $!" unless defined ($fpid);
 POSIX::setsid() or die "Can't start new session: $!";  POSIX::setsid() or die "Can't start new session: $!";
   
 #  #
 # Write our PID on disk  # Write our PID on disk
 my $execdir=$perlvar{'lonDaemons'};  my $execdir=$perlvar{'lonDaemons'};
Line 295  open (PIDSAVE,">$execdir/logs/lonsql.pid Line 318  open (PIDSAVE,">$execdir/logs/lonsql.pid
 print PIDSAVE "$$\n";  print PIDSAVE "$$\n";
 close(PIDSAVE);  close(PIDSAVE);
 &logthis("<font color=red>CRITICAL: ---------- Starting ----------</font>");  &logthis("<font color=red>CRITICAL: ---------- Starting ----------</font>");
   
 #  #
 # Ignore signals generated during initial startup  # Ignore signals generated during initial startup
 $SIG{HUP}=$SIG{USR1}='IGNORE';  $SIG{HUP}=$SIG{USR1}='IGNORE';
Line 303  $SIG{HUP}=$SIG{USR1}='IGNORE'; Line 327  $SIG{HUP}=$SIG{USR1}='IGNORE';
 for (1 .. $PREFORK) {  for (1 .. $PREFORK) {
     make_new_child();      make_new_child();
 }  }
   
 #  #
 # Install signal handlers.  # Install signal handlers.
 $SIG{CHLD} = \&REAPER;  $SIG{CHLD} = \&REAPER;
 $SIG{INT}  = $SIG{TERM} = \&HUNTSMAN;  $SIG{INT}  = $SIG{TERM} = \&HUNTSMAN;
 $SIG{HUP}  = \&HUPSMAN;  $SIG{HUP}  = \&HUPSMAN;
   
 #  #
 # And maintain the population.  # And maintain the population.
 while (1) {  while (1) {
Line 586  Writes $message to the logfile. Line 612  Writes $message to the logfile.
 sub logthis {  sub logthis {
     my $message=shift;      my $message=shift;
     my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
     my $fh=IO::File->new(">>$execdir/logs/lonsqlfinal.log");      my $fh=IO::File->new(">>$execdir/logs/lonsql.log");
     my $now=time;      my $now=time;
     my $local=localtime($now);      my $local=localtime($now);
     print $fh "$local ($$): $message\n";      print $fh "$local ($$): $message\n";
Line 874  sub userlog { Line 900  sub userlog {
     return join('&',sort(@results));      return join('&',sort(@results));
 }  }
   
   ########################################################
   ########################################################
   
   =pod
   
   =item Functions required for forking
   
   =over 4
   
   =item REAPER
   
   REAPER takes care of dead children.
   
   =item HUNTSMAN
   
   Signal handler for SIGINT.
   
   =item HUPSMAN
   
   Signal handler for SIGHUP
   
   =item DISCONNECT
   
   Disconnects from database.
   
   =back
   
   =cut
   
   ########################################################
   ########################################################
   sub REAPER {                   # takes care of dead children
       $SIG{CHLD} = \&REAPER;
       my $pid = wait;
       $children --;
       &logthis("Child $pid died");
       delete $children{$pid};
   }
   
   sub HUNTSMAN {                      # signal handler for SIGINT
       local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children
       kill 'INT' => keys %children;
       my $execdir=$perlvar{'lonDaemons'};
       unlink("$execdir/logs/lonsql.pid");
       &logthis("<font color=red>CRITICAL: Shutting down</font>");
       $unixsock = "mysqlsock";
       my $port="$perlvar{'lonSockDir'}/$unixsock";
       unlink($port);
       exit;                           # clean up with dignity
   }
   
   sub HUPSMAN {                      # signal handler for SIGHUP
       local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children
       kill 'INT' => keys %children;
       close($server);                # free up socket
       &logthis("<font color=red>CRITICAL: Restarting</font>");
       my $execdir=$perlvar{'lonDaemons'};
       $unixsock = "mysqlsock";
       my $port="$perlvar{'lonSockDir'}/$unixsock";
       unlink($port);
       exec("$execdir/lonsql");         # here we go again
   }
   
   sub DISCONNECT {
       $dbh->disconnect or 
       &logthis("<font color=blue>WARNING: Couldn't disconnect from database ".
                " $DBI::errstr : $@</font>");
       exit;
   }
   
   
   
   

Removed from v.1.51  
changed lines
  Added in v.1.57


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>