Optimized pooling and cache of frequently used object in mustache and partitioning

This commit is contained in:
Daniele Teti 2024-01-31 16:00:56 +01:00
parent d4c7e449ae
commit d1b14eb24a
2 changed files with 71 additions and 49 deletions

View File

@ -4486,42 +4486,51 @@ begin
}
if not PartitionInfoCache.TryGetValue(PartitionClause + '|' + RQLCompilerClass.ClassName, Result) then
begin
lRQLCompiler := RQLCompilerClass.Create(nil);
TMonitor.Enter(PartitionInfoCache);
try
Result := TPartitionInfo.Create;
try
lPieces := PartitionClause.Split([';']);
for lPiece in lPieces do
begin
lItems := lPiece.Split(['=', '(', ')'], TStringSplitOptions.ExcludeEmpty);
if Length(lItems) <> 3 then
begin
raise EMVCActiveRecord.Create('Invalid partitioning clause: ' + lPiece +
'. [HINT] Partioning must be in the form: "[fieldname1=(integer|string)value1]"');
end;
Result.FieldNames.Add(lItems[0]);
if lItems[1] = 'integer' then
Result.FieldTypes.Add(ftInteger)
else if lItems[1] = 'string' then
begin
Result.FieldTypes.Add(ftString)
end
else
begin
raise EMVCActiveRecord.Create('Unknown data type in partitioning: ' + lItems[1] +
'. [HINT] data type can be "integer" or "string"');
end;
Result.FieldValues.Add(lItems[2]);
end;
except
Result.Free;
raise;
if PartitionInfoCache.TryGetValue(PartitionClause + '|' + RQLCompilerClass.ClassName, Result) then
begin
Exit;
end;
lRQLCompiler := RQLCompilerClass.Create(nil);
try
Result := TPartitionInfo.Create;
try
lPieces := PartitionClause.Split([';']);
for lPiece in lPieces do
begin
lItems := lPiece.Split(['=', '(', ')'], TStringSplitOptions.ExcludeEmpty);
if Length(lItems) <> 3 then
begin
raise EMVCActiveRecord.Create('Invalid partitioning clause: ' + lPiece +
'. [HINT] Partioning must be in the form: "[fieldname1=(integer|string)value1]"');
end;
Result.FieldNames.Add(lItems[0]);
if lItems[1] = 'integer' then
Result.FieldTypes.Add(ftInteger)
else if lItems[1] = 'string' then
begin
Result.FieldTypes.Add(ftString)
end
else
begin
raise EMVCActiveRecord.Create('Unknown data type in partitioning: ' + lItems[1] +
'. [HINT] data type can be "integer" or "string"');
end;
Result.FieldValues.Add(lItems[2]);
end;
except
Result.Free;
raise;
end;
Result.InitializeFilterStrings(lRQLCompiler);
PartitionInfoCache.Add(PartitionClause + '|' + RQLCompilerClass.ClassName, Result);
finally
lRQLCompiler.Free;
end;
Result.InitializeFilterStrings(lRQLCompiler);
PartitionInfoCache.Add(PartitionClause + '|' + RQLCompilerClass.ClassName, Result);
finally
lRQLCompiler.Free;
TMonitor.Exit(PartitionInfoCache);
end;
end;
end;

View File

@ -32,7 +32,7 @@ interface
uses
MVCFramework, System.SysUtils, System.Generics.Collections,
MVCFramework.Commons, System.IOUtils, System.RTTI,
System.Classes, Data.DB, SynMustache, SynCommons;
System.Classes, Data.DB, SynMustache, SynCommons, MVCFramework.IntfObjectPool;
type
{ This class implements the mustache view engine for server side views }
@ -42,6 +42,7 @@ type
private
class var fPartials: TSynMustachePartials;
class var fHelpers: TSynMustacheHelpers;
class var fSerializerPool: IIntfObjectPool;
var FJSONModelAsString: string;
procedure LoadPartials;
procedure LoadHelpers;
@ -55,6 +56,7 @@ type
const AViewDataSets: TObjectDictionary<string, TDataSet>;
const AContentType: string); override;
class destructor Destroy;
class constructor Create;
end;
TLoadCustomHelpersProc = reference to procedure(var MustacheHelpers: TSynMustacheHelpers);
@ -107,6 +109,16 @@ begin
LoadHelpers;
end;
class constructor TMVCMustacheViewEngine.Create;
begin
fSerializerPool := MVCFramework.IntfObjectPool.TIntfObjectPool.Create(10000, 10,1,
function: IInterface
begin
Result := TMVCJsonDataObjectsSerializer.Create(nil);
RegisterOptionalCustomTypesSerializers(Result as IMVCSerializer);
end);
end;
class destructor TMVCMustacheViewEngine.Destroy;
begin
fPartials.Free;
@ -207,7 +219,7 @@ procedure TMVCMustacheViewEngine.PrepareModels;
var
DataObj: TPair<string, TValue>;
lDSPair: TPair<string, TDataSet>;
lSer: TMVCJsonDataObjectsSerializer;
lSer: IMVCSerializer;
lJSONModel: TJsonObject;
begin
if Assigned(FJSONModel) and (not Assigned(ViewModel)) and (not Assigned(ViewDataSets)) then
@ -217,9 +229,10 @@ begin
Exit;
end;
lSer := TMVCJsonDataObjectsSerializer.Create;
lSer := fSerializerPool.GetFromPool(True) as IMVCSerializer;
try
RegisterOptionalCustomTypesSerializers(lSer);
if Assigned(FJSONModel) then
begin
lJSONModel := FJSONModel.Clone as TJsonObject;
@ -233,16 +246,16 @@ begin
begin
for DataObj in ViewModel do
begin
lSer.TValueToJSONObjectProperty(lJSONModel, DataObj.Key, DataObj.Value, TMVCSerializationType.stDefault, nil, nil);
// lList := TDuckTypedList.Wrap(DataObj.Value);
// if lList <> nil then
// begin
// lSer.ListToJsonArray(lList, lJSONModel.A[DataObj.Key], TMVCSerializationType.stProperties, nil);
// end
// else
// begin
// lSer.ObjectToJsonObject(DataObj.Value, lJSONModel.O[DataObj.Key], TMVCSerializationType.stProperties, nil);
// end;
TMVCJsonDataObjectsSerializer(lSer).TValueToJSONObjectProperty(lJSONModel, DataObj.Key, DataObj.Value, TMVCSerializationType.stDefault, nil, nil);
// lList := TDuckTypedList.Wrap(DataObj.Value);
// if lList <> nil then
// begin
// lSer.ListToJsonArray(lList, lJSONModel.A[DataObj.Key], TMVCSerializationType.stProperties, nil);
// end
// else
// begin
// lSer.ObjectToJsonObject(DataObj.Value, lJSONModel.O[DataObj.Key], TMVCSerializationType.stProperties, nil);
// end;
end;
end;
@ -250,7 +263,7 @@ begin
begin
for lDSPair in ViewDataSets do
begin
lSer.DataSetToJsonArray(lDSPair.Value, lJSONModel.A[lDSPair.Key], TMVCNameCase.ncAsIs, nil);
TMVCJsonDataObjectsSerializer(lSer).DataSetToJsonArray(lDSPair.Value, lJSONModel.A[lDSPair.Key], TMVCNameCase.ncAsIs, nil);
end;
end;
FJSONModelAsString := lJSONModel.ToJSON(False);
@ -258,7 +271,7 @@ begin
lJSONModel.Free;
end;
finally
lSer.Free;
fSerializerPool.ReleaseToPool(lSer)
end;
end;