{$IfDef FPC}{$CodePage cp1251}{$EndIf FPC}
unit m3QueryResultSetFromLongintList;
// --------------------------------------------------------------------------
// Родители: "Results" <> MUID: (66FFBFC00196) :: "m3" <> MUID: (66FB10950007) :: "Shared Delphi For Archi" <> MUID: (4ABA2360025A)
// --------------------------------------------------------------------------
// Модуль: "w:\common\components\rtl\Garant\m3\m3QueryResultSetFromLongintList.pas" GeneratorVersion: 1.0.0.883901
// Стереотип: "<>"
// Элемент модели: "Tm3QueryResultSetFromLongintList" MUID: (66FFC047009C)
// --------------------------------------------------------------------------
//#UC START# *66FFC047009CbeforeDefines*
(*{$IfDef FPC}
{$IFNDEF VER3_2}
{$modeswitch functionreferences}
{$modeswitch anonymousfunctions}
{$ENDIF}
{$EndIf FPC}*)
//#UC END# *66FFC047009CbeforeDefines*
{$Include daDefine.inc}
interface
uses
l3IntfUses
, l3CProtoObject
, daQueryInterfaces
, l3LongintList
, m3IntegerToDocInfoMap
, l3Ranges
, l3Interfaces
, l3Types
, evdDATypes
, m3DocInfo
, daSchemeTypes
, l3CoreInterfaces
, m3IntegerToDocInfoMapSafe
, m3DBInterfaces
, m3IntegerToIPdaDocListAccessRecHolderMap
, m3AttrIndexInterfaces
, Classes
;
type
Tm3DocInfoHolder = class(Tl3CProtoObject, IPdaDocListAccessRecHolder)
private
f_DocInfo: Tm3DocInfo;
protected
function Get_Holded: PdaDocListAccessRec;
function Get_Name: Il3CString;
function Get_Comment: Il3CString;
procedure ClearFields; override;
public
constructor Create(const aDocInfo: Tm3DocInfo); reintroduce;
class function Make(const aDocInfo: Tm3DocInfo): IPdaDocListAccessRecHolder; reintroduce;
{$If NOT Defined(l3NoSRT)}
function SetRefTo(var thePlace: Tm3DocInfoHolder): Boolean; overload; {$If Defined(l3HasInl)}inline;{$IfEnd}
{$IfEnd} // NOT Defined(l3NoSRT)
end;//Tm3DocInfoHolder
Tm3QueryResultSetFromIl3IntegerList = class(Tl3CProtoObject, IdaQueryResultSet)
private
f_List: Il3IntegerList;
f_DocInfoMap: Tm3IntegerToDocInfoMapSafe;
f_BaseName: AnsiString;
f_InLoad: Boolean;
f_DB: Im3DB;
f_Map: Tm3IntegerToIPdaDocListAccessRecHolderMap;
f_Searcher: Im3AttrIndexSearcher;
f_Loader: TThread;
f_MapIsGlobal: Boolean;
f_SearcherForLoader: Im3AttrIndexSearcher;
protected
function GetItem(aIndex: TListIndex): IPdaDocListAccessRecHolder;
function IsEmpty: Boolean;
function Get_Count: Integer;
procedure Sort(aField: TdaSortField;
anOrder: TdaSortOrder);
procedure DelItem(anIndex: Integer);
procedure Cleanup; override;
{* Функция очистки полей объекта. }
procedure ClearFields; override;
public
constructor Create(const aList: Il3IntegerList;
const aBaseName: AnsiString); reintroduce;
class function Make(const aList: Il3IntegerList;
const aBaseName: AnsiString): IdaQueryResultSet; reintroduce;
{$If NOT Defined(l3NoSRT)}
function SetRefTo(var thePlace: Tm3QueryResultSetFromIl3IntegerList): Boolean; overload; {$If Defined(l3HasInl)}inline;{$IfEnd}
{$IfEnd} // NOT Defined(l3NoSRT)
end;//Tm3QueryResultSetFromIl3IntegerList
Tm3QueryResultSetFromLongintList = class(Tl3CProtoObject, IdaQueryResultSet)
private
f_List: Tl3LongintList;
f_BaseName: AnsiString;
f_DocInfoMap: Tm3IntegerToDocInfoMap;
protected
function GetItem(aIndex: TListIndex): IPdaDocListAccessRecHolder;
function IsEmpty: Boolean;
function Get_Count: Integer;
procedure Sort(aField: TdaSortField;
anOrder: TdaSortOrder);
procedure DelItem(anIndex: Integer);
procedure Cleanup; override;
{* Функция очистки полей объекта. }
public
constructor Create(aList: Tl3LongintList;
const aBaseName: AnsiString); reintroduce;
class function Make(aList: Tl3LongintList;
const aBaseName: AnsiString): IdaQueryResultSet; reintroduce; overload;
class function Make(const anEnumerable: Il3RangeEnumerable;
const aBaseName: AnsiString): IdaQueryResultSet; overload;
class function Make(const aList: Il3IntegerList;
const aBaseName: AnsiString): IdaQueryResultSet; overload;
{$If NOT Defined(l3NoSRT)}
function SetRefTo(var thePlace: Tm3QueryResultSetFromLongintList): Boolean; overload; {$If Defined(l3HasInl)}inline;{$IfEnd}
{$IfEnd} // NOT Defined(l3NoSRT)
end;//Tm3QueryResultSetFromLongintList
implementation
uses
l3ImplUses
, m3AttrIndexSearcher
, m3IntegerToDocInfoHolderMapGlobal
//#UC START# *66FFC047009Cimpl_uses*
{$IfDef FPC}
, LCLVersion
{$EndIf FPC}
//, Classes
, SysUtils
, l3MinMax
, l3Chars
, l3Except
, l3Base
, l3Enumerators
//, m3AttrIndexInterfaces
//, m3AttrIndexSearcher
//, m3DBInterfaces
, m3StorageInterfaces
, m3DB
, m3Exceptions
(* {$If NOT Defined(NoVCL) AND NOT Defined(NoVisual)}
, Controls
, Forms
{$IfEnd} // NOT Defined(NoVCL) AND NOT Defined(NoVisual)*)
;
type
Tm3LoaderThread = class(TThread)
private
f_Min : Integer;
f_Loader : Tm3QueryResultSetFromIl3IntegerList;
protected
procedure Execute; override;
public
constructor Create(aMin : Integer;
aLoader : Tm3QueryResultSetFromIl3IntegerList);
class procedure Run(aMin : Integer;
aLoader : Tm3QueryResultSetFromIl3IntegerList);
destructor Destroy; override;
end;//Tm3LoaderThread
const
cDelta = 4{20};
cGap = 100{60}{50};
constructor Tm3LoaderThread.Create(aMin : Integer;
aLoader : Tm3QueryResultSetFromIl3IntegerList);
begin//Tm3LoaderThread.Create
f_Min := aMin;
aLoader.SetRefTo(f_Loader);
inherited Create(true);
Self.FreeOnTerminate := true;
end;//Tm3LoaderThread.Create
class procedure Tm3LoaderThread.Run(aMin : Integer;
aLoader : Tm3QueryResultSetFromIl3IntegerList);
var
l_T : TThread;
begin//Tm3LoaderThread.Run
l_T := Self.Create(aMin, aLoader);
l_T.Resume;
end;//Tm3LoaderThread.Run
destructor Tm3LoaderThread.Destroy;
begin//Tm3LoaderThread.Destroy
if (f_Loader <> nil) then
f_Loader.f_DB := nil;
if (f_Loader <> nil) then
begin
if (f_Loader.f_Loader = Self) then
f_Loader.f_Loader := nil;
f_Loader.f_InLoad := false;
end;//f_Loader <> nil
FreeAndNil(f_Loader);
inherited;
end;//Tm3LoaderThread.Destroy
procedure Tm3LoaderThread.Execute;
var
l_L : Il3IntegerList;
l_DocInfoMap : Tm3IntegerToDocInfoMapSafe;
l_Searcher : Im3AttrIndexSearcher;
function LoadItem(anIndex: Integer): Boolean;
var
l_ID : Integer;
l_Index : Integer;
l_DocInfo : Tm3DocInfo;
begin//LoadItem
Result := false;
if (anIndex < 0) then
Exit;
if (anIndex >= l_L.Count) then
Exit;
Result := true;
l_ID := l_L[anIndex];
l_DocInfoMap.Lock;
try
if l_DocInfoMap.Has(l_ID, l_Index) then
begin
Result := false;
end//l_DocInfoMap.Has(l_ID, l_Index)
else
begin
l_DocInfo := Tm3DocInfo_C(l_ID, l_Searcher);
if not l_DocInfoMap.Has(l_ID, l_Index) then
try
l_DocInfoMap.Add(l_ID, l_DocInfo);
except
on El3DuplicateItem do
;
end;//try..except
end;//l_DocInfoMap.Has(l_ID, l_Index)
finally
l_DocInfoMap.Unlock;
end;//try..finally
end;//LoadItem
var
l_DB : Im3DB;
l_BaseName : TFileName;
i : Integer;
l_NewMin : Integer;
l_C : Integer;
l_B1, l_B2 : Boolean;
begin//Tm3LoaderThread.Execute
Assert(f_Loader <> nil);
f_Loader.f_InLoad := true;
l_BaseName := f_Loader.f_BaseName;
l_L := f_Loader.f_List;
try
l_DocInfoMap := f_Loader.f_DocInfoMap.Use;
try
try
try
l_DB := f_Loader.f_DB;
if (l_DB = nil) then
l_DB := Tm3DB.Make(l_BaseName);
Sleep(100);
l_DB.Start(m3_saRead);
try
l_Searcher := f_Loader.f_SearcherForLoader;
if (l_Searcher = nil) then
begin
if (l_DB = nil) then
l_Searcher := Tm3AttrIndexSearcher.Make(l_BaseName)
else
l_Searcher := Tm3AttrIndexSearcher.Make(l_DB);
end;//l_Searcher = nil
l_NewMin := f_Min;
l_C := Max(0, l_NewMin - cDelta - 1);
for i := 0 to cGap do
begin
l_B1 := LoadItem(l_NewMin + i);
l_B2 := LoadItem(l_C - i);
if not l_B1 AND not l_B2 then
break;
if (f_Loader.RefCount <= 1) then
break;
if l3SystemDown then
break;
if Self.Terminated then
break;
end;//for i
finally
l_DB.Finish;
end;//try..finally
except
end;//try..except
finally
f_Loader.f_InLoad := false;
end;//try..fonally
finally
FreeAndNil(l_DocInfoMap);
end;//try..finally
finally
l_L := nil;
end;//try..finally
end;//Tm3LoaderThread.Execute
const
cFakeConst = 1
//#UC END# *66FFC047009Cimpl_uses*
;
constructor Tm3DocInfoHolder.Create(const aDocInfo: Tm3DocInfo);
//#UC START# *66FFD97A0176_66FFD804003A_var*
//#UC END# *66FFD97A0176_66FFD804003A_var*
begin
//#UC START# *66FFD97A0176_66FFD804003A_impl*
Self.f_DocInfo := aDocInfo;
inherited Create;
//#UC END# *66FFD97A0176_66FFD804003A_impl*
end;//Tm3DocInfoHolder.Create
class function Tm3DocInfoHolder.Make(const aDocInfo: Tm3DocInfo): IPdaDocListAccessRecHolder;
var
l_Inst : Tm3DocInfoHolder;
begin
l_Inst := Create(aDocInfo);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//Tm3DocInfoHolder.Make
{$If NOT Defined(l3NoSRT)}
function Tm3DocInfoHolder.SetRefTo(var thePlace: Tm3DocInfoHolder): Boolean;
begin
if (thePlace = Self) then
Result := false
else
begin
Result := true;
thePlace.Free;
thePlace := Self.Use;
end;//thePlace = Self
end;//Tm3DocInfoHolder.SetRefTo
{$IfEnd} // NOT Defined(l3NoSRT)
function Tm3DocInfoHolder.Get_Holded: PdaDocListAccessRec;
//#UC START# *66FE74F4032D_66FFD804003Aget_var*
//#UC END# *66FE74F4032D_66FFD804003Aget_var*
begin
//#UC START# *66FE74F4032D_66FFD804003Aget_impl*
Result := @Self.f_DocInfo.rHTDocInfo;
//#UC END# *66FE74F4032D_66FFD804003Aget_impl*
end;//Tm3DocInfoHolder.Get_Holded
function Tm3DocInfoHolder.Get_Name: Il3CString;
//#UC START# *66FFAFC900E6_66FFD804003Aget_var*
//#UC END# *66FFAFC900E6_66FFD804003Aget_var*
begin
//#UC START# *66FFAFC900E6_66FFD804003Aget_impl*
Result := Self.f_DocInfo.rName;
//#UC END# *66FFAFC900E6_66FFD804003Aget_impl*
end;//Tm3DocInfoHolder.Get_Name
function Tm3DocInfoHolder.Get_Comment: Il3CString;
//#UC START# *66FFAFEE038D_66FFD804003Aget_var*
//#UC END# *66FFAFEE038D_66FFD804003Aget_var*
begin
//#UC START# *66FFAFEE038D_66FFD804003Aget_impl*
Result := Self.f_DocInfo.rComment;
//#UC END# *66FFAFEE038D_66FFD804003Aget_impl*
end;//Tm3DocInfoHolder.Get_Comment
procedure Tm3DocInfoHolder.ClearFields;
begin
Finalize(f_DocInfo);
inherited;
end;//Tm3DocInfoHolder.ClearFields
constructor Tm3QueryResultSetFromIl3IntegerList.Create(const aList: Il3IntegerList;
const aBaseName: AnsiString);
//#UC START# *6712417403D8_6712407F03B9_var*
var
l_Map : Tm3IntegerToDocInfoHolderMapGlobal;
//#UC END# *6712417403D8_6712407F03B9_var*
begin
//#UC START# *6712417403D8_6712407F03B9_impl*
Assert(aBaseName <> '');
f_DocInfoMap := Tm3IntegerToDocInfoMapSafe.Create;
f_DocInfoMap.Duplicates := l3_dupIgnore;
f_BaseName := aBaseName;
if (f_Map = nil) then
begin
f_Map := Tm3IntegerToDocInfoHolderMapGlobal.Instance.Use;
if (f_Map <> nil) then
begin
l_Map := Tm3IntegerToDocInfoHolderMapGlobal(f_Map);
if (l_Map.BaseName = '') then
begin
l_Map.Lock;
try
f_MapIsGlobal := true;
if (l_Map.BaseName = '') then
begin
l_Map.BaseName := Self.f_BaseName;
l_Map.Duplicates := l3_dupIgnore;
end//l_Map.BaseName = ''
else
if (l_Map.BaseName <> Self.f_BaseName) then
begin
f_MapIsGlobal := false;
FreeAndNil(f_Map);
end;//l_Map.BaseName <> Self.f_BaseName
finally
l_Map.Unlock;
end;//try..finally
end//Tm3IntegerToDocInfoHolderMapGlobal(f_Map).BaseName = ''
else
begin
if (l_Map.BaseName <> Self.f_BaseName) then
begin
f_MapIsGlobal := false;
FreeAndNil(f_Map);
end;//l_Map.BaseName <> Self.f_BaseName
end;//Tm3IntegerToDocInfoHolderMapGlobal(f_Map).BaseName = ''
end;//f_Map <> nil
if (f_Map = nil) then
begin
f_Map := Tm3IntegerToIPdaDocListAccessRecHolderMap.Create;
f_Map.Duplicates := l3_dupIgnore;
f_MapIsGlobal := false;
end;//f_Map = nil
end;//f_Map = nil
Assert(aList <> nil);
f_List := aList;
inherited Create;
//#UC END# *6712417403D8_6712407F03B9_impl*
end;//Tm3QueryResultSetFromIl3IntegerList.Create
class function Tm3QueryResultSetFromIl3IntegerList.Make(const aList: Il3IntegerList;
const aBaseName: AnsiString): IdaQueryResultSet;
var
l_Inst : Tm3QueryResultSetFromIl3IntegerList;
begin
l_Inst := Create(aList, aBaseName);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//Tm3QueryResultSetFromIl3IntegerList.Make
{$If NOT Defined(l3NoSRT)}
function Tm3QueryResultSetFromIl3IntegerList.SetRefTo(var thePlace: Tm3QueryResultSetFromIl3IntegerList): Boolean;
begin
if (thePlace = Self) then
Result := false
else
begin
Result := true;
thePlace.Free;
thePlace := Self.Use;
end;//thePlace = Self
end;//Tm3QueryResultSetFromIl3IntegerList.SetRefTo
{$IfEnd} // NOT Defined(l3NoSRT)
function Tm3QueryResultSetFromIl3IntegerList.GetItem(aIndex: TListIndex): IPdaDocListAccessRecHolder;
//#UC START# *5F3CDA8102D2_6712407F03B9_var*
var
l_ID : Integer;
l_DocInfo : Tm3DocInfo;
l_Index : Integer;
l_DB : Im3DB;
l_Map : Tm3IntegerToDocInfoHolderMapGlobal;
//#UC END# *5F3CDA8102D2_6712407F03B9_var*
begin
//#UC START# *5F3CDA8102D2_6712407F03B9_impl*
Result := nil;
l_ID := Self.f_List[aIndex];
if f_MapIsGlobal then
begin
if false then
// - положим мы считаем, что к f_Map НЕТ многопоточных обращений
l_Map := nil
else
begin
l_Map := Tm3IntegerToDocInfoHolderMapGlobal(f_Map);
if (l_Map.OtherUserThreads <= 0) then
// - нет ДРУГИХ заявленных пользователей
l_Map := nil;
end;//false
end//f_MapIsGlobal
else
l_Map := nil;
if (l_Map <> nil) then
begin
if l_Map.Has(l_ID, l_Index) then
// - double lock
begin
l_Map.Lock;
try
if l_Map.Has(l_ID, l_Index) then
begin
Result := l_Map.ItemSlot(l_Index).rValue;
Exit;
end;//l_Map.Has(l_ID, l_Index)
finally
l_Map.Unlock;
end;//try..finally
end;//if l_Map.Has(l_ID, l_Index)
end//l_Map <> nil
else
begin
if f_Map.Has(l_ID, l_Index) then
begin
Result := f_Map.ItemSlot(l_Index).rValue;
Exit;
end;//f_Map.Has(l_ID, l_Index)
end;//l_Map <> nil
while (Result = nil) do
begin
f_DocInfoMap.Lock;
try
if f_DocInfoMap.Has(l_ID, l_Index) then
begin
if f_InLoad then
begin
while true do
begin
if (f_DocInfoMap.ItemSlot(l_Index).rValue.rHTDocInfo.rID = l_ID) then
begin
Result := Tm3DocInfoHolder.Make(f_DocInfoMap.ItemSlot(l_Index).rValue);
break;
end;//l_DocInfo.rHTDocInfo.rID = l_ID
f_DocInfoMap.Unlock;
try
Sleep(100);
// - типа пусть другие нити поработают
finally
f_DocInfoMap.Lock;
end;//try..finally
if not f_DocInfoMap.Has(l_ID, l_Index) then
// - ну а "вдруг"?
break;
end;//while true
end//f_InLoad
else
Result := Tm3DocInfoHolder.Make(f_DocInfoMap.ItemSlot(l_Index).rValue);
end//f_DocInfoMap.Has(l_ID, l_Index)
else
begin
l_DB := f_DB;
try
if (f_Searcher = nil) then
f_Searcher := Tm3AttrIndexSearcher.Make(Self.f_BaseName);
if (l_DB <> nil) then
begin
while true do
begin
try
l_DB.Start(m3_saRead);
try
l_DocInfo := Tm3DocInfo_C(l_ID, f_Searcher);
break;
finally
l_DB.Finish;
end;//try..finally
except
on Em3RegionLocked do
begin
f_DocInfoMap.Unlock;
try
Sleep(100);
// - типа пусть другие нити поработают
finally
f_DocInfoMap.Lock;
end;//try..finally
continue;
end;//on Em3RegionLocked
end;//try..except
end;//while true
end//l_DB <> nil
else
begin
while true do
begin
try
l_DocInfo := Tm3DocInfo_C(l_ID, f_Searcher);
break;
except
on Em3RegionLocked do
begin
f_DocInfoMap.Unlock;
try
Sleep(100);
// - типа пусть другие нити поработают
finally
f_DocInfoMap.Lock;
end;//try..finally
continue;
end;//on Em3RegionLocked
end;//try..except
end;//while true
end;//l_DB <> nil
Result := Tm3DocInfoHolder.Make(l_DocInfo);
if not f_DocInfoMap.Has(l_ID, l_Index) then
try
f_DocInfoMap.Add(l_ID, l_DocInfo);
except
on El3DuplicateItem do
;
end;//try..except
{$IfNDef Linux}
//if false then
{$EndIf Linux}
if not f_InLoad then
begin
f_InLoad := true;
if (f_DB = nil) then
f_DB := Tm3DB.Make(f_BaseName);
if (f_SearcherForLoader = nil) then
begin
if (f_DB = nil) then
f_SearcherForLoader := Tm3AttrIndexSearcher.Make(Self.f_BaseName)
else
f_SearcherForLoader := Tm3AttrIndexSearcher.Make(f_DB);
end;//f_SearcherForLoader = nil
Tm3LoaderThread.Run(aIndex + cDelta, Self);
end;//not f_InLoad
finally
l_DB := nil;
end;//try..finally
end;//f_DocInfoMap.Has(l_ID, l_Index)
finally
f_DocInfoMap.Unlock;
end;//try..finally
end;//while (Result = nil)
if (l_Map <> nil) then
begin
l_Map.Lock;
try
l_Map.Add(l_ID, Result);
finally
l_Map.Unlock;
end;//try..finally
end//l_Map <> nil
else
f_Map.Add(l_ID, Result);
//#UC END# *5F3CDA8102D2_6712407F03B9_impl*
end;//Tm3QueryResultSetFromIl3IntegerList.GetItem
function Tm3QueryResultSetFromIl3IntegerList.IsEmpty: Boolean;
//#UC START# *5F3CDAF40370_6712407F03B9_var*
//#UC END# *5F3CDAF40370_6712407F03B9_var*
begin
//#UC START# *5F3CDAF40370_6712407F03B9_impl*
Result := f_List.Empty;
//#UC END# *5F3CDAF40370_6712407F03B9_impl*
end;//Tm3QueryResultSetFromIl3IntegerList.IsEmpty
function Tm3QueryResultSetFromIl3IntegerList.Get_Count: Integer;
//#UC START# *5F3CDB5400B2_6712407F03B9get_var*
//#UC END# *5F3CDB5400B2_6712407F03B9get_var*
begin
//#UC START# *5F3CDB5400B2_6712407F03B9get_impl*
Result := f_List.Count;
//#UC END# *5F3CDB5400B2_6712407F03B9get_impl*
end;//Tm3QueryResultSetFromIl3IntegerList.Get_Count
procedure Tm3QueryResultSetFromIl3IntegerList.Sort(aField: TdaSortField;
anOrder: TdaSortOrder);
//#UC START# *5F3CF0770195_6712407F03B9_var*
//#UC END# *5F3CF0770195_6712407F03B9_var*
begin
//#UC START# *5F3CF0770195_6712407F03B9_impl*
Assert(false);
//#UC END# *5F3CF0770195_6712407F03B9_impl*
end;//Tm3QueryResultSetFromIl3IntegerList.Sort
procedure Tm3QueryResultSetFromIl3IntegerList.DelItem(anIndex: Integer);
//#UC START# *5F3E965801BC_6712407F03B9_var*
//#UC END# *5F3E965801BC_6712407F03B9_var*
begin
//#UC START# *5F3E965801BC_6712407F03B9_impl*
//Assert(false);
// - ничего не делаем. Пусть делают Executor'ы.
//#UC END# *5F3E965801BC_6712407F03B9_impl*
end;//Tm3QueryResultSetFromIl3IntegerList.DelItem
procedure Tm3QueryResultSetFromIl3IntegerList.Cleanup;
{* Функция очистки полей объекта. }
//#UC START# *479731C50290_6712407F03B9_var*
var
l_Loader : TThread;
//#UC END# *479731C50290_6712407F03B9_var*
begin
//#UC START# *479731C50290_6712407F03B9_impl*
if (f_Loader <> nil) then
begin
l_Loader := f_Loader;
f_Loader := nil;
try
l_Loader.Terminate;
l_Loader.WaitFor;
except
end;//try..except
end;//f_Loader <> nil
f_List := nil;
try
FreeAndNil(f_DocInfoMap);
finally
try
FreeAndNil(f_Map);
finally
f_SearcherForLoader := nil;
f_Searcher := nil;
f_DB := nil;
inherited;
end;//try..finally
end;//try..finally
//#UC END# *479731C50290_6712407F03B9_impl*
end;//Tm3QueryResultSetFromIl3IntegerList.Cleanup
procedure Tm3QueryResultSetFromIl3IntegerList.ClearFields;
begin
f_List := nil;
f_DB := nil;
f_Searcher := nil;
f_SearcherForLoader := nil;
inherited;
end;//Tm3QueryResultSetFromIl3IntegerList.ClearFields
constructor Tm3QueryResultSetFromLongintList.Create(aList: Tl3LongintList;
const aBaseName: AnsiString);
//#UC START# *66FFC0D1036A_66FFC047009C_var*
//#UC END# *66FFC0D1036A_66FFC047009C_var*
begin
//#UC START# *66FFC0D1036A_66FFC047009C_impl*
f_DocInfoMap := Tm3IntegerToDocInfoMap.Create;
f_DocInfoMap.Duplicates := l3_dupIgnore;
f_BaseName := aBaseName;
aList.SetRefTo(f_List);
inherited Create;
//#UC END# *66FFC0D1036A_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.Create
class function Tm3QueryResultSetFromLongintList.Make(aList: Tl3LongintList;
const aBaseName: AnsiString): IdaQueryResultSet;
var
l_Inst : Tm3QueryResultSetFromLongintList;
begin
l_Inst := Create(aList, aBaseName);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//Tm3QueryResultSetFromLongintList.Make
class function Tm3QueryResultSetFromLongintList.Make(const anEnumerable: Il3RangeEnumerable;
const aBaseName: AnsiString): IdaQueryResultSet;
//#UC START# *66FFC42A0297_66FFC047009C_var*
var
l_List : Tl3LongintList;
l_It : Il3IntegerEnumerator;
//#UC END# *66FFC42A0297_66FFC047009C_var*
begin
//#UC START# *66FFC42A0297_66FFC047009C_impl*
l_List := Tl3LongintList.CreateSorted;
try
l_It := Il3RangeEnumerable_GetIntegerEnumerator(anEnumerable);
if (l_It <> nil) then
while l_It.MoveNext do
l_List.Add(l_It.Current);
Result := Self.Make(l_List, aBaseName);
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *66FFC42A0297_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.Make
class function Tm3QueryResultSetFromLongintList.Make(const aList: Il3IntegerList;
const aBaseName: AnsiString): IdaQueryResultSet;
//#UC START# *671240EF005F_66FFC047009C_var*
//#UC END# *671240EF005F_66FFC047009C_var*
begin
//#UC START# *671240EF005F_66FFC047009C_impl*
Result := Tm3QueryResultSetFromIl3IntegerList.Make(aList, aBaseName);
//#UC END# *671240EF005F_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.Make
{$If NOT Defined(l3NoSRT)}
function Tm3QueryResultSetFromLongintList.SetRefTo(var thePlace: Tm3QueryResultSetFromLongintList): Boolean;
begin
if (thePlace = Self) then
Result := false
else
begin
Result := true;
thePlace.Free;
thePlace := Self.Use;
end;//thePlace = Self
end;//Tm3QueryResultSetFromLongintList.SetRefTo
{$IfEnd} // NOT Defined(l3NoSRT)
function Tm3QueryResultSetFromLongintList.GetItem(aIndex: TListIndex): IPdaDocListAccessRecHolder;
//#UC START# *5F3CDA8102D2_66FFC047009C_var*
var
l_ID : Integer;
l_DocInfo : Tm3DocInfo;
l_Index : Integer;
//#UC END# *5F3CDA8102D2_66FFC047009C_var*
begin
//#UC START# *5F3CDA8102D2_66FFC047009C_impl*
l_ID := Self.f_List[aIndex];
if f_DocInfoMap.Has(l_ID, l_Index) then
Result := Tm3DocInfoHolder.Make(f_DocInfoMap.ItemSlot(l_Index).rValue)
else
begin
l_DocInfo := Tm3DocInfo_C(l_ID, Self.f_BaseName);
f_DocInfoMap.Add(l_ID, l_DocInfo);
Result := Tm3DocInfoHolder.Make(l_DocInfo);
end;//f_DocInfoMap.Has(l_ID, l_Index)
//#UC END# *5F3CDA8102D2_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.GetItem
function Tm3QueryResultSetFromLongintList.IsEmpty: Boolean;
//#UC START# *5F3CDAF40370_66FFC047009C_var*
//#UC END# *5F3CDAF40370_66FFC047009C_var*
begin
//#UC START# *5F3CDAF40370_66FFC047009C_impl*
Result := f_List.Empty;
//#UC END# *5F3CDAF40370_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.IsEmpty
function Tm3QueryResultSetFromLongintList.Get_Count: Integer;
//#UC START# *5F3CDB5400B2_66FFC047009Cget_var*
//#UC END# *5F3CDB5400B2_66FFC047009Cget_var*
begin
//#UC START# *5F3CDB5400B2_66FFC047009Cget_impl*
Result := f_List.Count;
//#UC END# *5F3CDB5400B2_66FFC047009Cget_impl*
end;//Tm3QueryResultSetFromLongintList.Get_Count
procedure Tm3QueryResultSetFromLongintList.Sort(aField: TdaSortField;
anOrder: TdaSortOrder);
//#UC START# *5F3CF0770195_66FFC047009C_var*
//#UC END# *5F3CF0770195_66FFC047009C_var*
begin
//#UC START# *5F3CF0770195_66FFC047009C_impl*
Assert(false);
//#UC END# *5F3CF0770195_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.Sort
procedure Tm3QueryResultSetFromLongintList.DelItem(anIndex: Integer);
//#UC START# *5F3E965801BC_66FFC047009C_var*
//#UC END# *5F3E965801BC_66FFC047009C_var*
begin
//#UC START# *5F3E965801BC_66FFC047009C_impl*
Assert(false);
//#UC END# *5F3E965801BC_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.DelItem
procedure Tm3QueryResultSetFromLongintList.Cleanup;
{* Функция очистки полей объекта. }
//#UC START# *479731C50290_66FFC047009C_var*
//#UC END# *479731C50290_66FFC047009C_var*
begin
//#UC START# *479731C50290_66FFC047009C_impl*
FreeAndNil(f_List);
FreeAndNil(f_DocInfoMap);
inherited;
//#UC END# *479731C50290_66FFC047009C_impl*
end;//Tm3QueryResultSetFromLongintList.Cleanup
//#UC START# *66FFC047009CforDiagramm*
(*
[*
=============================================================================
m3QueryResultSetFromLongintList
Преобразование списка ID документов в выборку для GUI
=============================================================================
IdaQueryResultSet (интерфейс)
- GetItem(aIndex): IPdaDocListAccessRecHolder // получить документ
- Count: Integer // количество
- Empty: Boolean // пусто?
- Sort(aField, anOrder) // сортировка (not impl)
- DelItem(anIndex) // удалить (not impl)
Tm3QueryResultSetFromLongintList Tm3QueryResultSetFromIl3IntegerList
(простая версия) (с фоновой загрузкой)
Поля: Поля:
- f_List: Tl3LongintList - f_List: Il3IntegerList
- f_BaseName: AnsiString - f_BaseName: AnsiString
- f_DocInfoMap: Tm3IntegerToDocInfoMap - f_DocInfoMap: Tm3IntegerToDocInfoMapSafe
- f_DB: Im3DB
- f_Searcher: Im3AttrIndexSearcher
- f_Loader: TThread
- f_Map: глобальный кэш
GetItem: GetItem:
1. l_ID := f_List[aIndex] 1. l_ID := f_List[aIndex]
2. if f_DocInfoMap.Has(l_ID) then 2. if f_Map.Has(l_ID) then
взять из кэша взять из глобального кэша
else else if f_DocInfoMap.Has then
l_DocInfo := Tm3DocInfo_C взять из локального кэша
f_DocInfoMap.Add(l_ID, ...) else
Result := Tm3DocInfoHolder l_DocInfo := Tm3DocInfo_C
f_DocInfoMap.Add(...)
запустить фоновую загрузку
Tm3DocInfoHolder
(holder для IPdaDocListAccessRecHolder)
Поля:
f_DocInfo: Tm3DocInfo
Методы:
Get_Holded: PdaDocListAccessRec // указатель на структуру
Get_Name: Il3CString // имя документа
Get_Comment: Il3CString // комментарий
Tm3DocInfo
(структура документа для списка)
Поля:
rHTDocInfo: TdaDocListAccessRec // ID, внешний ID, тип, активность
rName: Il3CString // имя (интернированная строка)
rComment: Il3CString // комментарий
TdaDocListAccessRec
(структура из HyTech, статические буферы)
Поля:
rID: TdaDocID // внутренний ID
rExtID: TdaDocID // внешний ID
rTyp: Byte // тип документа (dtLaw, dtLetter...)
rFlag: Byte // флаги (версия, активность)
rName: array[1..255] of AnsiChar // имя (статический буфер)
rUrgency: Byte // срочность
rStatus: Word // статус
rIsActive: LongBool // активен?
rIsInclude: LongBool (опц.) // включён в выборку?
rComment: array[1..255] of AnsiChar // комментарий
=============================================================================
ФОНОВАЯ ЗАГРУЗКА
=============================================================================
Tm3QueryResultSetFromIl3IntegerList (новая версия)
запрос первого документа
GetItem(0)
1. Загружает документ
2. Запускает фоновый поток: Tm3LoaderThread.Run(aIndex + cDelta, Self)
cDelta = 4 // загружать на 4 документа вперёд
Tm3LoaderThread (поток)
Execute:
for i := 0 to cGap do
LoadItem(l_NewMin + i) // загрузить следующие документы
LoadItem(l_C - i) // загрузить предыдущие документы
cGap = 100 // порция загрузки
=============================================================================
КЭШИРОВАНИЕ
=============================================================================
Три уровня кэширования
Уровень 1: Глобальный кэш (f_Map)
- Tm3IntegerToDocInfoHolderMapGlobal
- Разделяется между всеми выборками из одной базы
- Потокобезопасный (Lock/Unlock)
Уровень 2: Локальный кэш (f_DocInfoMap)
- Tm3IntegerToDocInfoMapSafe
- Принадлежит конкретному экземпляру выборки
- Заполняется фоновым потоком
Уровень 3: Внутренний кэш (f_List)
- Il3IntegerList
- Список ID документов в выборке
=============================================================================
ПОТОК ЗАГРУЗКИ
=============================================================================
Tm3LoaderThread
Параметры:
cDelta = 4 // сколько документов загружать вперёд
cGap = 100 // максимальная порция загрузки
Алгоритм:
l_NewMin := текущий индекс
for i := 0 to cGap do
LoadItem(l_NewMin + i) // загрузить вперёд
LoadItem(l_C - i) // загрузить назад
Защита:
- if RefCount <= 1 then break // объект уничтожается
- if Terminated then break // поток остановлен
- if l3SystemDown then break // система завершается
=============================================================================
ОБРАБОТКА БЛОКИРОВОК
=============================================================================
Защита от Em3RegionLocked
while true do
begin
try
l_DocInfo := Tm3DocInfo_C(l_ID, f_Searcher);
break;
except
on Em3RegionLocked do
begin
f_DocInfoMap.Unlock;
Sleep(100); // подождать, пока другой поток отпустит
f_DocInfoMap.Lock;
continue; // попробовать снова
end;
end;
end;
=============================================================================
ПОЛНЫЙ ПОТОК ДАННЫХ
=============================================================================
Индексы (m3AttrIndex)
SearchByType(dtLaw) Il3RangeEnumerable
Il3RangeEnumerable_GetIntegerEnumerator Il3IntegerEnumerator
Tl3LongintList / Il3IntegerList (список ID)
Tm3QueryResultSetFromLongintList / Tm3QueryResultSetFromIl3IntegerList
GetItem(index) Tm3DocInfoHolder
Tm3DocInfo_C(ID, aSearcher)
Im3AttrIndexSearcher:
- InternalHandleToExternalHandle(ID) внешний ID
- TypeByID(ID) тип документа
- UserTypeByID(ID) флаги
- NameByInternalHandle(ID) имя (Il3CString)
- CommentByInternalHandle(ID) комментарий
TdaDocListAccessRec (статический буфер) + Il3CString
IPdaDocListAccessRecHolder GUI
=============================================================================
КЛЮЧЕВЫЕ ПРИНЦИПЫ
=============================================================================
1. ЛЕНИВАЯ ЗАГРУЗКА
- Документы загружаются только при обращении к GetItem
- Не загружаем всю выборку целиком
2. ФОНОВАЯ ПРЕДЗАГРУЗКА
- При запросе первого документа запускается поток
- Поток загружает следующие cGap = 100 документов
- Пользователь не ждёт при скроллинге
3. КЭШИРОВАНИЕ
- Глобальный кэш для всех выборок из одной базы
- Локальный кэш для конкретной выборки
- Дубликаты игнорируются (l3_dupIgnore)
4. ЗАЩИТА ОТ БЛОКИРОВОК
- При Em3RegionLocked ждём 100 мс и пробуем снова
- Не падаем, если документ временно недоступен
5. ДВЕ РЕАЛИЗАЦИИ
- Простая: Tm3QueryResultSetFromLongintList (синхронная)
- Продвинутая: Tm3QueryResultSetFromIl3IntegerList (с фоновой загрузкой)
=============================================================================
*]
*)
//#UC END# *66FFC047009CforDiagramm*
end.
Заметки о тестировании, программировании и прочий "поток сознания", который жалко писать "в стол"
воскресенье, 12 апреля 2026 г.
m3QueryResultSetFromLongintList
Подписаться на:
Комментарии к сообщению (Atom)
Комментариев нет:
Отправить комментарий