UPCOperationsBlockValidator.pas 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. unit UPCOperationsBlockValidator;
  2. { Copyright (c) 2019 by Albert Molina
  3. Distributed under the MIT software license, see the accompanying file LICENSE
  4. or visit http://www.opensource.org/licenses/mit-license.php.
  5. This unit is a part of the PascalCoin Project, an infinitely scalable
  6. cryptocurrency. Find us here:
  7. Web: https://www.pascalcoin.org
  8. Source: https://github.com/PascalCoin/PascalCoin
  9. If you like it, consider a donation using Bitcoin:
  10. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  11. THIS LICENSE HEADER MUST NOT BE REMOVED.
  12. }
  13. {
  14. This unit adds a TPCOperationsBlockValidator class that will check
  15. TOperationBlock in a multithread mode
  16. NOTE: This object is only a helper for fast processing speed when
  17. multithreading can help. There is no warranty that will validate all
  18. }
  19. interface
  20. {$I config.inc}
  21. {$IFDEF FPC}
  22. {$MODE Delphi}
  23. {$ENDIF}
  24. Uses UThread, UAccounts, UPCOrderedLists, UBlockChain,
  25. {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
  26. type
  27. TPCOperationsBlockValidator = Class;
  28. TPCOperationsBlockValidatorThread = Class(TPCThread)
  29. private
  30. FValidator : TPCOperationsBlockValidator;
  31. //
  32. protected
  33. procedure BCExecute; override;
  34. public
  35. Constructor Create(AValidator : TPCOperationsBlockValidator);
  36. End;
  37. TPCOperationsBlockValidator = Class
  38. private
  39. FLock : TPCCriticalSection;
  40. //
  41. FPCOperationsCompList : TList<TPCOperationsComp>;
  42. FLastIndexOperationsBlock : Integer;
  43. //
  44. FValidatedOkCount : Integer;
  45. FValidatedErrorCount : Integer;
  46. protected
  47. function GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
  48. procedure SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated : Boolean);
  49. public
  50. Constructor Create;
  51. destructor Destroy; override;
  52. function Validate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
  53. class function MultiThreadValidateOperationsBlock(APCOperationsCompList : TList<TPCOperationsComp>) : Boolean;
  54. End;
  55. implementation
  56. Uses
  57. SysUtils,
  58. ULog, UBaseTypes,
  59. UCommon;
  60. var _Cpus : Integer = 0;
  61. { TPCOperationsBlockValidator }
  62. constructor TPCOperationsBlockValidator.Create;
  63. begin
  64. FLastIndexOperationsBlock := -1;
  65. FLock := TPCCriticalSection.Create('');
  66. end;
  67. destructor TPCOperationsBlockValidator.Destroy;
  68. begin
  69. FreeAndNil(FLock);
  70. inherited;
  71. end;
  72. function TPCOperationsBlockValidator.GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
  73. begin
  74. FLock.Acquire;
  75. try
  76. // Search new
  77. AIndex := FLastIndexOperationsBlock + 1; // Move to next
  78. if (AIndex<FPCOperationsCompList.Count) then begin
  79. ANextOperationBlock := FPCOperationsCompList[AIndex].OperationBlock;
  80. Result := True;
  81. FLastIndexOperationsBlock := AIndex;
  82. end else Result := False;
  83. finally
  84. FLock.Release;
  85. end;
  86. end;
  87. class function TPCOperationsBlockValidator.MultiThreadValidateOperationsBlock(APCOperationsCompList: TList<TPCOperationsComp>): Boolean;
  88. var LMultiThreadValidator : TPCOperationsBlockValidator;
  89. LValidatedOk, LValidatedError, LValidatedTotal : Integer;
  90. LTC : TTickCount;
  91. begin
  92. if _Cpus<=0 then begin
  93. _Cpus := TLogicalCPUCount.GetLogicalCPUCount;
  94. end;
  95. if _Cpus<=1 then Exit;
  96. if APCOperationsCompList.Count<_Cpus then Exit; // If less than cpus, no need for multithreading...
  97. LTC := TPlatform.GetTickCount;
  98. LMultiThreadValidator := TPCOperationsBlockValidator.Create;
  99. try
  100. LValidatedTotal := LMultiThreadValidator.Validate(APCOperationsCompList,LValidatedOk,LValidatedError);
  101. LTC := TPlatform.GetElapsedMilliseconds(LTC);
  102. if (LValidatedTotal>0) and (LTC>0) then begin
  103. 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]));
  104. end;
  105. Result := LValidatedOk = LValidatedTotal;
  106. finally
  107. LMultiThreadValidator.Free;
  108. end;
  109. end;
  110. procedure TPCOperationsBlockValidator.SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated: Boolean);
  111. begin
  112. FLock.Acquire;
  113. try
  114. if AValidated then inc(FValidatedOkCount)
  115. else inc(FValidatedErrorCount);
  116. FPCOperationsCompList[AIndex].HasValidOperationBlockInfo := AValidated;
  117. finally
  118. FLock.Release;
  119. end;
  120. end;
  121. function TPCOperationsBlockValidator.Validate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
  122. var LMaxThreads : Integer;
  123. LThreads : TList<TPCOperationsBlockValidatorThread>;
  124. i,LTerminatedThreads : Integer;
  125. begin
  126. FValidatedOkCount := 0;
  127. FValidatedErrorCount := 0;
  128. if APCOperationsCompList.Count<=0 then Exit(0);
  129. FLastIndexOperationsBlock := -1;
  130. if _Cpus<=0 then begin
  131. _Cpus := TLogicalCPUCount.GetLogicalCPUCount;
  132. end;
  133. LMaxThreads := _Cpus-1;
  134. if (LMaxThreads<=0) then LMaxThreads := 1;
  135. LThreads := TList<TPCOperationsBlockValidatorThread>.Create;
  136. Try
  137. // Init values
  138. FLastIndexOperationsBlock := -1;
  139. FPCOperationsCompList := APCOperationsCompList;
  140. // Step 1: Create the threads:
  141. for i := 1 to LMaxThreads do begin
  142. LThreads.Add( TPCOperationsBlockValidatorThread.Create(Self) );
  143. end;
  144. // Step 2: Start the threads
  145. for i := 0 to LThreads.Count-1 do begin
  146. LThreads[i].Suspended := False;
  147. end;
  148. // Step 3: Wait until error of finalized
  149. repeat
  150. LTerminatedThreads := 0;
  151. for i := 0 to LThreads.Count-1 do begin
  152. if LThreads[i].Terminated then inc(LTerminatedThreads);
  153. end;
  154. Sleep(1);
  155. until (LTerminatedThreads>=LThreads.Count);
  156. Finally
  157. for i := 0 to LThreads.Count-1 do begin
  158. LThreads[i].Terminate;
  159. LThreads[i].WaitFor;
  160. LThreads[i].Free;
  161. end;
  162. LThreads.Free;
  163. End;
  164. AValidatedOkCount := FValidatedOkCount;
  165. AValidatedErrorCount := FValidatedErrorCount;
  166. Result := FPCOperationsCompList.Count;
  167. end;
  168. { TPCOperationsBlockValidatorThread }
  169. procedure TPCOperationsBlockValidatorThread.BCExecute;
  170. var LOperationBlock : TOperationBlock;
  171. LErrors : String;
  172. LValidated : Boolean;
  173. LIndex : Integer;
  174. begin
  175. repeat
  176. if FValidator.GetNextOperationBlock( LOperationBlock, LIndex ) then begin
  177. LValidated := TPCSafeBox.IsValidOperationBlock(LOperationBlock,LErrors);
  178. FValidator.SetOperationBlockResult(LOperationBlock, LIndex, LValidated);
  179. end else Terminate;
  180. until (Terminated);
  181. end;
  182. constructor TPCOperationsBlockValidatorThread.Create(AValidator : TPCOperationsBlockValidator);
  183. begin
  184. FValidator := AValidator;
  185. inherited Create(True);
  186. FreeOnTerminate := False;
  187. end;
  188. end.