762 lines
19 KiB
ObjectPascal
762 lines
19 KiB
ObjectPascal
|
|
||
|
{******************************************}
|
||
|
{ }
|
||
|
{ FastReport VCL }
|
||
|
{ Server cahce module }
|
||
|
{ }
|
||
|
{ Copyright (c) 1998-2021 }
|
||
|
{ by Fast Reports Inc. }
|
||
|
{ }
|
||
|
{******************************************}
|
||
|
|
||
|
unit frxServerCache;
|
||
|
|
||
|
{$I frx.inc}
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
{$IFNDEF Linux}
|
||
|
Windows,
|
||
|
{$ENDIF}
|
||
|
{$IFDEF LCLGTK2}
|
||
|
gdk2,
|
||
|
{$ENDIF}
|
||
|
Classes, SysUtils, frxUtils, frxServerUtils, frxNetUtils,
|
||
|
frxVariables, frxClass, frxServerLog, SyncObjs;
|
||
|
|
||
|
type
|
||
|
TfrxServerCacheItem = class(TCollectionItem)
|
||
|
private
|
||
|
FReportName: String;
|
||
|
FVariables: TfrxVariables;
|
||
|
FFileName: String;
|
||
|
FExpTime: TDateTime;
|
||
|
FSessionId: String;
|
||
|
FStream: TStream;
|
||
|
FInternalId: String;
|
||
|
FFileType: TfrxServerFormat;
|
||
|
public
|
||
|
constructor Create(Collection: TCollection); override;
|
||
|
destructor Destroy; override;
|
||
|
published
|
||
|
property ReportName: String read FReportName write FReportName;
|
||
|
property Variables: TfrxVariables read FVariables write FVariables;
|
||
|
property FileName: String read FFileName write FFileName;
|
||
|
property FileType: TfrxServerFormat read FFileType write FFileType;
|
||
|
property ExpTime: TDateTime read FExpTime write FExpTime;
|
||
|
property SessionId: String read FSessionId write FSessionId;
|
||
|
property Stream: TStream read FStream write FStream;
|
||
|
property InternalId: String read FInternalId write FInternalId;
|
||
|
end;
|
||
|
|
||
|
TfrxServerCacheSpool = class(TCollection)
|
||
|
private
|
||
|
function GetItems(Index: Integer): TfrxServerCacheItem;
|
||
|
function EqualVariables(const Var1: TfrxVariables; const Var2: TfrxVariables): Boolean;
|
||
|
public
|
||
|
constructor Create;
|
||
|
destructor Destroy; override;
|
||
|
property Items[Index: Integer]: TfrxServerCacheItem read GetItems;
|
||
|
procedure Clear;
|
||
|
published
|
||
|
function Add: TfrxServerCacheItem;
|
||
|
function Insert(Index: Integer): TfrxServerCacheItem;
|
||
|
function IndexOf(const ReportName: String; const Variables: TfrxVariables; const SessionId: String; const aFileFormat: TfrxServerFormat): Integer;
|
||
|
end;
|
||
|
|
||
|
TfrxServerCache = class (TThread)
|
||
|
protected
|
||
|
FCACHE_PREFIX: String;
|
||
|
FCachePath: String;
|
||
|
FActive: Boolean;
|
||
|
FLatency: Integer;
|
||
|
FHeap: TfrxServerCacheSpool;
|
||
|
FMemoryCache: Boolean;
|
||
|
FThreadActive: Boolean;
|
||
|
procedure SetActive(const Value: Boolean);
|
||
|
procedure CleanUpFiles; virtual;
|
||
|
procedure RemoveExpired; virtual;
|
||
|
procedure Execute; override;
|
||
|
public
|
||
|
constructor Create(WithInitialization: Boolean = True);
|
||
|
destructor Destroy; override;
|
||
|
function GetCachedStream(const Report: TfrxReport; const ReportName: String; const Variables: TfrxVariables; const Id: String): Boolean; overload;
|
||
|
function GetCachedReportById(const Report: TfrxReport; const Id: String): Boolean;
|
||
|
function IsReportInCache(const ReportName: String; const Variables: TfrxVariables; const Id: String; const aFileFormat: TfrxServerFormat = sfFRP): Boolean;
|
||
|
function CopyCacheFileIfExist(const aFileName: String; const ReportName: String; const Variables: TfrxVariables; const Id: String; const aFileFormat: TfrxServerFormat = sfFRP): Boolean;
|
||
|
procedure Open;
|
||
|
procedure Close;
|
||
|
procedure Clear;
|
||
|
procedure AddReport(const Report: TfrxReport;
|
||
|
const ReportName: String; const Variables: TfrxVariables; const Id: String; const InternalId: String);
|
||
|
procedure AddFileFormat(const sStream: TStream; const aFileFormat: TfrxServerFormat;
|
||
|
const ReportName: String; const Variables: TfrxVariables; const Id: String; const InternalId: String); virtual;
|
||
|
|
||
|
property Active: Boolean read FActive write SetActive;
|
||
|
property CachePath: String read FCachePath write FCachePath;
|
||
|
property DefaultLatency: Integer read FLatency write FLatency;
|
||
|
property Heap: TfrxServerCacheSpool read FHeap;
|
||
|
property MemoryCache: Boolean read FMemoryCache write FMemoryCache;
|
||
|
property CACHE_PREFIX: String read FCACHE_PREFIX write FCACHE_PREFIX;
|
||
|
end;
|
||
|
|
||
|
TfrxResultCache = class (TfrxServerCache) //for caching fp3 export results
|
||
|
protected
|
||
|
procedure CleanUpFiles; override;
|
||
|
public
|
||
|
constructor Create(aCachePath, aCACHE_PREFIX: String); overload;
|
||
|
procedure AddFileFormat(const sStream: TStream; const aFileFormat: TfrxServerFormat;
|
||
|
const ReportName: String; const Variables: TfrxVariables; const Id: String; const InternalId: String); override;
|
||
|
procedure RemoveExpired; override;
|
||
|
procedure UpdExpTime(const ReportName: String; const Variables: TfrxVariables; const SessionId: String; const aFileFormat: TfrxServerFormat);
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
CacheCS1: TCriticalSection;
|
||
|
ReportCache: TfrxServerCache;
|
||
|
ResultCache: TfrxResultCache;
|
||
|
|
||
|
procedure RemoveAll(path: string);
|
||
|
function GetFileCount(Dir: string): Integer;
|
||
|
|
||
|
implementation
|
||
|
|
||
|
uses frxFileUtils, frxServerConfig, frxServerReportsList, frxIOTransportIntf;
|
||
|
|
||
|
procedure Lock();
|
||
|
begin
|
||
|
{$IFDEF LCLGTK2}
|
||
|
gdk_threads_enter;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
procedure Unlock();
|
||
|
begin
|
||
|
{$IFDEF LCLGTK2}
|
||
|
gdk_threads_leave;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{ TfrxServerCacheSpool }
|
||
|
|
||
|
function TfrxServerCacheSpool.Add: TfrxServerCacheItem;
|
||
|
begin
|
||
|
Result := TfrxServerCacheItem.Create(Self);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCacheSpool.Clear;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
for i := 0 to Count - 1 do
|
||
|
if Assigned(Items[i].Stream) then
|
||
|
begin
|
||
|
Items[i].Stream.Free;
|
||
|
Items[i].Stream := nil;
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
inherited Clear;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxServerCacheSpool.Create;
|
||
|
begin
|
||
|
inherited Create(TfrxServerCacheItem);
|
||
|
end;
|
||
|
|
||
|
destructor TfrxServerCacheSpool.Destroy;
|
||
|
begin
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCacheSpool.EqualVariables(const Var1,
|
||
|
Var2: TfrxVariables): Boolean;
|
||
|
var
|
||
|
i, j, k: Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if Assigned(Var1) and Assigned(Var2) then
|
||
|
begin
|
||
|
j := Var1.Count;
|
||
|
if j = Var2.Count then
|
||
|
begin
|
||
|
Result := True;
|
||
|
for i := 0 to j - 1 do
|
||
|
begin
|
||
|
k := Var2.IndexOf(Var1.Items[i].Name);
|
||
|
if (k = -1) or (Var2.Items[k].Value <> Var1.Items[i].Value) then
|
||
|
begin
|
||
|
Result := False;
|
||
|
Break;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
else if Var1 = Var2 then
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCacheSpool.GetItems(Index: Integer): TfrxServerCacheItem;
|
||
|
begin
|
||
|
Result := TfrxServerCacheItem(inherited Items[Index]);
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCacheSpool.IndexOf(const ReportName: String;
|
||
|
const Variables: TfrxVariables; const SessionId: String; const
|
||
|
aFileFormat: TfrxServerFormat): Integer;
|
||
|
var
|
||
|
i: Integer;
|
||
|
s: String;
|
||
|
begin
|
||
|
Result := -1;
|
||
|
for i := 0 to Count - 1 do
|
||
|
begin
|
||
|
s := Items[i].SessionId;
|
||
|
if ((aFileFormat = Items[i].FileType) and
|
||
|
(AnsiCompareText(ReportName, Items[i].ReportName) = 0) and
|
||
|
EqualVariables(Items[i].Variables, Variables)) and (s = '') or
|
||
|
((AnsiCompareText(SessionId, s) = 0) and (s <> '')) then
|
||
|
begin
|
||
|
Result := i;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCacheSpool.Insert(Index: Integer): TfrxServerCacheItem;
|
||
|
begin
|
||
|
Result := TfrxServerCacheItem(inherited Insert(Index));
|
||
|
end;
|
||
|
|
||
|
{ TfrxServerCacheItem }
|
||
|
|
||
|
constructor TfrxServerCacheItem.Create(Collection: TCollection);
|
||
|
begin
|
||
|
inherited Create(Collection);
|
||
|
FStream := nil;
|
||
|
FFileType := sfFRP;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxServerCacheItem.Destroy;
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
if Assigned(FStream) then
|
||
|
FStream.Free;
|
||
|
if Assigned(FVariables) then
|
||
|
FVariables.Free;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
{ TfrxServerCache }
|
||
|
|
||
|
procedure TfrxServerCache.AddReport(const Report: TfrxReport;
|
||
|
const ReportName: String; const Variables: TfrxVariables; const Id: String; const InternalId: String);
|
||
|
var
|
||
|
Item: TfrxServerCacheItem;
|
||
|
Lat: TDateTime;
|
||
|
begin
|
||
|
if Active then
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
Lat := ReportsList.GetCacheLatency(ReportName) / 86400;
|
||
|
if Lat > 0 then
|
||
|
begin
|
||
|
Item := FHeap.Add;
|
||
|
Item.ReportName := ReportName;
|
||
|
Item.InternalId := InternalId;
|
||
|
if Assigned(Variables) then
|
||
|
begin
|
||
|
Item.Variables := TfrxVariables.Create;
|
||
|
Item.Variables.Assign(Variables);
|
||
|
end;
|
||
|
Item.ExpTime := Now + Lat;
|
||
|
if Id <> '' then
|
||
|
Item.ExpTime := Item.ExpTime * 20;
|
||
|
if FMemoryCache then
|
||
|
begin
|
||
|
Item.Stream := TMemoryStream.Create;
|
||
|
try
|
||
|
Report.PreviewPages.SaveToStream(Item.Stream);
|
||
|
Item.Stream.Position := 0;
|
||
|
except
|
||
|
Item.Stream.Free;
|
||
|
FMemoryCache := False;
|
||
|
end;
|
||
|
end;
|
||
|
if not FMemoryCache then
|
||
|
begin
|
||
|
Item.FileName := GetUniqueFileName(FCachePath, CACHE_PREFIX);
|
||
|
try
|
||
|
Report.PreviewPages.SaveToFile(Item.FileName);
|
||
|
except
|
||
|
Active := False;
|
||
|
end;
|
||
|
end;
|
||
|
Item.SessionId := Id;
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.CleanUpFiles;
|
||
|
var
|
||
|
SRec: TSearchRec;
|
||
|
i: Integer;
|
||
|
begin
|
||
|
if DirectoryExists(FCachePath) then
|
||
|
begin
|
||
|
i := FindFirst(FCachePath + CACHE_PREFIX + '*.*', 0, SRec);
|
||
|
try
|
||
|
while i = 0 do
|
||
|
begin
|
||
|
try
|
||
|
DeleteFile(FCachePath + SRec.Name);
|
||
|
except
|
||
|
end;
|
||
|
i := FindNext(SRec);
|
||
|
end;
|
||
|
finally
|
||
|
FindClose(SRec);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.Clear;
|
||
|
begin
|
||
|
FHeap.Clear;
|
||
|
CleanUpFiles;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.Close;
|
||
|
begin
|
||
|
if FActive then
|
||
|
begin
|
||
|
Suspend;
|
||
|
Clear;
|
||
|
FActive := False;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCache.CopyCacheFileIfExist(const aFileName,
|
||
|
ReportName: String; const Variables: TfrxVariables; const Id: String;
|
||
|
const aFileFormat: TfrxServerFormat): Boolean;
|
||
|
var
|
||
|
FileIn , FileOut: TFileStream;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if Active then
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
if FHeap.IndexOf(ReportName, Variables, Id, aFileFormat) <> - 1 then
|
||
|
begin
|
||
|
FileOut := TFileStream.Create(aFileName, fmCreate);
|
||
|
FileIn := TFileStream.Create(ReportCache.CachePath + CACHE_PREFIX + ReportName, fmOpenRead or fmShareDenyWrite);
|
||
|
try
|
||
|
FileIn.Position := 0;
|
||
|
FileOut.CopyFrom(FileIn, FileIn.Size);
|
||
|
Result := FileIn.Size > 0;
|
||
|
finally
|
||
|
FileIn.Free;
|
||
|
FileOut.Free;
|
||
|
end;
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
if Result then
|
||
|
LogWriter.StatAddCacheHit;
|
||
|
end;
|
||
|
|
||
|
constructor TfrxServerCache.Create(WithInitialization: Boolean = True);
|
||
|
begin
|
||
|
inherited Create(True);
|
||
|
FMemoryCache := ServerConfig.GetValue('server.cache.target') = 'memory';
|
||
|
FActive := ServerConfig.GetValue('server.cache.active') = 'yes';
|
||
|
FLatency := StrToInt(ServerConfig.GetValue('server.cache.defaultlatency'));
|
||
|
FHeap := TfrxServerCacheSpool.Create;
|
||
|
if (WithInitialization) then
|
||
|
begin
|
||
|
FCachePath := frxGetAbsPathDir(ServerConfig.GetValue('server.cache.path'), ServerConfig.ConfigFolder);
|
||
|
FCACHE_PREFIX := '$fr_';
|
||
|
end;
|
||
|
CleanUpFiles;
|
||
|
Resume;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxServerCache.Destroy;
|
||
|
begin
|
||
|
Clear;
|
||
|
Terminate;
|
||
|
PMessages;
|
||
|
while FThreadActive do
|
||
|
Sleep(10);
|
||
|
FHeap.Free;
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.Execute;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
FThreadActive := True;
|
||
|
while not Terminated do
|
||
|
begin
|
||
|
RemoveExpired;
|
||
|
i := 0;
|
||
|
while (not Terminated) and (i < 100) do
|
||
|
begin
|
||
|
Sleep(100);
|
||
|
Inc(i);
|
||
|
PMessages;
|
||
|
end;
|
||
|
end;
|
||
|
FThreadActive := False;
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCache.GetCachedStream(const Report: TfrxReport;
|
||
|
const ReportName: String; const Variables: TfrxVariables; const Id: String): Boolean;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if Active then
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
i := FHeap.IndexOf(ReportName, Variables, Id, sfFRP);
|
||
|
if i <> -1 then
|
||
|
begin
|
||
|
try
|
||
|
FHeap.Items[i].ExpTime := Now + StrToInt(ServerConfig.GetValue('server.cache.defaultlatency')) / 86400;
|
||
|
if Assigned(FHeap.Items[i].Stream) then
|
||
|
begin
|
||
|
FHeap.Items[i].Stream.Position := 0;
|
||
|
try
|
||
|
Lock;
|
||
|
Report.PreviewPages.LoadFromStream(FHeap.Items[i].Stream);
|
||
|
finally
|
||
|
Unlock;
|
||
|
end;
|
||
|
Result := True;
|
||
|
end
|
||
|
else if FileExists(FHeap.Items[i].FileName) then
|
||
|
begin
|
||
|
try
|
||
|
Lock;
|
||
|
Report.PreviewPages.LoadFromFile(FHeap.Items[i].FileName);
|
||
|
finally
|
||
|
Unlock;
|
||
|
end;
|
||
|
Result := True;
|
||
|
end;
|
||
|
except
|
||
|
on e: Exception do
|
||
|
begin
|
||
|
LogWriter.Write(ERROR_LEVEL, DateTimeToStr(Now) + #9 + Id + #9'cache read error: ' + FHeap.Items[i].FileName + ' ' + Report.Errors.Text + e.Message);
|
||
|
LogWriter.ErrorReached;
|
||
|
Result := False;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
if Result then
|
||
|
LogWriter.StatAddCacheHit;
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCache.IsReportInCache(const ReportName: String;
|
||
|
const Variables: TfrxVariables; const Id: String; const aFileFormat: TfrxServerFormat = sfFRP): Boolean;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if Active then
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
i := FHeap.IndexOf(ReportName, Variables, Id, aFileFormat);
|
||
|
if i <> - 1 then
|
||
|
begin
|
||
|
FHeap.Items[i].ExpTime := Now + StrToInt(ServerConfig.GetValue('server.cache.defaultlatency')) / 86400;
|
||
|
Result := True;
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
if Result then
|
||
|
LogWriter.StatAddCacheHit;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.Open;
|
||
|
begin
|
||
|
if not FActive then
|
||
|
begin
|
||
|
Resume;
|
||
|
FActive := True;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.RemoveExpired;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
i := 0;
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
while i < FHeap.Count do
|
||
|
begin
|
||
|
if FHeap.Items[i].ExpTime <= Now then
|
||
|
begin
|
||
|
if Assigned(FHeap.Items[i].Stream) then
|
||
|
begin
|
||
|
FHeap.Items[i].Stream.Free;
|
||
|
FHeap.Items[i].Stream := nil;
|
||
|
end;
|
||
|
if FileExists(FHeap.Items[i].FileName) then
|
||
|
DeleteFile(FHeap.Items[i].FileName);
|
||
|
FHeap.Items[i].Free; // Delete(i);
|
||
|
end else Inc(i);
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.SetActive(const Value: Boolean);
|
||
|
begin
|
||
|
if Value <> FActive then
|
||
|
if Value then Open
|
||
|
else Close;
|
||
|
end;
|
||
|
|
||
|
function TfrxServerCache.GetCachedReportById(const Report: TfrxReport;
|
||
|
const Id: String): Boolean;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if Active then
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
for i := 0 to FHeap.Count - 1 do
|
||
|
begin
|
||
|
if FHeap.Items[i].InternalId = Id then
|
||
|
begin
|
||
|
try
|
||
|
if Assigned(FHeap.Items[i].Stream) then
|
||
|
begin
|
||
|
FHeap.Items[i].Stream.Position := 0;
|
||
|
try
|
||
|
Lock;
|
||
|
Report.PreviewPages.LoadFromStream(FHeap.Items[i].Stream);
|
||
|
finally
|
||
|
Unlock;
|
||
|
end;
|
||
|
//Result := True;
|
||
|
end
|
||
|
else if FileExists(FHeap.Items[i].FileName) then
|
||
|
begin
|
||
|
try
|
||
|
Lock;
|
||
|
Report.PreviewPages.LoadFromFile(FHeap.Items[i].FileName);
|
||
|
finally
|
||
|
Unlock;
|
||
|
end;
|
||
|
//Result := True;
|
||
|
end;
|
||
|
except
|
||
|
on e: Exception do
|
||
|
begin
|
||
|
LogWriter.Write(ERROR_LEVEL, DateTimeToStr(Now) + #9 + Id + #9'cache read error: ' + FHeap.Items[i].FileName + ' ' + Report.Errors.Text + e.Message);
|
||
|
LogWriter.ErrorReached;
|
||
|
//Result := False;
|
||
|
end;
|
||
|
end;
|
||
|
Result := True;
|
||
|
break;
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
if Result then
|
||
|
LogWriter.StatAddCacheHit;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxServerCache.AddFileFormat(const sStream: TStream;
|
||
|
const aFileFormat: TfrxServerFormat; const ReportName: String;
|
||
|
const Variables: TfrxVariables; const Id, InternalId: String);
|
||
|
begin
|
||
|
//
|
||
|
end;
|
||
|
|
||
|
{TfrxResultCache}
|
||
|
|
||
|
constructor TfrxResultCache.Create(aCachePath, aCACHE_PREFIX: String);
|
||
|
begin
|
||
|
FCachePath := aCachePath;
|
||
|
FCACHE_PREFIX := aCACHE_PREFIX;
|
||
|
inherited Create(False);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxResultCache.CleanUpFiles;
|
||
|
var
|
||
|
searchResult: TSearchRec;
|
||
|
begin
|
||
|
if FindFirst(FCachePath + CACHE_PREFIX + '*', faDirectory, searchResult) = 0 then
|
||
|
begin
|
||
|
repeat
|
||
|
RemoveAll(FCachePath + searchResult.Name);
|
||
|
until FindNext(searchResult) <> 0;
|
||
|
FindClose(searchResult);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxResultCache.AddFileFormat(const sStream: TStream; const aFileFormat: TfrxServerFormat;
|
||
|
const ReportName: String; const Variables: TfrxVariables; const Id: String; const InternalId: String);
|
||
|
var
|
||
|
Item: TfrxServerCacheItem;
|
||
|
Lat: TDateTime;
|
||
|
begin
|
||
|
if Active then
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
Lat := ReportsList.GetCacheLatency(ReportName) / 86400;
|
||
|
if Lat > 0 then
|
||
|
begin
|
||
|
Item := FHeap.Add;
|
||
|
Item.FileType := aFileFormat;
|
||
|
Item.ReportName := ReportName;
|
||
|
Item.InternalId := InternalId;
|
||
|
if Assigned(Variables) then
|
||
|
begin
|
||
|
Item.Variables := TfrxVariables.Create;
|
||
|
Item.Variables.Assign(Variables);
|
||
|
end;
|
||
|
Item.ExpTime := Now + Lat;
|
||
|
Item.FileName := FCachePath + PathDelim + Id + PathDelim+ ReportName;
|
||
|
Item.ReportName := ReportName;
|
||
|
Item.SessionId := Id;
|
||
|
sStream.Position := 0;
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxResultCache.RemoveExpired;
|
||
|
var
|
||
|
i: Integer;
|
||
|
folder: String;
|
||
|
begin
|
||
|
i := 0;
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
while i < FHeap.Count do
|
||
|
begin
|
||
|
if FHeap.Items[i].ExpTime <= Now then
|
||
|
begin
|
||
|
if FileExists(FHeap.Items[i].FileName) then
|
||
|
begin
|
||
|
DeleteFile(FHeap.Items[i].FileName);
|
||
|
folder := ExtractFileDir(FHeap.Items[i].FileName);
|
||
|
if GetFileCount(folder) = 0 then
|
||
|
RemoveDir(folder);
|
||
|
end;
|
||
|
FHeap.Items[i].Free; // Delete(i);
|
||
|
end else Inc(i);
|
||
|
end;
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxResultCache.UpdExpTime(const ReportName: String; const Variables: TfrxVariables; const SessionId: String; const aFileFormat: TfrxServerFormat);
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
if Active then
|
||
|
begin
|
||
|
CacheCS1.Enter;
|
||
|
try
|
||
|
i := FHeap.IndexOf(ReportName, Variables, SessionId, aFileFormat);
|
||
|
if i <> -1 then
|
||
|
begin
|
||
|
FHeap.Items[i].ExpTime := Now + StrToInt(ServerConfig.GetValue('server.cache.defaultlatency')) / 86400;
|
||
|
end
|
||
|
finally
|
||
|
CacheCS1.Leave;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{other function}
|
||
|
|
||
|
procedure RemoveAll(path: string);
|
||
|
var
|
||
|
sr: TSearchRec;
|
||
|
begin
|
||
|
if FindFirst(path + PathDelim + '*.*', faAnyFile, sr) = 0 then
|
||
|
begin
|
||
|
repeat
|
||
|
if sr.Attr and faDirectory = 0 then
|
||
|
begin
|
||
|
DeleteFile(path + PathDelim + sr.name);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if pos('.', sr.name) <= 0 then
|
||
|
RemoveAll(path + PathDelim + sr.name);
|
||
|
end;
|
||
|
until
|
||
|
FindNext(sr) <> 0;
|
||
|
end;
|
||
|
FindClose(sr);
|
||
|
{$IFNDEF FPC}
|
||
|
RemoveDirectory(PChar(path));
|
||
|
{$ELSE}
|
||
|
DeleteFolder(path);
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
function GetFileCount(Dir: string): Integer;
|
||
|
var
|
||
|
fs: TSearchRec;
|
||
|
begin
|
||
|
Result:=0;
|
||
|
if FindFirst(Dir + PathDelim + '*.*',faAnyFile - faDirectory - faVolumeID, fs) = 0 then
|
||
|
repeat
|
||
|
inc(Result);
|
||
|
until FindNext(fs) <> 0;
|
||
|
FindClose(fs);
|
||
|
end;
|
||
|
|
||
|
initialization
|
||
|
CacheCS1 := TCriticalSection.Create;
|
||
|
|
||
|
finalization
|
||
|
CacheCS1.Free;
|
||
|
|
||
|
end.
|