-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDMPools.pas
219 lines (187 loc) · 4.69 KB
/
DMPools.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
unit DMPools;
interface
uses
System.SysUtils, System.Classes, System.Types, Generics.Collections, YWTypes;
type
TDataModuleClass = class of TDataModule;
TDataModuleHelper = class helper for TDataModule
procedure ReturnToPool;
procedure ResetPool;
procedure AfterGet; virtual;
procedure BeforeReturn; virtual;
end;
TDMHolder = class(TComponent)
protected
DestroyPool : Boolean;
AllocateTime : TDateTime;
public
function DM : TDataModule; virtual; abstract;
class function DMClass : TDataModuleClass; virtual; abstract;
class function GetFromPool:TDMHolder; virtual; abstract;
procedure ReturnToPool; virtual; abstract;
class procedure RegisterClass; virtual;
constructor Create; reintroduce; virtual;
end;
TDMHolder<T : TDataModule,constructor> = class(TDMHolder)
private
_DM : T;
public
class var Pool : TRingQueue512;
class var DestroyTime : TDateTime;
class function DMClass : TDataModuleClass; override;
class function GetFromPool:TDMHolder; override;
class procedure Return(D: TDMHolder); inline; static;
class destructor Done;
function DM : TDataModule; override;
procedure ReturnToPool; override;
constructor Create; override;
end;
TDMHolderClass = class of TDMHolder;
DMPool = class
private
type THolderRec = record
DC : TDataModuleClass;
HC : TDMHolderClass;
end;
class var
Pools : TList<THolderRec>;
class procedure RegisterClass(H : TDMHolderClass); static;
public
class function GetDM<T : TDataModule,constructor>:T; overload;
class function GetDM(C : TDataModuleClass) : TDataModule; overload;
class constructor Create;
class destructor Destroy;
end;
implementation
uses Threading;
{%CLASSGROUP 'System.Classes.TPersistent'}
{ DMPool }
class constructor DMPool.Create;
begin
Pools := TList<THolderRec>.Create;
end;
class destructor DMPool.Destroy;
begin
Pools.Free;
end;
class function DMPool.GetDM(C: TDataModuleClass): TDataModule;
var L : THolderRec;
R : TDMHolder;
begin
Result := nil;
for L in Pools do if L.DC=C then begin
R := L.HC.GetFromPool;
if R=nil then R := L.HC.Create;
Result := R.DM;
try
Result.AfterGet;
except on E: Exception do
end;
exit;
end;
end;
class function DMPool.GetDM<T>: T;
var R : TDMHolder<T>;
begin
R := TDMHolder<T>(TDMHolder<T>.GetFromPool);
if R=nil then R := TDMHolder<T>.Create;
Result := R._DM;
try
Result.AfterGet;
except on E: Exception do
end;
end;
class procedure DMPool.RegisterClass(H: TDMHolderClass);
var L : THolderRec;
begin
for L in Pools do if L.HC=H then exit;
L.DC := H.DMClass;
L.HC := H;
Pools.Add(L);
end;
{ TDataModuleHelper }
procedure TDataModuleHelper.AfterGet;
begin
end;
procedure TDataModuleHelper.BeforeReturn;
begin
end;
procedure TDataModuleHelper.ResetPool;
begin
if self.Owner is TDMHolder then begin
TDMHolder(Owner).DestroyPool := true;
TDMHolder(Owner).ReturnToPool;
end;
end;
procedure TDataModuleHelper.ReturnToPool;
begin
if self.Owner is TDMHolder then
TDMHolder(Owner).ReturnToPool;
end;
{ TDMHolder<T> }
constructor TDMHolder<T>.Create;
begin
inherited;
_DM := T(DMClass.Create(Self));
end;
function TDMHolder<T>.DM: TDataModule;
begin
Result := _DM;
end;
class function TDMHolder<T>.DMClass: TDataModuleClass;
begin
Result := T;
end;
class destructor TDMHolder<T>.Done;
var a : TDMHolder;
begin
a := TDMHolder(Pool.Get);
while a<>nil do begin
a.free;
a := TDMHolder(Pool.Get);
end;
end;
class function TDMHolder<T>.GetFromPool: TDMHolder;
begin
Result := TDMHolder(Pool.Get);
while (Result<>nil)and(Result.AllocateTime<DestroyTime) do begin
Result.Free;
Result := TDMHolder(Pool.Get);
end;
end;
class procedure TDMHolder<T>.Return(D: TDMHolder);
begin
if D.DestroyPool then begin
DestroyTime := Now;
D.Free;
TTask.Run(procedure begin
var a := TDMHolder(Pool.Get);
while (a<>nil)and(a.AllocateTime<DestroyTime) do begin
a.Free;
a := TDMHolder(Pool.Get);
end;
if (a<>nil)and(not Pool.Put(a)) then a.Free;
end);
end else if (D.AllocateTime<DestroyTime) or (not Pool.Put(D)) then D.Free;
end;
procedure TDMHolder<T>.ReturnToPool;
begin
try
_DM.BeforeReturn;
except
Free;
exit;
end;
Return(self);
end;
{ TDMHolder }
constructor TDMHolder.Create;
begin
inherited Create(nil);
AllocateTime := Now;
end;
class procedure TDMHolder.RegisterClass;
begin
DMPool.RegisterClass(self);
end;
end.