You are not logged in.
Pages: 1
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
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.
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
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
Pages: 1