Memory hole in Data-Join fixed

This commit is contained in:
Michael Schimmel
2025-07-24 13:07:29 +02:00
parent 4859c49738
commit ff5b379fde
5 changed files with 141 additions and 137 deletions
+36 -51
View File
@@ -31,6 +31,16 @@ type
class property Null: IConsumer<T> read FNull;
end;
// A consumer implementation that is owned by a controller.
TMycGenericConsumer<T> = class(TMycConsumer<T>)
private
FProc: TConstFunc<T, TState>;
protected
function Consume(const Value: T): TState; override; final;
public
constructor Create(const Controller: IInterface; const AProc: TConstFunc<T, TState>);
end;
TMycProducer<T> = class(TInterfacedObject, IProducer<T>)
strict private
type
@@ -79,18 +89,7 @@ type
FNull: IConverter<S, T>;
class constructor CreateClass;
private
type
TConsumer = class(TMycConsumer<S>)
private
FOwner: TMycConverter<S, T>;
protected
function Consume(const Value: S): TState; override; final;
public
constructor Create(AOwner: TMycConverter<S, T>);
end;
private
FConsumer: TConsumer;
FConsumer: TMycGenericConsumer<S>;
function GetConsumer: IConsumer<S>;
protected
// To be implemented by descendants to perform the actual conversion.
@@ -162,16 +161,6 @@ type
constructor Create(const AFieldName: String);
end;
// A consumer implementation that is owned by a controller.
TMycGenericConsumer<T> = class(TMycConsumer<T>)
private
FProc: TConstFunc<T, TState>;
protected
function Consume(const Value: T): TState; override;
public
constructor Create(const Controller: IInterface; const AProc: TConstFunc<T, TState>);
end;
// Endpoint that collects data into a series.
TMycDataEndpoint<T> = class(TInterfacedObject, TLazy<TSeries<T>>.ILazy)
private
@@ -183,9 +172,7 @@ type
end;
private
FConsumer: TMycGenericConsumer<T>;
FTag: TTag;
FProducer: IProducer<T>;
FLookback: Int64;
FLookback: Integer;
FChanged: TFlag;
FLock: TLightweightMREW;
FFirst: PItem;
@@ -193,9 +180,11 @@ type
function GetChanged: TState;
function Consume(const Value: T): TState;
public
constructor Create(const AProducer: TProducer<T>; ALookback: Int64);
constructor Create(ALookback: Integer);
destructor Destroy; override;
function Update(var Value: TSeries<T>): Boolean;
class function CreateDataEndpoint(Lookback: Integer; out Series: TLazy<TSeries<T>>): IConsumer<T>;
end;
TTickAggregation = class(TMycConverter<TDataPoint<Double>, TDataPoint<TOhlcItem>>)
@@ -239,9 +228,7 @@ type
TMycDataJoin<T> = class(TInterfacedObject, IProducer<TArray<T>>)
private
FConsumers: array of record
Producer: IProducer<T>;
Consumer: TMycGenericConsumer<T>;
Tag: TTag;
Queue: TQueue<T>;
end;
@@ -249,11 +236,13 @@ type
FLock: TSpinLock;
FCount: Integer;
function Consume(Idx: Integer; const Value: T): TState;
function GetConsumers(Idx: Integer): IConsumer<T>;
function Link(const Consumer: IConsumer<TArray<T>>): TTag;
procedure Unlink(Tag: TTag);
public
constructor Create(const AProducers: TArray<TProducer<T>>);
constructor Create(ACount: Integer);
destructor Destroy; override;
property Consumers[Idx: Integer]: IConsumer<T> read GetConsumers;
end;
TMycComposedConverter<S, T> = class(TInterfacedObject, IConverter<S, T>)
@@ -363,7 +352,7 @@ end;
constructor TMycConverter<S, T>.Create;
begin
inherited Create;
FConsumer := TConsumer.Create(Self);
FConsumer := TMycGenericConsumer<S>.Create(Self, Consume);
end;
{ TMycConverter<S, T> }
@@ -486,19 +475,15 @@ end;
{ TMycDataEndpoint<T> }
constructor TMycDataEndpoint<T>.Create(const AProducer: TProducer<T>; ALookback: Int64);
constructor TMycDataEndpoint<T>.Create(ALookback: Integer);
begin
inherited Create;
FProducer := AProducer;
FLookback := ALookback;
FConsumer := TMycGenericConsumer<T>.Create(Self, Consume);
FTag := FProducer.Link(FConsumer);
end;
destructor TMycDataEndpoint<T>.Destroy;
begin
FProducer.Unlink(FTag);
FConsumer.Free;
inherited;
end;
@@ -524,6 +509,15 @@ begin
end;
end;
class function TMycDataEndpoint<T>.CreateDataEndpoint(Lookback: Integer; out Series: TLazy<TSeries<T>>): IConsumer<T>;
var
endPoint: TMycDataEndpoint<T>;
begin
endPoint := TMycDataEndpoint<T>.Create(Lookback);
Result := endPoint.FConsumer;
Series := endPoint;
end;
function TMycDataEndpoint<T>.Update(var Value: TSeries<T>): Boolean;
begin
FLock.BeginWrite;
@@ -801,11 +795,11 @@ end;
{ TMycDataJoin<T> }
constructor TMycDataJoin<T>.Create(const AProducers: TArray<TProducer<T>>);
constructor TMycDataJoin<T>.Create(ACount: Integer);
begin
inherited Create;
SetLength(FConsumers, Length(AProducers));
SetLength(FConsumers, ACount);
FLock := TSpinLock.Create(false);
FCount := Length(FConsumers);
@@ -822,9 +816,7 @@ begin
with FConsumers[i] do
begin
Queue := TQueue<T>.Create;
Producer := AProducers[i];
Consumer := TMycGenericConsumer<T>.Create(Self, cFunc(i));
Tag := Producer.Link(Consumer);
end;
end;
@@ -833,7 +825,6 @@ begin
for var i := High(FConsumers) downto 0 do
with FConsumers[i] do
begin
Producer.Unlink(FConsumers[i].Tag);
Consumer.Free;
Queue.Free;
end;
@@ -884,6 +875,11 @@ begin
FContainedProvider.Broadcast(Arr);
end;
function TMycDataJoin<T>.GetConsumers(Idx: Integer): IConsumer<T>;
begin
Result := FConsumers[Idx].Consumer;
end;
{ TMycGenericAggregator<S, T> }
constructor TMycGenericAggregator<S, T>.Create(const AFunc: TConstFunc<S, TConverter<S, T>.TBroadcastProc, TState>);
@@ -1005,15 +1001,4 @@ begin
end;
constructor TMycConverter<S, T>.TConsumer.Create(AOwner: TMycConverter<S, T>);
begin
inherited Create(AOwner);
FOwner := AOwner;
end;
function TMycConverter<S, T>.TConsumer.Consume(const Value: S): TState;
begin
Result := FOwner.Consume(Value);
end;
end.