--- loncom/loncnew 2003/05/05 23:40:27 1.6 +++ loncom/loncnew 2003/06/03 01:59:39 1.7 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # lonc maintains the connections to remote computers # -# $Id: loncnew,v 1.6 2003/05/05 23:40:27 foxr Exp $ +# $Id: loncnew,v 1.7 2003/06/03 01:59:39 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -34,13 +34,22 @@ # - Add timer dispatch. (done) # - Add ability to accept lonc UNIX domain sockets. (done) # - Add ability to create/negotiate lond connections (done). -# - Add general logic for dispatching requests and timeouts. -# - Add support for the lonc/lond requests. +# - Add general logic for dispatching requests and timeouts. (done). +# - Add support for the lonc/lond requests. (done). # - Add logging/status monitoring. # - Add Signal handling - HUP restarts. USR1 status report. -# - Add Configuration file I/O +# - Add Configuration file I/O (done). # - Add Pending request processing on startup. # - Add management/status request interface. +# - Add deferred request capability. +# + +# Change log: +# $Log: loncnew,v $ +# Revision 1.7 2003/06/03 01:59:39 foxr +# complete coding to support deferred transactions. +# +# use lib "/home/httpd/lib/perl/"; use lib "/home/foxr/newloncapa/types"; @@ -55,6 +64,7 @@ use Crypt::IDEA; use LONCAPA::Queue; use LONCAPA::Stack; use LONCAPA::LondConnection; +use LONCAPA::LondTransaction; use LONCAPA::Configuration; use LONCAPA::HashIterator; @@ -96,10 +106,10 @@ my $RemoteHost; # Name of host child i my $UnixSocketDir= "/home/httpd/sockets"; my $IdleConnections = Stack->new(); # Set of idle connections my %ActiveConnections; # Connections to the remote lond. -my %ActiveTransactions; # Transactions in flight. +my %ActiveTransactions; # LondTransactions in flight. my %ActiveClients; # Serial numbers of active clients by socket. my $WorkQueue = Queue->new(); # Queue of pending transactions. -my $ClientQueue = Queue->new(); # Queue of clients causing xactinos. +# my $ClientQueue = Queue->new(); # Queue of clients causing xactinos. my $ConnectionCount = 0; my $IdleSeconds = 0; # Number of seconds idle. @@ -257,24 +267,20 @@ long enough, it will be shut down and re sub ServerToIdle { my $Socket = shift; # Get the socket. + delete($ActiveTransactions{$Socket}); # Server has no transaction &Debug(6, "Server to idle"); # If there's work to do, start the transaction: - $reqdata = $WorkQueue->dequeue(); - Debug(9, "Queue gave request data: ".$reqdata); + $reqdata = $WorkQueue->dequeue(); # This is a LondTransaction unless($reqdata eq undef) { - my $unixSocket = $ClientQueue->dequeue(); - &Debug(6, "Starting new work request"); - &Debug(7, "Request: ".$reqdata); - - &StartRequest($Socket, $unixSocket, $reqdata); + Debug(9, "Queue gave request data: ".$reqdata->getRequest()); + &StartRequest($Socket, $reqdata); } else { # There's no work waiting, so push the server to idle list. &Debug(8, "No new work requests, server connection going idle"); - delete($ActiveTransactions{$Socket}); $IdleConnections->push($Socket); } } @@ -378,30 +384,46 @@ Parameters: Socket on which the lond transaction occured. This is a LondConnection. The data received is in the TransactionReply member. -=item Client +=item Transaction -Unix domain socket open on the ultimate client. +The transaction that is being completed. =cut sub CompleteTransaction { &Debug(6,"Complete transaction"); my $Socket = shift; - my $Client = shift; + my $Transaction = shift; - my $data = $Socket->GetReply(); # Data to send. - StartClientReply($Client, $data); + if (!$Transaction->isDeferred()) { # Normal transaction + my $data = $Socket->GetReply(); # Data to send. + StartClientReply($Transaction, $data); + } else { # Delete deferred transaction file. + unlink $Transaction->getFile(); + } } =pod =head1 StartClientReply Initiates a reply to a client where the reply data is a parameter. +=head2 parameters: + +=item Transaction + + The transaction for which we are responding to the client. + +=item data + + The data to send to apached client. + =cut sub StartClientReply { - my $Client = shift; + my $Transaction = shift; my $data = shift; + my $Client = $Transaction->getClient(); + &Debug(8," Reply was: ".$data); my $Serial = $ActiveClients{$Client}; my $desc = sprintf("Connection to lonc client %d", @@ -417,32 +439,46 @@ sub StartClientReply { =head2 FailTransaction Finishes a transaction with failure because the associated lond socket - disconnected. It is up to our client to retry if desired. + disconnected. There are two possibilities: + - The transaction is deferred: in which case we just quietly + delete the transaction since there is no client connection. + - The transaction is 'live' in which case we initiate the sending + of "con_lost" to the client. + +Deleting the transaction means killing it from the +%ActiveTransactions hash. Parameters: =item client - The UNIX domain socket open on our client. - + The LondTransaction we are failing. + =cut sub FailTransaction { - my $client = shift; - - StartClientReply($client, "con_lost"); + my $transaction = shift; + my $Lond = $transaction->getServer(); + if (!$client->isDeferred()) { # If the transaction is deferred we'll get to it. + my $client = $transcation->getClient(); + StartClientReply($client, "con_lost"); + } +# not needed, done elsewhere if active. +# delete $ActiveTransactions{$Lond}; } =pod =head1 EmptyQueue + Fails all items in the work queue with con_lost. + Note that each item in the work queue is a transaction. + =cut sub EmptyQueue { while($WorkQueue->Count()) { - my $request = $WorkQUeue->dequeue(); # Just to help it become empty. - my $client = $ClientQueue->dequeue(); # Need to con_lost this guy. - FailTransaction($client); + my $request = $Workqueue->dequeue(); # This is a transaction + FailTransaction($request); } } @@ -471,8 +507,11 @@ nonzero if we are allowed to create a ne sub KillSocket { my $Socket = shift; - # If the socket came from the active connection set, delete it. - # otherwise it came from the idle set and has already been destroyed: + # If the socket came from the active connection set, + # delete its transaction... note that FailTransaction should + # already have been called!!! + # otherwise it came from the idle set. + # if(exists($ActiveTransactions{$Socket})) { delete ($ActiveTransactions{$Socket}); @@ -695,7 +734,7 @@ sub LondWritable { my @data = $Watcher->data; Debug(6,"LondWritable State = ".$State." data has ".@data." elts.\n"); - my $Socket = $data[0]; # I know there's at least a socket. + my $Socket = $data; # I know there's at least a socket. # Figure out what to do depending on the state of the socket: @@ -814,7 +853,9 @@ sub QueueDelayed { my $Handle = IO::File->new($reqfile); my $cmd = <$Handle>; chomp($cmd); - QueueTransaction($NullSocket, $cmd); + my $Transaction = LondTransaction->new($cmd); + $Transaction->SetDeferred($reqfile); + QueueTransaction($Transaction); } } @@ -857,7 +898,7 @@ sub MakeLondConnection { $event = Event->io(fd => $Socket, poll => 'w', cb => \&LondWritable, - data => ($Connection, undef), + data => \$Connection, desc => 'Connection to lond server'); $ActiveConnections{$Connection} = $event; @@ -896,16 +937,16 @@ The text of the request to send. sub StartRequest { my $Lond = shift; - my $Client = shift; - my $Request = shift; + my $Request = shift; # This is a LondTransaction. - Debug(6, "StartRequest: ".$Request); + Debug(6, "StartRequest: ".$Request->getRequest()); my $Socket = $Lond->GetSocket(); - $ActiveTransactions{$Lond} = $Client; # Socket to relay to client. + $Request->Activate($Lond); + $ActiveTransactions{$Lond} = $Request; - $Lond->InitiateTransaction($Request); + $Lond->InitiateTransaction($Request->getRequest()); $event = Event->io(fd => $Lond->GetSocket(), poll => "w", cb => \&LondWritable, @@ -937,15 +978,15 @@ data to send to the lond. =cut sub QueueTransaction { - my $requestSocket = shift; - my $requestData = shift; - Debug(6,"QueueTransaction: ".$requestData); + my $requestData = shift; # This is a LondTransaction. + my $cmd = $requestData->getRequest(); + + Debug(6,"QueueTransaction: ".$cmd); my $LondSocket = $IdleConnections->pop(); if(!defined $LondSocket) { # Need to queue request. Debug(8,"Must queue..."); - $ClientQueue->enqueue($requestSocket); $WorkQueue->enqueue($requestData); if($ConnectionCount < $MaxConnectionCount) { Debug(4,"Starting additional lond connection"); @@ -953,7 +994,7 @@ sub QueueTransaction { } } else { # Can start the request: Debug(8,"Can start..."); - StartRequest($LondSocket, $requestSocket, $requestData); + StartRequest($LondSocket, $requestData); } } @@ -993,7 +1034,9 @@ sub ClientRequest { $watcher->data($data); if($data =~ /(.*\n)/) { # Request entirely read. Debug(8, "Complete transaction received: ".$data); - QueueTransaction($socket, $data); + my $Transaction = new LondTransaction->new($data); + $Transaction->SetClient($socket); + QueueTransaction($Transaction); $watcher->cancel(); # Done looking for input data. } @@ -1055,7 +1098,7 @@ Returns the host whose lond we talk with =cut -sub GetServerHost { # Stub - get this from config. +sub GetServerHost { return $RemoteHost; # Setup by the fork. } @@ -1067,7 +1110,7 @@ Returns the lond port number. =cut -sub GetServerPort { # Stub - get this from config. +sub GetServerPort { return $perlvar{londPort}; } @@ -1088,7 +1131,7 @@ sub SetupLoncListener { my $socket; my $SocketName = GetLoncSocketPath(); unlink($SocketName); - unless ($socket = IO::Socket::UNIX->new(Local => $SocketName, + unless ($socket =IO::Socket::UNIX->new(Local => $SocketName, Listen => 10, Type => SOCK_STREAM)) { die "Failed to create a lonc listner socket";