P R O G R A M U J E M Eage – poèet udávajúci, ko¾ko predchádzajúcich verzií interface je kompatibilných s tým<strong>na</strong>jnovším. Toto èíslo nesmie by väèšie ako current. Keby bol current <strong>na</strong>príklad 5 a age 2,potom by sme s touto kninicou mohli spusti aj programy, ktoré boli linkované s inter−face 3, 4 aj 5.Tieto tri èísla musíme meni v podstate pri kadom release kninice a treba to robiopatrne a dôsledne. Staèí, ak si dobre uvedomíme, èo z<strong>na</strong>me<strong>na</strong>jú jednotlivé èísla, a ak sabudeme riadi <strong>na</strong>sledujúcimi pravidlami: Vdy, keï zmeníme zdrojové kódy kninice, inkrementujeme revision. Teda ideo novú revíziu aktuálneho interface (došlo iba k interným zmenám). Ak zmeníme interface (<strong>na</strong>príklad pridáme argument do <strong>na</strong>šej funkcie hello()),inkrementujeme current a revision <strong>na</strong>stavíme <strong>na</strong> nulu. Ide o prvú revíziu novéhointerface. Ak je nový interface rozšírením predchádzajúceho, ale všetky funkciez predchádzajúceho interface ostali nezmenené (èo sa týka interface, nieimplementácie), inkrementujeme aj age. Nový interface je spätne kompatibilný s týmpredchádzajúcim. Ak v novom interface odstránime funkciu, ktorá sa <strong>na</strong>chádzala v predchádzajúcominterface, porušíme tým spätnú kompatibilitu a age musíme vynulova. Teda mámenový, ale spätne nekompatibilný interface.Prvý release vôbec má oz<strong>na</strong>èenie 0:0:0. Tu je súbor hello.h:#include 3void hello(char* <strong>na</strong>me);A tu je hello.c:#include void hello(char* <strong>na</strong>me){printf("hello, %s", <strong>na</strong>me);}Funkcia síce robí to, èo má, ale v záujme estetickosti výpisu <strong>na</strong> koniec vypisovanéhoreazca pridáme z<strong>na</strong>k prechodu <strong>na</strong> nový riadok \n. Bohuia¾, absenciu tohto z<strong>na</strong>ku sme sivšimli a po prvom release. Jeho pridanie je z nášho poh¾adu dos dôleitá udalos <strong>na</strong> to,aby sme spravili nový release ☺. Inkrementujeme teda revision a dostaneme oz<strong>na</strong>èenieverzie: 0:1:0. Medzitým, samozrejme, zmeníme aj súbor configure.in, ktorý vyzerá takto:dnl Process this file with autoconf to produce a configure script.AC_INIT(src/Makefile.am)AM_INIT_AUTOMAKE(hello, 2.0)AC_PREFIX_DEFAULT(/usr/local)AM_CONFIG_HEADER(config.h)AC_PROG_INSTALLAC_PROG_LN_SAM_PROG_LIBTOOLAC_OUTPUT(Makefile src/Makefile test/Makefile doc/Makefile)Zme<strong>na</strong> sa týka druhého riadka, ktorý definuje názov balíka a jeho verziu. To, ako bude−me meni tento riadok, je iba <strong>na</strong> nás. Záleí to <strong>na</strong> mnohých veciach; okrem iných aj <strong>na</strong>tom, èi sme sa rozhodli pouíva dve, tri alebo štyri èísla. Ako sme si u povedali, nemáto <strong>na</strong> oz<strong>na</strong>èovanie verzií, ktoré pouíva libtool, nijaký vplyv.Ne<strong>sk</strong>ôr sme sa rozhodli znovu zlepši <strong>na</strong>šu kninicu a znovu to bola iba interná zme<strong>na</strong>(Èo sa dá <strong>na</strong> takej funkcii meni? U ma niè ne<strong>na</strong>padá ☺), a tak sme sa dopracovali k ver−zii 0:2:0. Potom sme pridali funkciu hi(), take tu je hello.h:#include void hello(char*);void hi(char*);Nasleduje hello.c:#include void hello(char* <strong>na</strong>me){printf("Hello, %s!\n", <strong>na</strong>me);}void hi(char* <strong>na</strong>me){printf("Hi, %s!\n", <strong>na</strong>me);}Pridanie novej funkcie však nijako neovplyvnilo funkènos funkcie hello() – nový inter−face je spätne kompatibilný s tým predchádzajúcim. Preto vynulujeme revision (mámenový interface) a inkrementujeme current a age (pre neporušenú kompatibilitu). Takedostávame verziu 1:0:1. Ne<strong>sk</strong>ôr sme sa však rozhodli prida prvej funkcii parameter type,od ktorého závisí, ako bude vyzera výsledný pozdrav. Take <strong>na</strong>jprv hello.h:#include void hello(char*, int);void hi(char*);A teraz hello.c:#includevoid hello(char* <strong>na</strong>me, int type){if (type == 1)printf("hello, %s\n", <strong>na</strong>me);else if (type == 2)printf("hello, %s!\n", <strong>na</strong>me);else if (type == 3)printf("Hello, %s\n", <strong>na</strong>me);elseprintf("Hello, %s!\n", <strong>na</strong>me);}void hi(char* <strong>na</strong>me){printf("Hi, %s!\n", <strong>na</strong>me);}Sami vidíte, e funkciu hello() musíme vola trošku ináè, a preto sme dostali nekom−patibilnú verziu. Vynulujeme teda age a revision a inkrementujeme current – dostali smesa k verzii 2:0:0, ktorú, bohuia¾, u nemôeme poui pre programy, ktoré pouívalipredchádzajúce verzie <strong>na</strong>šej kninice. Ukáme si ešte výsledný Makefile.am:## Process this file with automake to produce Makefile.inlib_LTLIBRARIES = libhello.lalibhello_la_SOURCES = hello.clibhello_la_LDFLAGS = −version−info 2:0:0include_HEADERS = hello.hDISTCLEANFILES = ./.deps/* ./.deps/.PPri zmene interface neh¾adíme iba <strong>na</strong> to, èi sme zmenili API (teda tých pár funkcií, ktorémôe pouíva nejaký program vyuívajúci <strong>na</strong>šu kninicu). Musíme si <strong>sk</strong>ontrolova aj to,èi sme nezmenili nejaký formát súboru, sieový protokol, a všetko, s èím <strong>na</strong>ša kninicapracuje (samozrejme, teraz nemám <strong>na</strong> mysli kninicu hello ☺).Na záver tejto témy si ešte uvedieme príklad súèasného pouitia parametrov −version−info a −release. Predstavte si, e vaša kninica sa utešene rozrastá a dostala sa do štádia,keï by ju bolo dobré rozdeli <strong>na</strong> stabilnú a nestabilnú verziu. Vy však nechcete, aby sipouívatelia museli svoje programy prelinkova s vašou kninicou vdy, keï vydáte novýrelease. V tomto prípade pouijeme −release <strong>na</strong> oz<strong>na</strong>èenie verzie priamo v názve súborukninice. Pre prvý release stabilnej vývojovej vetvy pouijeme −release 1.0, pre nestabilnúvetvu to bude −release 1.1. Takto si zároveò zabezpeèíte binárnu nekompatibilitu medzitýmito vetvami a pouívatelia si nebudú môc vy<strong>sk</strong>úša kombinova <strong>na</strong>príklad programzaloený <strong>na</strong> stabilnej verzii kninice s nestabilnou kninicou a <strong>na</strong>opak a nespôsobia simoný pád programu.CFLAGS. Na zaèiatku tejto èasti sme spomí<strong>na</strong>li parametre programu libtool, ktoré sapouijú v móde linkovania. Takisto sme spomenuli, e existuje viacero iných módov. Násteraz bude zaujíma kompilovací mód. Všetko, èo priradíme premennej ..._la_LDFLAGS, sapouije ako parameter pri linkovaní. Predstavte si však, e by ste chceli odovzda nejaképarametre kompilátoru, a nie linkeru. Na to pouijeme premennú CFLAGS, tentoraz tobude bez akéhoko¾vek prefixu, pretoe táto premenná je spoloèná pre všetky súbory aprogramy, ktoré má daný súbor Makefile.am.Všetky parametre, ktoré môeme v kompilovacom móde programu libtool poui, sizobrazíme spustením libtool −−help −−mode=compile. Nie je ich a tak ve¾a (dva), zaujímavýje dokonca iba jeden z nich: −static. Tento parameter „presvedèí“ libtool, aby vytvoril ibastatickú kninicu – štandardne sa toti vytvára statická aj dy<strong>na</strong>mická kninica. O rozdie−loch medzi nimi sme si u èo−to povedali minule. Teraz si dáme dokopy to, èo sme sadozvedeli v predchádzajúcom aj tomto odseku, a vytvoríme nový súbor Makefile.am, ktorýnám vytvorí iba statickú kninicu, ktorú <strong>na</strong>vyše optimalizuje prepí<strong>na</strong>èom prekladaèa −O3.## Process this file with automake to produce Makefile.inlib_LTLIBRARIES = libhello.lalibhello_la_SOURCES = hello.clibhello_la_LDFLAGS = −version−info 2:0:0CFLAGS = −O3 −staticinclude_HEADERS = hello.hDISTCLEANFILES = ./.deps/* ./.deps/.PA týmto by sme <strong>sk</strong>onèili ïalšie pokraèovanie nášho seriálu o programoch z rodinky Auto−tools. Teším sa <strong>na</strong> ïalšie stretnutie!Oto Komiòák12/2002 PC REVUE 163
P R O G R A M U J E M EMalé ve¾ké databázy III.7. (závereèná) èasV tejto èasti seriálu sa pozrieme <strong>na</strong> databázu MySQL zo systémového h¾adi<strong>sk</strong>a. Poviemesi nieèo o tom, èo by mala silná databáza ma a èo MySQL má èi nemá, ako to rieši a akovyladi server <strong>na</strong> plný výkon.Výkonný produkt – áno èi nie?V dnešnej dobe relatívne neobmedzených informácií sa vynára potreba èo <strong>na</strong>jvýkonnej−šieho databázového produktu. Výkonnos kadého produktu je daná dvoma aspektmi:a) robustnosou databázového systémub) optimalizáciou behu systémuROBUSTNOS SYSTÉMU. Pod týmto pojmom si môeme predstavi poèet a efek−tivitu funkcií systému. Systému, ktorý obsahuje viac (<strong>na</strong>ozaj) potrebných funkcií, hovorí−me, e je robustnejší.Medzi <strong>na</strong>jdôleitejšie funkcie systému zaraïujeme: transakcie – transactions uloené procedúry – stored procedures kurzory – cursors spúšaèe – triggers obmedzujúce pravidlá – constrainsRobustnos je však <strong>na</strong> úkor rýchlosti systému. Spravidla systém, ktorý obsahuje viacfunkcií, a je teda robustnejší, býva aj pomalší.Naopak, systém, ktorý neobsahuje niektoré funkcie, býva ve¾mi rýchly. Nesmieme si všakzamieòa pojem rýchly s pojmom výkonný! Výkonnos je akýsi kompromis medzi robust−nosou a rýchlosou systému.Pozrime sa informatívne <strong>na</strong> jednotlivé funkcie a porov<strong>na</strong>jme ich s monosami MySQL.TRANSAKCIE. Transakcia je <strong>sk</strong>upi<strong>na</strong> spracúvaných èinností, ktoré sú kompletne celédokonèené, alebo keï nie sú dokonèené, sú databázy a systém spracúvania ponechané v rov−<strong>na</strong>kom stave ako pred zaèatím transakcie. Transakcie sa povaujú za atomické operácie.Pre názornos si uveïme príklad:Majme databázu FINANCIE a v nej tabu¾ku VYPLATY s dvoma ståpcami ZAMESTNANECa PLAT. Teraz nezáleí <strong>na</strong> type jednotlivých ståpcov.Predstavme si, e zrazu <strong>na</strong>stane fantastický deò, keï sa vedenie podniku rozhodne, esa všetkým zamest<strong>na</strong>ncom zvyšujú platy o 30 %. My ako programátori èi obsluha systé−mu musíme zabezpeèi túto úlohu. Zadáme príkaz, aby sa prepoèítali všetky platy. Úlohabeí, keï tu zrazu <strong>na</strong>stane neoèakávaný výpadok servera! Po obnove servera dostávamenepravdivé informácie. Èas platov je zvýšená, zvyšok ešte nie. Ale ktoré sú to?Práve transakcie zabezpeèia, e dáta, <strong>na</strong>d ktorými úloha nie je z rôznych dôvodov úpl−ne dokonèená, sa vrátia do pôvodného stavu.Preto <strong>na</strong>šu úlohu budeme rieši pomocou transakcie. V prípade podobného výpadku ser−vera sa dáta vrátia do stavu pred spustením úlohy (teda nezmení sa ani jeden plat, pokia¾nie sú zmenené všetky). V prípade, e ne<strong>na</strong>stanú iadne komplikácie, úloha sa správa akobená èinnos servera.Transakèná èinnos je vnútorná èinnos databázového stroja, preto sa o òu ve¾mi ne−musíme stara. Staèí, ak príkazy <strong>na</strong>šej úlohy uzavrieme medzi transakèné príkazy BEGINTRANS, COMMIT alebo ROLLBACK TRANS.MySQL u v posledných verziách podporuje transakcie, ale iba <strong>na</strong> tabu¾kách typuInnoDB. V bene pouívanom type MyISAM transakcie nefungujú. Treba priz<strong>na</strong>, e sú ibav zaèiatkoch a ich kvalita sa bude zlepšova.Musíme si uvedomi, e práve transakcie <strong>na</strong>jviac zdrujú èinnos databázového stroja,teda ho podstatne spoma¾ujú.ULOENÉ PROCEDÚRY. Uloená procedúra je postupnos preloených (<strong>sk</strong>ompilo−vaných) príkazov SQL (presnejšie jazyka Transact SQL), uloených v databáze priamo <strong>na</strong>databázovom serveri.Uloené procedúry ponúkajú mnoho výhod. Jednou z nich je monos odovzdávania para−metrov. Zároveò zvyšujú bezpeènos databázy – pouívate¾, ktorý nemá explicitné práva po−uíva urèitú tabu¾ku, môe s touto tabu¾kou pracova práve pomocou uloených procedúr.Jedným z hlavných prínosov uloených procedúr je, e sú vykonávané ove¾a rýchlejšie akobené príkazy.Pouívanie uloených procedúr nemá v podstate nijaké nevýhody (okrem tej, e takéto pro−cedúry musia by pripravené dopredu a vopred uloené <strong>na</strong> serveri).MySQL zatia¾ nemá monos uloených procedúr, dá sa však oèakáva, e sa v <strong>na</strong>jblišíchverziách objavia (presnejšie by mali by vo verzii 4.1).MySQL server zatia¾ rieši tento nedostatok metódou tzv. pouívate¾<strong>sk</strong>y definovaných funk−cií – user defined function – UDF. Sú to funkcie, ktoré musia by <strong>na</strong>písané v jazyku C aleboC++.KURZORY. Kurzory umoòujú pracova s jednotlivými riadkami výslednej súpravy. Ichpouitie sa ve¾mi podobá prechádzaniu výslednej súpravy pomocou objektov rozhraniaAPI. Kurzor umoòuje programátorovi alebo správcovi databázy vykonáva <strong>na</strong> strane ser−vera pomerne zloité operácie. Je to celkom praktická funkcia, ale práca s kurzormi vya−duje hlbšie z<strong>na</strong>losti.Nevýhodou kurzorov je ich slabý výkon, <strong>na</strong>vyše sú z<strong>na</strong>ène pomalé. MySQL neobsahu−je kurzory – a to je len dobre.SPÚŠAÈE. Spúšaè – trigger – je v podstate uloená procedúra, ktorá sa spustí auto−maticky ako reakcia <strong>na</strong> urèitú akciu a ktorá slúi <strong>na</strong> zachovanie integrity databázy. Akcie,ktoré môu spusti spúšaè, sú príkazy UPDATE, DELETE a INSERT.Majme tabu¾ky KNIHY a ARCHIV_KNIH. Predpokladajme, e chceme, aby sa kadýzáz<strong>na</strong>m odstránený z tabu¾ky KNIHY uloil do tabu¾ky ARCHIV_KNIH.Namiesto toho, aby sme pridávali zloitý kód do aplikácie, ktorá záz<strong>na</strong>m odstráni apresunie do druhej tabu¾ky, alebo aby sme volali uloenú procedúru ruène, môemepoui spúšaè. Ten sa automaticky spustí pri kadom odstránení záz<strong>na</strong>mu z tabu¾ky KNI−HY a jeho úlohou je odstraòovaný záz<strong>na</strong>m uloi do tabu¾ky ARCHIV_KNIH.Spúšaèe majú celý rad výhod. U¾ahèujú zachovávanie referenènej integrity a vyuívajúsa <strong>na</strong> zaistenie platnosti relácií medzi záz<strong>na</strong>mami zviazaných tabuliek. Práve preto, e súspúšané automaticky ako dôsledok inej akcie, môu slúi ako nástroj automatickejúdrby databázy.Ïalšou zaujímavou vlastnosou spúšaèov je ka<strong>sk</strong>ádový efekt. K tomu dochádza, keïspúšaè spustený ako dôsledok urèitej udalosti v jednej tabu¾ke vyvolá spustenie inéhospúšaèa, ktorý zase reaguje <strong>na</strong> príslušnú udalos vo svojej tabu¾ke. To môe by <strong>na</strong> jed−nej strane ve¾mi uitoèné, ale <strong>na</strong> druhej strane aj ve¾mi nebezpeèné.Majme tabu¾ky OBCHODY, kde vedieme obchodnú èinnos, OBJEDNÁVKY, kde evidu−jeme objednávky jednotlivých zákazníkov, a OPERACIE, kde sú evidované všetky obchod−né operácie v súvislosti s objednávkami. Predpokladajme, e chceme odstráni všetkyzáz<strong>na</strong>my v tabu¾ke OBCHODY, ktoré sa viau ku konkrétnemu zákazníkovi. Namiesto to−ho, aby sme tvorili špeciálny program v <strong>na</strong>šej aplikácii, ktorý by po danom zákazníkovi„upratal“, pouijeme spúšaè. Vytvoríme taký spúšaè, ktorý odstráni všetky záz<strong>na</strong>my vtabu¾ke OBJEDNAVKY viazané <strong>na</strong> odstraòovaného zákazníka. A k tabu¾ke OBJEDNAVKYmôeme pripoji ïalší spúšaè, ktorý odstráni všetky obchodné operácie spojené s od−straòovanými záz<strong>na</strong>mami o objednávkach v tabu¾ke OPERACIE.Uvedomme si, e spúšaèe sú uloené <strong>na</strong> strane servera, ich kód je v pamäti systémua spúšajú sa automaticky!Preto ich vôbec nemusíme vola v zdrojovom kóde <strong>na</strong>šej aplikácie!Nevýhodou spúšaèov je fakt, e spoma¾ujú a zaaujú systém. Pri kadej operácii <strong>na</strong>ddanou tabu¾kou sa musí databázový stroj presvedèi, èi sa <strong>na</strong> danú akciu neviae niekto−rý spúšaè. Ak áno, musí ho spusti a vyko<strong>na</strong>. Táto èinnos blokuje èas procesora a týmèas celého systému.MySQL nemá monos poui spúšaèe. Môeme to však obís dobrým návrhom data−bázy a následných aplikácií. Najlepšie je zaisova integritu databázy priamo v kóde apli−kácií. Upratujme po sebe v dátach a nebudeme potrebova spúšaèe!(No musím priz<strong>na</strong>, e by som takúto funkciu v MySQL privítal. V prípade, e by som junechcel pouíva, dal by som to serveru pri spustení <strong>na</strong>javo nejakým prepí<strong>na</strong>èom, aby saz<strong>na</strong>ène zrýchlil. A keï by som ich v inej aplikácii potreboval, tak by som ich zase „zapol“).Pod¾a vyjadrenia autorov MySQL triggermi sa budú zaobera od verzie 4.1 vyššie.OBMEDZUJÚCE PRAVIDLÁ. Obmedzujúce pravidlo (constraint) je spôsob, ako vy−núti dodriavanie pravidiel zaistenia platnosti relácií medzi záz<strong>na</strong>mami zviazaných tabu−liek. Existuje nieko¾ko typov obmedzujúcich pravidiel, ale všetky majú spoloèný cie¾ − zais−tenie referenènej integrity.Predstavme si pole tabu¾ky alfanumerického typu, ktoré by malo obsahova iba pís−mená. Môeme <strong>na</strong>stavi obmedzujúce pravidlo, ktoré pouívate¾ovi zabráni vloi akéko¾−vek èíslo! A tento kód nemusíme implementova <strong>na</strong> strane aplikácie, ale priamo <strong>na</strong> serveri.Obmedzujúce pravidlá však ve¾mi zaaujú systém, a preto sa v MySQL ne<strong>na</strong>chádzajú.Zaistenie integrity dát je teda úplne v rukách programátorov a správcov databázy.OPTIMALIZÁCIA BEHU SYSTÉMU. Ve¾mi èasto (teda <strong>sk</strong>oro vdy!) sa stáva,e po urèitej dobe funkènosti nášho dobrého projektu opadne poèiatoèné <strong>na</strong>dšenie aprogramátori a pouívatelia sa zaènú saova <strong>na</strong> pomalos celého systému. Preto budepotrebné pristúpi k optimalizácii systému, èím dosiahneme urèité zrýchlenie.Faktorov spoma¾ujúcich samotnú rýchlos systému je nieko¾ko a spravidla vdy sa vzmysle Murphyho zákonov spájajú do tej <strong>na</strong>jhoršej kombinácie.Èinnosti eliminujúce tieto faktory si môeme rozdeli do týchto <strong>sk</strong>upín: dolaïovanie výkonu databázy zostavovanie lepších dopytov SQL uvo¾òovanie nevyuitého priestoru úprava a kompilácia zdrojových kódov serveraDOLAÏOVANIE VÝKONU DATABÁZY. Jedným z prvých faktorov, <strong>na</strong> ktorý by smesa mali zamera, je samotný systém. Na akom type poèítaèa je spustený náš databázovýserver? Ko¾ko pamäte má k dispozícii? Aký rýchly je procesor? A di<strong>sk</strong>?Samozrejme, e <strong>na</strong>jlepšie by bolo, keby bol databázový server spustený <strong>na</strong> samostat−nom stroji <strong>na</strong>jmodernejšej konštrukcie s èo <strong>na</strong>jlepšími parametrami. Ale sami vieme, e tonie je vdy moné, a preto treba pristúpi k rozumným kompromisom.Našastie MySQL (<strong>na</strong> rozdiel od iných databázových strojov) nemá ve¾mi vysoké náro−ky <strong>na</strong> hardvér. Asi <strong>na</strong>jviac ho bude „tlaèi“ ve¾kos operaènej pamäte. To preto, leboMySQL je viacvláknový systém. Pri <strong>na</strong>dviazaní spojenia s klientom je vytvorené nové vlák−no – podproces, ktorého úlohou je plni poiadavky klienta. Kadé vlákno poaduje urèi−tú èas operaènej pamäte. Take èím viac pamäte, tým lepšie! Systém s väèšou operaè−nou pamäou býva výkonnejší.Ak teda musíte voli medzi rýchlejším procesorom alebo väèšou pamäou, siahnite popamäti!164 PC REVUE 12/2002