{$IfDef FPC}{$CodePage cp1251}{$EndIf FPC}
unit m3AttrIndexDumperJoin;
// --------------------------------------------------------------------------
// Родители: "Attributes" <> MUID: (667D35D300BC) :: "m3" <> MUID: (548712F60101) :: "Shared Delphi Low Level" <> MUID: (4ABCC25A0322)
// --------------------------------------------------------------------------
// Модуль: "w:\common\components\rtl\Garant\m3\m3AttrIndexDumperJoin.pas" GeneratorVersion: 1.0.0.883901
// Стереотип: "<>"
// Элемент модели: "Tm3AttrIndexDumperJoin" MUID: (67175F5B013B)
// --------------------------------------------------------------------------
//#UC START# *67175F5B013BbeforeDefines*
//#UC END# *67175F5B013BbeforeDefines*
{$Include m3Define.inc}
interface
uses
l3IntfUses
, l3CProtoObject
, m3SearcherInterfaces
, l3Ranges
, l3CoreInterfaces
, SysUtils
, m3AttrDumperEnum
, Im3AttrIndexDumperList
, m3IndexElements
;
type
Tm3AttrIndexDumperJoinProxy = class(Tl3CProtoObject, Im3AttrIndexDumper)
{* [RequestLink:902333387] }
private
f_Last: Im3AttrIndexDumper;
{* Последний в цепочке }
f_OtherJoin: Im3AttrIndexDumper;
f_Files: Im3FilesEnumerable;
f_TimeStamp: TDateTime;
f_IsDirect: Boolean;
f_Modified: Il3RangeEnumerable;
f_Count: Integer;
f_MinKeyID: Integer;
f_MaxKeyID: Integer;
f_Others: TIm3AttrIndexDumperList;
f_SearchMode: Tm3SearchMode;
f_OthersForSeq: TIm3AttrIndexDumperList;
{* "Другие" для последовательного перебора }
private
procedure CheckOther;
protected
function pm_GetFirst: Il3RangeEnumerable;
function pm_GetLast: Il3RangeEnumerable;
function pm_GetCount: Integer;
function ModifiedDocuments: Il3RangeEnumerable;
function IndexedVersions: Im3IndexedVersions;
function Get_Range: Tm3IDRange;
function ValuesByKey(aKey: Integer): Il3RangeEnumerable;
function TimeStamp: TDateTime;
function Get_MaxKeyID: Integer;
function Get_Operation: Tm3GroupOperation;
function Get_MinKeyID: Integer;
procedure Set_SearchMode(aValue: Tm3SearchMode);
function Get_Sequential: Boolean;
function ToTheLeftOf(const anOther: Im3AttrIndexDumper): Boolean;
procedure Cleanup; override;
{* Функция очистки полей объекта. }
procedure ClearFields; override;
public
constructor Create(const aFiles: Im3FilesEnumerable;
aIsDirect: Boolean); reintroduce;
class function Make(const aFiles: Im3FilesEnumerable;
aIsDirect: Boolean): Im3AttrIndexDumper; reintroduce;
{$If NOT Defined(l3NoSRT)}
function SetRefTo(var thePlace: Tm3AttrIndexDumperJoinProxy): Boolean; overload; {$If Defined(l3HasInl)}inline;{$IfEnd}
{$IfEnd} // NOT Defined(l3NoSRT)
function GetEnumerator: Im3AttrIndexElementEnumerator;
{* Получает Enumerator для перебора элементов "контейнера".
Вся эта конструкция совместима с "синтаксическим сахаром" вида:
for Item in Container do Process(Item);
Который поддерживается в "новых" Delphi.
См. http://mdp.garant.ru/pages/viewpage.action?pageId=152961307 }
public
property First: Il3RangeEnumerable
read pm_GetFirst;
{* Первый элемент. }
property Last: Il3RangeEnumerable
read pm_GetLast;
{* Последний элемент. }
property Count: Integer
read pm_GetCount;
{* Число элементов. }
end;//Tm3AttrIndexDumperJoinProxy
Tm3AttrIndexDumperJoin = class(Tl3CProtoObject, Im3AttrIndexDumper)
private
f_Main: Im3AttrIndexDumper;
f_Delta: Im3AttrIndexDumper;
f_IsDirect: Boolean;
f_Modified: Il3RangeEnumerable;
f_Versions: Im3IndexedVersions;
f_Count: Integer;
protected
function pm_GetFirst: Il3RangeEnumerable;
function pm_GetLast: Il3RangeEnumerable;
function pm_GetCount: Integer;
function ModifiedDocuments: Il3RangeEnumerable;
function IndexedVersions: Im3IndexedVersions;
function Get_Range: Tm3IDRange;
function ValuesByKey(aKey: Integer): Il3RangeEnumerable;
function TimeStamp: TDateTime;
function Get_MaxKeyID: Integer;
function Get_Operation: Tm3GroupOperation;
function Get_MinKeyID: Integer;
procedure Set_SearchMode(aValue: Tm3SearchMode);
function Get_Sequential: Boolean;
function ToTheLeftOf(const anOther: Im3AttrIndexDumper): Boolean;
procedure Cleanup; override;
{* Функция очистки полей объекта. }
procedure ClearFields; override;
public
constructor Create(const aMain: Im3AttrIndexDumper;
const aDelta: Im3AttrIndexDumper;
aIsDirect: Boolean); reintroduce;
class function MakePrim(const aMain: Im3AttrIndexDumper;
const aDelta: Im3AttrIndexDumper;
aIsDirect: Boolean): Im3AttrIndexDumper; reintroduce;
class function Make(const aMain: Im3AttrIndexDumper;
const aDelta: Im3AttrIndexDumper;
aIsDirect: Boolean): Im3AttrIndexDumper;
class function MakeFromMask(const aMask: TFileName;
aIsDirect: Boolean): Im3AttrIndexDumper;
class function MakeFromFilesEnum(const aFiles: Im3FilesEnumerator;
aIsDirect: Boolean): Im3AttrIndexDumper;
class function MakeFromFiles(const aFiles: Im3FilesEnumerable;
aIsDirect: Boolean): Im3AttrIndexDumper;
class function MakeFromList(const aList: Im3AttrIndexDumperEnumerable;
aIsDirect: Boolean): Im3AttrIndexDumper;
class function MakeForAttribute(const aBaseName: TFileName;
anAttrID: Integer;
aIsDirect: Boolean): Im3AttrIndexDumper; overload;
class function MakeForAttribute(const aBaseName: TFileName;
const anAttrName: AnsiString;
aIsDirect: Boolean): Im3AttrIndexDumper; overload;
class function MakeForAttribute(const aBaseName: TFileName;
const anAttrID: array of Integer;
aIsDirect: Boolean): Im3AttrIndexDumper; overload;
class function MakeNameForAttr(const aName: Il3CString;
const anAttrID: AnsiString;
aIsDirect: Boolean): Il3CString;
class function MakeFilesForAttr(const aFiles: Im3FilesEnumerable;
const anAttrID: AnsiString;
aIsDirect: Boolean): Im3FilesEnumerable;
{$If NOT Defined(l3NoSRT)}
function SetRefTo(var thePlace: Tm3AttrIndexDumperJoin): Boolean; overload; {$If Defined(l3HasInl)}inline;{$IfEnd}
{$IfEnd} // NOT Defined(l3NoSRT)
function GetEnumerator: Im3AttrIndexElementEnumerator;
{* Получает Enumerator для перебора элементов "контейнера".
Вся эта конструкция совместима с "синтаксическим сахаром" вида:
for Item in Container do Process(Item);
Который поддерживается в "новых" Delphi.
См. http://mdp.garant.ru/pages/viewpage.action?pageId=152961307 }
public
property First: Il3RangeEnumerable
read pm_GetFirst;
{* Первый элемент. }
property Last: Il3RangeEnumerable
read pm_GetLast;
{* Последний элемент. }
property Count: Integer
read pm_GetCount;
{* Число элементов. }
end;//Tm3AttrIndexDumperJoin
Tm3AttrIndexDumperJoinProxy_IndexElement = class(Tl3CProtoObject, Im3AttrIndexElement)
private
f_ID: Integer;
f_Values: Il3RangeEnumerable;
protected
function Get_ID: Integer;
function Get_Values: Il3RangeEnumerable;
procedure Cleanup; override;
{* Функция очистки полей объекта. }
procedure ClearFields; override;
public
constructor Create(anID: Integer;
const aValues: Il3RangeEnumerable); reintroduce;
class function Make(anID: Integer;
const aValues: Il3RangeEnumerable): Im3AttrIndexElement; reintroduce;
{$If NOT Defined(l3NoSRT)}
function SetRefTo(var thePlace: Tm3AttrIndexDumperJoinProxy_IndexElement): Boolean; overload; {$If Defined(l3HasInl)}inline;{$IfEnd}
{$IfEnd} // NOT Defined(l3NoSRT)
end;//Tm3AttrIndexDumperJoinProxy_IndexElement
Tm3AttrIndexDumperJoinProxy_Enumerator = class(Tl3CProtoObject, Im3AttrIndexElementEnumerator)
private
f_Proxy: Tm3AttrIndexDumperJoinProxy;
f_Current: Im3AttrIndexElement;
f_Min: Integer;
f_Max: Integer;
f_Key: Integer;
f_Values: Il3RangeEnumerable;
protected
function Get_Current: Im3AttrIndexElement;
procedure Cleanup; override;
{* Функция очистки полей объекта. }
procedure ClearFields; override;
public
constructor Create(aProxy: Tm3AttrIndexDumperJoinProxy); reintroduce;
class function Make(aProxy: Tm3AttrIndexDumperJoinProxy): Im3AttrIndexElementEnumerator; reintroduce;
{$If NOT Defined(l3NoSRT)}
function SetRefTo(var thePlace: Tm3AttrIndexDumperJoinProxy_Enumerator): Boolean; overload; {$If Defined(l3HasInl)}inline;{$IfEnd}
{$IfEnd} // NOT Defined(l3NoSRT)
function MoveNext: Boolean;
{* Перемещается на следующий элемент контейнера.
Возвращает true если элемент валидный. }
function pCurrent: Im3AttrIndexElementEnumerator_PCurrentItemType;
{* Указатель на текущий элемент. Он "закеширован" }
function CanMoveNext: Boolean;
{* Определяет - можно ли переместиться на следующий элемент контейнера. }
public
property Current: Im3AttrIndexElement
read Get_Current;
{* Текущий элемент. Он "закеширован" }
end;//Tm3AttrIndexDumperJoinProxy_Enumerator
implementation
uses
l3ImplUses
, m3AttrIndexDumper
, m3IndexedVersionsSortedJoin
, Im3AttrIndexDumperByTimeStampList
, Im3AttrIndexElementEnumeratorWithFilteredModified
, Im3AttrIndexElementEnumeratorSortedJoin
, Im3DirectAttrIndexElementEnumeratorSortedJoin
, DateUtils
, Math
//#UC START# *67175F5B013Bimpl_uses*
, Types
{$IfDef Linux}
{$IfDef AppClientSide}
, ddClientBaseEngine
{$EndIf AppClientSide}
{$EndIf Linux}
//, SysUtils
, l3MinMax
, l3Base
, l3String
, l3Stubs
, l3FileUtils
, l3Date
, l3StringList
, l3PrimString
, l3SharedConstString
, k2Attributes
//, Im3DirectAttrIndexElementEnumeratorWithFilteredModified
//, Im3DirectAttrIndexElementEnumeratorSortedJoin
, m3DBHelper
, m3StorageHolderList
, l3Enumerators
//#UC END# *67175F5B013Bimpl_uses*
;
type
TIm3DirectAttrIndexElementEnumeratorWithFilteredModified = class(Tl3CProtoObject, Im3AttrIndexElementEnumerator)
private
f_Other: Im3AttrIndexElementEnumerator;
f_Modified: Il3RangeEnumerable;
f_ModifiedIt: Il3RangeEnumerator;
protected
function Get_Current: Im3AttrIndexElement;
procedure ClearFields; override;
public
constructor Create(const anOther: Im3AttrIndexElementEnumerator;
const aModified: Il3RangeEnumerable); reintroduce;
class function Make(const anOther: Im3AttrIndexElementEnumerator;
const aModified: Il3RangeEnumerable): Im3AttrIndexElementEnumerator; reintroduce;
function MoveNext: Boolean;
{* Перемещается на следующий элемент контейнера.
Возвращает true если элемент валидный. }
function pCurrent: Im3AttrIndexElementEnumerator_PCurrentItemType;
{* Указатель на текущий элемент. Он "закеширован" }
function CanMoveNext: Boolean;
{* Определяет - можно ли переместиться на следующий элемент контейнера. }
public
property Current: Im3AttrIndexElement
read Get_Current;
{* Текущий элемент. Он "закеширован" }
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified
constructor Tm3AttrIndexDumperJoinProxy_IndexElement.Create(anID: Integer;
const aValues: Il3RangeEnumerable);
//#UC START# *69BB4759017E_69BB46D900B8_var*
//#UC END# *69BB4759017E_69BB46D900B8_var*
begin
//#UC START# *69BB4759017E_69BB46D900B8_impl*
inherited Create;
f_ID := anID;
f_Values := aValues;
//#UC END# *69BB4759017E_69BB46D900B8_impl*
end;//Tm3AttrIndexDumperJoinProxy_IndexElement.Create
class function Tm3AttrIndexDumperJoinProxy_IndexElement.Make(anID: Integer;
const aValues: Il3RangeEnumerable): Im3AttrIndexElement;
var
l_Inst : Tm3AttrIndexDumperJoinProxy_IndexElement;
begin
l_Inst := Create(anID, aValues);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//Tm3AttrIndexDumperJoinProxy_IndexElement.Make
{$If NOT Defined(l3NoSRT)}
function Tm3AttrIndexDumperJoinProxy_IndexElement.SetRefTo(var thePlace: Tm3AttrIndexDumperJoinProxy_IndexElement): Boolean;
begin
if (thePlace = Self) then
Result := false
else
begin
Result := true;
thePlace.Free;
thePlace := Self.Use;
end;//thePlace = Self
end;//Tm3AttrIndexDumperJoinProxy_IndexElement.SetRefTo
{$IfEnd} // NOT Defined(l3NoSRT)
function Tm3AttrIndexDumperJoinProxy_IndexElement.Get_ID: Integer;
//#UC START# *666AD8510295_69BB46D900B8get_var*
//#UC END# *666AD8510295_69BB46D900B8get_var*
begin
//#UC START# *666AD8510295_69BB46D900B8get_impl*
Result := f_ID;
//#UC END# *666AD8510295_69BB46D900B8get_impl*
end;//Tm3AttrIndexDumperJoinProxy_IndexElement.Get_ID
function Tm3AttrIndexDumperJoinProxy_IndexElement.Get_Values: Il3RangeEnumerable;
//#UC START# *666ADD3000B4_69BB46D900B8get_var*
//#UC END# *666ADD3000B4_69BB46D900B8get_var*
begin
//#UC START# *666ADD3000B4_69BB46D900B8get_impl*
Result := f_Values;
//#UC END# *666ADD3000B4_69BB46D900B8get_impl*
end;//Tm3AttrIndexDumperJoinProxy_IndexElement.Get_Values
procedure Tm3AttrIndexDumperJoinProxy_IndexElement.Cleanup;
{* Функция очистки полей объекта. }
//#UC START# *479731C50290_69BB46D900B8_var*
//#UC END# *479731C50290_69BB46D900B8_var*
begin
//#UC START# *479731C50290_69BB46D900B8_impl*
f_Values := nil;
inherited;
//#UC END# *479731C50290_69BB46D900B8_impl*
end;//Tm3AttrIndexDumperJoinProxy_IndexElement.Cleanup
procedure Tm3AttrIndexDumperJoinProxy_IndexElement.ClearFields;
begin
f_Values := nil;
inherited;
end;//Tm3AttrIndexDumperJoinProxy_IndexElement.ClearFields
constructor Tm3AttrIndexDumperJoinProxy_Enumerator.Create(aProxy: Tm3AttrIndexDumperJoinProxy);
//#UC START# *69BB238C0112_69BB232003AC_var*
//#UC END# *69BB238C0112_69BB232003AC_var*
begin
//#UC START# *69BB238C0112_69BB232003AC_impl*
Assert(aProxy <> nil);
inherited Create;
aProxy.SetRefTo(f_Proxy);
f_Proxy.Set_SearchMode(m3_smSeq);
f_Min := f_Proxy.Get_MinKeyID;
f_Max := f_Proxy.Get_MaxKeyID;
Assert(f_Min > Low(f_Min));
f_Key := f_Min - 1;
f_Proxy.CheckOther;
//#UC END# *69BB238C0112_69BB232003AC_impl*
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.Create
class function Tm3AttrIndexDumperJoinProxy_Enumerator.Make(aProxy: Tm3AttrIndexDumperJoinProxy): Im3AttrIndexElementEnumerator;
var
l_Inst : Tm3AttrIndexDumperJoinProxy_Enumerator;
begin
l_Inst := Create(aProxy);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.Make
{$If NOT Defined(l3NoSRT)}
function Tm3AttrIndexDumperJoinProxy_Enumerator.SetRefTo(var thePlace: Tm3AttrIndexDumperJoinProxy_Enumerator): Boolean;
begin
if (thePlace = Self) then
Result := false
else
begin
Result := true;
thePlace.Free;
thePlace := Self.Use;
end;//thePlace = Self
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.SetRefTo
{$IfEnd} // NOT Defined(l3NoSRT)
function Tm3AttrIndexDumperJoinProxy_Enumerator.MoveNext: Boolean;
{* Перемещается на следующий элемент контейнера.
Возвращает true если элемент валидный. }
//#UC START# *5ACB6780016E_69BB232003AC_var*
var
l_Values : Il3RangeEnumerable;
//#UC END# *5ACB6780016E_69BB232003AC_var*
begin
//#UC START# *5ACB6780016E_69BB232003AC_impl*
Result := false;
while CanMoveNext do
begin
Inc(f_Key);
if (f_Key <= f_Max) then
begin
l_Values := f_Proxy.ValuesByKey(f_Key);
f_Values := l_Values;
// - себе на всякий случай запомним
if (l_Values <> nil) then
// - ключу соответствует непустое значение
begin
f_Current := Tm3AttrIndexDumperJoinProxy_IndexElement.Make(f_Key, l_Values);
Result := true;
// - элемент найден
Exit;
// - выходим
end;//l_Values <> nil
end//f_Key <= f_Max
else
// - ушли за конец
break;
// - отваливаем
end;//while CanMoveNext
if not Result then
begin
f_Values := nil;
f_Current := nil;
if (f_Proxy <> nil) then
f_Proxy.Set_SearchMode(m3_smRandom);
end;//not Result
//#UC END# *5ACB6780016E_69BB232003AC_impl*
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.MoveNext
function Tm3AttrIndexDumperJoinProxy_Enumerator.pCurrent: Im3AttrIndexElementEnumerator_PCurrentItemType;
{* Указатель на текущий элемент. Он "закеширован" }
//#UC START# *5C4EFC140038_69BB232003AC_var*
//#UC END# *5C4EFC140038_69BB232003AC_var*
begin
//#UC START# *5C4EFC140038_69BB232003AC_impl*
Result := @f_Current;
//#UC END# *5C4EFC140038_69BB232003AC_impl*
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.pCurrent
function Tm3AttrIndexDumperJoinProxy_Enumerator.CanMoveNext: Boolean;
{* Определяет - можно ли переместиться на следующий элемент контейнера. }
//#UC START# *5E60D4B30164_69BB232003AC_var*
//#UC END# *5E60D4B30164_69BB232003AC_var*
begin
//#UC START# *5E60D4B30164_69BB232003AC_impl*
Result := (f_Key < f_Max);
//#UC END# *5E60D4B30164_69BB232003AC_impl*
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.CanMoveNext
function Tm3AttrIndexDumperJoinProxy_Enumerator.Get_Current: Im3AttrIndexElement;
//#UC START# *6739C0470374_69BB232003ACget_var*
//#UC END# *6739C0470374_69BB232003ACget_var*
begin
//#UC START# *6739C0470374_69BB232003ACget_impl*
Result := f_Current;
//#UC END# *6739C0470374_69BB232003ACget_impl*
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.Get_Current
procedure Tm3AttrIndexDumperJoinProxy_Enumerator.Cleanup;
{* Функция очистки полей объекта. }
//#UC START# *479731C50290_69BB232003AC_var*
//#UC END# *479731C50290_69BB232003AC_var*
begin
//#UC START# *479731C50290_69BB232003AC_impl*
f_Values := nil;
if (f_Proxy <> nil) then
f_Proxy.Set_SearchMode(m3_smRandom);
FreeAndNil(f_Proxy);
inherited;
//#UC END# *479731C50290_69BB232003AC_impl*
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.Cleanup
procedure Tm3AttrIndexDumperJoinProxy_Enumerator.ClearFields;
begin
f_Current := nil;
f_Values := nil;
inherited;
end;//Tm3AttrIndexDumperJoinProxy_Enumerator.ClearFields
constructor Tm3AttrIndexDumperJoinProxy.Create(const aFiles: Im3FilesEnumerable;
aIsDirect: Boolean);
//#UC START# *69B94B46031D_69B94A1A036F_var*
//#UC END# *69B94B46031D_69B94A1A036F_var*
begin
//#UC START# *69B94B46031D_69B94A1A036F_impl*
inherited Create;
f_Files := aFiles;
f_TimeStamp := BadDateTime;
f_IsDirect := aIsDirect;
f_Count := -1;
f_MinKeyID := High(f_MinKeyID);
f_MaxKeyID := Low(f_MaxKeyID);
//#UC END# *69B94B46031D_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.Create
class function Tm3AttrIndexDumperJoinProxy.Make(const aFiles: Im3FilesEnumerable;
aIsDirect: Boolean): Im3AttrIndexDumper;
var
l_Inst : Tm3AttrIndexDumperJoinProxy;
begin
l_Inst := Create(aFiles, aIsDirect);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//Tm3AttrIndexDumperJoinProxy.Make
procedure Tm3AttrIndexDumperJoinProxy.CheckOther;
//#UC START# *69B94FF003CF_69B94A1A036F_var*
var
l_It : Im3FilesEnumerator;
l_Count : Integer;
l_Other : Im3AttrIndexDumper;
//#UC END# *69B94FF003CF_69B94A1A036F_var*
begin
//#UC START# *69B94FF003CF_69B94A1A036F_impl*
if (f_OtherJoin = nil) then
begin
Assert(Self.f_Files <> nil);
l_It := Self.f_Files.GetEnumerator;
if (l_It <> nil) then
begin
if (f_Last <> nil) then
begin
l_Count := Self.f_Files.Count - 1;
while (l_Count > 0)
AND l_It.MoveNext
do
begin
Dec(l_Count);
if (f_Others = nil) then
f_Others := TIm3AttrIndexDumperList.Create;
l_Other := Tm3AttrIndexDumper.Make(l_It.Current.AsString);
l_Other.SearchMode := Self.f_SearchMode;
f_Others.Add(l_Other);
end;//l_It.MoveNext
if (f_Others = nil) then
f_Others := TIm3AttrIndexDumperList.Create;
f_Last.SearchMode := Self.f_SearchMode;
f_Others.Add(f_Last);
end//f_Last <> nil
else
begin
while l_It.MoveNext do
begin
if (f_Others = nil) then
f_Others := TIm3AttrIndexDumperList.Create;
l_Other := Tm3AttrIndexDumper.Make(l_It.Current.AsString);
l_Other.SearchMode := Self.f_SearchMode;
f_Others.Add(l_Other);
end;//l_It.MoveNext
end;//f_Last <> nil
end;//l_It <> nil
if (f_Others <> nil) then
f_OtherJoin := Tm3AttrIndexDumperJoin.MakeFromList(f_Others.AsEnumerable, f_IsDirect)
else
f_OtherJoin := f_Last;
//f_OtherJoin := Tm3AttrIndexDumperJoin.MakeFromFilesEnum(Self.f_Files.GetEnumerator, Self.f_IsDirect);
if (f_OtherJoin = nil) then
// - тут делаем NULL-объект
f_OtherJoin := Tm3AttrIndexDumper.Make('');
end;//f_OtherJoin = nil
//#UC END# *69B94FF003CF_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.CheckOther
{$If NOT Defined(l3NoSRT)}
function Tm3AttrIndexDumperJoinProxy.SetRefTo(var thePlace: Tm3AttrIndexDumperJoinProxy): Boolean;
begin
if (thePlace = Self) then
Result := false
else
begin
Result := true;
thePlace.Free;
thePlace := Self.Use;
end;//thePlace = Self
end;//Tm3AttrIndexDumperJoinProxy.SetRefTo
{$IfEnd} // NOT Defined(l3NoSRT)
function Tm3AttrIndexDumperJoinProxy.pm_GetFirst: Il3RangeEnumerable;
//#UC START# *47D8233603DD_69B94A1A036Fget_var*
//#UC END# *47D8233603DD_69B94A1A036Fget_var*
begin
//#UC START# *47D8233603DD_69B94A1A036Fget_impl*
Result := nil;
l3NI;
//#UC END# *47D8233603DD_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.pm_GetFirst
function Tm3AttrIndexDumperJoinProxy.pm_GetLast: Il3RangeEnumerable;
//#UC START# *47D823570315_69B94A1A036Fget_var*
//#UC END# *47D823570315_69B94A1A036Fget_var*
begin
//#UC START# *47D823570315_69B94A1A036Fget_impl*
Result := nil;
l3NI;
//#UC END# *47D823570315_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.pm_GetLast
function Tm3AttrIndexDumperJoinProxy.pm_GetCount: Integer;
//#UC START# *4BB08B8902F2_69B94A1A036Fget_var*
{$IfDef nsTest}
var
l_CountForCompare : Integer;
{$EndIf nsTest}
var
{$IfDef nsTest}
l_Total : Integer;
l_PartCount : Integer;
{$EndIf nsTest}
l_Index : Integer;
l_Modified : Il3RangeEnumerable;
l_IE : Il3IntegerEnumerable;
//#UC END# *4BB08B8902F2_69B94A1A036Fget_var*
begin
//#UC START# *4BB08B8902F2_69B94A1A036Fget_impl*
if (f_Count < 0) then
begin
CheckOther;
if f_IsDirect then
begin
{$IfDef nsTest}
l_CountForCompare := f_OtherJoin.Count;
{$EndIf nsTest}
if (f_Others = nil) then
begin
f_Count := f_OtherJoin.Count;
end//f_Others = nil
else
begin
if (f_Modified = nil) then
begin
{$IfDef nsTest}
l_Total := 0;
{$EndIf nsTest}
for l_Index := 0 to f_Others.Count - 1 do
begin
l_Modified := f_Others[l_Index].ModifiedDocuments;
{$IfDef nsTest}
l_PartCount := 0;
if (l_Modified <> nil) then
begin
l_IE := Il3RangeEnumerable_ToIntegerEnumerable(l_Modified);
if (l_IE = nil) then
l_PartCount := 0
else
l_PartCount := l_IE.Count;
//l_PartCount := l_Modified.Count;
Inc(l_Total, l_PartCount);
end;//l_Modified <> nil
{$EndIf nsTest}
f_Modified := Il3RangeEnumerable_JoinWithOther(f_Modified, l_Modified);
end;//for l_Index
if (f_Modified = nil) then
f_Count := 0
else
begin
l_IE := Il3RangeEnumerable_ToIntegerEnumerable(f_Modified);
if (l_IE = nil) then
f_Count := 0
else
f_Count := l_IE.Count;
//f_Count := f_Modified.Count;
end;//f_Modified = nil
end;//f_Modified = nil
{$IfDef nsTest}
if (l_CountForCompare <> f_Count) then
begin
Assert(l_CountForCompare <= f_Count);
l3System.Msg2Log(Self.f_Files.First.AsString
+ ' CountForCompare: '
+ IntToStr(l_CountForCompare)
+ ' Count: '
+ IntToStr(f_Count)
+ ' Total: '
+ IntToStr(l_Total)
);
{
Понятно почему тут "рассинхронизация".
Потому что в Builder'ах ЕДИНЫЕ modified и range
для всех индексов.
}
end;//l_CountForCompare <> f_Count
{$EndIf nsTest}
end;//f_Others = nil
end//f_IsDirect
else
f_Count := f_OtherJoin.Count;
end;//f_Count < 0
Result := f_Count;
//#UC END# *4BB08B8902F2_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.pm_GetCount
function Tm3AttrIndexDumperJoinProxy.GetEnumerator: Im3AttrIndexElementEnumerator;
{* Получает Enumerator для перебора элементов "контейнера".
Вся эта конструкция совместима с "синтаксическим сахаром" вида:
for Item in Container do Process(Item);
Который поддерживается в "новых" Delphi.
См. http://mdp.garant.ru/pages/viewpage.action?pageId=152961307 }
//#UC START# *5AB8C6B0003A_69B94A1A036F_var*
{$If Defined(nsTest) OR Defined(FPC)}
{$Define use_Proxy_Enumerator}
{$IfEnd} // {$If Defined(nsTest) OR Defined(FPC)}
var
l_PartsCount : Integer;
l_D : Integer;
l_Min : Integer;
l_Max : Integer;
l_Count : Integer;
l_Div : Integer;
//#UC END# *5AB8C6B0003A_69B94A1A036F_var*
begin
//#UC START# *5AB8C6B0003A_69B94A1A036F_impl*
CheckOther;
if f_IsDirect then
begin
{$IfDef use_Proxy_Enumerator}
//Result := f_OtherJoin.GetEnumerator;
if (f_Others = nil) then
l_PartsCount := 0
else
l_PartsCount := f_Others.Count;
if (l_PartsCount > 200) then
// - типа частей до хера
begin
Result := Tm3AttrIndexDumperJoinProxy_Enumerator.Make(Self);
Exit;
end;//l_PartsCount > 200
l_Min := Self.Get_MinKeyID;
l_Max := Self.Get_MaxKeyID;
l_D := l_Max - l_Min;
if (l_D > 10000) then
// - дельта типа до хера большая
begin
l_Count := Self.Count;
// - попробуем оценить максимальную дельту
if (l_Count >= l_D) then
// - дельта совсем сравнима с числом элементов
Result := Tm3AttrIndexDumperJoinProxy_Enumerator.Make(Self)
else
begin
if (l_Count = 0) then
// - вроде как документов нет
Result := f_OtherJoin.GetEnumerator
// - давайте попробуем работат по-старому
else
begin
l_Div := l_D div l_Count;
// - считаем пропорцию
if (l_Div > 5) then
Result := f_OtherJoin.GetEnumerator
// - давайте попробуем работат по-старому
else
Result := Tm3AttrIndexDumperJoinProxy_Enumerator.Make(Self);
// - тут работаем по-новому
end;//l_Count = 0
end;//l_Count >= l_D
end//l_D > 10000
else
Result := Tm3AttrIndexDumperJoinProxy_Enumerator.Make(Self);
{$Else use_Proxy_Enumerator}
Result := f_OtherJoin.GetEnumerator;
{$EndIf use_Proxy_Enumerator}
end//f_IsDirect
else
Result := f_OtherJoin.GetEnumerator;
//#UC END# *5AB8C6B0003A_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.GetEnumerator
function Tm3AttrIndexDumperJoinProxy.ModifiedDocuments: Il3RangeEnumerable;
//#UC START# *5B2B66730195_69B94A1A036F_var*
//#UC END# *5B2B66730195_69B94A1A036F_var*
begin
//#UC START# *5B2B66730195_69B94A1A036F_impl*
if (f_Modified <> nil) then
Result := f_Modified
else
begin
CheckOther;
Result := f_OtherJoin.ModifiedDocuments;
end;//f_Modified <> nil
//#UC END# *5B2B66730195_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.ModifiedDocuments
function Tm3AttrIndexDumperJoinProxy.IndexedVersions: Im3IndexedVersions;
//#UC START# *5B2E194003AE_69B94A1A036F_var*
//#UC END# *5B2E194003AE_69B94A1A036F_var*
begin
//#UC START# *5B2E194003AE_69B94A1A036F_impl*
CheckOther;
Result := f_OtherJoin.IndexedVersions;
//#UC END# *5B2E194003AE_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.IndexedVersions
function Tm3AttrIndexDumperJoinProxy.Get_Range: Tm3IDRange;
//#UC START# *5DA9C0270207_69B94A1A036Fget_var*
//#UC END# *5DA9C0270207_69B94A1A036Fget_var*
begin
//#UC START# *5DA9C0270207_69B94A1A036Fget_impl*
CheckOther;
Result := f_OtherJoin.Range;
//#UC END# *5DA9C0270207_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.Get_Range
function Tm3AttrIndexDumperJoinProxy.ValuesByKey(aKey: Integer): Il3RangeEnumerable;
//#UC START# *66B4B9740318_69B94A1A036F_var*
var
l_Others : TIm3AttrIndexDumperList;
l_Index : Integer;
l_Range : Tm3IDRange;
l_Modified : Il3RangeEnumerable;
//#UC END# *66B4B9740318_69B94A1A036F_var*
begin
//#UC START# *66B4B9740318_69B94A1A036F_impl*
CheckOther;
(* if (f_OtherJoin = nil) then
// - это ловушка для отладки
CheckOther;*)
if f_IsDirect then
// https://mdp.garant.ru/pages/viewpage.action?pageId=902334979
begin
l_Others := f_Others;
if (l_Others = nil) then
// - хм... у нас нет Others, ну ладно, бывает
// тогда "попробуем как при бабушке" (С)
{
«Теперь всё будет, как при бабушке» — это выражение, означающее возвращение к прежнему, более привычному порядку.
Возникновение фразы связано с восшествием на престол Александра I после убийства его отца Павла I в 1801 году. Александр хотел восстановить порядки, существовавшие при его бабушке, Екатерине II. Эти слова стали выражением надежды на возвращение к стабильности, справедливости и просвещённому абсолютизму, который был характерен для екатерининской эпохи.
Хотя фраза сохранилась в культурной памяти, она не получила широкого распространения, но используется в разговорной речи в значении «всё будет, как прежде».
}
Result := f_OtherJoin.ValuesByKey(aKey)
else
begin
// - тут попрбуем по-новому
Assert(l_Others <> nil);
// - возможно тут ещё надо оценить l_Others.Count да и не дёргаться
if true then
// - тут пробуем по-новому
begin
// Тут "списывать будем" из Tm3AttrIndexDumperJoin.ValuesByKey
Result := nil;
// - пока не нашли
for l_Index := l_Others.Count - 1 downto 0 do
// - перебираем с конца, ибо дельты так сортированы
begin
l_Range := l_Others.ItemSlot(l_Index).Range;
if not l_Range.Has(aKey) then
// - если не попали в диапазон, то значит это не в нашем куске
continue
// - на другой виток цикла
else
begin
l_Modified := l_Others.ItemSlot(l_Index).ModifiedDocuments;
// - наши документы
if (l_Modified = nil) then
// - нет наших документов
continue
// - на другой виток цикла
else
if not l_Modified.Has(Tl3Range_C(aKey)) then
// - aKey не в наших документах
continue
// - на другой виток цикла
else
begin
Result := l_Others.ItemSlot(l_Index).ValuesByKey(aKey);
// - а вот тут берём наши значения
Exit;
// - ну нам точно тут пора отваливать
end;//else
end;//not l_Range.Has(aKey)
end;//for l_Index
end//true
else
Result := f_OtherJoin.ValuesByKey(aKey);
end;//l_Others = nil
end//f_IsDirect
else
Result := f_OtherJoin.ValuesByKey(aKey);
//#UC END# *66B4B9740318_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.ValuesByKey
function Tm3AttrIndexDumperJoinProxy.TimeStamp: TDateTime;
//#UC START# *66C46E6801D3_69B94A1A036F_var*
//#UC END# *66C46E6801D3_69B94A1A036F_var*
begin
//#UC START# *66C46E6801D3_69B94A1A036F_impl*
if not SameValue(f_TimeStamp, BadDateTime) then
Result := f_TimeStamp
else
begin
if (f_OtherJoin <> nil) then
Result := f_OtherJoin.TimeStamp
// -- берём timestamp "от всего объединения", раз уж оно создано
else
begin
if (f_Last = nil) then
begin
Assert(Self.f_Files <> nil);
f_Last := Tm3AttrIndexDumper.Make(f_Files.Last.AsString);
f_Last.SearchMode := Self.f_SearchMode;
end;//f_Last = nil
Result := f_Last.TimeStamp;
// -- берём timestamp от самого "крайнего справа".
end;//f_OtherJoin <> nil
f_TimeStamp := Result;
end;//not SameValue(f_TimeStamp, 0)
//#UC END# *66C46E6801D3_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.TimeStamp
function Tm3AttrIndexDumperJoinProxy.Get_MaxKeyID: Integer;
//#UC START# *671D18210090_69B94A1A036Fget_var*
//#UC END# *671D18210090_69B94A1A036Fget_var*
begin
//#UC START# *671D18210090_69B94A1A036Fget_impl*
if (f_MaxKeyID = Low(f_MaxKeyID)) then
begin
CheckOther;
f_MaxKeyID := f_OtherJoin.MaxKeyID;
end;//f_MaxKeyID = Low(f_MaxKeyID)
Result := f_MaxKeyID;
//#UC END# *671D18210090_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.Get_MaxKeyID
function Tm3AttrIndexDumperJoinProxy.Get_Operation: Tm3GroupOperation;
//#UC START# *68E135160346_69B94A1A036Fget_var*
//#UC END# *68E135160346_69B94A1A036Fget_var*
begin
//#UC START# *68E135160346_69B94A1A036Fget_impl*
CheckOther;
Result := f_OtherJoin.Operation;
//#UC END# *68E135160346_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.Get_Operation
function Tm3AttrIndexDumperJoinProxy.Get_MinKeyID: Integer;
//#UC START# *69B14AAE0155_69B94A1A036Fget_var*
//#UC END# *69B14AAE0155_69B94A1A036Fget_var*
begin
//#UC START# *69B14AAE0155_69B94A1A036Fget_impl*
if (f_MinKeyID = High(f_MinKeyID)) then
begin
CheckOther;
f_MinKeyID := f_OtherJoin.MinKeyID;
end;//f_MinKeyID = High(f_MinKeyID)
Result := f_MinKeyID;
//#UC END# *69B14AAE0155_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.Get_MinKeyID
procedure Tm3AttrIndexDumperJoinProxy.Set_SearchMode(aValue: Tm3SearchMode);
//#UC START# *69BBB8A101BA_69B94A1A036Fset_var*
var
l_Index : Integer;
//#UC END# *69BBB8A101BA_69B94A1A036Fset_var*
begin
//#UC START# *69BBB8A101BA_69B94A1A036Fset_impl*
Self.f_SearchMode := aValue;
if f_IsDirect then
begin
Case Self.f_SearchMode of
m3_smSeq:
begin
CheckOther;
if (f_Others <> nil) then
begin
for l_Index := 0 to Pred(f_Others.Count) do
begin
f_Others[l_Index].SearchMode := Self.f_SearchMode;
end;//for l_Index
end;//f_Others <> nil
end;//m3_smSeq
m3_smRandom:
begin
if (f_Others <> nil) then
begin
for l_Index := 0 to Pred(f_Others.Count) do
begin
f_Others[l_Index].SearchMode := Self.f_SearchMode;
end;//for l_Index
end;//f_Others <> nil
end;//m3_smRandom
end;//Case aValue
end;//f_IsDirect
//#UC END# *69BBB8A101BA_69B94A1A036Fset_impl*
end;//Tm3AttrIndexDumperJoinProxy.Set_SearchMode
function Tm3AttrIndexDumperJoinProxy.Get_Sequential: Boolean;
//#UC START# *69C1D45B01E5_69B94A1A036Fget_var*
//#UC END# *69C1D45B01E5_69B94A1A036Fget_var*
begin
//#UC START# *69C1D45B01E5_69B94A1A036Fget_impl*
CheckOther;
Result := f_OtherJoin.Sequential;
//#UC END# *69C1D45B01E5_69B94A1A036Fget_impl*
end;//Tm3AttrIndexDumperJoinProxy.Get_Sequential
function Tm3AttrIndexDumperJoinProxy.ToTheLeftOf(const anOther: Im3AttrIndexDumper): Boolean;
//#UC START# *69C1DE0300B2_69B94A1A036F_var*
//#UC END# *69C1DE0300B2_69B94A1A036F_var*
begin
//#UC START# *69C1DE0300B2_69B94A1A036F_impl*
CheckOther;
Result := f_OtherJoin.ToTheLeftOf(anOther);
//#UC END# *69C1DE0300B2_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.ToTheLeftOf
procedure Tm3AttrIndexDumperJoinProxy.Cleanup;
{* Функция очистки полей объекта. }
//#UC START# *479731C50290_69B94A1A036F_var*
//#UC END# *479731C50290_69B94A1A036F_var*
begin
//#UC START# *479731C50290_69B94A1A036F_impl*
f_Last := nil;
f_OtherJoin := nil;
f_Files := nil;
f_TimeStamp := 0;
f_IsDirect := false;
FreeAndNil(f_OthersForSeq);
FreeAndNil(f_Others);
inherited;
//#UC END# *479731C50290_69B94A1A036F_impl*
end;//Tm3AttrIndexDumperJoinProxy.Cleanup
procedure Tm3AttrIndexDumperJoinProxy.ClearFields;
begin
f_Last := nil;
f_OtherJoin := nil;
f_Files := nil;
f_Modified := nil;
inherited;
end;//Tm3AttrIndexDumperJoinProxy.ClearFields
constructor Tm3AttrIndexDumperJoin.Create(const aMain: Im3AttrIndexDumper;
const aDelta: Im3AttrIndexDumper;
aIsDirect: Boolean);
//#UC START# *67175FC70110_67175F5B013B_var*
//#UC END# *67175FC70110_67175F5B013B_var*
begin
//#UC START# *67175FC70110_67175F5B013B_impl*
f_Count := -1;
Assert(aMain <> nil);
Assert(aDelta <> nil);
f_Main := aMain;
f_Delta := aDelta;
f_IsDirect := aIsDirect;
if false then
// - пока отключаем, ибо падает на D:\SuperBase\garant\bserv001#ExternalHandle_(d)#
if CompareDateTime(aMain.TimeStamp, aDelta.TimeStamp) = GreaterThanValue then
raise Exception.Create(l3ForceUTF8FPC('Ошибка: Основной индекс новее дельты'));
inherited Create;
//#UC END# *67175FC70110_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.Create
class function Tm3AttrIndexDumperJoin.MakePrim(const aMain: Im3AttrIndexDumper;
const aDelta: Im3AttrIndexDumper;
aIsDirect: Boolean): Im3AttrIndexDumper;
var
l_Inst : Tm3AttrIndexDumperJoin;
begin
l_Inst := Create(aMain, aDelta, aIsDirect);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//Tm3AttrIndexDumperJoin.MakePrim
class function Tm3AttrIndexDumperJoin.Make(const aMain: Im3AttrIndexDumper;
const aDelta: Im3AttrIndexDumper;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *6717604D0301_67175F5B013B_var*
//#UC END# *6717604D0301_67175F5B013B_var*
begin
//#UC START# *6717604D0301_67175F5B013B_impl*
if (aMain = nil) then
Result := aDelta
else
if (aDelta = nil) then
Result := aMain
else
begin
Result := MakePrim(aMain, aDelta, aIsDirect);
end;//aDelta = nil
//#UC END# *6717604D0301_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.Make
class function Tm3AttrIndexDumperJoin.MakeFromMask(const aMask: TFileName;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *671768C9027E_67175F5B013B_var*
var
l_IsEtalon : Boolean;
var
l_L : TIm3AttrIndexDumperByTimeStampList;
l_Purge : Im3FilesEnumerable;
function DoFile(const aFileName: string): Boolean;
var
l_Dumper : Im3AttrIndexDumper;
l_Ext : TFileName;
l_S : Tl3PrimString;
begin//DoFile
Result := true;
if FileExists(aFileName) then
begin
l_Ext := ExtractFileExt(aFileName);
if (l_Ext <> '.idxdeltas') then
begin
if l_IsEtalon then
begin
if not (Pos('.etalon.', ExtractFileName(aFileName)) > 0) then
Exit;
end//l_IsEtalon
else
begin
if (Pos('.etalon.', ExtractFileName(aFileName)) > 0) then
Exit;
end;//l_IsEtalon
if (l_Purge <> nil) then
begin
if not l_Purge.Empty then
begin
l_S := Tl3SharedConstString.CreateShared(aFileName);
try
if l_Purge.Has(l_S) then
Exit;
finally
FreeAndNil(l_S);
end;//try..finally
end;//not l_Purge.Empty
end;//l_Purge <> nil
l_Dumper := nil;
try
l_Dumper := Tm3AttrIndexDumper.Make(aFileName);
except
l_Dumper := nil;
end;//try..finally
if (l_Dumper <> nil) then
begin
l_L.Add(l_Dumper);
end;//l_Dumper <> nil
end;//l_Ext <> '.idxdeltas'
end;//FileExists(aFileName)
end;//DoFile
(*var
l_Dumper : Im3AttrIndexDumper;
l_NewDumper : Im3AttrIndexDumper;
function DoFile(const aFileName: string): Boolean;
begin//DoFile
Result := true;
if FileExists(aFileName) then
begin
l_NewDumper := Tm3AttrIndexDumper.Make(aFileName);
if (l_NewDumper <> nil) then
begin
if (l_Dumper = nil) then
l_Dumper := l_NewDumper
else
l_Dumper := Self.Make(l_Dumper, l_NewDumper, aIsDirect);
end;//l_NewDumper <> nil
end;//FileExists(aFileName)
end;//DoFile*)
var
l_Folder : TFileName;
l_Mask : TFileName;
l_FPStub : Pointer;
l_Helper : Im3DBHelper;
l_BaseName : TFileName;
// l_Index : Integer;
//#UC END# *671768C9027E_67175F5B013B_var*
begin
//#UC START# *671768C9027E_67175F5B013B_impl*
Result := nil;
//l_Dumper := nil;
//l_NewDumper := nil;
l_BaseName := ChangeFileExt(aMask, '');
l_Purge := nil;
try
l_Helper := Tm3DBHelper.Make(l_BaseName);
try
l_Purge := l_Helper.GetIndexForPurgeFiles;
finally
l_Helper := nil;
end;//try..finally
l_Folder := ExtractFilePath(aMask);
l_Mask := ExtractFileName(aMask);
l_IsEtalon := Pos('.etalon.', l_Mask) > 0;
l_L := TIm3AttrIndexDumperByTimeStampList.CreateSorted;
try
l_FPStub := l3LocalStub(@DoFile);
try
ProcessFilesWithMask(l_Folder, l_Mask, TFileProcessingFunc(l_FPStub));
finally
l3FreeLocalStub(l_FPStub);
end;//try..finally
Result := Self.MakeFromList(l_L.AsEnumerable, aIsDirect);
(* for l_Index := 0 to Pred(l_L.Count) do
begin
if (Result = nil) then
Result := l_L.Items[l_Index]
else
Result := Self.Make(Result, l_L.Items[l_Index], aIsDirect);
end;//for l_Index*)
finally
FreeAndNil(l_L);
end;//try..finally
//Result := l_Dumper;
finally
l_Purge := nil;
end;//try..finallt
//#UC END# *671768C9027E_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeFromMask
class function Tm3AttrIndexDumperJoin.MakeFromFilesEnum(const aFiles: Im3FilesEnumerator;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *6717CE9E016D_67175F5B013B_var*
var
l_L : TIm3AttrIndexDumperByTimeStampList;
var
//l_Dumper : Im3AttrIndexDumper;
l_NewDumper : Im3AttrIndexDumper;
//#UC END# *6717CE9E016D_67175F5B013B_var*
begin
//#UC START# *6717CE9E016D_67175F5B013B_impl*
Result := nil;
if (aFiles <> nil) then
begin
//l_Dumper := nil;
l_L := TIm3AttrIndexDumperByTimeStampList.CreateSorted;
try
while aFiles.MoveNext do
begin
{$If not Defined(Archi) OR not Defined(Linux)}
{$If not Defined(Linux) OR not Defined(nsTest)}
{$If not Defined(NanoServer)}
{$If not Defined(m3DBCheck)}
l3System.Msg2Log('Tm3AttrIndexDumperJoin.MakeFromFilesEnum: ' + aFiles.Current.AsString);
{$IfEnd}
{$IfEnd}
{$IfEnd}
{$IfEnd}
l_NewDumper := Tm3AttrIndexDumper.Make(aFiles.Current.AsString);
if (l_NewDumper <> nil) then
begin
l_L.Add(l_NewDumper);
(* if (l_Dumper = nil) then
l_Dumper := l_NewDumper
else
l_Dumper := Make(l_Dumper, l_NewDumper, aIsDirect);*)
end;//l_NewDumper <> nil
end;//while aFiles.MoveNext
//Result := l_Dumper;
Result := Self.MakeFromList(l_L.AsEnumerable, aIsDirect);
finally
FreeAndNil(l_L);
end;//try..finally
end;//aFiles <> nil
//#UC END# *6717CE9E016D_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeFromFilesEnum
class function Tm3AttrIndexDumperJoin.MakeFromFiles(const aFiles: Im3FilesEnumerable;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *6717CECE007E_67175F5B013B_var*
//#UC END# *6717CECE007E_67175F5B013B_var*
begin
//#UC START# *6717CECE007E_67175F5B013B_impl*
(* if (aFiles = nil) then
Result := nil
else*)
begin
if (aFiles = nil)
OR aFiles.Empty
then
Result := Tm3AttrIndexDumper.Make('')
else
if (aFiles.Count = 1) then
Result := Tm3AttrIndexDumper.Make(aFiles.First.AsString)
else
Result := Tm3AttrIndexDumperJoinProxy.Make(aFiles, aIsDirect);
//Result := MakeFromFilesEnum(aFiles.GetEnumerator, aIsDirect);
end;//aFiles = nil
//#UC END# *6717CECE007E_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeFromFiles
class function Tm3AttrIndexDumperJoin.MakeFromList(const aList: Im3AttrIndexDumperEnumerable;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *6717D4380255_67175F5B013B_var*
var
//l_Index : Integer;
l_It : Im3AttrIndexDumperEnumerator;
//#UC END# *6717D4380255_67175F5B013B_var*
begin
//#UC START# *6717D4380255_67175F5B013B_impl*
Result := nil;
if (aList <> nil) then
begin
l_It := aList.GetEnumerator;
if (l_It <> nil) then
while l_It.MoveNext do
begin
if (Result = nil) then
Result := l_It.Current
else
Result := Self.Make(Result, l_It.Current, aIsDirect);
end;//while l_It.MoveNext
end;//aList <> nil
(* for l_Index := 0 to Pred(aList.Count) do
begin
if (Result = nil) then
Result := aList.Items[l_Index]
else
Result := Self.Make(Result, aList.Items[l_Index], aIsDirect);
end;//for l_Index*)
//#UC END# *6717D4380255_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeFromList
class function Tm3AttrIndexDumperJoin.MakeForAttribute(const aBaseName: TFileName;
anAttrID: Integer;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *6717EC2E03D3_67175F5B013B_var*
(*var
l_Name : TFileName;*)
//#UC END# *6717EC2E03D3_67175F5B013B_var*
begin
//#UC START# *6717EC2E03D3_67175F5B013B_impl*
(* l_Name := aBaseName;
l_Name := l_Name + '#' + Tk2Attributes.Instance.NameByID(anAttrID);
if aIsDirect then
l_Name := l_Name + '_' + '(d)';
l_Name := l_Name + '#';
l_Name := l_Name + '.idx';
l_Name := l_Name + '*';
Result := Self.MakeFromMask(l_Name, aIsDirect);*)
Result := Self.MakeForAttribute(aBaseName, Tk2Attributes.Instance.NameByID(anAttrID), aIsDirect);
//Result := Self.MakeFromMask(l_Name + '*', aIsDirect);
//#UC END# *6717EC2E03D3_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeForAttribute
class function Tm3AttrIndexDumperJoin.MakeForAttribute(const aBaseName: TFileName;
const anAttrName: AnsiString;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *671A2EAB038F_67175F5B013B_var*
var
l_Name : TFileName;
l_BaseName : TFileName;
l_Helper : Im3DBHelper;
l_A : Im3FilesEnumerable;
//#UC END# *671A2EAB038F_67175F5B013B_var*
begin
//#UC START# *671A2EAB038F_67175F5B013B_impl*
l_Name := aBaseName;
l_Name := l_Name + '#' + anAttrName;
if aIsDirect then
l_Name := l_Name + '_' + '(d)';
l_Name := l_Name + '#';
l_BaseName := l_Name;
// -- https://mdp.garant.ru/pages/viewpage.action?pageId=872809175
// PurgeIndexDeltas - не забыть вызывать. При поиске например.
(* l_Name := l_Name + '.idx';
l_Name := l_Name + '*';*)
// - не надо наверное по маске искать ибо там вообще могут быть недостроенные дельты
l_A := nil;
l_Helper := Tm3DBHelper.Make(l_BaseName);
try
Tm3StorageHolderList.DropFiles(l_Helper.GetIndexForPurgeFiles);
{$IfDef Linux}
{$IfDef AppClientSide}
if (g_BaseEngine <> nil) then
if not g_BaseEngine.WorkWithServer then
l_Helper.PurgeIndexDeltas;
{$Else AppClientSide}
// - тут надо проверять WorkWithServer
l_Helper.PurgeIndexDeltas;
{$EndIf AppClientSide}
{$Else Linux}
l_Helper.PurgeIndexDeltas;
{$EndIf Linux}
l_A := l_Helper.GetAllIndexFiles;
finally
l_Helper := nil;
end;//try..finally
if (l_A <> nil)
AND (l_A.Count > 0)
then
Result := Self.MakeFromFiles(l_A, aIsDirect)
else
Result := Tm3AttrIndexDumper.Make('');
// - Stub or Null-Object for caching
//Result := nil;
//Result := nil;
// - не надо наверное по маске искать ибо там вообще могут быть недостроенные дельты
// Result := Self.MakeFromMask(l_Name, aIsDirect);
//#UC END# *671A2EAB038F_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeForAttribute
class function Tm3AttrIndexDumperJoin.MakeForAttribute(const aBaseName: TFileName;
const anAttrID: array of Integer;
aIsDirect: Boolean): Im3AttrIndexDumper;
//#UC START# *671A58B30070_67175F5B013B_var*
var
l_Name : TFileName;
l_Index : Integer;
//#UC END# *671A58B30070_67175F5B013B_var*
begin
//#UC START# *671A58B30070_67175F5B013B_impl*
l_Name := '';
for l_Index := Low(anAttrID) to High(anAttrID) do
begin
if (l_Name = '') then
l_Name := Tk2Attributes.Instance.NameByID(anAttrID[l_Index])
else
l_Name := l_Name + '_' + Tk2Attributes.Instance.NameByID(anAttrID[l_Index]);
end;//for l_Index
Result := MakeForAttribute(aBaseName, l_Name, aIsDirect);
//#UC END# *671A58B30070_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeForAttribute
class function Tm3AttrIndexDumperJoin.MakeNameForAttr(const aName: Il3CString;
const anAttrID: AnsiString;
aIsDirect: Boolean): Il3CString;
//#UC START# *671CDDC20340_67175F5B013B_var*
var
l_S : TFileName;
l_Ext : TFileName;
//#UC END# *671CDDC20340_67175F5B013B_var*
begin
//#UC START# *671CDDC20340_67175F5B013B_impl*
l_S := Il3CString_ToFileName(aName);
l_Ext := ExtractFileExt(l_S);
l_S := ChangeFileExt(l_S, '');
l_S := l_S + '#' + anAttrID;
if aIsDirect then
l_S := l_S + '_' + '(d)';
l_S := l_S + '#';
l_S := l_S + l_Ext;
Result := Il3CString_C(l_S);
//#UC END# *671CDDC20340_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeNameForAttr
class function Tm3AttrIndexDumperJoin.MakeFilesForAttr(const aFiles: Im3FilesEnumerable;
const anAttrID: AnsiString;
aIsDirect: Boolean): Im3FilesEnumerable;
//#UC START# *671CDDD501F2_67175F5B013B_var*
var
l_L : Tl3StringList;
l_It : Im3FilesEnumerator;
l_S : Il3CString;
//#UC END# *671CDDD501F2_67175F5B013B_var*
begin
//#UC START# *671CDDD501F2_67175F5B013B_impl*
l_L := Tl3StringList.Create;
try
l_It := aFiles.GetEnumerator;
if (l_It <> nil) then
while l_It.MoveNext do
begin
l_S := l_It.Current.AsCStr;
l_S := Self.MakeNameForAttr(l_S, anAttrID, aIsDirect);
if FileExists(Il3CString_ToFileName(l_S)) then
l_L.Add(l_S);
end;//l_It.MoveNext
Result := l_L.AsEnumerable;
finally
FreeAndNil(l_L);
end;//finally
//#UC END# *671CDDD501F2_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.MakeFilesForAttr
{$If NOT Defined(l3NoSRT)}
function Tm3AttrIndexDumperJoin.SetRefTo(var thePlace: Tm3AttrIndexDumperJoin): Boolean;
begin
if (thePlace = Self) then
Result := false
else
begin
Result := true;
thePlace.Free;
thePlace := Self.Use;
end;//thePlace = Self
end;//Tm3AttrIndexDumperJoin.SetRefTo
{$IfEnd} // NOT Defined(l3NoSRT)
function Tm3AttrIndexDumperJoin.pm_GetFirst: Il3RangeEnumerable;
//#UC START# *47D8233603DD_67175F5B013Bget_var*
//#UC END# *47D8233603DD_67175F5B013Bget_var*
begin
//#UC START# *47D8233603DD_67175F5B013Bget_impl*
Result := nil;
l3NI;
//#UC END# *47D8233603DD_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.pm_GetFirst
function Tm3AttrIndexDumperJoin.pm_GetLast: Il3RangeEnumerable;
//#UC START# *47D823570315_67175F5B013Bget_var*
//#UC END# *47D823570315_67175F5B013Bget_var*
begin
//#UC START# *47D823570315_67175F5B013Bget_impl*
Result := nil;
l3NI;
//#UC END# *47D823570315_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.pm_GetLast
function Tm3AttrIndexDumperJoin.pm_GetCount: Integer;
//#UC START# *4BB08B8902F2_67175F5B013Bget_var*
var
l_It : Im3AttrIndexElementEnumerator;
//#UC END# *4BB08B8902F2_67175F5B013Bget_var*
begin
//#UC START# *4BB08B8902F2_67175F5B013Bget_impl*
if (f_Count < 0) then
begin
f_Count := 0;
l_It := Self.GetEnumerator;
if (l_It <> nil) then
while l_It.MoveNext do
Inc(f_Count);
end;//f_Count < 0
Result := f_Count;
//#UC END# *4BB08B8902F2_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.pm_GetCount
function Tm3AttrIndexDumperJoin.GetEnumerator: Im3AttrIndexElementEnumerator;
{* Получает Enumerator для перебора элементов "контейнера".
Вся эта конструкция совместима с "синтаксическим сахаром" вида:
for Item in Container do Process(Item);
Который поддерживается в "новых" Delphi.
См. http://mdp.garant.ru/pages/viewpage.action?pageId=152961307 }
//#UC START# *5AB8C6B0003A_67175F5B013B_var*
var
l_MainEnum : Im3AttrIndexElementEnumerator;
l_DeltaEnum : Im3AttrIndexElementEnumerator;
l_Modified : Il3RangeEnumerable;
l_MainRange : Tm3IDRange;
l_DeltaRange : Tm3IDRange;
//#UC END# *5AB8C6B0003A_67175F5B013B_var*
begin
//#UC START# *5AB8C6B0003A_67175F5B013B_impl*
Result := nil;
if f_IsDirect then
begin
l_MainEnum := f_Main.GetEnumerator;
try
if (l_MainEnum <> nil) then
begin
l_MainRange := f_Main.Range;
l_DeltaRange := f_Delta.Range;
if l_MainRange.IntersectsWith(l_DeltaRange) then
l_Modified := f_Delta.ModifiedDocuments
else
l_Modified := nil;
if (l_Modified <> nil) then
begin
l_MainEnum := TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.Make(l_MainEnum, l_Modified);
//l_MainEnum := TIm3AttrIndexElementEnumeratorWithFilteredModified.Make(l_MainEnum, l_Modified);
end;//l_Modified <> nil
end;//l_MainEnum <> nil
l_DeltaEnum := f_Delta.GetEnumerator;
try
Result := TIm3DirectAttrIndexElementEnumeratorSortedJoin.Make(l_MainEnum, l_DeltaEnum);
//Result := TIm3AttrIndexElementEnumeratorSortedJoin.Make(l_MainEnum, l_DeltaEnum);
finally
l_DeltaEnum := nil;
end;//try..finally
finally
l_MainEnum := nil;
end;//try..finally
end//f_IsDirect
else
begin
l_MainEnum := f_Main.GetEnumerator;
try
if (l_MainEnum <> nil) then
begin
l_MainRange := f_Main.Range;
l_DeltaRange := f_Delta.Range;
if l_MainRange.IntersectsWith(l_DeltaRange) then
l_Modified := f_Delta.ModifiedDocuments
else
l_Modified := nil;
if (l_Modified <> nil) then
begin
l_MainEnum := TIm3AttrIndexElementEnumeratorWithFilteredModified.Make(l_MainEnum, l_Modified);
end;//l_Modified <> nil
end;//l_MainEnum <> nil
l_DeltaEnum := f_Delta.GetEnumerator;
try
Result := TIm3AttrIndexElementEnumeratorSortedJoin.Make(l_MainEnum, l_DeltaEnum);
finally
l_DeltaEnum := nil;
end;//try..finally
finally
l_MainEnum := nil;
end;//try..finally
end;//f_IsDirect
//#UC END# *5AB8C6B0003A_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.GetEnumerator
function Tm3AttrIndexDumperJoin.ModifiedDocuments: Il3RangeEnumerable;
//#UC START# *5B2B66730195_67175F5B013B_var*
var
l_Main : Il3RangeEnumerable;
l_Delta : Il3RangeEnumerable;
//#UC END# *5B2B66730195_67175F5B013B_var*
begin
//#UC START# *5B2B66730195_67175F5B013B_impl*
if (f_Modified = nil) then
begin
l_Main := f_Main.ModifiedDocuments;
l_Delta := f_Delta.ModifiedDocuments;
f_Modified := Il3RangeEnumerable_JoinWithOther(l_Main, l_Delta);
// http://mdp.garant.ru/pages/viewpage.action?pageId=853281243 // Делать SortedJoin вместо Join, если возможно
//f_Modified := l_Main.ModifiedDocuments.Join(l_Delta);
end;//f_Modified = nil
Result := f_Modified;
//#UC END# *5B2B66730195_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.ModifiedDocuments
function Tm3AttrIndexDumperJoin.IndexedVersions: Im3IndexedVersions;
//#UC START# *5B2E194003AE_67175F5B013B_var*
var
l_MV : Im3IndexedVersions;
l_DV : Im3IndexedVersions;
//#UC END# *5B2E194003AE_67175F5B013B_var*
begin
//#UC START# *5B2E194003AE_67175F5B013B_impl*
if (f_Versions = nil) then
begin
l_MV := f_Main.IndexedVersions;
l_DV := f_Delta.IndexedVersions;
f_Versions := Tm3IndexedVersionsSortedJoin.Make(l_MV, l_DV);
end;//f_Versions = nil
Result := f_Versions;
//#UC END# *5B2E194003AE_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.IndexedVersions
function Tm3AttrIndexDumperJoin.Get_Range: Tm3IDRange;
//#UC START# *5DA9C0270207_67175F5B013Bget_var*
//#UC END# *5DA9C0270207_67175F5B013Bget_var*
begin
//#UC START# *5DA9C0270207_67175F5B013Bget_impl*
Result := f_Main.Range.Add(f_Delta.Range);
//#UC END# *5DA9C0270207_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.Get_Range
function Tm3AttrIndexDumperJoin.ValuesByKey(aKey: Integer): Il3RangeEnumerable;
//#UC START# *66B4B9740318_67175F5B013B_var*
var
l_Modified : Il3RangeEnumerable;
l_Main : Il3RangeEnumerable;
l_Delta : Il3RangeEnumerable;
l_MainRange : Tm3IDRange;
l_DeltaRange : Tm3IDRange;
//#UC END# *66B4B9740318_67175F5B013B_var*
begin
//#UC START# *66B4B9740318_67175F5B013B_impl*
Result := nil;
l_MainRange := f_Main.Range;
l_DeltaRange := f_Delta.Range;
(* if not f_IsDirect then
// https://mdp.garant.ru/pages/viewpage.action?pageId=875135987
// -- ибо там неправильно обнулялось l_Modified
begin
if l_MainRange.IntersectsWith(l_DeltaRange) then
l_Modified := f_Delta.ModifiedDocuments
else
l_Modified := nil;
end//not f_IsDirect
else
{l_Modified := f_Delta.ModifiedDocuments};*)
if f_IsDirect then
begin
{ if l_DeltaRange.Has(aKey) then
// - типа немного оптимизируем - не вычитываем Modified раньше
Result := f_Delta.ValuesByKey(aKey)}
// - НЕЛЬЗЯ ТАК оптимизировать - l_DeltaRange - ДВЕ ТОЧКИ, и между ними может быть ДЫРКА
// и aKey НА САМОМ деле лежит в f_Main
{ Возможно надо написать так:
if not l_DeltaRange.Has(aKey) then
// - типа немного оптимизируем - не вычитываем Modified раньше
Result := f_Main.ValuesByKey(aKey)}
{ Tm3AttrIndexSearcher.InternalHandleToExternalHandle - почему-то не находит в ПРЯМОМ индексе в БАЗЕ у коллег
Номера:
6
7
8
9
10
11
12
13}
// else
begin
if not l_DeltaRange.Has(aKey) then
// - если не попали в диапазон, то значит это не в нашем куске
begin
Result := f_Main.ValuesByKey(aKey);
end//not l_DeltaRange.Has(aKey)
else
begin
l_Modified := f_Delta.ModifiedDocuments;
if (l_Modified = nil) then
Result := f_Main.ValuesByKey(aKey)
else
if l_Modified.Has(Tl3Range_C(aKey)) then
Result := f_Delta.ValuesByKey(aKey)
else
Result := f_Main.ValuesByKey(aKey);
end;//not l_DeltaRange.Has(aKey)
end;//l_DeltaRange.Has(aKey)
end//f_IsDirect
else
begin
l_Main := f_Main.ValuesByKey(aKey);
l_Delta := f_Delta.ValuesByKey(aKey);
if (l_Main = nil) then
begin
Result := l_Delta;
Exit;
end;//l_Main = nil
if l_MainRange.IntersectsWith(l_DeltaRange) then
l_Modified := f_Delta.ModifiedDocuments
else
l_Modified := nil;
Result := Il3RangeEnumerable_Diff(l_Main, l_Modified);
if l_MainRange.Less(l_DeltaRange) then
begin
if (Result = nil) then
Result := l_Delta
else
Result := Result.Join(l_Delta);
end//l_MainRange.Less(l_DeltaRange)
else
if l_DeltaRange.Less(l_MainRange) then
begin
if (l_Delta <> nil) then
Result := l_Delta.Join(Result);
//else
// Result := Result
end//l_DeltaRange.Less(l_MainRange)
else
Result := Il3RangeEnumerable_JoinWithOther(Result, l_Delta);
end;//f_IsDirect
//#UC END# *66B4B9740318_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.ValuesByKey
function Tm3AttrIndexDumperJoin.TimeStamp: TDateTime;
//#UC START# *66C46E6801D3_67175F5B013B_var*
//#UC END# *66C46E6801D3_67175F5B013B_var*
begin
//#UC START# *66C46E6801D3_67175F5B013B_impl*
Result := BadDateTime;
if (f_Delta <> nil) then
Result := f_Delta.TimeStamp
else
if (f_Main <> nil) then
Result := f_Main.TimeStamp;
//#UC END# *66C46E6801D3_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.TimeStamp
function Tm3AttrIndexDumperJoin.Get_MaxKeyID: Integer;
//#UC START# *671D18210090_67175F5B013Bget_var*
//#UC END# *671D18210090_67175F5B013Bget_var*
begin
//#UC START# *671D18210090_67175F5B013Bget_impl*
Result := l3MinMax.Max(f_Main.MaxKeyID, f_Delta.MaxKeyID);
//#UC END# *671D18210090_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.Get_MaxKeyID
function Tm3AttrIndexDumperJoin.Get_Operation: Tm3GroupOperation;
//#UC START# *68E135160346_67175F5B013Bget_var*
//#UC END# *68E135160346_67175F5B013Bget_var*
begin
//#UC START# *68E135160346_67175F5B013Bget_impl*
if (f_Main = nil) then
Result := f_Delta.Operation
else
if (f_Delta = nil) then
Result := f_Main.Operation
else
begin
Result := f_Main.Operation;
Assert(f_Delta.Operation = Result);
Assert(Result = m3_gopSet);
end;//f_Delta = nil
//#UC END# *68E135160346_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.Get_Operation
function Tm3AttrIndexDumperJoin.Get_MinKeyID: Integer;
//#UC START# *69B14AAE0155_67175F5B013Bget_var*
//#UC END# *69B14AAE0155_67175F5B013Bget_var*
begin
//#UC START# *69B14AAE0155_67175F5B013Bget_impl*
Result := l3MinMax.Min(f_Main.MinKeyID, f_Delta.MinKeyID);
//#UC END# *69B14AAE0155_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.Get_MinKeyID
procedure Tm3AttrIndexDumperJoin.Set_SearchMode(aValue: Tm3SearchMode);
//#UC START# *69BBB8A101BA_67175F5B013Bset_var*
//#UC END# *69BBB8A101BA_67175F5B013Bset_var*
begin
//#UC START# *69BBB8A101BA_67175F5B013Bset_impl*
if (f_Main <> nil) then
f_Main.SearchMode := aValue;
if (f_Delta <> nil) then
f_Delta.SearchMode := aValue;
//#UC END# *69BBB8A101BA_67175F5B013Bset_impl*
end;//Tm3AttrIndexDumperJoin.Set_SearchMode
function Tm3AttrIndexDumperJoin.Get_Sequential: Boolean;
//#UC START# *69C1D45B01E5_67175F5B013Bget_var*
//#UC END# *69C1D45B01E5_67175F5B013Bget_var*
begin
//#UC START# *69C1D45B01E5_67175F5B013Bget_impl*
if f_Delta.Sequential then
begin
if f_Main.Sequential then
begin
if f_Main.ToTheLeftOf(f_Delta) then
Result := true
else
if f_Delta.ToTheLeftOf(f_Main) then
Result := true
else
Result := false;
end//f_Main.Sequential
else
Result := false;
end//f_Delta.Sequential
else
Result := false;
//#UC END# *69C1D45B01E5_67175F5B013Bget_impl*
end;//Tm3AttrIndexDumperJoin.Get_Sequential
function Tm3AttrIndexDumperJoin.ToTheLeftOf(const anOther: Im3AttrIndexDumper): Boolean;
//#UC START# *69C1DE0300B2_67175F5B013B_var*
//#UC END# *69C1DE0300B2_67175F5B013B_var*
begin
//#UC START# *69C1DE0300B2_67175F5B013B_impl*
Result := (Self.Get_MaxKeyID < anOther.MinKeyID);
//#UC END# *69C1DE0300B2_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.ToTheLeftOf
procedure Tm3AttrIndexDumperJoin.Cleanup;
{* Функция очистки полей объекта. }
//#UC START# *479731C50290_67175F5B013B_var*
//#UC END# *479731C50290_67175F5B013B_var*
begin
//#UC START# *479731C50290_67175F5B013B_impl*
inherited;
f_Main := nil;
f_Delta := nil;
f_Modified := nil;
f_Versions := nil;
//#UC END# *479731C50290_67175F5B013B_impl*
end;//Tm3AttrIndexDumperJoin.Cleanup
procedure Tm3AttrIndexDumperJoin.ClearFields;
begin
f_Main := nil;
f_Delta := nil;
f_Modified := nil;
f_Versions := nil;
inherited;
end;//Tm3AttrIndexDumperJoin.ClearFields
constructor TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.Create(const anOther: Im3AttrIndexElementEnumerator;
const aModified: Il3RangeEnumerable);
//#UC START# *69BD1854034C_69BD13C5026D_var*
//#UC END# *69BD1854034C_69BD13C5026D_var*
begin
//#UC START# *69BD1854034C_69BD13C5026D_impl*
Assert(anOther <> nil);
Assert(aModified <> nil);
f_Other := anOther;
f_Modified := aModified;
f_ModifiedIt := f_Modified.GetEnumerator;
if not f_ModifiedIt.MoveNext then
f_ModifiedIt := nil;
inherited Create;
//#UC END# *69BD1854034C_69BD13C5026D_impl*
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.Create
class function TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.Make(const anOther: Im3AttrIndexElementEnumerator;
const aModified: Il3RangeEnumerable): Im3AttrIndexElementEnumerator;
var
l_Inst : TIm3DirectAttrIndexElementEnumeratorWithFilteredModified;
begin
l_Inst := Create(anOther, aModified);
try
Result := l_Inst;
finally
l_Inst.Free;
end;//try..finally
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.Make
function TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.MoveNext: Boolean;
{* Перемещается на следующий элемент контейнера.
Возвращает true если элемент валидный. }
//#UC START# *5ACB6780016E_69BD13C5026D_var*
var
l_NeedSkip : Boolean;
l_ID : Integer;
l_R : Tm3IDRange;
l_NeedMoveOther : Boolean;
//#UC END# *5ACB6780016E_69BD13C5026D_var*
begin
//#UC START# *5ACB6780016E_69BD13C5026D_impl*
if (f_Other = nil) then
Result := false
else
begin
if (f_ModifiedIt = nil) then
begin
Result := f_Other.MoveNext;
if not Result then
f_Other := nil;
Exit;
end;//f_ModifiedIt = nil
l_NeedMoveOther := true;
while true do
begin
if l_NeedMoveOther then
Result := f_Other.MoveNext;
if Result then
begin
if (f_ModifiedIt = nil) then
break
else
begin
l_ID := f_Other.pCurrent^.ID;
l_R := f_ModifiedIt.Current;
l_NeedSkip := l_R.Has(l_ID);
// - мы попали внутрь текущего диапазона
if l_NeedSkip then
begin
// - фильтруем те, которые попали в дельту
l_NeedMoveOther := true;
continue;
end//l_NeedSkip
else
begin
if (l_ID < l_R.rLow) then
// - мы находимся левее текущего диапазона
break
else
begin
if f_ModifiedIt.MoveNext then
begin
l_R := f_ModifiedIt.Current;
if (l_ID < l_R.rLow) then
// - мы находимся левее текущего диапазона
break
else
begin
l_NeedMoveOther := false;
continue;
// - уходим на следующий круг, но без сдвига текущего
end;//l_ID < l_R.rLow
end//f_ModifiedIt.MoveNext
else
begin
f_ModifiedIt := nil;
break;
end;//f_ModifiedIt.MoveNext
end;//l_ID < l_R.rLow
end;//l_NeedSkip
end;//f_ModifiedIt <> nil
(* l_NeedSkip := f_Modified.Has(Tl3Range_C(f_Other.pCurrent^.ID));
if l_NeedSkip then
// - фильтруем те, которые попали в дельту
// Это можно сделать оптимальнее двигая ОБА итератора (курсора) но пока - так.
continue
else
break;*)
end//Result
else
begin
f_Other := nil;
break;
end;//Result
end;//while true
end;//f_Other = nil
//#UC END# *5ACB6780016E_69BD13C5026D_impl*
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.MoveNext
function TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.pCurrent: Im3AttrIndexElementEnumerator_PCurrentItemType;
{* Указатель на текущий элемент. Он "закеширован" }
//#UC START# *5C4EFC140038_69BD13C5026D_var*
//#UC END# *5C4EFC140038_69BD13C5026D_var*
begin
//#UC START# *5C4EFC140038_69BD13C5026D_impl*
Result := f_Other.pCurrent;
//#UC END# *5C4EFC140038_69BD13C5026D_impl*
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.pCurrent
function TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.CanMoveNext: Boolean;
{* Определяет - можно ли переместиться на следующий элемент контейнера. }
//#UC START# *5E60D4B30164_69BD13C5026D_var*
//#UC END# *5E60D4B30164_69BD13C5026D_var*
begin
//#UC START# *5E60D4B30164_69BD13C5026D_impl*
if (f_Other = nil) then
Result := false
else
Result := f_Other.CanMoveNext;
//#UC END# *5E60D4B30164_69BD13C5026D_impl*
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.CanMoveNext
function TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.Get_Current: Im3AttrIndexElement;
//#UC START# *6739C0470374_69BD13C5026Dget_var*
//#UC END# *6739C0470374_69BD13C5026Dget_var*
begin
//#UC START# *6739C0470374_69BD13C5026Dget_impl*
Result := f_Other.pCurrent^;
//#UC END# *6739C0470374_69BD13C5026Dget_impl*
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.Get_Current
procedure TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.ClearFields;
begin
f_Other := nil;
f_Modified := nil;
f_ModifiedIt := nil;
inherited;
end;//TIm3DirectAttrIndexElementEnumeratorWithFilteredModified.ClearFields
//#UC START# *67175F5B013BforDiagramm*
(*
+-----------------------------------------------------------------------+
| m3AttrIndexDumperJoin - Объединение индексов |
| (основной индекс + дельты) без физического слияния |
+-----------------------------------------------------------------------+
+-----------------------------------------------------------------------+
| Класс Tm3AttrIndexDumperJoin (объединяет ДВА индекса) |
+-----------------------------------------------------------------------+
| f_Main : Im3AttrIndexDumper // основной индекс (полный) |
| f_Delta : Im3AttrIndexDumper // дельта (изменения) |
| f_IsDirect: Boolean // true = прямой, false = обратный |
+-----------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------+
| Логика поиска ValuesByKey(aKey) |
+-----------------------------------------------------------------------+
| |
| +-----------------------------------------------------------------+ |
| | Если f_IsDirect = true (ПРЯМОЙ индекс: ключ -> значения) | |
| +-----------------------------------------------------------------+ |
| | | |
| | if Дельта содержит aKey? | |
| | | | |
| | +-- Да --> if aKey в ModifiedDocuments? | |
| | | | | |
| | | +-- Да --> Result := f_Delta.ValuesByKey | |
| | | | (берём из дельты) | |
| | | | | |
| | | +-- Нет --> Result := f_Main.ValuesByKey | |
| | | (берём из основного) | |
| | | | |
| | +-- Нет --> Result := f_Main.ValuesByKey | |
| | (берём из основного) | |
| | | |
| | Вывод: дельта ПЕРЕОПРЕДЕЛЯЕТ (добавляет/заменяет) значения | |
| +-----------------------------------------------------------------+ |
| |
| +-----------------------------------------------------------------+ |
| | Если f_IsDirect = false (ОБРАТНЫЙ индекс: значение -> ключи) | |
| +-----------------------------------------------------------------+ |
| | | |
| | l_Main := f_Main.ValuesByKey(aKey) // из основного | |
| | l_Delta := f_Delta.ValuesByKey(aKey) // из дельты | |
| | l_Modified := f_Delta.ModifiedDocuments | |
| | | |
| | Result := l_Main МИНУС l_Modified | |
| | Result := Result ОБЪЕДИНИТЬ с l_Delta | |
| | | |
| | Вывод: дельта УДАЛЯЕТ из основного и добавляет новые значения | |
| +-----------------------------------------------------------------+ |
+-----------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------+
| Метод GetEnumerator - объединённый перебор |
+-----------------------------------------------------------------------+
| |
| l_MainEnum := f_Main.GetEnumerator |
| l_DeltaEnum := f_Delta.GetEnumerator |
| |
| Result := SortedJoin.Make(l_MainEnum, l_DeltaEnum) |
| |
| // Слияние двух отсортированных списков (как в сортировке слиянием) |
| // Результат: объединённый список без дубликатов |
+-----------------------------------------------------------------------+
+-----------------------------------------------------------------------+
| Класс Tm3AttrIndexDumperJoinProxy (объединяет МНОГО индексов) |
+-----------------------------------------------------------------------+
| |
| Поля: |
| +-- f_Files : список индексных файлов |
| +-- f_OtherJoin : результат объединения всех, кроме последнего |
| +-- f_IsDirect : направление индекса |
| |
+-----------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------+
| Схема объединения нескольких файлов |
+-----------------------------------------------------------------------+
| |
| Файлы: [A.idx] [B.idxdelta] [C.idxdelta] [D.idxdelta] |
| | | | | |
| v v v v |
| +-----------------------------------------------------------------+ |
| | | |
| | f_OtherJoin = Join( Join( Join(A, B), C), D) | |
| | | |
| | // рекурсивное объединение: сначала два, потом результат | |
| | // с третьим, и т.д. | |
| | | |
| +-----------------------------------------------------------------+ |
+-----------------------------------------------------------------------+
+-----------------------------------------------------------------------+
| Эвристики выбора стратегии для больших индексов |
+-----------------------------------------------------------------------+
| |
| +-----------------------------------------------------------------+ |
| | Если частей > 200: | |
| | -> последовательный перебор (дешевле, чем ходить в файл) | |
| +-----------------------------------------------------------------+ |
| | |
| v |
| +-----------------------------------------------------------------+ |
| | Вычислить плотность = (maxKey - minKey) / кол-во элементов | |
| | | |
| | Если плотность > 5 (редкие ключи): | |
| | -> бинарный поиск (быстрее, чем перебирать пустые ключи) | |
| | | |
| | Если плотность <= 5 (частые ключи): | |
| | -> последовательный перебор (эффективнее) | |
| +-----------------------------------------------------------------+ |
+-----------------------------------------------------------------------+
+-----------------------------------------------------------------------+
| Схема использования в подсистеме m3 |
+-----------------------------------------------------------------------+
+-------------+ +-------------+ +-------------+
| Основной | | Дельта 1 | | Дельта 2 |
| индекс | | (изменения) | | (изменения) |
| (полный) | | | | |
+------+------+ +------+------+ +------+------+
| | |
+-------------------+-------------------+
|
v
+---------------------------------------+
| m3AttrIndexDumperJoin |
| |
| Логическое объединение без |
| физического слияния файлов |
+---------------------------------------+
|
v
+---------------------------------------+
| Im3AttrIndexDumper |
| (единый интерфейс) |
+---------------------------------------+
|
v
+---------------------------------------+
| m3AttrIndexSearcher |
| (поиск документов) |
+---------------------------------------+
+-----------------------------------------------------------------------+
| Ключевая идея: дельты НАКАПЛИВАЮТСЯ, поиск идёт по ЛОГИЧЕСКИ |
| ОБЪЕДИНЁННОМУ индексу, физическое слияние происходит ТОЛЬКО |
| при достижении лимита. |
+-----------------------------------------------------------------------+
*)
//#UC END# *67175F5B013BforDiagramm*
end.
Заметки о тестировании, программировании и прочий "поток сознания", который жалко писать "в стол"
воскресенье, 12 апреля 2026 г.
m3AttrIndexDumperJoin
Подписаться на:
Комментарии к сообщению (Atom)
Комментариев нет:
Отправить комментарий