Browse Source

Merge pull request #51 from PascalCoinDev/master

AbstractMem library to v1.4
Albert Molina 3 years ago
parent
commit
ffd4af52b1

+ 1 - 0
src/core/UAccounts.pas

@@ -4196,6 +4196,7 @@ begin
   end;
 end;
 
+
 class function TPCSafeBox.ValidAccountName(const new_name: TRawBytes; var errors : String): Boolean;
   { Note:
     This function is case senstive, and only lower case chars are valid.

+ 2 - 2
src/core/UNetProtocol.pas

@@ -3405,7 +3405,7 @@ var responseStream, accountsStream : TMemoryStream;
   pubKey : TAccountKey;
   sbakl : TSafeboxPubKeysAndAccounts;
   ocl : TAccountsNumbersList;
-  LAccountsList : TList<Integer>;
+  LAccountsList : TList<Int64>;
 begin
   {
   This call is used to obtain Accounts used by a Public key
@@ -3452,7 +3452,7 @@ begin
     if Assigned(sbakl) then begin
       ocl := sbakl.GetAccountsUsingThisKey(pubKey);
       if Assigned(ocl) then begin
-        LAccountsList := TList<Integer>.Create;
+        LAccountsList := TList<Int64>.Create;
         try
           ocl.FillList(start,max,LAccountsList);
           for i := 0 to LaccountsList.Count-1 do begin

+ 1 - 1
src/core/UNode.pas

@@ -801,7 +801,7 @@ function TNode.TryFindPublicSaleAccount(AMaximumPrice: Int64; APreventRaceCondit
   // Finds an account at or below argument purchase price (or returns false)
   // APreventRaceCondition: When True will return a random account in valid range price
   // Limitations: Account must be >0
-var LtempAccNumber : Integer;
+var LtempAccNumber : Int64;
   LLastValidAccount, LCurrAccount : TAccount;
   LContinueSearching : Boolean;
 begin

+ 1 - 1
src/core/UPCAbstractMem.pas

@@ -503,7 +503,7 @@ begin
 
   FCheckingThread := Nil;
   FLockAbstractMem := TPCCriticalSection.Create(Self.ClassName);
-  FAccountCache := TAccountCache.Create(10000,_AccountCache_Comparision);
+  FAccountCache := TAccountCache.Create(50000,_AccountCache_Comparision);
   FSavingNewSafeboxMode := False;
 
   FAggregatedHashrate := TBigNum.Create(0);

+ 3 - 3
src/core/UPCAbstractMemAccountKeys.pas

@@ -10,7 +10,7 @@ uses Classes, SysUtils,
   SyncObjs,
   UAbstractMem, UFileMem, UAbstractMemTList,
   UAbstractBTree, UAbstractAVLTree,
-  UPCDataTypes, UBaseTypes, UAVLCache, UAbstractMemBTree,
+  UPCDataTypes, UBaseTypes, UAVLCache, UAbstractMemBTree, UOrderedList,
   {$IFNDEF FPC}System.Generics.Collections,System.Generics.Defaults{$ELSE}Generics.Collections,Generics.Defaults{$ENDIF};
 
 type
@@ -262,7 +262,7 @@ end;
 procedure TPCAbstractMemAccountKeys.GetAccountsUsingKey(
   const AAccountKey: TAccountKey; const AList: TList<Cardinal>);
 var Lautk : TAccountsUsingThisKey;
-  i : Integer;
+  i : TAbstractMemPosition;
 begin
   AList.Clear;
   FAccountKeysLock.Acquire;
@@ -539,7 +539,7 @@ begin
 end;
 
 function TAccountsUsingThisKey.Get(Index: Integer): Cardinal;
-var i : Integer;
+var i : TAbstractMemPosition;
 begin
   if Not FindIndex(Index,i) then raise Exception.Create(Format('Accounts using this key index %d not found',[Index]));
   Result := i;

+ 1 - 1
src/core/UPCAbstractMemAccounts.pas

@@ -38,7 +38,7 @@ type
 
 implementation
 
-uses UAccounts;
+uses UAccounts, UOrderedList;
 
 { TPCAbstractMemListAccounts }
 

+ 10 - 4
src/core/UPCAccountsOrdenations.pas

@@ -28,7 +28,7 @@ uses Classes, SysUtils,
   UAbstractMem,
   UAbstractMemBTree,
   UAbstractBTree,
-  UPCDataTypes, UBaseTypes,
+  UPCDataTypes, UBaseTypes, UOrderedList,
   {$IFNDEF FPC}System.Generics.Collections,System.Generics.Defaults{$ELSE}Generics.Collections,Generics.Defaults{$ENDIF};
 
 type
@@ -41,7 +41,7 @@ type
       TAccounstByUpdatedBlockBTree = Class({$IFDEF USE_ABSTRACTMEM}TAbstractMemBTree{$ELSE}TMemoryBTree<Integer>{$ENDIF})
       protected
         FCallReturnAccount : TCallReturnAccount;
-        FSearching_AccountNumber : Integer;
+        FSearching_AccountNumber : Int64;
         FSearching_UpdatedBlock : Integer;
         function DoCompareData(const ALeftData, ARightData: TAbstractMemPosition): Integer; override;
       public
@@ -105,22 +105,28 @@ begin
 end;
 
 function TAccountsOrderedByUpdatedBlock.First(var AAccountNumber : Integer) : Boolean;
+var i : Int64;
 begin
   FBTree.Lock;
   Try
     FBTree.FSearching_AccountNumber := -1;
-    Result := FBTree.FindLowest(AAccountNumber);
+    i := AAccountNumber;
+    Result := FBTree.FindLowest(i);
+    AAccountNumber := i;
   Finally
     FBTree.Unlock;
   End;
 end;
 
 function TAccountsOrderedByUpdatedBlock.Next(var AAccountNumber : Integer): Boolean;
+var i : Int64;
 begin
   FBTree.Lock;
   Try
     FBTree.FSearching_AccountNumber := -1;
-    Result := FBTree.FindSuccessor(AAccountNumber,AAccountNumber);
+    i := AAccountNumber;
+    Result := FBTree.FindSuccessor(i,i);
+    AAccountNumber := i;
   Finally
     FBTree.Unlock;
   End;

+ 2 - 3
src/core/UPCRPCFileUtils.pas

@@ -86,7 +86,7 @@ class function TRPCFileUtils.AbstractMemStats(const ASender: TRPCProcess;
   const AMethodName: String; AInputParams, AJSONResponse: TPCJSONObject;
   var AErrorNum: Integer; var AErrorDesc: String): Boolean;
 var LStrings, LReport : TStrings;
-   LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : Integer;
+   LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : Int64;
    i, nMax : Integer;
    Lobj : TPCJSONObject;
    Larray : TPCJSONArray;
@@ -101,7 +101,7 @@ begin
     if AInputParams.GetAsVariant('report').AsBoolean(False) then LReport := LStrings
     else LReport := Nil;
     Lobj := AJSONResponse.GetAsObject('result').GetAsObject('abstractmem');
-    if TNode.Node.Bank.SafeBox.PCAbstractMem.AbstractMem.CheckConsistency(LReport, Nil, LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount) then begin
+    if TNode.Node.Bank.SafeBox.PCAbstractMem.AbstractMem.CheckConsistency(LReport,Nil, LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount) then begin
       Lobj.GetAsVariant('checkconsistency').Value := True;
     end else begin
       Lobj.GetAsVariant('checkconsistency').Value := False;
@@ -121,7 +121,6 @@ begin
         dec(nMax);
       end;
     end;
-
     Result := True;
   Finally
     LStrings.Free;

+ 2 - 2
src/core/UPCRPCFindAccounts.pas

@@ -152,7 +152,7 @@ var
   LAccPubKey : TAccountKey;
   LOutput : TPCJSONArray;
   LStartsWith : TOrderedRawList;
-  LAccountsList : TList<Integer>;
+  LAccountsList : TList<Int64>;
 begin
   // Get Parameters
   Result := False;
@@ -279,7 +279,7 @@ begin
   end else begin
     // Search by type-forSale-balance
     if (LSearchByPubkey) then begin
-      LAccountsList := TList<Integer>.Create;
+      LAccountsList := TList<Int64>.Create;
       try
         LAccountsNumbersList.FillList(LStart,LEnd-LStart+1,LAccountsList);
         for i := 0 to LAccountsList.Count-1 do begin

+ 5 - 5
src/core/URPC.pas

@@ -2991,7 +2991,7 @@ Var c,c2,c3 : Cardinal;
   jsonarr : TPCJSONArray;
   jso : TPCJSONObject;
   LRPCProcessMethod : TRPCProcessMethod;
-  LAccountsList : TList<Integer>;
+  LAccountsList : TList<Int64>;
 begin
   _ro := Nil;
   _ra := Nil;
@@ -3053,7 +3053,7 @@ begin
       Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
       k := params.AsInteger('max',100);
       l := params.AsInteger('start',0);
-      LAccountsList := TList<Integer>.Create;
+      LAccountsList := TList<Int64>.Create;
       Try
         Lanl.FillList(l,k,LAccountsList);
         for j := 0 to LAccountsList.Count - 1 do begin
@@ -3070,7 +3070,7 @@ begin
       c := 0;
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
         Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
-        LAccountsList := TList<Integer>.Create;
+        LAccountsList := TList<Int64>.Create;
         Try
           Lanl.FillList(0,Lanl.Count,LAccountsList);
           for j := 0 to LAccountsList.Count - 1 do begin
@@ -3140,7 +3140,7 @@ begin
       Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
       account.balance := 0;
 
-      LAccountsList := TList<Integer>.Create;
+      LAccountsList := TList<Int64>.Create;
       Try
         Lanl.FillList(0,Lanl.Count,LAccountsList);
         for j := 0 to LAccountsList.Count - 1 do begin
@@ -3159,7 +3159,7 @@ begin
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
         Lanl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
 
-        LAccountsList := TList<Integer>.Create;
+        LAccountsList := TList<Int64>.Create;
         Try
           Lanl.FillList(0,Lanl.Count,LAccountsList);
           for j := 0 to LAccountsList.Count - 1 do begin

+ 6 - 1
src/libraries/abstractmem/ConfigAbstractMem.inc

@@ -56,8 +56,13 @@
   Version 1.3 - Jul 2021
   - Added TAbstractMemZoneInfo that allows to Analyze TAbstractMem using CheckConsistency and returns all blocks information
   - Added TAVLCacheStats that allows to obtain stats from any TAVLCache<T> object
+  
+  Version 1.4 -
+  - Fixed but to allow files up to 4 Gb. Limitation is due to internal 4 bytes positioning. 4 bytes = 4 Gb maximum size
 
 }
 
 const
-  CT_ABSTRACTMEM_VERSION = 1.3; // Each revision should increase this version...
+  CT_ABSTRACTMEM_VERSION = 1.4; // Each revision should increase this version...
+
+

+ 23 - 21
src/libraries/abstractmem/UAbstractBTree.pas

@@ -145,25 +145,25 @@ type
     procedure Unlock;
   End;
 
-  TMemoryBTree<TData> = Class( TAbstractBTree<Integer,TData> )
+  TMemoryBTree<TData> = Class( TAbstractBTree<TAbstractMemPosition,TData> )
   private
-    FBuffer : TList<TAbstractBTree<Integer,TData>.TAbstractBTreeNode> ;
+    FBuffer : TList<TAbstractBTree<TAbstractMemPosition,TData>.TAbstractBTreeNode> ;
     Froot : Integer;
     FDisposed : Integer;
     FDisposedMinPos : Integer;
   protected
-    function GetRoot: TAbstractBTree<Integer,TData>.TAbstractBTreeNode; override;
-    procedure SetRoot(var Value: TAbstractBTree<Integer,TData>.TAbstractBTreeNode); override;
-    function NewNode : TAbstractBTree<Integer,TData>.TAbstractBTreeNode; override;
-    procedure DisposeNode(var ANode : TAbstractBTree<Integer,TData>.TAbstractBTreeNode); override;
-    procedure SetNil(var AIdentify : Integer); override;
-    procedure SaveNode(var ANode : TAbstractBTree<Integer,TData>.TAbstractBTreeNode); override;
-    procedure CheckConsistencyFinalized(ADatas : TList<TData>; AIdents : TOrderedList<Integer>; Alevels, ANodesCount, AItemsCount : Integer); override;
+    function GetRoot: TAbstractBTree<TAbstractMemPosition,TData>.TAbstractBTreeNode; override;
+    procedure SetRoot(var Value: TAbstractBTree<TAbstractMemPosition,TData>.TAbstractBTreeNode); override;
+    function NewNode : TAbstractBTree<TAbstractMemPosition,TData>.TAbstractBTreeNode; override;
+    procedure DisposeNode(var ANode : TAbstractBTree<TAbstractMemPosition,TData>.TAbstractBTreeNode); override;
+    procedure SetNil(var AIdentify : TAbstractMemPosition); override;
+    procedure SaveNode(var ANode : TAbstractBTree<TAbstractMemPosition,TData>.TAbstractBTreeNode); override;
+    procedure CheckConsistencyFinalized(ADatas : TList<TData>; AIdents : TOrderedList<TAbstractMemPosition>; Alevels, ANodesCount, AItemsCount : Integer); override;
   public
-    function IsNil(const AIdentify : Integer) : Boolean; override;
+    function IsNil(const AIdentify : TAbstractMemPosition) : Boolean; override;
     constructor Create(const AOnCompareDataMethod: TComparison<TData>; AAllowDuplicates : Boolean; AOrder : Integer);
     destructor Destroy; override;
-    function GetNode(AIdentify : Integer) : TAbstractBTree<Integer,TData>.TAbstractBTreeNode; override;
+    function GetNode(AIdentify : TAbstractMemPosition) : TAbstractBTree<TAbstractMemPosition,TData>.TAbstractBTreeNode; override;
     property Count;
   End;
 
@@ -178,6 +178,8 @@ type
 
 implementation
 
+uses UAbstractMem;
+
 { TAbstractBTree<TIdentify, TData> }
 
 function TAbstractBTree<TIdentify, TData>.Add(const AData: TData): Boolean;
@@ -1377,7 +1379,7 @@ end;
 
 { TMemoryBTree<TData> }
 
-procedure TMemoryBTree<TData>.CheckConsistencyFinalized(ADatas: TList<TData>; AIdents: TOrderedList<Integer>; Alevels, ANodesCount, AItemsCount: Integer);
+procedure TMemoryBTree<TData>.CheckConsistencyFinalized(ADatas: TList<TData>; AIdents: TOrderedList<TAbstractMemPosition>; Alevels, ANodesCount, AItemsCount: Integer);
 var i,iPos,nDisposed, LDisposedMinPos : Integer;
 begin
   inherited;
@@ -1403,7 +1405,7 @@ constructor TMemoryBTree<TData>.Create(const AOnCompareDataMethod: TComparison<T
 begin
   FBuffer := TList<TAbstractBTreeNode>.Create;
   Froot := -1;
-  inherited Create(TComparison_Integer,AOnCompareDataMethod,AAllowDuplicates,AOrder);
+  inherited Create(TComparison_TAbstractMemPosition,AOnCompareDataMethod,AAllowDuplicates,AOrder);
   FCount := 0;
   FDisposed := 0;
   FDisposedMinPos := -1;
@@ -1416,7 +1418,7 @@ begin
   inherited;
 end;
 
-procedure TMemoryBTree<TData>.DisposeNode(var ANode: TAbstractBTree<Integer, TData>.TAbstractBTreeNode);
+procedure TMemoryBTree<TData>.DisposeNode(var ANode: TAbstractBTree<TAbstractMemPosition, TData>.TAbstractBTreeNode);
 var Lpos : Integer;
 begin
   Lpos := ANode.identify;
@@ -1427,13 +1429,13 @@ begin
   if (FDisposedMinPos<0) or (FDisposedMinPos>Lpos) then FDisposedMinPos := Lpos;
 end;
 
-function TMemoryBTree<TData>.GetNode(AIdentify: Integer): TAbstractBTree<Integer, TData>.TAbstractBTreeNode;
+function TMemoryBTree<TData>.GetNode(AIdentify: TAbstractMemPosition): TAbstractBTree<TAbstractMemPosition, TData>.TAbstractBTreeNode;
 begin
   Result := FBuffer[AIdentify];
   if (Result.identify<>AIdentify) then raise EAbstractBTree.Create(Format('Found %d Identify instead of %d',[Result.identify,AIdentify]));
 end;
 
-function TMemoryBTree<TData>.GetRoot: TAbstractBTree<Integer, TData>.TAbstractBTreeNode;
+function TMemoryBTree<TData>.GetRoot: TAbstractBTree<TAbstractMemPosition, TData>.TAbstractBTreeNode;
 begin
   if (Froot<0) then begin
     ClearNode(Result);
@@ -1442,12 +1444,12 @@ begin
   Result := GetNode(Froot);
 end;
 
-function TMemoryBTree<TData>.IsNil(const AIdentify: Integer): Boolean;
+function TMemoryBTree<TData>.IsNil(const AIdentify: TAbstractMemPosition): Boolean;
 begin
   Result := AIdentify<0;
 end;
 
-function TMemoryBTree<TData>.NewNode: TAbstractBTree<Integer, TData>.TAbstractBTreeNode;
+function TMemoryBTree<TData>.NewNode: TAbstractBTree<TAbstractMemPosition, TData>.TAbstractBTreeNode;
 begin
   ClearNode(Result);
   if (FDisposed > 0) And (FDisposed > (Count DIV 5)) then begin // 20% max disposed nodes
@@ -1467,7 +1469,7 @@ begin
   FBuffer.Insert(Result.identify,Result);
 end;
 
-procedure TMemoryBTree<TData>.SaveNode(var ANode: TAbstractBTree<Integer, TData>.TAbstractBTreeNode);
+procedure TMemoryBTree<TData>.SaveNode(var ANode: TAbstractBTree<TAbstractMemPosition, TData>.TAbstractBTreeNode);
 begin
   if (ANode.identify<0) then begin
     raise EAbstractBTree.Create('Save undefined node '+ToString(ANode));
@@ -1479,12 +1481,12 @@ begin
   end;
 end;
 
-procedure TMemoryBTree<TData>.SetNil(var AIdentify: Integer);
+procedure TMemoryBTree<TData>.SetNil(var AIdentify: TAbstractMemPosition);
 begin
   AIdentify := -1;
 end;
 
-procedure TMemoryBTree<TData>.SetRoot(var Value: TAbstractBTree<Integer, TData>.TAbstractBTreeNode);
+procedure TMemoryBTree<TData>.SetRoot(var Value: TAbstractBTree<TAbstractMemPosition, TData>.TAbstractBTreeNode);
 begin
   Froot := Value.identify;
 end;

+ 52 - 30
src/libraries/abstractmem/UAbstractMem.pas

@@ -35,16 +35,15 @@ uses
   Classes, SysUtils,
   SyncObjs,
   UAbstractAVLTree
-  {$IFNDEF FPC},System.Generics.Collections,System.Generics.Defaults{$ELSE},Generics.Collections,Generics.Defaults{$ENDIF};
+  {$IFNDEF FPC},System.Generics.Collections,System.Generics.Defaults{$ELSE},Generics.Collections,Generics.Defaults{$ENDIF},
+  UOrderedList;
 
 {$I ./ConfigAbstractMem.inc }
 
 Type
-  TAbstractMemPosition = Integer;
-
   TAMZone = record
     position : TAbstractMemPosition;
-    size : Integer;
+    size : Int64;
     procedure Clear;
     function ToString : String;
   end;
@@ -109,17 +108,17 @@ Type
     FReadOnly : Boolean;
     FHeaderInitialized : Boolean;
     FInitialPosition : Integer;
-    FNextAvailablePos : Integer;
-    FMaxAvailablePos : Integer;
+    FNextAvailablePos : Int64;
+    FMaxAvailablePos : Int64;
     FMemLeaks : TAbstractMemMemoryLeaks;
     //
   protected
     FLock : TCriticalSection;
     function AbsoluteWrite(const AAbsolutePosition : Int64; const ABuffer; ASize : Integer) : Integer; virtual; abstract;
     function AbsoluteRead(const AAbsolutePosition : Int64; var ABuffer; ASize : Integer) : Integer; virtual; abstract;
-    procedure DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos : Integer; ANeedSize : Integer); virtual; abstract;
+    procedure DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos : Int64; ANeedSize : Integer); virtual; abstract;
     //
-    function PositionToAbsolute(const APosition : Integer) : Int64;
+    function PositionToAbsolute(const APosition : Int64) : Int64;
     procedure IncreaseSize(ANeedSize : Integer);
     //
     function GetZoneType(APosition : TAbstractMemPosition; out AAMZone : TAMZone) : TAbstractMemZoneType;
@@ -127,8 +126,8 @@ Type
     function IsAbstractMemInfoStable : Boolean; virtual;
     procedure SaveHeader;
   public
-    function Write(const APosition : Integer; const ABuffer; ASize : Integer) : Integer; overload; virtual;
-    function Read(const APosition : Integer; var ABuffer; ASize : Integer) : Integer; overload; virtual;
+    function Write(const APosition : Int64; const ABuffer; ASize : Integer) : Integer; overload; virtual;
+    function Read(const APosition : Int64; var ABuffer; ASize : Integer) : Integer; overload; virtual;
 
     Constructor Create(AInitialPosition : Integer; AReadOnly : Boolean); virtual;
     Destructor Destroy; override;
@@ -140,7 +139,7 @@ Type
     procedure Dispose(const APosition : TAbstractMemPosition); overload;
     function GetUsedZoneInfo(const APosition : TAbstractMemPosition; ACheckForUsedZone : Boolean; out AAMZone : TAMZone) : Boolean;
     function ToString : String; override;
-    function CheckConsistency(const AStructure : TStrings; const AAbstractMemZoneInfoList : TList<TAbstractMemZoneInfo>; out ATotalUsedSize, ATotalUsedBlocksCount, ATotalLeaksSize, ATotalLeaksBlocksCount : Integer) : Boolean;
+    function CheckConsistency(const AStructure : TStrings; const AAbstractMemZoneInfoList : TList<TAbstractMemZoneInfo>; out ATotalUsedSize, ATotalUsedBlocksCount, ATotalLeaksSize, ATotalLeaksBlocksCount : Int64) : Boolean;
     function ReadFirstData(var AFirstDataZone : TAMZone; var AFirstData : TBytes) : Boolean;
     class function GetAbstractMemVersion : String;
     property ReadOnly : Boolean read FReadOnly;
@@ -148,6 +147,9 @@ Type
     procedure CopyFrom(ASource : TAbstractMem);
     function GetStatsReport(AClearStats : Boolean) : String; virtual;
     class function SizeOfPosition : Integer;
+    property NextAvailablePos : Int64 read FNextAvailablePos;
+    property MaxAvailablePos : Int64 read FMaxAvailablePos;
+    property HeaderInitialized : Boolean read FHeaderInitialized;
   End;
 
   TMem = Class(TAbstractMem)
@@ -156,7 +158,7 @@ Type
   protected
     function AbsoluteWrite(const AAbsolutePosition : Int64; const ABuffer; ASize : Integer) : Integer; override;
     function AbsoluteRead(const AAbsolutePosition : Int64; var ABuffer; ASize : Integer) : Integer; override;
-    procedure DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos : Integer; ANeedSize : Integer); override;
+    procedure DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos : Int64; ANeedSize : Integer); override;
   public
     Constructor Create(AInitialPosition : Integer; AReadOnly : Boolean); override;
   End;
