Page 1 of 1

Is there any chance of the TCustomMyDataSet class doesn't be threadsafe?

Posted: Thu 07 Mar 2019 01:26
by viniciusfbb
Hello,

I'm making a high-performance multithread server where there can be up to 100,000 concurrent connections. And, during my performance tests, I sometimes got the same exception, by destroying the TCustomMyDataSet class.
This happens with a certain rarity, more or less every 100,000 request-response, so I came to believe that it could be a multithreading problem of the TCustomMyDataSet classes (TMyStoredProc base class, among others).

The following code is the only function I use during my tests, which is the call of a database stored procedure, which returns the data of an address:

Code: Select all

procedure TipServerDatabase.GetPostalCodeData(ACountryCode, APostalCode: TipNullable<string>; out APostalCodeAddress, APostalCodeDependentLocality, APostalCodeLocalityDistrict, APostalCodeLocality, APostalCodeAdministrativeArea: TipNullable<string>);
var
  LConnection: TMyConnection;
  LStoredProc: TipMyStoredProc;
  LStopwatch: TipStopwatchLite;
begin
  LConnection := GetConnection;
  try
    LStoredProc := TipMyStoredProc.Create(LConnection);
    try
      LStoredProc.Connection := LConnection;
      LStoredProc.StoredProcName := 'get_postal_code_data';
      LStoredProc.PrepareSQL;
      try
        if ACountryCode.IsNull then
          LStoredProc.ParamByName('in_country_code').Clear
        else
          LStoredProc.ParamByName('in_country_code').AsString := ACountryCode.Value;
        if APostalCode.IsNull then
          LStoredProc.ParamByName('in_postal_code').Clear
        else
          LStoredProc.ParamByName('in_postal_code').AsString := APostalCode.Value;
        LStopwatch := TipStopwatchLite.StartNew;
        LStoredProc.Execute;
        try
          DoCallFetched(LStoredProc.StoredProcName, LStopwatch.Miliseconds / 1000);
          if LStoredProc.FieldByName('@out_postal_code_address').IsNull then
            APostalCodeAddress.IsNull := True
          else
            APostalCodeAddress.Value := string(LStoredProc.FieldByName('@out_postal_code_address').AsString);
          if LStoredProc.FieldByName('@out_postal_code_dependent_locality').IsNull then
            APostalCodeDependentLocality.IsNull := True
          else
            APostalCodeDependentLocality.Value := string(LStoredProc.FieldByName('@out_postal_code_dependent_locality').AsString);
          if LStoredProc.FieldByName('@out_postal_code_locality_district').IsNull then
            APostalCodeLocalityDistrict.IsNull := True
          else
            APostalCodeLocalityDistrict.Value := string(LStoredProc.FieldByName('@out_postal_code_locality_district').AsString);
          if LStoredProc.FieldByName('@out_postal_code_locality').IsNull then
            APostalCodeLocality.IsNull := True
          else
            APostalCodeLocality.Value := string(LStoredProc.FieldByName('@out_postal_code_locality').AsString);
          if LStoredProc.FieldByName('@out_postal_code_administrative_area').IsNull then
            APostalCodeAdministrativeArea.IsNull := True
          else
            APostalCodeAdministrativeArea.Value := string(LStoredProc.FieldByName('@out_postal_code_administrative_area').AsString);
        finally
          LStoredProc.Close;
        end;
      except
        on E: EDatabaseError do
          raise EipDatabase.CreateFmt(CALL_ERROR, [E.Message, LStoredProc.StoredProcName]);
      else
        raise;
      end;
    finally
      LStoredProc.Free;
    end;
  finally
    if MultiConnection then
      LConnection.Free;
  end;
end;
And above the madExcept
Image

I am using the last version of the MyDac and the delphi Tokyo 10.2.3

Re: Is there any chance of the TCustomMyDataSet class doesn't be threadsafe?

Posted: Thu 07 Mar 2019 07:03
by ViktorV
MyDAC is thread-safe, but the restriction is that you cannot use one connection (the TMyConnection component) in several threads, and you should use a separate connection in each thread.

Re: Is there any chance of the TCustomMyDataSet class doesn't be threadsafe?

Posted: Thu 07 Mar 2019 11:14
by viniciusfbb
ViktorV, Yes, I read about it, and each thread have it own connection.

My version of MyDAC don't have source, otherwise I could better investigate what happens in the destroy of the class "TMyStoredProc" and its classes relatives.

This problem always occurs in the destroy of it. Here is the debugger view (without mydac source, the callstack of the madExcept is better):

Image

Sorry for my bad english.

Re: Is there any chance of the TCustomMyDataSet class doesn't be threadsafe?

Posted: Thu 07 Mar 2019 12:17
by ViktorV
Unfortunately, we can't reproduce the issue on the latest MyDAC 9.3.9
To understand the issue cause, we need a test sample where the issue is stably reproduced. As soon as we get such a sample, and if the cause of the issue is in the code of our product, we will try to fix it as soon as possible.
Therefore, please compose a small sample demonstrating the described behavior and send it to us using the contact form https://devart.com/company/contactform.html, including scripts for creating and filling database objects.

Re: Is there any chance of the TCustomMyDataSet class doesn't be threadsafe?

Posted: Thu 14 Mar 2019 00:51
by viniciusfbb
Problem solved.

Re: Is there any chance of the TCustomMyDataSet class doesn't be threadsafe?

Posted: Thu 14 Mar 2019 14:08
by ViktorV
It is good to see that the problem has been solved.
Feel free to contact us if you have any further questions about our products.