Diff for /loncom/loncnew between versions 1.82 and 1.90

version 1.82, 2007/03/28 21:44:05 version 1.90, 2010/12/20 11:15:51
Line 72  my %perlvar    = %{$perlvarref}; Line 72  my %perlvar    = %{$perlvarref};
 #  #
 #  parent and shared variables.  #  parent and shared variables.
   
 my %ChildHash; # by pid -> host.  my %ChildPid; # by pid -> host.
   my %ChildHost; # by host.
 my %listening_to; # Socket->host table for who the parent  my %listening_to; # Socket->host table for who the parent
                                 # is listening to.                                  # is listening to.
 my %parent_dispatchers;         # host-> listener watcher events.   my %parent_dispatchers;         # host-> listener watcher events. 
Line 84  my $ClientConnection = 0; # Uniquifier f Line 85  my $ClientConnection = 0; # Uniquifier f
   
 my $DebugLevel = 0;  my $DebugLevel = 0;
 my $NextDebugLevel= 2; # So Sigint can toggle this.  my $NextDebugLevel= 2; # So Sigint can toggle this.
 my $IdleTimeout= 600; # Wait 10 minutes before pruning connections.  my $IdleTimeout= 7200; # Wait two hours before pruning connections.
   
 my $LogTransactions = 0; # When True, all transactions/replies get logged.  my $LogTransactions = 0; # When True, all transactions/replies get logged.
 my $executable      = $0; # Get the full path to me.  my $executable      = $0; # Get the full path to me.
Line 157  sub LogPerm { Line 158  sub LogPerm {
     my $now=time;      my $now=time;
     my $local=localtime($now);      my $local=localtime($now);
     my $fh=IO::File->new(">>$execdir/logs/lonnet.perm.log");      my $fh=IO::File->new(">>$execdir/logs/lonnet.perm.log");
       chomp($message);
     print $fh "$now:$message:$local\n";      print $fh "$now:$message:$local\n";
 }  }
   
Line 501  the data and Event->w->fd is the socket Line 503  the data and Event->w->fd is the socket
 sub ClientWritable {  sub ClientWritable {
     my $Event    = shift;      my $Event    = shift;
     my $Watcher  = $Event->w;      my $Watcher  = $Event->w;
       if (!defined($Watcher)) {
    &child_exit(-1,'No watcher for event in ClientWritable');
       }
     my $Data     = $Watcher->data;      my $Data     = $Watcher->data;
     my $Socket   = $Watcher->fd;      my $Socket   = $Watcher->fd;
   
Line 564  sub ClientWritable { Line 569  sub ClientWritable {
  }   }
     } else {      } else {
  $Watcher->cancel(); # A delayed request...just cancel.   $Watcher->cancel(); # A delayed request...just cancel.
    return;
     }      }
 }  }
   
Line 603  sub CompleteTransaction { Line 609  sub CompleteTransaction {
  StartClientReply($Transaction, $data);   StartClientReply($Transaction, $data);
     } else { # Delete deferred transaction file.      } else { # Delete deferred transaction file.
  Log("SUCCESS", "A delayed transaction was completed");   Log("SUCCESS", "A delayed transaction was completed");
  LogPerm("S:$Transaction->getClient() :".$Transaction->getRequest());   LogPerm("S:".$Transaction->getClient().":".$Transaction->getRequest());
  unlink $Transaction->getFile();   unlink($Transaction->getFile());
     }      }
 }  }
   
Line 755  sub KillSocket { Line 761  sub KillSocket {
  delete ($ActiveTransactions{$Socket});   delete ($ActiveTransactions{$Socket});
     }      }
     if(exists($ActiveConnections{$Socket})) {      if(exists($ActiveConnections{$Socket})) {
    $ActiveConnections{$Socket}->cancel;
  delete($ActiveConnections{$Socket});   delete($ActiveConnections{$Socket});
  $ConnectionCount--;   $ConnectionCount--;
  if ($ConnectionCount < 0) { $ConnectionCount = 0; }   if ($ConnectionCount < 0) { $ConnectionCount = 0; }
Line 766  sub KillSocket { Line 773  sub KillSocket {
  EmptyQueue();   EmptyQueue();
  CloseAllLondConnections; # Should all already be closed but...   CloseAllLondConnections; # Should all already be closed but...
     }      }
       UpdateStatus();
 }  }
   
 =pod  =pod
