--- loncom/loncnew 2004/09/20 18:40:06 1.55 +++ loncom/loncnew 2004/09/29 10:37:35 1.61 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # lonc maintains the connections to remote computers # -# $Id: loncnew,v 1.55 2004/09/20 18:40:06 albertel Exp $ +# $Id: loncnew,v 1.61 2004/09/29 10:37:35 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -106,6 +106,11 @@ my $LondVersion = "unknown"; # Versi my $KeyMode = ""; # e.g. ssl, local, insecure from last connect. my $LondConnecting = 0; # True when a connection is being built. + +# DO NOT SET THE NEXT VARIABLE TO NON ZERO!!!!!!!!!!!!!!! + +my $DieWhenIdle = 0; # When true children die when trimmed -> 0. + # # The hash below gives the HTML format for log messages # given a severity. @@ -119,6 +124,20 @@ $LogFormats{"WARNING"} = "$lock_file"); + print LOCK "Contents not important"; + close(LOCK); + + exit(0); + } } } else { $IdleSeconds = 0; # Reset idle count if not idle. @@ -330,23 +360,21 @@ sub Tick { # Do we have work in the queue, but no connections to service them? # If so, try to make some new connections to get things going again. # - + # Note this code is dead now... + # my $Requests = $WorkQueue->Count(); - if (($ConnectionCount == 0) && ($Requests > 0)) { + if (($ConnectionCount == 0) && ($Requests > 0) && (!$LondConnecting)) { if ($ConnectionRetriesLeft > 0) { - my $Connections = ($Requests <= $MaxConnectionCount) ? - $Requests : $MaxConnectionCount; - Debug(5,"Work but no connections, start ".$Connections." of them"); - my $successCount = 0; - for (my $i =0; $i < $Connections; $i++) { - $successCount += MakeLondConnection(); - } - if($successCount == 0) { # All connections failed: + Debug(5,"Work but no connections, Make a new one"); + my $success; + $success = &MakeLondConnection; + if($success == 0) { # All connections failed: Debug(5,"Work in queue failed to make any connectiouns\n"); EmptyQueue(); # Fail pending transactions with con_lost. CloseAllLondConnections(); # Should all be closed but.... } } else { + $LondConnecting = 0; ShowStatus(GetServerHost()." >>> DEAD!!! <<<"); Debug(5,"Work in queue, but gave up on connections..flushing\n"); EmptyQueue(); # Connections can't be established. @@ -799,6 +827,11 @@ sub LondReadable { "Lond connection lost."); if(exists($ActiveTransactions{$Socket})) { FailTransaction($ActiveTransactions{$Socket}); + } else { + # Socket is connecting and failed... need to mark + # no longer connecting. + + $LondConnecting = 0; } $Watcher->cancel(); KillSocket($Socket); @@ -990,6 +1023,10 @@ sub LondWritable { " has been disconnected"); if(exists($ActiveTransactions{$Socket})) { FailTransaction($ActiveTransactions{$Socket}); + } else { + # In the process of conneting, so need to turn that off. + + $LondConnecting = 0; } $Watcher->cancel(); KillSocket($Socket); @@ -1244,15 +1281,18 @@ sub QueueTransaction { if(!defined $LondSocket) { # Need to queue request. Debug(5,"Must queue..."); $WorkQueue->enqueue($requestData); - if(($ConnectionCount < $MaxConnectionCount) && !$LondConnecting) { + Debug(5, "Queue Transaction startnew $ConnectionCount $LondConnecting"); + if(($ConnectionCount < $MaxConnectionCount) && (! $LondConnecting)) { + if($ConnectionRetriesLeft > 0) { Debug(5,"Starting additional lond connection"); - if(MakeLondConnection() == 0) { + if(&MakeLondConnection() == 0) { EmptyQueue(); # Fail transactions, can't make connection. CloseAllLondConnections; # Should all be closed but... } } else { ShowStatus(GetServerHost()." >>> DEAD !!!! <<<"); + $LondConnecting = 0; EmptyQueue(); # It's worse than that ... he's dead Jim. CloseAllLondConnections; # Should all be closed but.. } @@ -1358,10 +1398,20 @@ sub NewClient { Returns the name of the UNIX socket on which to listen for client connections. +=head2 Parameters: + + host (optional) - Name of the host socket to return.. defaults to + the return from GetServerHost(). + =cut sub GetLoncSocketPath { - return $UnixSocketDir."/".GetServerHost(); + + my $host = GetServerHost(); # Default host. + if (@_) { + ($host) = @_; # Override if supplied. + } + return $UnixSocketDir."/".$host; } =pod @@ -1398,22 +1448,28 @@ connection. The event handler establish (creating a communcations channel), that int turn will establish another event handler to subess requests. +=head2 Parameters: + + host (optional) Name of the host to set up a unix socket to. + =cut sub SetupLoncListener { + my $host = GetServerHost(); # Default host. + if (@_) { + ($host) = @_ # Override host with parameter. + } + my $socket; - my $SocketName = GetLoncSocketPath(); + my $SocketName = GetLoncSocketPath($host); unlink($SocketName); unless ($socket =IO::Socket::UNIX->new(Local => $SocketName, Listen => 250, Type => SOCK_STREAM)) { die "Failed to create a lonc listner socket"; } - Event->io(cb => \&NewClient, - poll => 'r', - desc => 'Lonc listener Unix Socket', - fd => $socket); + return $socket; } # @@ -1515,6 +1571,9 @@ sub ToggleDebug { =head2 ChildProcess This sub implements a child process for a single lonc daemon. +Optional parameter: + $socket - if provided, this is a socket already open for listen + on the client socket. Otherwise, a new listen is set up. =cut @@ -1523,7 +1582,7 @@ sub ChildProcess { # # Signals must be handled by the Event framework... -# + # Event->signal(signal => "QUIT", cb => \&SignalledToDeath, @@ -1541,7 +1600,15 @@ sub ChildProcess { data => "INT"); - SetupLoncListener(); + my ($socket) = @_; + if (!$socket) { + + $socket = SetupLoncListener(); + } + Event->io(cb => \&NewClient, + poll => 'r', + desc => 'Lonc Listener Unix Socket', + fd => $socket); $Event::Debuglevel = $DebugLevel; @@ -1549,7 +1616,7 @@ sub ChildProcess { # Setup the initial server connection: - # &MakeLondConnection(); // let first work requirest do it. + # &MakeLondConnection(); // let first work requirest do it. Debug(9,"Entering event loop"); @@ -1581,8 +1648,89 @@ sub CreateChild { sigprocmask(SIG_UNBLOCK, $sigset); ChildProcess; # Does not return. } +} + +# parent_client_connection: +# Event handler that processes client connections for the parent process. +# This sub is called when the parent is listening on a socket and +# a connection request arrives. We must: +# Start a child process to accept the connection request. +# Kill our listen on the socket. +# Setup an event to handle the child process exit. (SIGCHLD). +# Parameter: +# event - The event object that was created to monitor this socket. +# event->w->fd is the socket. +# Returns: +# NONE +# +sub parent_client_connection { + die "DieWhenIdle processing not completely operational yet"; + +} + +# parent_listen: +# Opens a socket and starts a listen for the parent process on a client UNIX +# domain socket. +# +# This involves: +# Creating a socket for listen. +# Removing any socket lock file +# Adding an event handler for this socket becoming readable +# To the parent's event dispatcher. +# Parameters: +# loncapa_host - LonCAPA cluster name of the host represented by the client +# socket. +# Returns: +# NONE +# +sub parent_listen { + my ($loncapa_host) = @_; + Debug(5, "parent_listen: $loncapa_host"); + + my $socket = &SetupLoncListener($loncapa_host); + if (!$socket) { + die "Unable to create a listen socket for $loncapa_host"; + } + + my $lock_file = &GetLoncSocketPath().".lock"; + unlink($lock_file); # No problem if it doesn't exist yet [startup e.g.] + + Event->io(cb => &parent_client_connection, + poll => 'r', + desc => 'Parent listener unix socket', + fd => $socket); } + + +# listen_on_all_unix_sockets: +# This sub initiates a listen on all unix domain lonc client sockets. +# This will be called in the case where we are trimming idle processes. +# When idle processes are trimmed, loncnew starts up with no children, +# and only spawns off children when a connection request occurs on the +# client unix socket. The spawned child continues to run until it has +# been idle a while at which point it eventually exits and once more +# the parent picks up the listen. +# +# Parameters: +# NONE +# Implicit Inputs: +# The configuration file that has been read in by LondConnection. +# Returns: +# 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->[0]; + Debug(9, "Listen for $host_name"); + &parent_listen($host_name); + $host_iterator->next(); + } +} + # # Parent process logic pass 1: # For each entry in the hosts table, we will @@ -1632,44 +1780,61 @@ Log("CRITICAL", "--------------- Startin LondConnection::ReadConfig; # Read standard config files. my $HostIterator = LondConnection::GetHostIterator; -while (! $HostIterator->end()) { - my $hostentryref = $HostIterator->get(); - CreateChild($hostentryref->[0]); - $HostHash{$hostentryref->[0]} = $hostentryref->[4]; - $HostIterator->next(); +if ($DieWhenIdle) { + $RemoteHost = "[parent]"; + &listen_on_all_unix_sockets(); +} else { + + while (! $HostIterator->end()) { + + my $hostentryref = $HostIterator->get(); + CreateChild($hostentryref->[0]); + $HostHash{$hostentryref->[0]} = $hostentryref->[4]; + $HostIterator->next(); + } } + $RemoteHost = "Parent Server"; # Maintain the population: ShowStatus("Parent keeping the flock"); -# -# Set up parent signals: -# -$SIG{INT} = \&Terminate; -$SIG{TERM} = \&Terminate; -$SIG{HUP} = \&Restart; -$SIG{USR1} = \&CheckKids; -$SIG{USR2} = \&UpdateKids; # LonManage update request. - -while(1) { - my $deadchild = wait(); - if(exists $ChildHash{$deadchild}) { # need to restart. - my $deadhost = $ChildHash{$deadchild}; - delete($HostToPid{$deadhost}); - delete($ChildHash{$deadchild}); - Log("WARNING","Lost child pid= ".$deadchild. - "Connected to host ".$deadhost); - Log("INFO", "Restarting child procesing ".$deadhost); - CreateChild($deadhost); +if ($DieWhenIdle) { + $Event::DebugLevel = $DebugLevel; + Debug(9, "Parent entering event loop"); + my $ret = Event::loop(); + die "Main Event loop exited: $ret"; + + +} else { + # + # Set up parent signals: + # + + $SIG{INT} = \&Terminate; + $SIG{TERM} = \&Terminate; + $SIG{HUP} = \&Restart; + $SIG{USR1} = \&CheckKids; + $SIG{USR2} = \&UpdateKids; # LonManage update request. + + while(1) { + my $deadchild = wait(); + if(exists $ChildHash{$deadchild}) { # need to restart. + my $deadhost = $ChildHash{$deadchild}; + delete($HostToPid{$deadhost}); + delete($ChildHash{$deadchild}); + Log("WARNING","Lost child pid= ".$deadchild. + "Connected to host ".$deadhost); + Log("INFO", "Restarting child procesing ".$deadhost); + CreateChild($deadhost); + } } } - =pod =head1 CheckKids