@@ -181,6 +183,7 @@ Type
     class function GetSize : Integer;
   end;
 
+function TComparison_TAbstractMemPosition(const ALeft, ARight: TAbstractMemPosition): Integer;
 
 implementation
 
@@ -192,13 +195,20 @@ const
   CT_HeaderSize = 16; // Magic(7) + Version(1) + MemLeak_root_position(4) + NextAvailable_position(4) = 16 bytes
   CT_ExtraSizeForUsedZoneType = 4;
 
+function TComparison_TAbstractMemPosition(const ALeft, ARight: TAbstractMemPosition): Integer;
+begin
+  if ALeft<ARight then Result := -1
+  else if ALeft>ARight then Result := 1
+  else Result := 0;
+end;
+
 { TAbstractMem }
 
-function TAbstractMem.CheckConsistency(const AStructure : TStrings; const AAbstractMemZoneInfoList : TList<TAbstractMemZoneInfo>; out ATotalUsedSize, ATotalUsedBlocksCount, ATotalLeaksSize, ATotalLeaksBlocksCount : Integer) : Boolean;
+function TAbstractMem.CheckConsistency(const AStructure : TStrings; const AAbstractMemZoneInfoList : TList<TAbstractMemZoneInfo>; out ATotalUsedSize, ATotalUsedBlocksCount, ATotalLeaksSize, ATotalLeaksBlocksCount : Int64) : Boolean;
 var LPosition : TAbstractMemPosition;
   LZone : TAMZone;
   LAMZoneInfo : TAbstractMemZoneInfo;
