Subject | Is XNet local connection thread safe? |
---|---|
Author | |
Post date | 2018-06-13T14:24:40Z |
Hi,
I have been having some problems with a threaded application which creates local Xnet connections in multiple threads. If two or more threads are calling ISC_ATTACH_DATABASE at the same time, the connection fails with error -901 (335544741) Connection Lost to Database.
If I wrap the call to ISC_ATTACH_DATABASE in a critical section so that only one thread can call it at a time there is no problem.
I get the same issue with IBX and IBDac (devart) but not FireDAC. On reading the source, FireDAC wraps everything it does with the database client in a critical section. So it is stable but slow in a threaded application.
If I use a localhost TCP IP connection, there are no problems.
This feels like a thread safety bug in the Firebird client. Should it be thread safe for calls to ISC_ATTACH_DATABASE?
If this is, or could be a bug, what is the correct way to report it?
Sample code below.
Regards,
Will.
Delphi XE.
Using IBX or Devart IBDAC
Firebird Classic 2.5.7
Windows 10
unit uFBClientMCVEMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TDBWorkerThread = class(TThread)
strict private
fConnectionString : String ;
protected
constructor Create(aConnectionString : String) ; overload ;
procedure Execute ; override ;
end;
var
Form1: TForm1;
implementation
uses IBDatabase ;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
i : integer ;
begin
for i := 0 to 10 do
begin
TDBWorkerThread.Create('SAMPLEDB');
end;
end;
{ TDBWorkerThread }
constructor TDBWorkerThread.Create(aConnectionString: String);
begin
inherited Create(false) ;
FreeOnTerminate := True ;
FConnectionString := aConnectionString ;
end;
procedure TDBWorkerThread.Execute;
var
DB : TIBDatabase ;
Trans : TIBTransaction ;
i : integer ;
begin
inherited;
DB := TIBDatabase.Create(nil) ;
Trans := TIBTransaction.Create(nil);
try
DB.Params.Clear ;
DB.DatabaseName := FConnectionString ;
DB.Params.Add('user_name=SYSDBA') ;
DB.Params.Add('password=masterkey') ;
DB.Params.Add('lc_ctype=ISO8859_1') ;
DB.LoginPrompt := False ;
Trans.DefaultDatabase := DB ;
Trans.Params.Clear ;
Trans.Params.Add('read_committed') ;
Trans.Params.Add('rec_version');
Trans.Params.Add('nowait');
Trans.Params.Add('read');
Trans.AllowAutoStart := False ;
DB.DefaultTransaction := Trans ;
for i := 0 to 99 do
begin
DB.Open;
sleep(10000) ;
//The application will crash before it has done any calls to DB.Close. ruling
//that out as an aggravating factor.
DB.Close ;
end;
finally
Trans.Free ;
DB.Free ;
end;
end;
end.