Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Патч для IIBSQLMonitorHook  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11281
Понадобилось мне разгрести бардак с транзакциями на IBX.

Полазив по коду самого IBX, увидел, что вся действия логируются через MonitorHook и далее выводятся через TIBSQLMonitor. Проблема в том, что логирование крайне скудное, а реализация IIBSQLMonitorHook скрыта так далеко в implementation, что до нее не добраться. Поэтому решил патчить VMT у IIBSQLMonitorHook.

Вот, что в итоге получилось. Может кому пригодится
+
uses
  IBSQLMonitor;

type
  TMyMonitorHook = class
  strict private
    type
      TTranProc = procedure (tr: TIBTransaction) of object;
      TErrProc = procedure (AMsg: string) of object;
    class var
      FTransactions: TThreadedDictionary<TIBTransaction, string>;
      FOldMethods: TList<TPair<Integer, Pointer>>;
  strict private
    class constructor Create;
    class destructor Destroy;
  strict private
    class function WriteAddr(const AHook: IIBSQLMonitorHook;
      AMethodIdx: Integer; const ANewMethod: TTranProc): Pointer; overload;
    class function WriteAddr(const AHook: IIBSQLMonitorHook;
      AMethodIdx: Integer; ANewMethod: Pointer): Pointer; overload;
  strict private
    class procedure TRStart(tr: TIBTransaction);
    class procedure TRCommit(tr: TIBTransaction);
    class procedure TRRollback(tr: TIBTransaction);
    class procedure SendError(AMsg : String);
  public
    class procedure Init;
  end;

{ TMyMonitorHook }

class constructor TMyMonitorHook.Create;
begin
  FTransactions := TThreadedDictionary<TIBTransaction, string>.Create;
  FOldMethods := TList<TPair<Integer, Pointer>>.Create;
end;

class destructor TMyMonitorHook.Destroy;
var
  LHook: IIBSQLMonitorHook;
  LPair: TPair<Integer, Pointer>;
begin
  if FOldMethods.Count > 0 then begin
    LHook := MonitorHook;
    for LPair in FOldMethods do
      WriteAddr(LHook, LPair.Key, LPair.Value);
  end;
  FTransactions.Free;
end;

class function TMyMonitorHook.WriteAddr(const AHook: IIBSQLMonitorHook;
  AMethodIdx: Integer; const ANewMethod: TTranProc): Pointer;
begin
  Result := WriteAddr(AHook, AMethodIdx, TMethod(ANewMethod).Code);
end;

class function TMyMonitorHook.WriteAddr(const AHook: IIBSQLMonitorHook;
  AMethodIdx: Integer; ANewMethod: Pointer): Pointer;
var
  LOffset: Cardinal;
  LMethodAddr: PPointer;
  LOldProt: Cardinal;
begin
  LOffset := (AMethodIdx + 3) * SizeOf(Pointer);  // 3 - count of methods IUnknown
  LMethodAddr := OffsetPtr(PPointer(AHook)^, LOffset);
  Win32Check(VirtualProtect(LMethodAddr, SizeOf(LMethodAddr^), PAGE_READWRITE, LOldProt));
  Result := LMethodAddr^;
  LMethodAddr^ := ANewMethod;
  Win32Check(VirtualProtect(LMethodAddr, SizeOf(LMethodAddr^), LOldProt, LOldProt));
end;

class procedure TMyMonitorHook.TRStart(tr: TIBTransaction);
var
  LStr: string;
