Expert Software Company : News

joi, 15 iulie 2010

buffering

Prima sugestie ar fi sa folosesti indecsi compusi (au extensia .cdx si contin toate cheile de indexare intr-un singur fisier). Index On cod Tag iVal si respectiv Index on Nume Tag iNume. Exista doua dezavantaje: 1. Indexarea trebuie sa fie facuta cu tabela deschisa exclusiv (dar operatiunea asta o faci o data cand creezi tabela si eventual daca iti crapa fisierul de index, deci nu e o problema de care te lovesti in fiecare zi), si 2. Nu poti sa indexezi o tabela deschisa in Table Buffering mode. Dar aceste doua dezavantaje sunt, dupa parerea mea, acoperite cu varf si indesat de avantajele pe care le obtii: unul ar fi ca indexul se deschide automat odata cu tabela si poti sa faci SET ORDER TO iVal si respectiv SET ORDER TO iNume oricand doresti, fara sa intampini eroarea aia pe care o ai acum. Altul ar fi ca poti folosi toate comenzile legate de indecsi (ATagInfo, de exemplu). Altul ar fi acela ca ori de cate ori modifici, stergi sau adaugi o inregistrare fisierul de index se actualizeaza automat, pe toate cheile de indexare, si nu ai nevoie sa faci reindexarea (care mananca timp) decat in situatii cu totul exceptionale.

Cat despre diferenta dintre Row si Table buffering, uite care-i treaba, folosind propriile mele cuvinte (s-ar putea sa difere de definitiile de prin carti/help):

Folosirea buffering-ului inseamna sa-l pui pe VFP sa creeze un spatiu intre tine si tabela de pe disc. Aparent USE tabela deschide tabela si poti sa inserezi, stergi sau modifica inregistrari. Totusi nu se intampla asa; tu de fapt scrii in spatiul ala, numit buffer. Daca modifici o inregistrare in buffer, ea nu se scrie in tabela decat la TableUpdate(). Daca modifici in buffer si dai QUIT, de exemplu, tabela ramane nemodificata (chestie foarte desteapta, de altfel. In FPD programatorii au folosit tot felul de tehnici pentru a-si proteja tabelele: tabele temporare, care la sfarsitul operatiunii erau varsate pe disc, in tabelele finale, sau SCATTER/GATHER, folosind variabile de memorie pe post de campuri. Toate astea numai pentru a reduce manevrele cu tabela "de baza", reducand astfel sansele ca ea sa crape).

Well... Buffering-ul este exact "tamponul" dintre aplicatie si tabela. Scrii in buffer pana te plictisesti, si cand te-ai plictisit, TABLEUPDATE() sau TABLEREVERT(). Ghici ce face fiecare dintre ele :).

Mai departe. Buffering-ul asta e de mai multe feluri: optimistic/pessimistic si respectiv row/table. Rezulta 4 combinatii, la care se adauga a 5-a - no buffering.

Daca-i pesimistic, la citirea inregistrarii se plaseaza un LOCK() pe inregistrarea respectiva. De remarcat faptul ca pot sa am buffering pe tabela sau pe rand si lock-ul se plaseaza corespunzator (pe inregistrare sau pe toata tabela).

Daca-i optimistic, lock-ul se plaseaza doar la tentativa de scriere in tabela, ceea ce permite ca mai multi utilizatori sa citeasca tabela simultan, si sa scrie cand doresc, dar care ridica o problema importanta: cum rezolvi conflictele de actualizare. Well.. asta-i alta discutie deja.

Daca-i table, bufferul este cat tabela. Cu alte cuvinte, daca scrii intr-o inregistrare, poti sa te muti la urmatoarea, si apoi la urmatoarea, etc, pana termini de actualizat toate inregistrarile, iar la sfarsit ii trantesti un TABLEUPDATE() peste ochi si gata - se salveaza. (daca nu se salveaza, TableUpdate() intoarce .F., iar daca executi imediat un AError(laErrorArray), in array-ul laErrorArray ai pe pozitia a 2-a mesajul de eroare).

Daca-i row, bufferul e doar de un rand. Scrii in inregistrarea aia, si daca ii dai TABLEUPDATE() sau TABLEREVERT() se comporta corect. In schimb, problema MAJORA (si am folosit majuscule) este ca daca nu dai nici tableupdate, nici tablerevert, dar te muti la alta inregistrare, VFP executa un TABLEUPDATE() automat, ceea ce poate sa nu-ti convina. Daca introduci o factura, de exemplu, factura aia trebuie salvata toata sau deloc (header-ul facturii, respectiv pozitiile din factura). In scenariul asta, tableupdate() executat de VFP cand vrea muschiu' lui este reteta sigura pentru date inconsistente.

Mai mult (hehe, ca in reclamele alea idioate: but wait! there's more!): Este posibil ca mutarea pointerului de inregistrare (care determina tableupdate necontrolat) sa se execute in situatii greu de anticipat. De exemplu, IndexSeek() muta pointerul. Quite nashpa, I'd say.

Ca atare, recomandarea mea ar fi sa nu folosesti Row Buffering. Cu exceptia indexarii (care vrea row buffering) tot ce poti face in Row Buffering poti face si in Table Buffering. Daca ai nevoie de indexare, atunci CursorSetProp("Buffering", 3), INDEX ON, CursorSetProp("Buffering",5) si-ai rezolvat problema.

Niciun comentariu:

Trimiteți un comentariu