-  i, nCount : Integer;
+  i: Integer;
   LMemLeakFound,LMemLeakToFind : TAbstractMemMemoryLeaksNode;
 begin
   // Will check since first position:
@@ -219,8 +229,8 @@ begin
             LAMZoneInfo.ZoneType := amzt_memory_leak;
             AAbstractMemZoneInfoList.Add(LAMZoneInfo);
           end;
-          Inc(LPosition, LZone.size);
-          inc(ATotalLeaksSize,LZone.size);
+          LPosition := LPosition + LZone.size;
+          ATotalLeaksSize := ATotalLeaksSize + LZone.size;
           inc(ATotalLeaksBlocksCount);
         end;
         amzt_used : begin
@@ -230,8 +240,8 @@ begin
             LAMZoneInfo.ZoneType := amzt_used;
             AAbstractMemZoneInfoList.Add(LAMZoneInfo);
           end;
-          inc(LPosition, LZone.size + CT_ExtraSizeForUsedZoneType);
-          inc(ATotalUsedSize,LZone.size + CT_ExtraSizeForUsedZoneType);
+          LPosition := Int64(LPosition) + Int64(LZone.size) + Int64( CT_ExtraSizeForUsedZoneType );
+          ATotalUsedSize := ATotalUsedSize + LZone.size + Int64( CT_ExtraSizeForUsedZoneType );
           inc(ATotalUsedBlocksCount);
         end;
       else