Line 1200  sub MakeLondConnection { Line 1208  sub MakeLondConnection {
  &GetServerPort(),   &GetServerPort(),
  &GetHostId());   &GetHostId());
   
     if($Connection eq undef) { # Needs to be more robust later.      if($Connection eq undef) {
  Log("CRITICAL","Failed to make a connection with lond.");   Log("CRITICAL","Failed to make a connection with lond.");
  $ConnectionRetriesLeft--;   $ConnectionRetriesLeft--;
  return 0; # Failure.   return 0; # Failure.
Line 1377  sub ClientRequest { Line 1385  sub ClientRequest {
     $data = $data.$thisread; # Append new data.      $data = $data.$thisread; # Append new data.
     $watcher->data($data);      $watcher->data($data);
     if($data =~ /\n$/) { # Request entirely read.      if($data =~ /\n$/) { # Request entirely read.
  if($data eq "close_connection_exit\n") {   if ($data eq "close_connection_exit\n") {
     Log("CRITICAL",      Log("CRITICAL",
  "Request Close Connection ... exiting");   "Request Close Connection ... exiting");
     CloseAllLondConnections();      CloseAllLondConnections();
     exit;      exit;
    } elsif ($data eq "reset_retries\n") {
       Log("INFO", "Resetting Connection Retries.");
       $ConnectionRetriesLeft = $ConnectionRetries;
       &UpdateStatus();
       my $Transaction = LondTransaction->new($data);
       $Transaction->SetClient($socket);
       StartClientReply($Transaction, "ok\n");
       $watcher->cancel();
       return;
  }   }
  Debug(8, "Complete transaction received: ".$data);   Debug(8, "Complete transaction received: ".$data);
  if($LogTransactions) {   if ($LogTransactions) {
     Log("SUCCESS", "Transaction: '$data'"); # Transaction has \n.      Log("SUCCESS", "Transaction: '$data'"); # Transaction has \n.
  }   }
  my $Transaction = LondTransaction->new($data);   my $Transaction = LondTransaction->new($data);
Line 1762  sub CreateChild { Line 1779  sub CreateChild {
     my $pid          = fork;      my $pid          = fork;
     if($pid) { # Parent      if($pid) { # Parent
  $RemoteHost = "Parent";   $RemoteHost = "Parent";
  $ChildHash{$pid} = $host;   $ChildPid{$pid} = $host;
  sigprocmask(SIG_UNBLOCK, $sigset);   sigprocmask(SIG_UNBLOCK, $sigset);
  undef(@all_host_ids);   undef(@all_host_ids);
     } else { # child.      } else { # child.
Line 1832  sub get_remote_hostname { Line 1849  sub get_remote_hostname {
   
     &Debug(5,"Creating child for $data (parent_client_connection)");      &Debug(5,"Creating child for $data (parent_client_connection)");
     (my $hostname,my $lonid,@all_host_ids) = split(':',$data);      (my $hostname,my $lonid,@all_host_ids) = split(':',$data);
     &CreateChild($hostname,$lonid);      $ChildHost{$hostname}++;
       if ($ChildHost{$hostname} == 1) {
    &CreateChild($hostname,$lonid);
       } else {
    &Log('WARNING',"Request for a second child on $hostname");
       }
     # Clean up the listen since now the child takes over until it exits.      # Clean up the listen since now the child takes over until it exits.
     $watcher->cancel(); # Nolonger listening to this event      $watcher->cancel(); # Nolonger listening to this event
     $socket->send("done\n");      $socket->send("done\n");
Line 1888  sub parent_listen { Line 1909  sub parent_listen {
   
 sub parent_clean_up {  sub parent_clean_up {
     my ($loncapa_host) = @_;      my ($loncapa_host) = @_;
     Debug(5, "parent_clean_up: $loncapa_host");      Debug(1, "parent_clean_up: $loncapa_host");
   
     my $socket_file = &GetLoncSocketPath($loncapa_host);      my $socket_file = &GetLoncSocketPath($loncapa_host);
     unlink($socket_file); # No problem if it doesn't exist yet [startup e.g.]      unlink($socket_file); # No problem if it doesn't exist yet [startup e.g.]
Line 1897  sub parent_clean_up { Line 1918  sub parent_clean_up {
 }  }
   
   
 # listen_on_all_unix_sockets:  
 #    This sub initiates a listen on all unix domain lonc client sockets.  #    This sub initiates a listen on the common unix domain lonc client socket.
 #    This will be called in the case where we are trimming idle processes.  #    loncnew starts up with no children, and only spawns off children when a
 #    When idle processes are trimmed, loncnew starts up with no children,  #    connection request occurs on the common client unix socket.  The spawned
 #    and only spawns off children when a connection request occurs on the  #    child continues to run until it has been idle a while at which point it
 #    client unix socket.  The spawned child continues to run until it has  #    eventually exits and once more the parent picks up the listen.
 #    been idle a while at which point it eventually exits and once more  
 #    the parent picks up the listen.  
 #  #
 #  Parameters:  #  Parameters:
 #      NONE  #      NONE
Line 1913  sub parent_clean_up { Line 1932  sub parent_clean_up {
 #  Returns:  #  Returns:
 #     NONE  #     NONE
 #  #
 sub listen_on_all_unix_sockets {  
     Debug(5, "listen_on_all_unix_sockets");  
     my $host_iterator      =   &LondConnection::GetHostIterator();  
     while (!$host_iterator->end()) {  
  my $host_entry_ref =   $host_iterator->get();  
  my $host_name      = $host_entry_ref->[3];  
  Debug(9, "Listen for $host_name");  
  &parent_listen($host_name);  
  $host_iterator->next();  
     }  
 }  
   
 sub listen_on_common_socket {  sub listen_on_common_socket {
     Debug(5, "listen_on_common_socket");      Debug(5, "listen_on_common_socket");
     &parent_listen();      &parent_listen();
Line 1949  sub server_died { Line 1956  sub server_died {
  }   }
  # need the host to restart:   # need the host to restart:
   
  my $host = $ChildHash{$pid};   my $host = $ChildPid{$pid};
  if($host) { # It's for real...   if($host) { # It's for real...
     &Debug(9, "Caught sigchild for $host");      &Debug(9, "Caught sigchild for $host");
     delete($ChildHash{$pid});      delete($ChildPid{$pid});
       delete($ChildHost{$host});
     &parent_clean_up($host);      &parent_clean_up($host);
   
  } else {   } else {
Line 2076  sub CheckKids { Line 2084  sub CheckKids {
     foreach my $host (keys %parent_dispatchers) {      foreach my $host (keys %parent_dispatchers) {
  print $fh "LONC Parent process listening for $host\n";   print $fh "LONC Parent process listening for $host\n";
     }      }
     foreach my $pid (keys %ChildHash) {      foreach my $pid (keys %ChildPid) {
  Debug(2, "Sending USR1 -> $pid");   Debug(2, "Sending USR1 -> $pid");
  kill 'USR1' => $pid; # Tell Child to report status.   kill 'USR1' => $pid; # Tell Child to report status.
     }      }
Line 2153  SIGHUP.  Responds to sigint and sigterm. Line 2161  SIGHUP.  Responds to sigint and sigterm.
   
 sub KillThemAll {  sub KillThemAll {
     Debug(2, "Kill them all!!");      Debug(2, "Kill them all!!");
     local($SIG{CHLD}) = 'IGNORE';      # Our children >will< die.      
     foreach my $pid (keys %ChildHash) {      #local($SIG{CHLD}) = 'IGNORE';
  my $serving = $ChildHash{$pid};      # Our children >will< die.
       # but we need to catch their death and cleanup after them in case this is 
       # a restart set of kills
       my @allpids = keys(%ChildPid);
       foreach my $pid (@allpids) {
    my $serving = $ChildPid{$pid};
  ShowStatus("Nicely Killing lonc for $serving pid = $pid");   ShowStatus("Nicely Killing lonc for $serving pid = $pid");
  Log("CRITICAL", "Nicely Killing lonc for $serving pid = $pid");   Log("CRITICAL", "Nicely Killing lonc for $serving pid = $pid");
  kill 'QUIT' => $pid;   kill 'QUIT' => $pid;
     }      }
       ShowStatus("Finished killing child processes off.");
 }  }
   
   
Line 2171  sub really_kill_them_all_dammit Line 2185  sub really_kill_them_all_dammit
 {  {
     Debug(2, "Kill them all Dammit");      Debug(2, "Kill them all Dammit");
     local($SIG{CHLD} = 'IGNORE'); # In case some purist reenabled them.      local($SIG{CHLD} = 'IGNORE'); # In case some purist reenabled them.
     foreach my $pid (keys %ChildHash) {      foreach my $pid (keys %ChildPid) {
  my $serving = $ChildHash{$pid};   my $serving = $ChildPid{$pid};
  &ShowStatus("Nastily killing lonc for $serving pid = $pid");   &ShowStatus("Nastily killing lonc for $serving pid = $pid");
  Log("CRITICAL", "Nastily killing lonc for $serving pid = $pid");   Log("CRITICAL", "Nastily killing lonc for $serving pid = $pid");
  kill 'KILL' => $pid;   kill 'KILL' => $pid;
  delete($ChildHash{$pid});   delete($ChildPid{$pid});
  my $execdir = $perlvar{'lonDaemons'};   my $execdir = $perlvar{'lonDaemons'};
  unlink("$execdir/logs/lonc.pid");   unlink("$execdir/logs/lonc.pid");
     }      }
Line 2253  A hash of lond connections that have no Line 2267  A hash of lond connections that have no
 can be closed if they are idle for a long enough time.  can be closed if they are idle for a long enough time.
   
 =cut  =cut
   
   =pod
   
   =head1 Log messages
   
   The following is a list of log messages that can appear in the 
   lonc.log file.  Each log file has a severity and a message.
   
   =over 2
   
   =item Warning  A socket timeout was detected
   
   If there are pending transactions in the socket's queue,
   they are failed (saved if critical).  If the connection
   retry count gets exceeded by this, the
   remote host is marked as dead.
   Called when timeouts occured during the connection and
   connection dialog with a remote host.
   
   =item Critical Host makred DEAD <hostname>   
   
   The numer of retry counts for contacting a host was
   exceeded. The host is marked dead an no 
   further attempts will be made by that child.
   
   =item Info lonc pipe client hung up on us     
   
   Write to the client pipe indicated no data transferred
   Socket to remote host is shut down.  Reply to the client 
   is discarded.  Note: This is commented out in &ClientWriteable
   
   =item Success  Reply from lond: <data>   
   
   Can be enabled for debugging by setting LogTransactions to nonzero.
   Indicates a successful transaction with lond, <data> is the data received
   from the remote lond.
   
   =item Success A delayed transaction was completed  
   
   A transaction that must be reliable was executed and completed
   as lonc restarted.  This is followed by a mesage of the form
   
     S: client-name : request
   
   =item WARNING  Failing transaction <cmd>:<subcmd>  
   
   Transaction failed on a socket, but the failure retry count for the remote
   node has not yet been exhausted (the node is not yet marked dead).
   cmd is the command, subcmd is the subcommand.  This results from a con_lost
   when communicating with lond.
   
   =item WARNING Shutting down a socket     
   
   Called when a socket is being closed to lond.  This is emitted both when 
   idle pruning is being done and when the socket has been disconnected by the remote.
   
   =item WARNING Lond connection lost.
   
   Called when a read from lond's socket failed indicating lond has closed the 
   connection or died.  This should be followed by one or more
   
    "WARNING Failing transaction..." msgs for each in-flight or queued transaction.
   
   =item INFO Connected to lond version:  <version> 
   
   When connection negotiation is complete, the lond version is requested and logged here.
   
   =item SUCCESS Connection n to host now ready for action
   
   Emitted when connection has been completed with lond. n is then number of 
   concurrent connections and host, the host to which the connection has just
   been established.
   
   =item WARNING Connection to host has been disconnected
   
   Write to a lond resulted in failure status.  Connection to lond is dropped.
   
   =item SUCCESS Created connection n to host host 
   
   Initial connection request to host..(before negotiation).
   
   =item CRITICAL Request Close Connection ... exiting
   
   Client has sent "close_connection_exit"   The loncnew server is exiting.
   
   =item INFO Resetting Connection Retries 
   
   Client has sent "reset_retries" The lond connection retries are reset to zero for the
   corresponding lond.
   
   =item SUCCESS Transaction <data>
   
   Only emitted if the global variable $LogTransactions was set to true.
   A client has requested a lond transaction <data> is the contents of the request.
   
   =item SUCCESS Toggled transaction logging <LogTransactions>
                                       
   The state of the $LogTransactions global has been toggled, and its current value
   (after being toggled) is displayed.  When non zero additional logging of transactions
   is enabled for debugging purposes.  Transaction logging is toggled on receipt of a USR2
   signal.
   
   =item CRITICAL Abnormal exit. Child <pid> for <host> died thorugh signal.
   
   QUIT signal received.  lonc child process is exiting.
   
   =item SUCCESS New debugging level for <RemoteHost> now <DebugLevel>
                                       
   Debugging toggled for the host loncnew is talking with.
   Currently debugging is a level based scheme with higher number 
   conveying more information.  The daemon starts out at
   DebugLevel 0 and can toggle back and forth between that and
   DebugLevel 2  These are controlled by
   the global variables $DebugLevel and $NextDebugLevel
   The debug level can go up to 9.
   SIGINT toggles the debug level.  The higher the debug level the 
   more debugging information is spewed.  See the Debug
   sub in loncnew.
   
   =item CRITICAL Forking server for host  
   
   A child is being created to service requests for the specified host.
   
   
   =item WARNING Request for a second child on hostname
                                       
   Somehow loncnew was asked to start a second child on a host that already had a child
   servicing it.  This request is not honored, but themessage is emitted.  This could happen
   due to a race condition.  When a client attempts to contact loncnew for a new host, a child
   is forked off to handle the requests for that server.  The parent then backs off the Unix
   domain socket leaving it for the child to service all requests.  If in the time between
   creating the child, and backing off, a new connection request comes in to the unix domain
   socket, this could trigger (unlikely but remotely possible),.
   
   =item CRITICAL ------ Starting Children ----
   
   This message should probably be changed to "Entering event loop"  as the loncnew only starts
   children as needed.  This message is emitted as new events are established and
   the event processing loop is entered.
   
   =item INFO Updating connections via SIGUSR2
                                       
   SIGUSR2 received. The original code would kill all clients, re-read the host file,
   then restart children for each host.  Now that childrean aree started on demand, this
   just kills all child processes and lets requests start them as needed again.
   
   
   =item CRITICAL Restarting
   
   SigHUP received.  all the children are killed and the script exec's itself to start again.
   
   =item CRITICAL Nicely killing lonc for host pid = <pid>
   
   Attempting to kill the child that is serving the specified host (pid given) cleanly via
   SIGQUIT  The child should handle that, clean up nicely and exit.
   
   =item CRITICAL Nastily killing lonc for host pid = <pid>
   
   The child specified did not die when requested via SIGQUIT.  Therefore it is killed
   via SIGKILL.
   
   =item CRITICAL Asked to kill children.. first be nice..
   
   In the parent's INT handler.  INT kills the child processes.  This inidicate loncnew
   is about to attempt to kill all known children via SIGQUIT.  This message should be followed 
   by one "Nicely killing" message for each extant child.
   
   =item CRITICAL Now kill children nasty 
   
   In the parent's INT handler. remaining children are about to be killed via
   SIGKILL. Should be followed by a Nastily killing... for each lonc child that 
   refused to die.
   
   =item CRITICAL Master process exiting
   
   In the parent's INT handler. just prior to the exit 0 call.
   
   =back
   
   =cut

Removed from v.1.82  
changed lines
  Added in v.1.90


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