Případ TinyDB a XE2

vložil Radek Červinka 28. ledna 2012 22:55

Pod článkem s anketou ohledně nejvyšší používané verze jsou i dva komentáře stěžující si na problémy s XE2. Leoš si stěžoval na design mód a stabilitu ohledně IBX komponent a JaroB na problémy s portací TinyDB z XE do XE2. Bohužel Leoše v tom asi musím nechat, jelikož IBX komponenty a já se nemáme rádi, ale ohledně TinyDB jsem si řekl, že bych to mohl zkusit.

Výsledkem byl zajímavý možný problém ohledně TStream.

JaroB udržuje haldu komponent a je velmi schopný. Jenže člověk někdy pak už trpí slepotou když se v něčem párá moc dlouho (vlastní zkušenost). Takže jsem mu napsal ať pošle testovací projekt a že zkusím štěstí. Pokud Vás nezajímají podrobnosti tak skočte rovnou na řešení.

Problém byl, že nefungovala podpora BLOB - výsledek byl prázdný stream dat s nulovou délkou, resp. při AsString to vracelo prázdný řetězec.

Nevěřil jsem, že by byl problém v kompilátoru - zvláště když se jednalo o 32bit verzi - ta je prý prakticky stejná jako v XE. Kdyby byl problém s 64bit kompilátorem tak bych i možná o tom uvažoval (pár minoritních problémů se opravovalo - upravuje). Takže zbýval problém zarovnání (nebyl jsem si jist, ale přišlo mi, že se tam s tím nějak zašachovalo), velikost nějaké struktury (kvůli 64bit se opravovalo x datových struktur, které jsou v předchozích verzích deklarovány nekorektně - ale tady kompilátor celkem spolehlivě hlásí varování nebo chyby) nebo nějaká změna ve VCL/RTL (také k vůli 64bitům).

Po ověření, že to tedy opravdu nefunguje jsem aplikoval klasický postup:

  • vypnutí optimalizací
  • zapnutí DEBUG dcu
  • vypnutí inline (to mne napadlo až po chvilce, když jsem stále nemohl krokovat kritickou část)
  • souběžné krokování v XE
procedure TTinyBlobStream.LoadBlobData;
var
  RecBuf: TRecordBuffer;
  BlobStream: TMemoryStream;
begin
  if FDataSet.GetActiveRecBuf(RecBuf) then
  begin
    Inc(RecBuf, FDataSet.GetFieldOffsetByFieldNo(FFieldNo));
    BlobStream := PMemoryStream(RecBuf)^;
    if Assigned(BlobStream) then
    begin
      Clear;
      CopyFrom(BlobStream, 0);
      Position := 0;
    end;
  end;
end;

A tady jsem v podstatě propadl částečnému zoufalství. BlobStream po přiřazení nic neobsahoval (resp. velikost byla 0) a přece se pokoušel z něho kopírovat. Bez úspěchu.

V souběžném krokování v Delphi XE, ale s úspěchem (ale tato situace byla jen poprvé, pak už před voláním 0 nebyla). Zde jsem se na nějakou dobu zasekl až mne napadlo vypnout inline a důsledně krokovat.

function TStream.CopyFrom(Source: TStream; Count: Int64): Int64;
const
  MaxBufSize = $F000;
var
  BufSize, N: Integer;
  Buffer: PByte;
begin
  if Count = 0 then
  begin
    Source.Position := 0;
    Count := Source.Size;
  end;
  Result := Count;
….

A tady bych měl vyhráno, kdybych nebyl medvědem. Dal jsem si totiž breakpoint na řádek s Count := Source.Size;, kde v XE2 se vracela 0, kdežto v XE hodnota. Problém byl v řádku Source.Position := 0;

Position je totiž property a volá Seek a tato metoda byla předefinována

function TOptimBlobStream.Seek(Offset: Integer; Origin: Word): Longint;
begin
  LoadBlobData;
  Result := inherited Seek(Offset, Origin);
end;

LoadBlobData navíc kontroluje zda je třeba data nahrávat (cache) což úžasně komplikovalo ladění. Jenže proč to v XE2 nefunguje?

Řešení

Třída TStream byla v XE2 rozšířena o 64bit verzi Seek. Přičemž 64bit varianta volá defaultně 32bit variantu a naopak pokud je to třeba.

  TStream = class(TObject)
…
    function Seek(Offset: Longint; Origin: Word): Longint; overload; virtual;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; virtual;

Vše funguje v případě, že predefinujete buďto 32bit nebo 64bit a nebudete volat původní implementaci.

A protože TCustomMemoryStream využívá nově 64bit variantu a TOptimBlobStream předefinovává 32bit variantu (a volá základní třídu) je problém. Řešením ve 2 hod. ráno bylo přidat stejnou implementaci i pro 64bit verzi, ale teď si myslím, že by správně bylo jen použít 64bit variantu.

Tagy: , ,

Praxe

Komentování ukončeno

Naše nabídka

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Poslední komentáře

Comment RSS

Dle měsíců