@@ -306,7 +316,7 @@ end;
 
 procedure TAbstractMem.CopyFrom(ASource: TAbstractMem);
 var LBuff : TBytes;
-  iPos, LBuffDataCount : Integer;
+  iPos, LBuffDataCount : Int64;
   LMemLeakRelativeRootPos : TAbstractMemPosition;
 begin
   ASource.FLock.Acquire;
@@ -325,7 +335,7 @@ begin
       if LBuffDataCount>Length(LBuff) then LBuffDataCount := Length(LBuff);
       ASource.Read(iPos,LBuff[0],LBuffDataCount);
       Self.Write(iPos,LBuff[0],LBuffDataCount);
-      inc(iPos,LBuffDataCount);
+      iPos := iPos + LBuffDataCount;
     end;
 
     LMemLeakRelativeRootPos := ASource.FMemLeaks.FRootPosition;
@@ -390,6 +400,7 @@ procedure TAbstractMem.Dispose(const APosition: TAbstractMemPosition);
 var LZone : TAMZone;
 begin
   if APosition<=CT_HeaderSize then raise EAbstractMem.Create('Dispose: Invalid position '+IntToStr(APosition));
+  LZone.Clear;
   // @[APosition] - 4 bytes = position to size
   LZone.position := APosition;
   if Read(APosition - 4,LZone.size,4) <> 4 then raise EAbstractMem.Create('Dispose: Cannot read size');
@@ -438,6 +449,7 @@ begin
     if GetZoneType(APosition - CT_ExtraSizeForUsedZoneType,AAMZone)<>amzt_used then Exit(False)
     else Exit(True);
   end else begin
+    AAMZone.Clear;
     AAMZone.position := APosition;
     if Read(APosition - CT_ExtraSizeForUsedZoneType,AAMZone.size,4)<>4 then Exit(False); // This is the CT_ExtraSizeForUsedZoneType = 4 bytes for size indicator
     Result := (AAMZone.position + AAMZone.size <= FNextAvailablePos)  And ( ((((AAMZone.size-1) DIV 4)+1)*4) = AAMZone.size );
@@ -449,9 +461,11 @@ var LZone : TAMZone;
   LMemLeak, LSearchedMemLeak : TAbstractMemMemoryLeaksNode;
 begin
   Result := amzt_unknown;