begin
  if FTransactions.TryGetValue(tr, LStr) then
    Msg(LStr)
  else
    FTransactions.Add(tr, Format(#13#10'Thread: %u', [GetCurrentThreadId]) + GetStackInfo());
end;

class procedure TMyMonitorHook.TRCommit(tr: TIBTransaction);
begin
  FTransactions.Remove(tr);
end;

class procedure TMyMonitorHook.TRRollback(tr: TIBTransaction);
begin
  FTransactions.Remove(tr);
end;

class procedure TMyMonitorHook.SendError(AMsg: String);
var
  LMsg: string;
  LTrans: TDictionary<TIBTransaction, string>;
  LPair: TPair<TIBTransaction, string>;
begin
  LMsg := Format('Thread: %u'#13#10, [GetCurrentThreadId]);
  LTrans := FTransactions.BeginRead;
  try
    for LPair in LTrans do begin
      LMsg := LMsg + LPair.Key.Name + LPair.Value + sLineBreak;
    end;
  finally
    FTransactions.EndRead;
  end;
  ShowMessage(LMsg);
end;

class procedure TMyMonitorHook.Init;
var
  LHook: IIBSQLMonitorHook;
  LPair: TPair<Integer, Pointer>;
  LErr: TErrProc;
begin
  LHook := MonitorHook;
  LPair.Key := 8;
  LPair.Value := WriteAddr(LHook, LPair.Key, TRStart);
  FOldMethods.Add(LPair);

  LPair.Key := 9;
  LPair.Value := WriteAddr(LHook, LPair.Key, TRCommit);
  FOldMethods.Add(LPair);

  LPair.Key := 11;
  LPair.Value := WriteAddr(LHook, LPair.Key, TRRollback);
  FOldMethods.Add(LPair);

  LErr := SendError;
  LPair.Key := 19;
  LPair.Value := WriteAddr(LHook, LPair.Key, TMethod(LErr).Code);
  FOldMethods.Add(LPair);
end;


Дисклаймер. Класс использовался для поиска конкретной ошибки. При использовании класса при завершении программы вылетает AV, но его я уже не искал

С уважением, Vasilisk
18 сен 19, 12:57    [21973186]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30655

18.09.2019 12:57, _Vasilisk_ пишет:
> Полазив по коду самого IBX, увидел, что вся действия логируются через MonitorHook и далее выводятся через TIBSQLMonitor.
> Проблема в том, что логирование крайне скудное, а реализация IIBSQLMonitorHook
> скрыта так далеко в implementation, что до нее не добраться.
> Поэтому решил патчить VMT у IIBSQLMonitorHook.

манияк!
пересобрал бы нафиг весь IBX из исходников, да и дело с концом.

Posted via ActualForum NNTP Server 1.5

18 сен 19, 13:04    [21973190]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11281
Мимопроходящий
пересобрал бы нафиг весь IBX
Да ну нафиг. Вначале думал о модификации только модуля IBSQLMonitor, но потом подумал, что придется пересобирать все и отказался от идеи
18 сен 19, 13:08    [21973195]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30655

18.09.2019 13:08, _Vasilisk_ пишет:
> Да ну нафиг. Вначале думал о модификации только модуля IBSQLMonitor,
> но потом подумал, что придется пересобирать все и отказался от идеи

напрасно.
ибо глюков и откровенной лажы там поле непаханое.
не говоря уж об обработке isc_кодов_ошибок.
без напильника - не юзабельно.

Posted via ActualForum NNTP Server 1.5

18 сен 19, 13:19    [21973200]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11281
Мимопроходящий
без напильника - не юзабельно.
Как-то 15 лет уже юзаю. Единственное что добавил - наследника TIBDataSet для работы с двумя транзакциями
18 сен 19, 14:18    [21973253]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30655

18.09.2019 14:18, _Vasilisk_ пишет:
> Как-то 15 лет уже юзаю. Единственное что добавил - наследника TIBDataSet для работы с двумя транзакциями

а у нас прямо в TIBCustomDataSet встроено.
ТРИ транзакции!
третья - RefreshTransaction, по умолчании равна ModifyTransaction.

а обработчик ошибок IBX тебя не напрягает?

Posted via ActualForum NNTP Server 1.5

18 сен 19, 14:34    [21973265]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11281
Мимопроходящий
а обработчик ошибок IBX тебя не напрягает?
Нет. А что с ним не так?
18 сен 19, 14:40    [21973271]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30655

18.09.2019 14:40, _Vasilisk_ пишет:
> Нет. А что с ним не так?

статус-вектор обычно содержит 3-4 кода с аргументами (так их FB выдаёт).
IBX считает кодом ошибки самый первый (верхний), а остальные тают в тумане.
а это неправильно.
первый код зачастую указывает на некую "группу ошибок".
последующие её конкретизируют.
вплоть до номера строки, позиции символа и тому подобное.
IBX-у это всё до лампады.
у него один класс Exception-ов в котором присутствует один код ошибки (isc_xxx).
мне такая консерватория не нужна.


Posted via ActualForum NNTP Server 1.5

18 сен 19, 14:54    [21973289]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11281
Мимопроходящий
статус-вектор обычно содержит 3-4 кода с аргументами
Не знал. Но я на IB сижу. Там, скорее всего, все таки один код
18 сен 19, 15:33    [21973332]     Ответить | Цитировать Сообщить модератору
 Re: Патч для IIBSQLMonitorHook  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30655

18.09.2019 15:33, _Vasilisk_ пишет:
> Не знал. Но я на IB сижу.
> Там, скорее всего, все таки один код

нет.
дёрни функцию StatusVectorAsText и посмотри что там.

Posted via ActualForum NNTP Server 1.5

18 сен 19, 15:37    [21973335]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить