THRIFT-1880 Make named pipes server work asynchronously (overlapped) to allow for clean server stops
Patch: Jens Geyer
diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas
index 2f77de8..37fe7d7 100644
--- a/lib/delphi/test/TestClient.pas
+++ b/lib/delphi/test/TestClient.pas
@@ -19,6 +19,9 @@
unit TestClient;
+{.$DEFINE StressTest} // activate to stress-test the server with frequent connects/disconnects
+{.$DEFINE PerfTest} // activate to activate the performance test
+
interface
uses
@@ -63,6 +66,7 @@
procedure ClientTest;
procedure JSONProtocolReadWriteTest;
+ procedure StressTest(const client : TThriftTest.Iface);
protected
procedure Execute; override;
public
@@ -238,11 +242,11 @@
begin
if sPipeName <> '' then begin
Console.WriteLine('Using named pipe ('+sPipeName+')');
- streamtrans := TNamedPipeImpl.Create( sPipeName, 0, nil, TIMEOUT);
+ streamtrans := TNamedPipeTransportClientEndImpl.Create( sPipeName, 0, nil, TIMEOUT);
end
else if bAnonPipe then begin
Console.WriteLine('Using anonymous pipes ('+IntToStr(Integer(hAnonRead))+' and '+IntToStr(Integer(hAnonWrite))+')');
- streamtrans := TAnonymousPipeImpl.Create( hAnonRead, hAnonWrite, FALSE);
+ streamtrans := TAnonymousPipeTransportImpl.Create( hAnonRead, hAnonWrite, FALSE);
end
else begin
Console.WriteLine('Using sockets ('+host+' port '+IntToStr(port)+')');
@@ -370,6 +374,10 @@
client := TThriftTest.TClient.Create( FProtocol);
FTransport.Open;
+ {$IFDEF StressTest}
+ StressTest( client);
+ {$ENDIF StressTest}
+
// in-depth exception test
// (1) do we get an exception at all?
// (2) do we get the right exception?
@@ -422,6 +430,11 @@
s := client.testString('Test');
Expect( s = 'Test', 'testString(''Test'') = "'+s+'"');
+ s := client.testString(HUGE_TEST_STRING);
+ Expect( length(s) = length(HUGE_TEST_STRING),
+ 'testString( lenght(HUGE_TEST_STRING) = '+IntToStr(Length(HUGE_TEST_STRING))+') '
+ +'=> length(result) = '+IntToStr(Length(s)));
+
i8 := client.testByte(1);
Expect( i8 = 1, 'testByte(1) = ' + IntToStr( i8 ));
@@ -831,6 +844,7 @@
Expect( TRUE, 'Test Oneway(1)'); // success := no exception
// call time
+ {$IFDEF PerfTest}
StartTestGroup( 'Test Calltime()');
StartTick := GetTIckCount;
for k := 0 to 1000 - 1 do
@@ -838,12 +852,31 @@
client.testVoid();
end;
Console.WriteLine(' = ' + FloatToStr( (GetTickCount - StartTick) / 1000 ) + ' ms a testVoid() call' );
+ {$ENDIF PerfTest}
// no more tests here
StartTestGroup( '');
end;
+procedure TClientThread.StressTest(const client : TThriftTest.Iface);
+begin
+ while TRUE do begin
+ try
+ if not FTransport.IsOpen then FTransport.Open; // re-open connection, server has already closed
+ try
+ client.testString('Test');
+ Write('.');
+ finally
+ if FTransport.IsOpen then FTransport.Close;
+ end;
+ except
+ on e:Exception do Writeln(#10+e.message);
+ end;
+ end;
+end;
+
+
procedure TClientThread.JSONProtocolReadWriteTest;
// Tests only then read/write procedures of the JSON protocol
// All tests succeed, if we can read what we wrote before
diff --git a/lib/delphi/test/TestConstants.pas b/lib/delphi/test/TestConstants.pas
index b6664ef..f21a4bb 100644
--- a/lib/delphi/test/TestConstants.pas
+++ b/lib/delphi/test/TestConstants.pas
@@ -33,6 +33,79 @@
BINARY_STRICT_READ = FALSE;
BINARY_STRICT_WRITE = FALSE;
+ HUGE_TEST_STRING = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. '
+ + 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy '
+ + 'eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam '
+ + 'voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit '
+ + 'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam '
+ + 'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed '
+ + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
+ + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ';
+
implementation
// nothing
diff --git a/lib/delphi/test/TestServer.pas b/lib/delphi/test/TestServer.pas
index 791468b..7b74e58 100644
--- a/lib/delphi/test/TestServer.pas
+++ b/lib/delphi/test/TestServer.pas
@@ -21,6 +21,8 @@
{$WARN SYMBOL_PLATFORM OFF}
+{.$DEFINE RunEndless} // activate to interactively stress-test the server stop routines via Ctrl+C
+
interface
uses
@@ -46,6 +48,7 @@
ITestHandler = interface( TThriftTest.Iface )
procedure SetServer( const AServer : IServer );
+ procedure TestStop;
end;
TTestHandlerImpl = class( TInterfacedObject, ITestHandler )
@@ -73,17 +76,45 @@
function testMultiException(const arg0: string; const arg1: string): IXtruct;
procedure testOneway(secondsToSleep: Integer);
- procedure testStop;
-
+ procedure TestStop;
procedure SetServer( const AServer : IServer );
end;
- class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousServerPipe);
+ class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
class procedure Execute( const args: array of string);
end;
implementation
+
+var g_Handler : TTestServer.ITestHandler = nil;
+
+
+function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall;
+// Note that this Handler procedure is called from another thread
+var handler : TTestServer.ITestHandler;
+begin
+ result := TRUE;
+ try
+ case dwCtrlType of
+ CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed');
+ CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed');
+ CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal');
+ CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal');
+ CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal');
+ else
+ Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType)));
+ end;
+
+ handler := g_Handler;
+ if handler <> nil then handler.TestStop;
+
+ except
+ // catch all
+ end;
+end;
+
+
{ TTestServer.TTestHandlerImpl }
procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer);
@@ -405,7 +436,7 @@
{ TTestServer }
-class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousServerPipe);
+class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
//Launch child process and pass R/W anonymous pipe handles on cmd line.
//This is a simple example and does not include elevation or other
//advanced features.
@@ -457,8 +488,8 @@
testProcessor : IProcessor;
ServerTrans : IServerTransport;
ServerEngine : IServer;
- anonymouspipe : IAnonymousServerPipe;
- namedpipe : INamedServerPipe;
+ anonymouspipe : IAnonymousPipeServerTransport;
+ namedpipe : INamedPipeServerTransport;
TransportFactory : ITransportFactory;
ProtocolFactory : IProtocolFactory;
i : Integer;
@@ -542,12 +573,12 @@
if sPipeName <> '' then begin
Console.WriteLine('- named pipe ('+sPipeName+')');
- namedpipe := TNamedServerPipeImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, TIMEOUT);
+ namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, TIMEOUT);
servertrans := namedpipe;
end
else if AnonPipe then begin
Console.WriteLine('- anonymous pipes');
- anonymouspipe := TAnonymousServerPipeImpl.Create;
+ anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
servertrans := anonymouspipe;
end
else begin
@@ -580,11 +611,18 @@
if AnonPipe
then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
+ // install Ctrl+C handler before the server starts
+ g_Handler := testHandler;
+ SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE);
Console.WriteLine('');
- Console.WriteLine('Starting the server ...');
- serverEngine.Serve;
+ repeat
+ Console.WriteLine('Starting the server ...');
+ serverEngine.Serve;
+ until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF};
+
testHandler.SetServer( nil);
+ g_Handler := nil;
except
on E: Exception do
@@ -595,4 +633,5 @@
Console.WriteLine( 'done.');
end;
+
end.
diff --git a/lib/delphi/test/server.dpr b/lib/delphi/test/server.dpr
index 5fad6eb..ca485af 100644
--- a/lib/delphi/test/server.dpr
+++ b/lib/delphi/test/server.dpr
@@ -54,7 +54,7 @@
args[i-1] := arg;
end;
TTestServer.Execute( args );
- Readln;
+ Writeln('Press ENTER to close ... '); Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);