+  AAMZone.Clear;
   AAMZone.position := APosition;
   AAMZone.size := 0;
   LZone.position := (((APosition-1) DIV 4)+1)*4;
+  LZone.size := 0;
   if (LZone.position <> APosition) or (LZone.position<CT_HeaderSize) or (LZone.position>=FNextAvailablePos) then Exit;
   // Check if Memory leak
   LMemLeak.myPosition := LZone.position;
@@ -473,14 +487,22 @@ end;
 
 procedure TAbstractMem.IncreaseSize(ANeedSize: Integer);
   // This will guarantee at the end that FMaxAvailablePos-FNextAvailablePos+1 >= ANeededSize
-var LTmpNextAvailablePos, LTmpMaxAvailablePos : Integer;
+var LTmpNextAvailablePos, LTmpMaxAvailablePos : Int64;
 begin
   if FMaxAvailablePos-FNextAvailablePos+1 >= ANeedSize then Exit;
+
+  // Max 32 bits memory (4 Gb)
+  if Int64(FNextAvailablePos + Int64(ANeedSize)) >= Int64($FFFFFFFF) then begin
+    raise EAbstractMem.Create(Format('Cannot increase more size (Max 4Gb) current %d (max %d) needed %d overflow 0x%s',
+      [FNextAvailablePos,FMaxAvailablePos, ANeedSize,IntToHex(Int64(FNextAvailablePos + Int64(ANeedSize)),16)]));
+  end;
+
   LTmpNextAvailablePos := FNextAvailablePos;
   LTmpMaxAvailablePos := FMaxAvailablePos;
+
   DoIncreaseSize(LTmpNextAvailablePos,LTmpMaxAvailablePos,ANeedSize);
   // Check
-  if (LTmpNextAvailablePos + LTmpMaxAvailablePos + 1 < ANeedSize) then raise EAbstractMem.Create(FormaT('IncreaseSize error. Needed %d obtained from %d to %d = %d',
+  if ((LTmpMaxAvailablePos-LTmpNextAvailablePos)+1 < ANeedSize) and (ANeedSize>0) then raise EAbstractMem.Create(FormaT('IncreaseSize error. Needed %d obtained from %d to %d = %d',
     [ANeedSize,LTmpNextAvailablePos,LTmpMaxAvailablePos,(LTmpMaxAvailablePos-LTmpNextAvailablePos+1)]));
   //
   FNextAvailablePos := LTmpNextAvailablePos;
@@ -538,7 +560,7 @@ begin
   End;
 end;
 
-function TAbstractMem.PositionToAbsolute(const APosition: Integer): Int64;
+function TAbstractMem.PositionToAbsolute(const APosition: Int64): Int64;
 begin
   Result := FInitialPosition + APosition;
 end;
@@ -570,7 +592,7 @@ end;
 procedure TAbstractMem.SaveToStream(AStream: TStream);
 var LBuffer : TBytes;
   i : Integer;
-  LNextStart : Integer;
+  LNextStart : Int64;
 begin
   CheckInitialized(False);
   LNextStart := 0;
@@ -582,7 +604,7 @@ begin
       if (i>Length(LBuffer)) then i := Length(LBuffer);
       Read(LNextStart,LBuffer[0],i);
       AStream.Write(LBuffer[0],i);
-      inc(LNextStart,i);
+      LNextStart := LNextStart + i;
     end;
   Finally
     FLock.Release;
@@ -596,7 +618,7 @@ end;
 
 function TAbstractMem.ToString: String;
 var LAnalize : TStrings;
-  LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : Integer;
+  LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : Int64;
 begin
   LAnalize := TStringList.Create;
   try
@@ -612,7 +634,7 @@ begin
   end;
 end;
 
-function TAbstractMem.Read(const APosition: Integer; var ABuffer; ASize: Integer): Integer;
+function TAbstractMem.Read(const APosition: Int64; var ABuffer; ASize: Integer): Integer;
 begin
   FLock.Acquire;
   try
@@ -640,7 +662,7 @@ begin
   end;
 end;
 
-function TAbstractMem.Write(const APosition: Integer; const ABuffer; ASize: Integer) : Integer;
+function TAbstractMem.Write(const APosition: Int64; const ABuffer; ASize: Integer) : Integer;
 begin
   FLock.Acquire;
   Try
@@ -875,7 +897,7 @@ begin
   inherited;
 end;
 
-procedure TMem.DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos: Integer; ANeedSize: Integer);
+procedure TMem.DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos: Int64; ANeedSize: Integer);
 begin
   if (ANeedSize<=0) And (AMaxAvailablePos<=0) then begin
     SetLength(FMem,0); // Reset
@@ -887,7 +909,7 @@ begin
   ANeedSize := (((ANeedSize-1) DIV 256)+1)*256;
 
   SetLength(FMem, AMaxAvailablePos + ANeedSize);
-  Inc(AMaxAvailablePos,ANeedSize);
+  AMaxAvailablePos := AMaxAvailablePos + ANeedSize;
   //
 end;
 

+ 2 - 2
src/libraries/abstractmem/UAbstractMemBTree.pas

@@ -111,7 +111,6 @@ type
   End;
 
 
-
 implementation
 
 { TAbstractMemBTree<TData> }
@@ -129,7 +128,7 @@ begin
   FAbstractMem := AAbstractMem;
   FrootPosition := 0;
 
-  inherited Create(TComparison_Integer,TComparison_Integer,AAllowDuplicates,AOrder);
+  inherited Create(TComparison_TAbstractMemPosition,TComparison_TAbstractMemPosition,AAllowDuplicates,AOrder);
   FCount := 0;
   //
   if Not FAbstractMem.GetUsedZoneInfo(AInitialZone.position,False,FInitialZone) then begin
@@ -257,6 +256,7 @@ begin
   ClearNode(ANode);
   LItemsCount := 0;
   AChildsCount := 0;
+  AChildsPosition := 0;
   ANode.identify := APosition;
   Move(LBuff[0],ANode.parent,4);
   Move(LBuff[4],LItemsCount,1);

+ 2 - 1
src/libraries/abstractmem/UAbstractMemTList.pas

@@ -40,7 +40,8 @@ uses
   // Current version 3.0.4 does not contain valid support for Generics, using Generics from this:
   // https://github.com/PascalCoinDev/PascalCoin/tree/master/src/libraries/generics.collections
   // (Download and set folder as a "units include folder" in compiler options)
-  {$IFNDEF FPC}System.Generics.Collections,System.Generics.Defaults{$ELSE}Generics.Collections,Generics.Defaults{$ENDIF};
+  {$IFNDEF FPC}System.Generics.Collections,System.Generics.Defaults{$ELSE}Generics.Collections,Generics.Defaults{$ENDIF},
+  UOrderedList;
 
 {$I ./ConfigAbstractMem.inc }
 

+ 31 - 8
src/libraries/abstractmem/UFileMem.pas

@@ -71,17 +71,19 @@ type
     function GetMaxCacheDataBlocks: Integer;
     procedure SetMaxCacheDataBlocks(const Value: Integer);
     procedure CacheIsNOTStable; inline;
