воскресенье, 12 апреля 2026 г.

m3QueryResultSetFromLongintList

{$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.

Комментариев нет:

Отправить комментарий