#1 2024-10-08 14:07:07

WladiD
Member
From: Germany
Registered: 2010-10-27
Posts: 40

Exception with generic dictionary

Hi Arnaud,

we identified a broken change between v.2.2.6584 (works) and the current v.2.2.8711 (broken).

The following example reproduces it:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,

  mormot.core.base,
  mormot.core.collections;

type

  TMyValue = record
    Field01: TGUID;
    Field02: TGUID;
    Field03: TGUID;
  end;

  TCachedValues<TIdx; TRec> = class
   public type
    TRtcKey = record
      CustomId: Word;
      Key     : TIdx;
    end;
    TRtcValue = record
      CustomId: Integer;
      Rec     : TRec;
    end;
   private
    FDict: IKeyValue<TRtcKey,TRtcValue>;
    function HashKey(const AKey): Cardinal;
    function CompareKey(const A, B): Integer;
   public
    constructor Create;
    function  TryGet(const AKey: TIdx; out Rec: TRec): Boolean;
  end;

{ ======================================================================= }
{ TCachedValues<TIdx, TRec>                                               }
{ ======================================================================= }

constructor TCachedValues<TIdx, TRec>.Create;
begin
  FDict:=Collections.NewPlainKeyValue<TRtcKey,TRtcValue>;
//  FDict.Data.Keys.EventCompare:=CompareKey;
//  FDict.Data.Keys.EventHash:=HashKey;
end;

{ ----------------------------------------------------------------------- }

function TCachedValues<TIdx, TRec>.HashKey(const AKey): Cardinal;
begin
  Result:=DefaultHasher(0,@AKey,SizeOf(TRtcKey));
end;

{ ----------------------------------------------------------------------- }

function TCachedValues<TIdx, TRec>.CompareKey(const A, B): Integer;
begin
  Result:=MemCmp(@A,@B,SizeOf(TRtcKey));
end;

{ ----------------------------------------------------------------------- }

function TCachedValues<TIdx, TRec>.TryGet(const AKey: TIdx; out Rec: TRec): Boolean;
var
  Key: TRtcKey;
  Res: TRtcValue;
begin
  Key:=Default(TRtcKey);
  Key.Key:=AKey;
  Result:=FDict.TryGetValue(Key,Res);
  if Result
    then Rec:=Res.Rec;
end;

{ ======================================================================= }

var
  CachedValues: TCachedValues<TGUID,TMyValue>;
  OneValue    : TMyValue;
begin
  try
    CachedValues:=TCachedValues<TGUID,TMyValue>.Create;
    try
      if not CachedValues.TryGet(TGUID.NewGuid,OneValue)
        then raise Exception.Create('Not found');
    finally
      CachedValues.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  readln;
end.

This example throws the expected Exception "Not found" in v.2.2.6584, but a "EDynArray: TDynArrayHasher.FindOrNew fatal collision: aHashCode=00000000..." in the current version.

We investigated the cause and found a solution, we have to define a EventCompare and EventHash (commented lines in TCachedValues<TIdx, TRec>.Create). But we also not sure which way we have to go in the future and whether it is a bug or not.

Currently we prefer to stay on the stable v.2.2.6584.

Thank you for your clarification in advance.

Best regards

Offline

#2 2024-10-10 14:09:35

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,655
Website

Re: Exception with generic dictionary

Please follow the forum code and don't post code directly in the forum, but use e.g. a gist.
It always induces some delay in my response. wink

I was not able to let your code compile with FPC or Delphi XE8. It gives internal errors.
Seems to be due to the nested types definitions.

I simplified the code and was able to reproduce the issue.
This was indeed a regression, introduced by https://github.com/synopse/mORMot2/comm … fd98fcb333 which was too optimistic.

Should be fixed with
https://github.com/synopse/mORMot2/commit/d1133cfe
and with the associated regression tests, to avoid such regression in the future:
https://github.com/synopse/mORMot2/commit/d24d391d

I also noticed that such complex key definitions may benefit from being hashed with a first specific field:
https://github.com/synopse/mORMot2/commit/07ca9e74

Offline

#3 2024-10-21 07:04:03

WladiD
Member
From: Germany
Registered: 2010-10-27
Posts: 40

Re: Exception with generic dictionary

Hi Arnaud,

I'm back at work today and I've reviewed your changes.

It works fine now!

I think that the bug I reported is now fixed.

Sorry for posting such a long source code here in the forum, next time I will use a different way for that.

Thank you very much for this bug fix!

Best regards from Germany

Offline

Board footer

Powered by FluxBB