+    function GetUseCache: Boolean;
+    procedure SetUseCache(const Value: Boolean);
   protected
     function AbsoluteWrite(const AAbsolutePosition : Int64; const ABuffer; ASize : Integer) : Integer; override;
     function AbsoluteRead(const AAbsolutePosition : Int64; var ABuffer; ASize : Integer) : Integer; override;
-    procedure DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos : Integer; ANeedSize : Integer); override;
+    procedure DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos : Int64; ANeedSize : Integer); override;
     function IsAbstractMemInfoStable : Boolean; override;
   public
     Constructor Create(const AFileName : String; AReadOnly : Boolean); reintroduce;
     Destructor Destroy; override;
     function New(AMemSize : Integer) : TAMZone; override;
-    function Write(const APosition : Integer; const ABuffer; ASize : Integer) : Integer; overload; override;
-    function Read(const APosition : Integer; var ABuffer; ASize : Integer) : Integer; overload; override;
+    function Write(const APosition : Int64; const ABuffer; ASize : Integer) : Integer; overload; override;
+    function Read(const APosition : Int64; var ABuffer; ASize : Integer) : Integer; overload; override;
     {$IFDEF ABSTRACTMEM_TESTING_MODE}
     // Warning: Accessing Cache is not Safe Thread protected, use LockCache/UnlockCache instead
     property Cache : TCacheMem read FCache;
@@ -93,6 +95,7 @@ type
     function LockCache : TCacheMem;
     procedure UnlockCache;
     property FileName : String read FFileName;
+    property UseCache : Boolean read GetUseCache write SetUseCache;
     {$IFDEF ABSTRACTMEM_ENABLE_STATS}
     function GetStatsReport(AClearStats : Boolean) : String; override;
     {$ENDIF}
@@ -127,7 +130,7 @@ end;
 
 function TFileMem.AbsoluteRead(const AAbsolutePosition: Int64; var ABuffer; ASize: Integer): Integer;
 begin
-  FFileStream.Seek(AAbsolutePosition,soFromBeginning);
+  FFileStream.Position := AAbsolutePosition;
   Result := FFileStream.Read(ABuffer,ASize);
   {$IFDEF ABSTRACTMEM_ENABLE_STATS}
   inc(FStats.ReadsCount);
@@ -137,7 +140,7 @@ end;
 
 function TFileMem.AbsoluteWrite(const AAbsolutePosition: Int64; const ABuffer; ASize: Integer): Integer;
 begin
-  FFileStream.Seek(AAbsolutePosition,soFromBeginning);
+  FFileStream.Position := AAbsolutePosition;
   Result := FFileStream.Write(ABuffer,ASize);
   CacheIsNOTStable;
   {$IFDEF ABSTRACTMEM_ENABLE_STATS}
@@ -197,7 +200,7 @@ begin
   FreeAndNil(FCache);
 end;
 
-procedure TFileMem.DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos: Integer; ANeedSize: Integer);
+procedure TFileMem.DoIncreaseSize(var ANextAvailablePos, AMaxAvailablePos: Int64; ANeedSize: Integer);
 var LBuff : TBytes;
 begin
   if (ANeedSize<=0) And (AMaxAvailablePos<=0) then begin
@@ -264,6 +267,11 @@ begin
   Result := FCache.MaxCacheSize;
 end;
 
+function TFileMem.GetUseCache: Boolean;
+begin
+  Result := Assigned(FCache);
+end;
+
 {$IFDEF ABSTRACTMEM_ENABLE_STATS}
 function TFileMem.GetStatsReport(AClearStats : Boolean) : String;
 begin
@@ -309,7 +317,7 @@ begin
   Result := inherited Write(AStartPos,ABuffer,ASize);
 end;
 
-function TFileMem.Read(const APosition: Integer; var ABuffer; ASize: Integer): Integer;
+function TFileMem.Read(const APosition: Int64; var ABuffer; ASize: Integer): Integer;
 begin
   if Not Assigned(FCache) then begin
     Result := inherited;
@@ -347,12 +355,27 @@ begin
   End;
 end;
 
+procedure TFileMem.SetUseCache(const Value: Boolean);
+begin
+  FLock.Acquire;
+  Try
+    if Not Value then begin
+      If Not ReadOnly then FlushCache;
+      FreeAndNil(FCache);
+    end else if Not Assigned(FCache) then begin
+      FCache := TCacheMem.Create(OnCacheNeedDataProc,OnCacheSaveDataProc);
+    end;
+  Finally
+    FLock.Release;
+  End;
+end;
+
 procedure TFileMem.UnlockCache;
 begin
   FLock.Release;
 end;
 
-function TFileMem.Write(const APosition: Integer; const ABuffer; ASize: Integer) : Integer;
+function TFileMem.Write(const APosition: Int64; const ABuffer; ASize: Integer) : Integer;
 begin
   if (Not Assigned(FCache)) Or (FIsFlushingCache) then begin
     inherited;

+ 7 - 0
src/libraries/abstractmem/UOrderedList.pas

@@ -44,6 +44,8 @@ uses
 
 
 type
+  TAbstractMemPosition = Int64;
+
   {$IFDEF FPC}
   TComparison<T> = function(const Left, Right: T): Integer;
   {$ENDIF}
@@ -234,3 +236,8 @@ initialization
 finalization
 
 end.
+
+
+
+
+

+ 2 - 1
src/libraries/abstractmem/tests/AbstractMem.Tests.dpr

@@ -38,7 +38,8 @@ uses
   UCacheMem.Tests in 'src\UCacheMem.Tests.pas',
   UAbstractMem.Tests in 'src\UAbstractMem.Tests.pas',
   UAbstractBTree.Tests in 'src\UAbstractBTree.Tests.pas',
-  UAbstractMemBTree.Tests in 'src\UAbstractMemBTree.Tests.pas';
+  UAbstractMemBTree.Tests in 'src\UAbstractMemBTree.Tests.pas',
+  UFileMem.Tests in 'src\UFileMem.Tests.pas';
 
 {$IF Defined(FPC) and (Defined(CONSOLE_TESTRUNNER))}
 type

+ 57 - 1
src/libraries/abstractmem/tests/AbstractMem.Tests.lpi

@@ -32,11 +32,67 @@
         <PackageName Value="FCL"/>
       </Item3>
     </RequiredPackages>
-    <Units Count="1">
+    <Units Count="15">
       <Unit0>
         <Filename Value="AbstractMem.Tests.dpr"/>
         <IsPartOfProject Value="True"/>
       </Unit0>
+      <Unit1>
+        <Filename Value="..\UAbstractAVLTree.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="..\UAbstractBTree.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit2>
+      <Unit3>
+        <Filename Value="..\UAbstractMem.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit3>
+      <Unit4>
+        <Filename Value="..\UAbstractMemBTree.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit4>
+      <Unit5>
+        <Filename Value="..\UAbstractMemTList.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit5>
+      <Unit6>
+        <Filename Value="..\UAVLCache.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit6>
+      <Unit7>
+        <Filename Value="..\UCacheMem.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit7>
+      <Unit8>
+        <Filename Value="..\UFileMem.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit8>
+      <Unit9>
+        <Filename Value="..\UOrderedList.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit9>
+      <Unit10>
+        <Filename Value="src\UCacheMem.Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit10>
+      <Unit11>
+        <Filename Value="src\UAbstractMem.Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit11>
+      <Unit12>
+        <Filename Value="src\UAbstractBTree.Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit12>
+      <Unit13>
+        <Filename Value="src\UAbstractMemBTree.Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit13>
+      <Unit14>
+        <Filename Value="src\UFileMem.Tests.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit14>
     </Units>
   </ProjectOptions>
   <CompilerOptions>

