ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBActivityMonitor.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 9068 byte(s)
Log Message:
Committing updates for Release R2-0-0

File Contents

# User Rev Content
1 tony 45 (*
2     * Firebird Interface (fbintf). The fbintf components provide a set of
3     * Pascal language bindings for the Firebird API.
4     *
5     * The contents of this file are subject to the Initial Developer's
6     * Public License Version 1.0 (the "License"); you may not use this
7     * file except in compliance with the License. You may obtain a copy
8     * of the License here:
9     *
10     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11     *
12     * Software distributed under the License is distributed on an "AS
13     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     * implied. See the License for the specific language governing rights
15     * and limitations under the License.
16     *
17     * The Initial Developer of the Original Code is Tony Whyman.
18     *
19     * The Original Code is (C) 2016 Tony Whyman, MWA Software
20     * (http://www.mwasoftware.co.uk).
21     *
22     * All Rights Reserved.
23     *
24     * Contributor(s): ______________________________________.
25     *
26     *)
27     unit FBActivityMonitor;
28    
29     {$IFDEF FPC}
30     {$mode objfpc}{$H+}
31     {$interfaces COM}
32     {$ENDIF}
33    
34     interface
35    
36     uses
37     Classes, SysUtils, IBExternals;
38    
39     { $DEFINE DEBUGINTERFACES} {Define this to check that all interfaces are
40     being destroyed.}
41    
42     type
43     { TMonitoredObject is an optional class used to journal all interface creatino
44     and deletion as well as keeping a count of how many monitored interfaces
45     exist at any one time. It is used at development to look for memory leaks
46     due to interfaces not being discarded when no longer used.}
47    
48     {$IFDEF DEBUGINTERFACES}
49     TMonitoredObject = class(TInterfacedObject)
50     private
51     FObjectCount: integer; static;
52     public
53     constructor Create;
54     destructor Destroy; override;
55     end;
56    
57     {TFBInterfacedObject is used as the base class for interfaces objects and can
58     be either a synonym for TInterfacedObject (default) or TMonitored object}
59    
60     TFBInterfacedObject = TMonitoredObject;
61     {$ELSE}
62     TFBInterfacedObject = TInterfacedObject;
63     {$ENDIF}
64    
65     { TInterfaceOwner }
66    
67     TInterfaceOwner = class(TFBInterfacedObject)
68     private
69     FInterfaces: array of TInterfacedObject;
70     FInterfaceRefs: array of IUnknown;
71     FRetainInterfaces: boolean;
72     FMinInterfaces: integer;
73     function GetCount: integer;
74     procedure SetRetainInterfaces(AValue: boolean);
75     protected
76     procedure AddInterface(index: integer; obj: TInterfacedObject);
77     function HasInterface(index: integer): boolean;
78     procedure ReleaseInterfaces;
79     public
80     constructor Create(aInterfaces: integer=0);
81     destructor Destroy; override;
82     procedure AddObject(obj: TInterfacedObject);
83     function GetInterface(index: integer): TInterfacedObject;
84     procedure Remove(intf: TInterfacedObject);
85     property InterfaceCount: integer read GetCount;
86     property RetainInterfaces: boolean read FRetainInterfaces write SetRetainInterfaces;
87     end;
88    
89     {The IActivityMonitor interface is provided by classes that receive activity
90     reports.}
91    
92     IActivityMonitor = interface
93     procedure AddObject(obj: TInterfacedObject);
94     procedure Remove(intf: TInterfacedObject);
95     procedure SignalActivity;
96     end;
97    
98     { TActivityReporter is a base class for objects that need to report their activity
99     to an activity monitor, where activity is defined as use of a Firebird API call.
100     Objects descending from this class always used the "Call" method as a wrapper
101     for calls to the Firebird API. Each such call is then classed as activity
102     and reported to one or more activity monitors.
103    
104     In practice, a transaction monitors statements, blobs and arrays. A Database
105     monitors transactions and events. Transaction monitors use the ITransactionMonitor
106     interface, implemented through the helper object TTransactionMonitor.
107     }
108    
109     TActivityReporter = class(TInterfaceOwner)
110     private
111     FHasActivity: boolean;
112     FMonitors: array of IActivityMonitor;
113     function FindMonitor(aMonitor: IActivityMonitor): integer;
114     protected
115     function Call(ErrCode: ISC_STATUS; RaiseError: Boolean = true): ISC_STATUS;
116     procedure AddMonitor(aMonitor: IActivityMonitor);
117     procedure RemoveMonitor(aMonitor: IActivityMonitor);
118     public
119     constructor Create(aMonitor: IActivityMonitor;aInterfaces: integer=0);
120     destructor Destroy; override;
121     function HasActivity: boolean;
122     procedure SignalActivity;
123     end;
124    
125     { TActivityHandler is a base class for classes that receive activity reports.}
126    
127     TActivityHandler = class(TInterfaceOwner,IActivityMonitor)
128     private
129     FHasActivity: boolean;
130     public
131     function HasActivity: boolean;
132     procedure SignalActivity;
133     end;
134    
135     implementation
136    
137     uses FB25ClientAPI;
138    
139     { TActivityHandler }
140    
141     function TActivityHandler.HasActivity: boolean;
142     begin
143     Result := FHasActivity;
144     FHasActivity := false;
145     end;
146    
147     procedure TActivityHandler.SignalActivity;
148     begin
149     FHasActivity := true;
150     end;
151    
152     { TMonitoredObject }
153    
154     {$IFDEF DEBUGINTERFACES}
155     constructor TMonitoredObject.Create;
156     begin
157     inherited Create;
158     Inc(FObjectCount);
159     writeln('Creating ' + ClassName,', Obj Count = ',FObjectCount);
160     end;
161    
162     destructor TMonitoredObject.Destroy;
163     begin
164     Dec(FObjectCount);
165     writeln('Destroying ' + ClassName,' Obj Count = ',FObjectCount);
166     inherited Destroy;
167     end;
168     {$ENDIF}
169    
170     { TActivityReporter}
171    
172     function TActivityReporter.FindMonitor(aMonitor: IActivityMonitor): integer;
173     var i: integer;
174     begin
175     Result := -1;
176     for i := 0 to Length(FMonitors) - 1 do
177     if FMonitors[i] = aMonitor then
178     begin
179     Result := i;
180     Exit;
181     end;
182     end;
183    
184     function TActivityReporter.Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
185     begin
186     result := ErrCode;
187     SignalActivity;
188     if RaiseError and (ErrCode > 0) then
189     Firebird25ClientAPI.IBDataBaseError;
190     end;
191    
192     procedure TActivityReporter.AddMonitor(aMonitor: IActivityMonitor);
193     var i: integer;
194     begin
195     if FindMonitor(aMonitor) = -1 then
196     begin
197     i := Length(FMonitors);
198     Setlength(FMonitors,i+1);
199     FMonitors[i] := aMonitor;
200     aMonitor.AddObject(self);
201     end;
202     end;
203    
204     procedure TActivityReporter.RemoveMonitor(aMonitor: IActivityMonitor);
205     var i,j: integer;
206     begin
207     i := FindMonitor(aMonitor);
208     if i <> -1 then
209     begin
210     aMonitor.Remove(self);
211     if Length(FMonitors) = 1 then
212     SetLength(FMonitors,0)
213     else
214     begin
215     for j := i + 1 to Length(FMonitors) - 1 do
216     FMonitors[j-1] := FMonitors[j];
217     SetLength(FMonitors,Length(FMonitors)-1);
218     end;
219     end;
220     end;
221    
222     procedure TActivityReporter.SignalActivity;
223     var i: integer;
224     begin
225     FHasActivity := true;
226     for i := 0 to Length(FMonitors) - 1 do
227     FMonitors[i].SignalActivity;
228     end;
229    
230     constructor TActivityReporter.Create(aMonitor: IActivityMonitor;
231     aInterfaces: integer);
232     begin
233     inherited Create(aInterfaces);
234     if aMonitor <> nil then
235     begin
236     SetLength(FMonitors,1);
237     FMonitors[0] := aMonitor;
238     end;
239     end;
240    
241     destructor TActivityReporter.Destroy;
242     var i: integer;
243     begin
244     for i := 0 to Length(FMonitors) - 1 do
245     FMonitors[i].Remove(self);
246     inherited Destroy;
247     end;
248    
249     function TActivityReporter.HasActivity: boolean;
250     begin
251     Result := FHasActivity;
252     FHasActivity := false;
253     end;
254    
255     { TInterfaceOwner }
256    
257     constructor TInterfaceOwner.Create(aInterfaces: integer);
258     begin
259     inherited Create;
260     FMinInterfaces := aInterfaces;
261     SetLength(FInterfaces,aInterfaces);
262     SetLength(FInterfaceRefs,aInterfaces);
263     end;
264    
265     destructor TInterfaceOwner.Destroy;
266     begin
267     ReleaseInterfaces;
268     inherited Destroy;
269     end;
270    
271     procedure TInterfaceOwner.AddObject(obj: TInterfacedObject);
272     var index: integer;
273     begin
274     index := Length(FInterfaces);
275     SetLength(FInterfaces,index+1);
276     SetLength(FInterfaceRefs,index+1);
277     AddInterface(index,obj);
278     end;
279    
280     function TInterfaceOwner.GetInterface(index: integer): TInterfacedObject;
281     begin
282     Result := FInterfaces[index];
283     end;
284    
285     procedure TInterfaceOwner.SetRetainInterfaces(AValue: boolean);
286     begin
287     if FRetainInterfaces = AValue then Exit;
288     FRetainInterfaces := AValue;
289     if not FRetainInterfaces then
290     ReleaseInterfaces;
291     end;
292    
293     function TInterfaceOwner.GetCount: integer;
294     begin
295     Result := Length(FInterfaces);
296     end;
297    
298     procedure TInterfaceOwner.AddInterface(index: integer; obj: TInterfacedObject);
299     begin
300     FInterfaces[index] := obj;
301     if RetainInterfaces then
302     FInterfaceRefs[index] := obj;
303     end;
304    
305     function TInterfaceOwner.HasInterface(index: integer): boolean;
306     begin
307     Result := FInterfaces[index] <> nil;
308     end;
309    
310     procedure TInterfaceOwner.Remove(intf: TInterfacedObject);
311     var i, j: integer;
312     begin
313     for i := 0 to Length(FInterfaces) - 1 do
314     if FInterfaces[i] = intf then
315     begin
316     if i < FMinInterfaces then
317     begin
318     FInterfaceRefs[i] := nil;
319     FInterfaces[i] := nil;
320     end
321     else
322     begin
323     for j := i to Length(FInterfaces) - 2 do
324     begin
325     FInterfaceRefs[j] := FInterfaceRefs[j+1];
326     FInterfaces[j] := FInterfaces[j+1];
327     end;
328     SetLength(FInterfaces,Length(FInterfaces)-1);
329     SetLength(FInterfaceRefs,Length(FInterfaceRefs)-1);
330     end;
331     Exit;
332     end;
333     end;
334    
335     procedure TInterfaceOwner.ReleaseInterfaces;
336     var i: integer;
337     begin
338     for i := 0 to Length(FInterfaces) - 1 do
339     FInterfaceRefs[i] := nil;
340     end;
341    
342     end.
343