|
@@ -35,7 +35,7 @@ interface
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
|
|
-Uses UThread, UAccounts, UPCOrderedLists, UBlockChain,
|
|
|
|
|
|
+Uses UThread, UAccounts, UPCOrderedLists, UBlockChain, Classes,
|
|
{$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
|
|
{$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
|
|
|
|
|
|
type
|
|
type
|
|
@@ -53,20 +53,31 @@ type
|
|
|
|
|
|
TPCOperationsBlockValidator = Class
|
|
TPCOperationsBlockValidator = Class
|
|
private
|
|
private
|
|
- FLock : TPCCriticalSection;
|
|
|
|
|
|
+ FLockedList : TPCThreadList<TOperationBlock>;
|
|
|
|
+ FThreads : TList<TPCOperationsBlockValidatorThread>;
|
|
|
|
+ FErrorsList : TStringList;
|
|
//
|
|
//
|
|
- FPCOperationsCompList : TList<TPCOperationsComp>;
|
|
|
|
|
|
+ FPCOperationsCompList : TList<TPCOperationsComp>; // Optional field
|
|
FLastIndexOperationsBlock : Integer;
|
|
FLastIndexOperationsBlock : Integer;
|
|
//
|
|
//
|
|
FValidatedOkCount : Integer;
|
|
FValidatedOkCount : Integer;
|
|
FValidatedErrorCount : Integer;
|
|
FValidatedErrorCount : Integer;
|
|
protected
|
|
protected
|
|
function GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
|
|
function GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
|
|
- procedure SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated : Boolean);
|
|
|
|
|
|
+ procedure SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated : Boolean; const AErrorDetected : String);
|
|
public
|
|
public
|
|
Constructor Create;
|
|
Constructor Create;
|
|
destructor Destroy; override;
|
|
destructor Destroy; override;
|
|
- function Validate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
|
|
|
|
|
|
+ procedure AddToValidate(AList : TList<TOperationBlock>); overload;
|
|
|
|
+ procedure AddToValidate(AOperationBlock : TOperationBlock); overload;
|
|
|
|
+ procedure StartThreads;
|
|
|
|
+ procedure GetStatus(out AValidatedOk, AValidatedError, APendingToValidate : Integer);
|
|
|
|
+ procedure WaitUntilAllValidatedOrErrorFound;
|
|
|
|
+ procedure FillErrors(var AErrors : String);
|
|
|
|
+ procedure EndThreads;
|
|
|
|
+ property ValidatedOkCount : Integer read FValidatedOkCount;
|
|
|
|
+ property ValidatedErrorCount : Integer read FValidatedErrorCount;
|
|
|
|
+ function ValidateAndWaitUntilTerminate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
|
|
class function MultiThreadValidateOperationsBlock(APCOperationsCompList : TList<TPCOperationsComp>) : Boolean;
|
|
class function MultiThreadValidateOperationsBlock(APCOperationsCompList : TList<TPCOperationsComp>) : Boolean;
|
|
End;
|
|
End;
|
|
|
|
|
|
@@ -81,31 +92,116 @@ var _Cpus : Integer = 0;
|
|
|
|
|
|
{ TPCOperationsBlockValidator }
|
|
{ TPCOperationsBlockValidator }
|
|
|
|
|
|
|
|
+procedure TPCOperationsBlockValidator.AddToValidate(AList: TList<TOperationBlock>);
|
|
|
|
+var i : Integer;
|
|
|
|
+ LList : TList<TOperationBlock>;
|
|
|
|
+begin
|
|
|
|
+ LList := FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ for i := 0 to AList.Count-1 do begin
|
|
|
|
+ LList.Add(AList[i]);
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TPCOperationsBlockValidator.AddToValidate(AOperationBlock: TOperationBlock);
|
|
|
|
+var LList : TList<TOperationBlock>;
|
|
|
|
+begin
|
|
|
|
+ LList := FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ LList.Add(AOperationBlock);
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
constructor TPCOperationsBlockValidator.Create;
|
|
constructor TPCOperationsBlockValidator.Create;
|
|
begin
|
|
begin
|
|
FLastIndexOperationsBlock := -1;
|
|
FLastIndexOperationsBlock := -1;
|
|
- FLock := TPCCriticalSection.Create('');
|
|
|
|
|
|
+ FLockedList := TPCThreadList<TOperationBlock>.Create(ClassName);
|
|
|
|
+ FPCOperationsCompList := Nil; // This field is external
|
|
|
|
+ FThreads := Nil;
|
|
|
|
+ FErrorsList := TStringList.Create;
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TPCOperationsBlockValidator.Destroy;
|
|
destructor TPCOperationsBlockValidator.Destroy;
|
|
begin
|
|
begin
|
|
- FreeAndNil(FLock);
|
|
|
|
|
|
+ EndThreads;
|
|
|
|
+ FreeAndNil(FLockedList);
|
|
|
|
+ FreeAndNil(FErrorsList);
|
|
inherited;
|
|
inherited;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TPCOperationsBlockValidator.EndThreads;
|
|
|
|
+var i : Integer;
|
|
|
|
+begin
|
|
|
|
+ FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ if Not Assigned(FThreads) then Exit;
|
|
|
|
+
|
|
|
|
+ for i := 0 to FThreads.Count-1 do begin
|
|
|
|
+ FThreads[i].Terminate;
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+ // WaitFor without locking
|
|
|
|
+ for i := 0 to FThreads.Count-1 do begin
|
|
|
|
+ FThreads[i].WaitFor;
|
|
|
|
+ end;
|
|
|
|
+ // Finished
|
|
|
|
+ FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ for i := 0 to FThreads.Count-1 do begin
|
|
|
|
+ FThreads[i].Free;
|
|
|
|
+ end;
|
|
|
|
+ FreeAndNil(FThreads);
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TPCOperationsBlockValidator.FillErrors(var AErrors: String);
|
|
|
|
+begin
|
|
|
|
+ FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ AErrors := FErrorsList.Text;
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
function TPCOperationsBlockValidator.GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
|
|
function TPCOperationsBlockValidator.GetNextOperationBlock(var ANextOperationBlock : TOperationBlock; var AIndex : Integer) : Boolean;
|
|
|
|
+var LList : TList<TOperationBlock>;
|
|
begin
|
|
begin
|
|
- FLock.Acquire;
|
|
|
|
|
|
+ LList := FLockedList.LockList;
|
|
try
|
|
try
|
|
// Search new
|
|
// Search new
|
|
AIndex := FLastIndexOperationsBlock + 1; // Move to next
|
|
AIndex := FLastIndexOperationsBlock + 1; // Move to next
|
|
- if (AIndex<FPCOperationsCompList.Count) then begin
|
|
|
|
- ANextOperationBlock := FPCOperationsCompList[AIndex].OperationBlock;
|
|
|
|
|
|
+ if (AIndex<LList.Count) then begin
|
|
|
|
+ ANextOperationBlock := LList[AIndex];
|
|
Result := True;
|
|
Result := True;
|
|
FLastIndexOperationsBlock := AIndex;
|
|
FLastIndexOperationsBlock := AIndex;
|
|
end else Result := False;
|
|
end else Result := False;
|
|
finally
|
|
finally
|
|
- FLock.Release;
|
|
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TPCOperationsBlockValidator.GetStatus(out AValidatedOk, AValidatedError, APendingToValidate: Integer);
|
|
|
|
+var LList : TList<TOperationBlock>;
|
|
|
|
+begin
|
|
|
|
+ LList := FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ AValidatedOk := FValidatedOkCount;
|
|
|
|
+ AValidatedError := FValidatedErrorCount;
|
|
|
|
+ if LList.Count>0 then
|
|
|
|
+ APendingToValidate := LList.Count - (FLastIndexOperationsBlock + 1)
|
|
|
|
+ else APendingToValidate := 0;
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -123,7 +219,7 @@ begin
|
|
LTC := TPlatform.GetTickCount;
|
|
LTC := TPlatform.GetTickCount;
|
|
LMultiThreadValidator := TPCOperationsBlockValidator.Create;
|
|
LMultiThreadValidator := TPCOperationsBlockValidator.Create;
|
|
try
|
|
try
|
|
- LValidatedTotal := LMultiThreadValidator.Validate(APCOperationsCompList,LValidatedOk,LValidatedError);
|
|
|
|
|
|
+ LValidatedTotal := LMultiThreadValidator.ValidateAndWaitUntilTerminate(APCOperationsCompList,LValidatedOk,LValidatedError);
|
|
LTC := TPlatform.GetElapsedMilliseconds(LTC);
|
|
LTC := TPlatform.GetElapsedMilliseconds(LTC);
|
|
if (LValidatedTotal>0) and (LTC>0) then begin
|
|
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]));
|
|
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]));
|
|
@@ -134,28 +230,35 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TPCOperationsBlockValidator.SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated: Boolean);
|
|
|
|
|
|
+procedure TPCOperationsBlockValidator.SetOperationBlockResult(const AOperationBlock : TOperationBlock; AIndex : Integer; AValidated: Boolean; const AErrorDetected : String);
|
|
|
|
+var LList : TList<TOperationBlock>;
|
|
begin
|
|
begin
|
|
- FLock.Acquire;
|
|
|
|
|
|
+ LList := FLockedList.LockList;
|
|
try
|
|
try
|
|
if AValidated then inc(FValidatedOkCount)
|
|
if AValidated then inc(FValidatedOkCount)
|
|
- else inc(FValidatedErrorCount);
|
|
|
|
- FPCOperationsCompList[AIndex].HasValidOperationBlockInfo := AValidated;
|
|
|
|
|
|
+ else begin
|
|
|
|
+ FErrorsList.Add(AErrorDetected + ' ' + TPCOperationsComp.OperationBlockToText(AOperationBlock) );
|
|
|
|
+ inc(FValidatedErrorCount);
|
|
|
|
+ end;
|
|
|
|
+ if Assigned(FPCOperationsCompList) then begin
|
|
|
|
+ FPCOperationsCompList[AIndex].HasValidOperationBlockInfo := AValidated;
|
|
|
|
+ end;
|
|
finally
|
|
finally
|
|
- FLock.Release;
|
|
|
|
|
|
+ FLockedList.UnlockList;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TPCOperationsBlockValidator.Validate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
|
|
|
|
|
|
+procedure TPCOperationsBlockValidator.StartThreads;
|
|
var LMaxThreads : Integer;
|
|
var LMaxThreads : Integer;
|
|
- LThreads : TList<TPCOperationsBlockValidatorThread>;
|
|
|
|
- i,LTerminatedThreads : Integer;
|
|
|
|
|
|
+ i : Integer;
|
|
|
|
+ LList : TList<TOperationBlock>;
|
|
begin
|
|
begin
|
|
|
|
+ EndThreads; // Ensure no active threads
|
|
|
|
+
|
|
FValidatedOkCount := 0;
|
|
FValidatedOkCount := 0;
|
|
FValidatedErrorCount := 0;
|
|
FValidatedErrorCount := 0;
|
|
- if APCOperationsCompList.Count<=0 then Exit(0);
|
|
|
|
-
|
|
|
|
FLastIndexOperationsBlock := -1;
|
|
FLastIndexOperationsBlock := -1;
|
|
|
|
+ FErrorsList.Clear;
|
|
|
|
|
|
if _Cpus<=0 then begin
|
|
if _Cpus<=0 then begin
|
|
_Cpus := TLogicalCPUCount.GetLogicalCPUCount;
|
|
_Cpus := TLogicalCPUCount.GetLogicalCPUCount;
|
|
@@ -165,41 +268,70 @@ begin
|
|
if (LMaxThreads<=0) then LMaxThreads := 1;
|
|
if (LMaxThreads<=0) then LMaxThreads := 1;
|
|
if (LMaxThreads>7) then LMaxThreads := 7;
|
|
if (LMaxThreads>7) then LMaxThreads := 7;
|
|
|
|
|
|
- LThreads := TList<TPCOperationsBlockValidatorThread>.Create;
|
|
|
|
- Try
|
|
|
|
- // Init values
|
|
|
|
- FLastIndexOperationsBlock := -1;
|
|
|
|
- FPCOperationsCompList := APCOperationsCompList;
|
|
|
|
-
|
|
|
|
- // Step 1: Create the threads:
|
|
|
|
|
|
+ FThreads := TList<TPCOperationsBlockValidatorThread>.Create;
|
|
|
|
+ FLockedList.LockList;
|
|
|
|
+ try
|
|
for i := 1 to LMaxThreads do begin
|
|
for i := 1 to LMaxThreads do begin
|
|
- LThreads.Add( TPCOperationsBlockValidatorThread.Create(Self) );
|
|
|
|
|
|
+ FThreads.Add( TPCOperationsBlockValidatorThread.Create(Self) );
|
|
end;
|
|
end;
|
|
- // Step 2: Start the threads
|
|
|
|
- for i := 0 to LThreads.Count-1 do begin
|
|
|
|
- LThreads[i].Suspended := False;
|
|
|
|
|
|
+ for i := 0 to FThreads.Count-1 do begin
|
|
|
|
+ FThreads[i].Suspended := False;
|
|
end;
|
|
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;
|
|
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TPCOperationsBlockValidator.ValidateAndWaitUntilTerminate(APCOperationsCompList : TList<TPCOperationsComp>; var AValidatedOkCount, AValidatedErrorCount : Integer) : Integer;
|
|
|
|
+var
|
|
|
|
+ i,LTerminatedThreads : Integer;
|
|
|
|
+ LList : TList<TOperationBlock>;
|
|
|
|
+begin
|
|
|
|
+ FValidatedOkCount := 0;
|
|
|
|
+ FValidatedErrorCount := 0;
|
|
|
|
+ if APCOperationsCompList.Count<=0 then Exit(0);
|
|
|
|
+
|
|
|
|
+ EndThreads;
|
|
|
|
+
|
|
|
|
+ LList := FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ for i := 0 to APCOperationsCompList.Count-1 do begin
|
|
|
|
+ LList.Add(APCOperationsCompList[i].OperationBlock);
|
|
end;
|
|
end;
|
|
- LThreads.Free;
|
|
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ FPCOperationsCompList := APCOperationsCompList;
|
|
|
|
+
|
|
|
|
+ StartThreads;
|
|
|
|
+ try
|
|
|
|
+ // Wait until error of finalized
|
|
|
|
+ WaitUntilAllValidatedOrErrorFound;
|
|
|
|
+ Finally
|
|
|
|
+ EndThreads;
|
|
End;
|
|
End;
|
|
AValidatedOkCount := FValidatedOkCount;
|
|
AValidatedOkCount := FValidatedOkCount;
|
|
AValidatedErrorCount := FValidatedErrorCount;
|
|
AValidatedErrorCount := FValidatedErrorCount;
|
|
Result := FPCOperationsCompList.Count;
|
|
Result := FPCOperationsCompList.Count;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TPCOperationsBlockValidator.WaitUntilAllValidatedOrErrorFound;
|
|
|
|
+var LContinue : Boolean;
|
|
|
|
+ LList : TList<TOperationBlock>;
|
|
|
|
+begin
|
|
|
|
+ repeat
|
|
|
|
+ Sleep(10);
|
|
|
|
+ LList := FLockedList.LockList;
|
|
|
|
+ try
|
|
|
|
+ LContinue := (FValidatedErrorCount=0) And (FLastIndexOperationsBlock+1<LList.Count);
|
|
|
|
+ finally
|
|
|
|
+ FLockedList.UnlockList;
|
|
|
|
+ end;
|
|
|
|
+ until (Not LContinue);
|
|
|
|
+end;
|
|
|
|
+
|
|
{ TPCOperationsBlockValidatorThread }
|
|
{ TPCOperationsBlockValidatorThread }
|
|
|
|
|
|
procedure TPCOperationsBlockValidatorThread.BCExecute;
|
|
procedure TPCOperationsBlockValidatorThread.BCExecute;
|
|
@@ -211,8 +343,8 @@ begin
|
|
repeat
|
|
repeat
|
|
if FValidator.GetNextOperationBlock( LOperationBlock, LIndex ) then begin
|
|
if FValidator.GetNextOperationBlock( LOperationBlock, LIndex ) then begin
|
|
LValidated := TPCSafeBox.IsValidOperationBlock(LOperationBlock,LErrors);
|
|
LValidated := TPCSafeBox.IsValidOperationBlock(LOperationBlock,LErrors);
|
|
- FValidator.SetOperationBlockResult(LOperationBlock, LIndex, LValidated);
|
|
|
|
- end else Terminate;
|
|
|
|
|
|
+ FValidator.SetOperationBlockResult(LOperationBlock, LIndex, LValidated, LErrors);
|
|
|
|
+ end else Sleep(1);
|
|
until (Terminated);
|
|
until (Terminated);
|
|
end;
|
|
end;
|
|
|
|
|