+ 12 - 9
src/libraries/abstractmem/tests/src/UAbstractBTree.Tests.pas

@@ -13,16 +13,16 @@ uses
    {$ELSE}
    TestFramework,
    {$ENDIF}
-   UAbstractBTree, UOrderedList;
+   UAbstractBTree, UOrderedList, UAbstractMem;
 
 type
 
-  TIntegerBTree = Class( TMemoryBTree<Integer> )
+  TIntegerBTree = Class( TMemoryBTree<TAbstractMemPosition> )
   private
   protected
   public
     constructor Create(AAllowDuplicates : Boolean; AOrder : Integer);
-    function NodeDataToString(const AData : Integer) : String; override;
+    function NodeDataToString(const AData : TAbstractMemPosition) : String; override;
   End;
 
 
@@ -51,10 +51,10 @@ implementation
 
 constructor TIntegerBTree.Create(AAllowDuplicates: Boolean; AOrder: Integer);
 begin
-  inherited Create(TComparison_Integer,AAllowDuplicates,AOrder);
+  inherited Create(TComparison_TAbstractMemPosition,AAllowDuplicates,AOrder);
 end;
 
-function TIntegerBTree.NodeDataToString(const AData: Integer): String;
+function TIntegerBTree.NodeDataToString(const AData: TAbstractMemPosition): String;
 begin
   Result := AData.ToString;
 end;
@@ -199,7 +199,9 @@ end;
 
 procedure TestTAbstractBTree.TestPrecessorSuccessor;
 var Lbt : TIntegerBTree;
-  Lorder, i, intValue, valMin, valMax, Lregs : Integer;
+  Lorder : Integer;
+  i, intValue, valMin, valMax, Lregs : TAbstractMemPosition;
+
 begin
   for Lorder := 3 to 7 do begin
     Lbt := TIntegerBTree.Create(False,Lorder);
@@ -242,7 +244,8 @@ end;
 
 procedure TestTAbstractBTree.TestPrecessorSuccessor_Duplicates;
 var Lbt : TIntegerBTree;
-  Lorder, i, intValue, valMin, valMax, Lregs : Integer;
+  Lorder,
+  i, intValue, valMin, valMax, Lregs : TAbstractMemPosition;
 begin
   for Lorder := 3 to 7 do begin
     Lbt := TIntegerBTree.Create(True,Lorder);
@@ -282,7 +285,7 @@ end;
 
 procedure TestTAbstractBTree.Test_duplicate;
 var Lbt : TIntegerBTree;
-  Lorder, i, intValue : Integer;
+  Lorder, i, intValue : TAbstractMemPosition;
   LLastTree, LCurrentTree : String;
 
   procedure DoInsert(AValue : Integer);
@@ -345,7 +348,7 @@ end;
 
 procedure TestTAbstractBTree.TestDelete;
 var Lbt : TIntegerBTree;
-  Lorder, i, intValue : Integer;
+  Lorder, i, intValue : TAbstractMemPosition;
   LLastTree, LCurrentTree : String;
 
   procedure DoDelete(AValue : Integer);

+ 3 - 2
src/libraries/abstractmem/tests/src/UAbstractMem.Tests.pas

@@ -13,7 +13,8 @@ interface
    {$ELSE}
    TestFramework,
    {$ENDIF}
-   UCacheMem, UFileMem, UAbstractMem, UAbstractBTree, UAbstractMemTList
+   UCacheMem, UFileMem, UAbstractMem, UAbstractBTree, UAbstractMemTList,
+   UOrderedList
    {$IFNDEF FPC},System.Generics.Collections,System.Generics.Defaults{$ELSE},Generics.Collections,Generics.Defaults{$ENDIF};
  type
    // Test methods for class TCalc
@@ -55,7 +56,7 @@ var LAM : TAbstractMem;
   i,j, loops : Integer;
   LStrings : TStrings;
   LAbstractMemZoneInfoList : TList<TAbstractMemZoneInfo>;
-  LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : Integer;
+  LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : TAbstractMemPosition;
 begin
   LAM := TMem.Create(0,False);
   try

+ 4 - 3
src/libraries/abstractmem/tests/src/UAbstractMemBTree.Tests.pas

@@ -62,7 +62,7 @@ end;
 
 function TAbstractMemBTreeExampleInteger.DoCompareData(const ALeftData, ARightData: TAbstractMemPosition): Integer;
 begin
-  Result := ALeftData - ARightData;
+  Result := Integer( ALeftData - ARightData );
 end;
 
 function TAbstractMemBTreeExampleInteger.NodeDataToString(const AData: TAbstractMemPosition): String;
@@ -112,7 +112,7 @@ end;
 
 procedure TestTAbstractMemBTree.DoCheckAbstractMem(AAbstractMem: TAbstractMem; AUsedBytes: Integer);
 var
-  LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : Integer;
+  LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : TAbstractMemPosition;
 begin
   Assert(AAbstractMem.CheckConsistency(Nil,Nil,LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount));
   Assert(LTotalUsedSize=AUsedBytes,Format('Total used %d bytes (%d blocks) different from expected %d bytes - Total free %d bytes (%d blocks)',[LTotalUsedSize, AUsedBytes, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount]));
