Browse Source

Create UPCOperationsBlockValidator.pas

Introducing TPCOperationsBlockValidator class that will check TOperationBlock in a multithread mode
PascalCoin 6 years ago
parent
commit
4266d90675
1 changed files with 217 additions and 0 deletions
  1. 217 0
      src/core/UPCOperationsBlockValidator.pas

+ 217 - 0
src/core/UPCOperationsBlockValidator.pas

@@ -0,0 +1,217 @@
+unit UPCOperationsBlockValidator;
+
+{ Copyright (c) 2019 by Albert Molina
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  This unit is a part of the PascalCoin Project, an infinitely scalable
+  cryptocurrency. Find us here:
+  Web: https://www.pascalcoin.org
+  Source: https://github.com/PascalCoin/PascalCoin
+
+  If you like it, consider a donation using Bitcoin:
+  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
+
+  THIS LICENSE HEADER MUST NOT BE REMOVED.
+}
+
+{
+  This unit adds a TPCOperationsBlockValidator class that will check
+  TOperationBlock in a multithread mode
+
+  NOTE: This object is only a helper for fast processing speed when
+  multithreading can help. There is no warranty that will validate all
+
+  }
+
+
+interface
+
+{$I config.inc}
+
+Uses UThread, UAccounts, UPCOrderedLists, UBlockChain,
+  {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
+
+type
+  TPCOperationsBlockValidator = Class;
+
+  TPCOperationsBlockValidatorThread = Class(TPCThread)
+  private
+    FValidator : TPCOperationsBlockValidator;
+    //
+  protected
+    procedure BCExecute; override;
+  public
+    Constructor Create(AValidator : TPCOperationsBlockValidator);
+  End;
+
+  TPCOperationsBlockValidator = Class
+  private
+    FLock : TPCCriticalSection;
+    //
+    FPCOperationsCompList : TList<TPCOperationsComp>;
+    FLastIndexOperationsBlock : Integer;
+    //
+    FValidatedOkCount : Integer;
+    FValidatedErrorCount : Integer;
+  protected
+    function GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
+    procedure SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated : Boolean);
+  public
+    Constructor Create;
+    destructor Destroy; override;
+    function Validate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
+    class function MultiThreadValidateOperationsBlock(APCOperationsCompList : TList<TPCOperationsComp>) : Boolean;
+  End;
+
+implementation
+
+Uses
+  SysUtils,
+  ULog, UBaseTypes,
+  UCommon;
+
+var _Cpus : Integer = 0;
+
+{ TPCOperationsBlockValidator }
+
+constructor TPCOperationsBlockValidator.Create;
+begin
+  FLastIndexOperationsBlock := -1;
+  FLock := TPCCriticalSection.Create('');
+end;
+
+destructor TPCOperationsBlockValidator.Destroy;
+begin
+  FreeAndNil(FLock);
+  inherited;
+end;
+
+function TPCOperationsBlockValidator.GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
+begin
+  FLock.Acquire;
+  try
+    // Search new
+    AIndex := FLastIndexOperationsBlock + 1; // Move to next
+    if (AIndex<FPCOperationsCompList.Count) then begin
+      ANextOperationBlock := FPCOperationsCompList[AIndex].OperationBlock;
+      Result := True;
+      FLastIndexOperationsBlock := AIndex;
+    end else Result := False;
+  finally
+    FLock.Release;
+  end;
+end;
+
+class function TPCOperationsBlockValidator.MultiThreadValidateOperationsBlock(APCOperationsCompList: TList<TPCOperationsComp>): Boolean;
+var LMultiThreadValidator : TPCOperationsBlockValidator;
+  LValidatedOk, LValidatedError, LValidatedTotal : Integer;
+  LTC : TTickCount;
+begin
+  if _Cpus<=0 then begin
+    _Cpus := TLogicalCPUCount.GetLogicalCPUCount;
+  end;
+  if _Cpus<=1 then Exit;
+  if APCOperationsCompList.Count<_Cpus then Exit;   // If less than cpus, no need for multithreading...
+
+  LTC := TPlatform.GetTickCount;
+  LMultiThreadValidator := TPCOperationsBlockValidator.Create;
+  try
+    LValidatedTotal := LMultiThreadValidator.Validate(APCOperationsCompList,LValidatedOk,LValidatedError);
+    LTC := TPlatform.GetElapsedMilliseconds(LTC);
+    if (LValidatedTotal>0) and (LTC>0) then begin
+      TLog.NewLog(ltdebug,ClassName,Format('Validated %d Operation blocks info with %d valids and %d Errors in %d miliseconds avg %.2f op/sec',[LValidatedTotal,LValidatedOk,LValidatedError,LTC,LValidatedTotal*1000/LTC]));
+    end;
+    Result := LValidatedOk = LValidatedTotal;
+  finally
+    LMultiThreadValidator.Free;
+  end;
+end;
+
+procedure TPCOperationsBlockValidator.SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated: Boolean);
+begin
+  FLock.Acquire;
+  try
+    if AValidated then inc(FValidatedOkCount)
+    else inc(FValidatedErrorCount);
+    FPCOperationsCompList[AIndex].HasValidOperationBlockInfo := AValidated;
+  finally
+    FLock.Release;
+  end;
+end;
+
+function TPCOperationsBlockValidator.Validate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
+var LMaxThreads : Integer;
+  LThreads : TList<TPCOperationsBlockValidatorThread>;
+  i,LTerminatedThreads : Integer;
+begin
+  FValidatedOkCount := 0;
+  FValidatedErrorCount := 0;
+  if APCOperationsCompList.Count<=0 then Exit(0);
+
+  FLastIndexOperationsBlock := -1;
+
+  if _Cpus<=0 then begin
+    _Cpus := TLogicalCPUCount.GetLogicalCPUCount;
+  end;
+  LMaxThreads := _Cpus-1;
+  if (LMaxThreads<=0) then LMaxThreads := 1;
+  LThreads := TList<TPCOperationsBlockValidatorThread>.Create;
+  Try
+    // Init values
+    FLastIndexOperationsBlock := -1;
+    FPCOperationsCompList := APCOperationsCompList;
+
+    // Step 1: Create the threads:
+    for i := 1 to LMaxThreads do begin
+      LThreads.Add( TPCOperationsBlockValidatorThread.Create(Self) );
+    end;
+    // Step 2: Start the threads
+    for i := 0 to LThreads.Count-1 do begin
+      LThreads[i].Suspended := False;
+    end;
+    // Step 3: Wait until error of finalized
+    repeat
+      LTerminatedThreads := 0;
+      for i := 0 to LThreads.Count-1 do begin
+        if LThreads[i].Terminated then inc(LTerminatedThreads);
+      end;
+      Sleep(1);
+    until (LTerminatedThreads>=LThreads.Count);
+  Finally
+    for i := 0 to LThreads.Count-1 do begin
+      LThreads[i].Terminate;
+      LThreads[i].WaitFor;
+      LThreads[i].Free;
+    end;
+  End;
+  AValidatedOkCount := FValidatedOkCount;
+  AValidatedErrorCount := FValidatedErrorCount;
+  Result := FPCOperationsCompList.Count;
+end;
+
+{ TPCOperationsBlockValidatorThread }
+
+procedure TPCOperationsBlockValidatorThread.BCExecute;
+var LOperationBlock : TOperationBlock;
+  LErrors : String;
+  LValidated : Boolean;
+  LIndex : Integer;
+begin
+  repeat
+    if FValidator.GetNextOperationBlock( LOperationBlock, LIndex ) then begin
+      LValidated := TPCSafeBox.IsValidOperationBlock(LOperationBlock,LErrors);
+      FValidator.SetOperationBlockResult(LOperationBlock, LIndex, LValidated);
+    end else Terminate;
+  until (Terminated);
+end;
+
+constructor TPCOperationsBlockValidatorThread.Create(AValidator : TPCOperationsBlockValidator);
+begin
+  FValidator := AValidator;
+  inherited Create(True);
+  FreeOnTerminate := False;
+end;
+
+end.