@@ -136,7 +136,8 @@ procedure TestTAbstractMemBTree.TestInfinite_Integer(AOrder : Integer; AAllowDup
 var Lbt : TAbstractMemBTreeExampleInteger;
   Lbts : TAbstractMemBTreeExampleString;
   Lzone : TAMZone;
-  intValue, nRounds, nAdds, nDeletes, i, j : Integer;
+  intValue, nRounds, nAdds, nDeletes, i : Integer;
+  j : TAbstractMemPosition;
   Lnode : TIntegerBTree.TAbstractBTreeNode;
   Lmem : TAbstractMem;
   LCurr : String;

+ 223 - 0
src/libraries/abstractmem/tests/src/UFileMem.Tests.pas

@@ -0,0 +1,223 @@
+unit UFileMem.Tests;
+
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
+interface
+
+ uses
+   SysUtils, Classes,
+   {$IFDEF FPC}
+   fpcunit, testutils, testregistry,
+   {$ELSE}
+   TestFramework,
+   {$ENDIF}
+   {$IFNDEF FPC}System.Generics.Collections,System.Generics.Defaults,{$ELSE}Generics.Collections,Generics.Defaults,{$ENDIF}
+   UFileMem, UAbstractMem, UCacheMem, UOrderedList;
+
+{$I ./../../ConfigAbstractMem.inc }
+
+
+ type
+   // Test methods for class TCalc
+
+   { TestTFileMem }
+
+   TestTFileMem = class(TTestCase)
+   strict private
+  private
+   public
+     procedure SetUp; override;
+     procedure TearDown; override;
+     procedure Test_FileMem_Aux(AUseCache : Boolean);
+     procedure Test_AbstractMem_Aux(AAbstractMem : TAbstractMem; AStrings : TStrings; ACreateBlocks : Integer);
+     {$IFDEF FPC}
+     function ElapsedTestTime : Integer;
+     {$ENDIF}
+     function GetFullFileName(AFileName : String) : String;
+     procedure CheckConsistency(const AAbstractMem : TAbstractMem);
+   published
+     procedure Test_FileMem_Cache;
+     procedure Test_FileMem_No_Cache;
+     procedure Test_FileMame_MaxSize;
+   end;
+
+ implementation
+
+
+{$IFDEF FPC}
+function TestTFileMem.ElapsedTestTime: Integer;
+begin
+  Result := 0;
+end;
+{$ENDIF}
+
+procedure TestTFileMem.CheckConsistency(const AAbstractMem: TAbstractMem);
+var LStructure : TStrings;
+  LAbstractMemZoneInfoList : TList<TAbstractMemZoneInfo>;
+  LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount : TAbstractMemPosition;
+begin
+  LStructure := TStringList.Create;
+  Try
+    IF Not AAbstractMem.CheckConsistency(LStructure,Nil,LTotalUsedSize, LTotalUsedBlocksCount, LTotalLeaksSize, LTotalLeaksBlocksCount) then begin
+      raise Exception.Create(LStructure.Text);
+    end;
+  Finally
+    LStructure.Free;
+  End;
+end;
+
+function TestTFileMem.GetFullFileName(AFileName: String): String;
+begin
+//  Result := 'C:\Users\Albert\Desktop\TEMP\'+AFileName; // XXXXXXXXXXXXXXXX
+  Result := ExtractFileDir(ParamStr(0))+PathDelim+AFileName;
+// XXXXXXXXXXXXXXXX
+end;
+
+procedure TestTFileMem.SetUp;
+begin
+end;
+
+procedure TestTFileMem.TearDown;
+begin
+end;
+
+procedure TestTFileMem.Test_AbstractMem_Aux(AAbstractMem: TAbstractMem; AStrings : TStrings; ACreateBlocks: Integer);
+var LAMs : TList<TAMZone>;
+  i, j, k : integer;
+  LData : TBytes;
+begin
+  if ACreateBlocks<=0 then Exit;
+  Randomize;
+  LAMs := TList<TAMZone>.Create;
+  try
+    SetLength(LData,10000);
+    for i := 0 to Length(LData)-1 do begin
+      LData[i] := Byte(i+1);
+    end;
+    for i := 0 to ACreateBlocks do begin
+      LAMs.Add( AAbstractMem.New(20*(Random(15)+1)) );
+      AAbstractMem.Write(LAMs.Items[i].position,LData[0],LAMs.Items[i].size);
+    end;
+
+    AStrings.Add(Format('Create %d blocks with max %d bytes ET %d',[ACreateBlocks,Length(LData),ElapsedTestTime]));
+    // Blocks created
+    // Play with them
+    for i := 0 to ACreateBlocks*4 do begin
+      // Read randomly
+      j := Random(LAMs.Count DIV 10);
+      AAbstractMem.Read(LAMs.Items[j].position,LData[0],LAMs.Items[j].size);
+    end;
+    AStrings.Add(Format('Read %d blocks randomly ET %d',[ACreateBlocks,ElapsedTestTime]));
+    //
+    for i := 0 to ACreateBlocks*4 do begin
+      // Write randomly
+      j := Random(LAMs.Count DIV 10);
+      AAbstractMem.Write(LAMs.Items[j].position,LData[0],LAMs.Items[j].size);
+    end;
+    AStrings.Add(Format('Write %d blocks randomly ET %d',[ACreateBlocks,ElapsedTestTime]));
+
+  finally
+    LAMs.Free;
+  end;
+end;
+
+procedure TestTFileMem.Test_FileMame_MaxSize;
+var Lfm : TFileMem;
+  LTotalSize : Int64;
+  Lfile : TFileStream;
+  s : String;
+  LData : TBytes;
+  i : Integer;
+var LAMs : TList<TAMZone>;
+begin
+  Lfm := TFileMem.Create(GetFullFileName('test_FileMem_Maxsize.am'),False);
+  LAMs := TList<TAMZone>.Create;
+  try
+    Lfm.UseCache := False;
+    CheckConsistency(Lfm);
+    //
+    SetLength(LData,50000000);
+    for i := 0 to Length(LData)-1 do begin
+      LData[i] := Byte(i+1);
+    end;
+    LTotalSize := Lfm.NextAvailablePos;
+    i := 0;
+    while Lfm.NextAvailablePos<((Int64(2147483648)*2) + (Length(LData)*2)) do begin
+      LAMs.Add( Lfm.New(Length(LData)) );
+      inc(LTotalSize, Int64(Length(LData)) );
+      inc(i);
+      Lfm.FlushCache;
+      if Lfm.NextAvailablePos>MaxInt then begin
+        CheckConsistency(Lfm);
+      end;
+    end;
+
+  finally
+    LAMs.Free;
+    Lfm.Free;
+  end;
+end;
+
+procedure TestTFileMem.Test_FileMem_Aux(AUseCache: Boolean);
+var Lfm : TFileMem;
+  Ltc : Int64;
+  Lfs : TStrings;
+  Lfile : TFileStream;
+  s : String;
+begin
+  Lfm := TFileMem.Create(GetFullFileName('test_FileMem_Aux.am'),False);
+  Lfs := TStringList.Create;
+  try
+    Lfm.ClearContent;
+//    Lfm.UseCache := AUseCache;
+    if AUseCache then begin
+      Lfm.MaxCacheSize := 1024 * 1024 * 2; // 2 Mb
+      Lfm.MaxCacheDataBlocks := 10000; // 10 K
+      Lfs.Add(Format('Use cache with MaxCacheSize:%d and MaxCacheDataBlocks:%d',[Lfm.MaxCacheSize,Lfm.MaxCacheDataBlocks]));
+    end else begin
+      Lfs.Add('NO use cache');
+    end;
+    //
+    Test_AbstractMem_Aux(Lfm,Lfs,50000);
+    Lfm.FlushCache;
+
+    {$IFDEF ABSTRACTMEM_ENABLE_STATS}
+    if AUseCache then begin
+      Lfs.Add( Lfm.LockCache.CacheMemStats.ToString );
+      Lfm.UnlockCache;
+    end;
+    {$ENDIF}
+
+    Lfs.Add(Format('Elapsed time %d',[ElapsedTestTime]));
+    Lfs.Add('');
+
+    s := ExtractFileDir(ParamStr(0))+PathDelim+'test_FileMem_Aux.log';
+    if FileExists(s) then Lfile := TFileStream.Create(s,fmOpenReadWrite)
+    else Lfile := TFileStream.Create(s,fmCreate);
+    try
+      Lfile.Seek(0,soFromEnd);
+      Lfs.SaveToStream(lfile);
+    finally
+      Lfile.Free;
+    end;
+  finally
+    Lfs.Free;
+    Lfm.Free;
+  end;
+end;
+
+procedure TestTFileMem.Test_FileMem_Cache;
+begin
+  Test_FileMem_Aux(True);
+end;
+
+procedure TestTFileMem.Test_FileMem_No_Cache;
+begin
+  Test_FileMem_Aux(False);
+end;
+
+initialization
+  RegisterTest(TestTFileMem{$IFNDEF FPC}.Suite{$ENDIF});
+end.