Database Visual Foxpro: come aumentare la sua affidabilità


L'affidabilità di un Database anche di piccole e medie dimensioni è la condizione essenziale per una buona applicazione software. Ecco alcuni semplici suggerimenti pratici

Articolo di Andrea Nicchi ©

Il proliferare di applicazioni che lavorano su database di piccole e medie dimensioni, porta automaticamente a delle considerazioni sull'affidabilità di questo tipo di sistemi di gestione di basi di dati.
Non stiamo, quindi, parlando di Microsoft SQL Server o Oracle, che di per sé sono dotati di meccanismi per garantire il più possibile l'integrità logica e fisica dei dati.
Andiamo in questo articolo ad analizzare il sistema di gestione di basi di dati di Microsoft Visual Foxpro dalla versione 3.0 in poi. Vedremo come è possibile raggiungere un buon livello di affidabilità con dei semplici ma efficaci accorgimenti.

Malfunzionamenti software


Dobbiamo innanzitutto chiarire alcuni concetti che sono alla base degli argomenti trattati in questo articolo. Una base di dati è una rappresentazione della realtà osservata, per questo bisogna che i dati ivi memorizzati rappresentino informazioni significative.
Quando viene disegnata una base di dati, questa viene progettata sulla base delle specifiche fornite dall'utente. Queste regole devono essere soddisfatte dai dati presenti nella stessa base dati. Si dice che una base di dati si trova in uno "stato corretto" quando questa rappresenta coerentemente la realtà osservata nel rispetto delle specifiche.
Nel momento in cui modifichiamo una base dati, con il meccanismo delle transazioni la facciamo transitare in un nuovo stato.Ricordiamo che un transazione è un'unità logica di lavoro, quindi la base dati si considera transitata nel nuovo stato dopo la fine della transazione, in quanto tra il begin transaction e l'end transaction siamo in presenza di elaborazioni parziali e quindi di uno "stato transitorio". Qualora il nuovo stato non rappresentasse coerentemente la realtà osservata ci troveremmo in una situazione di dati non consistenti e, quindi, di transizione in uno "stato errato". Questo processo va sotto il nome di malfunzionamento software orIginato essenzialmente da un errore logico del software.
Quando, invece, dei "fallimenti" del sistema di elaborazione intaccano la struttura fisica dei dati rendendoli illeggibili, o, ancora peggio, modificano il contenuto semantico del dato o dell'informazione generale immediata o derivata, si parla di malfunzionamenti hardware e di sistema. Cercheremo di affrontare in questo articolo il problema di queste due ultime classi di anomalie.

Malfunzionamenti hardware


Anche un malfunzionamento hardware, quindi, è un evento che porta la base dati in uno stato non corretto e cosa molto più grave potrebbe addirittura comportare la perdita di dati in modo irreparabile.
Alcuni esempi di queste anomalie sono:
· rottura del dispositivo di memoria permanente;
· malfunzionamento della scheda di rete etc.
Come si può notare siamo in presenza di accadimenti determinati da fattori completamente fuori del nostro controllo, ma che comunque vanno intelligentemente gestiti per non determinare dei lunghi fermi del sistema informatico.
E' chiaro che di fronte alla rottura di un disco rigido o di altro dispositivo hardware non si può fare nulla se non prevenire rendendo fault tolerant il sistema di memorizzazione ad esempio con un sistema di mirroring o duplexing. Siamo, quindi, in situazioni in cui l'unica procedura di ripristino è quella che fa uso della ridondanza dei dati. Quest'ultima tecnica, in sostanza, è quella utilizzata anche da sistemi di gestione di basi di dati di fascia alta. Microsoft SQL Server nonostante faccia uso del giornale delle modifiche deve impostare il suo sistema di recovery in modo tale da ricostruire tutte le modifiche apportate sulla base dati a partire dall'ultima copia di back-up. Rimane, quindi, la malaugurata situazione in cui, dopo un crash di sistema si rovini in modo irrecuperabile il file di log . In questo caso anche per SQL Server non c'è possibilità di recuperare i dati.

Malfunzionamenti di sistema


Questa ulteriore classificazione dei malfunzionamenti che inficiano la struttura fisica della base dati sono in pratica quelli a cui cercheremo di far fronte in maniera automatica. Questi accadono facendo degli esempi quando si verifica:
· un calo improvviso della tensione elettrica;
· un fallimento del sistema operativo etc.;
le strutture dati più delicate di una base dati si potrebbero rovinare, come: gli indici o nel caso di tabelle DBF l'header della tabella stessa, che come sappiamo contiene preziose informazioni per il trattamento dei dati che essa memorizza come la struttura dei record e la cardinalità della tabella.
Puntiamo in questo caso in un recovery automatico che dia una tolleranza a questi tipi di guasti, che si presentano, nonostante tutto, con una frequenza non trascurabile (mediamente alcune volte l'anno) e con danni economici di una certa rilevanza nel caso si tratti di sistemi software che devono assicurare un servizio continuo.


figura 1: componenti che concorrono alla gestione fisica dei dati
Protezione da malfunzionamenti di sistema
Vediamo ora un modo per far fronte a queste anomalie.
Analizziamo in primis i componenti, vedi figura 1, che concorrono alla gestione fisica dei dati in Visual Foxpro. Essi sono essenzialmente due: il File System del Sistema Operativo e il Database di FoxPro.
Il File System da preferire è sicuramente l'NTFS di Windows NT, per la sua struttura e le suo livello di affidabilità, rispetto al File System di tipo FAT e su questo credo siamo tutti d'accordo.
Passiamo ora a descrivere la struttura del Database. Esso è costituito, vedi figura 2, dal Data Base Container e da un insieme di tabelle ad esso collegate. Occorre subito sottolineare che nel presente articolo prenderemo in considerazione un "database semplice" cioè un database privo di stored procedure, senza view locali o remote e da tabelle senza relazioni permanenti.
Il punto più debole di questa struttura è, come è facilmente intuibile, l'insieme dei collegamenti che tengono unite le singole tabelle con il "contenitore virtuale" e che danno la possibilità di vedere come un'unica entità il Database Foxpro
dal Database Designer. Il primi elementi che potrebbero essere intaccati nella loro integrità a seguito di un
malfunzionamento di sistema sono appunto le associazioni o meglio i link.

Il rimedio, sperimentato negli anni, è quello di "ricostruire" questi legami, quando si verificano queste situazioni o, anche, in modo preventivo periodicamente. Questo trucco non risolve tutte le possibili situazioni ma elimina sicuramente le più banali, che non sono poche, legate appunto alla perdita di queste informazioni essenziali per la vita di una database di Visual Foxpro.


Figura2: Struttura del Database di Visual FoxPro

Un esempio concreto


Con un semplice esempio concreto cerchiamo ora di chiarire meglio quanto detto prima. Per prima cosa creiamo una database Foxpro. Dopo aver aperto Visual Foxpro dal menu File selezioniamo la voce New … , quindi diamo il nome al nostro database nel caso particolare DataBase.dbc. Successivamente dal menu Database selezioniamo la voce New Table … ed aggiungiamo due banali tabelle table1 e table2. Associamo a queste un indice selezionando la tabella e dal menu Database scegliendo la voce Modify …. Dalla finestra che appare selezioniamo la scheda Indexes, digitiamo sulla colonna Name ad esempio nome e nella colonna Expression il nome del campo della tabella, confermiamo il tutto, facciamo le stesse cose anche per la seconda tabella. Alla fine dal Database Designer avremo una situazione come in figura 3.

Tutto questa attività, eseguita in maniera visiva intuitivamente, con il Database Designer ha prodotto questo elenco di file:

Database.DBC && Database
Database.DCT && Databse Memo
Database.DCX && Database Index
Table1.DBC
Table1.CDX
Table2.DBF
Table2.CDX

Figura 3: Database di Visual Foxpro da Database Designer

Anche se noi vediamo una cosa sola cioè un contenitore con delle tabelle dentro, di fatto, memorizzato nel file system, abbiamo questo elenco di tabelle, è il Database Designer che come per magia ci fa vedere un unico oggetto, diversamente da Access dove tutto è compresso in binario in un monoblocco il cui nome ha suffisso MDB.

Una prima osservazione evidenzia che l'apparente complessità del database Foxpro dà sicuramente allo sviluppatore una maggiore flessibilità e padronanza delle strutture che memorizzano i dati elementari.
Continuando nell'analisi il database Foxpro è costituito dai tre file rispettivamente con suffisso: DBC, DCT e DCX; di fatto una particolare tabella con un indice, contenente tutti i nomi delle tabelle che esso contiene e dei relativi indici vedi figura 4.
Ciascuna tabella, inoltre, contiene nel suo header un riferimento al Database Container, in altre parole il container conosce gli oggetti che gli appartengono e ciascuna tabella sa il nome del suo Database.

Figura 4: Il contenuto della tabella database .dbc

 

Il nome del database di appartenenza di una tabella si trova nell'header della tabella stessa. I dati in esso contenuti vengono usati con elevata frequenza nelle elaborazioni, ad esempio quando viene aggiunto un record alla tabella, o quando su questa viene fatto un lock nel caso di accesso condiviso alla stessa.
Questo dimostra perché è molto probabile che l'informazione contenuta nell'header di una tabella di tipo DBF possa corrompersi o perdersi.

La logica applicativa
Un rimedio per mantenere questa struttura è quello di integrare in una procedura applicativa un codice di "ripristino" del tipo di quello del listato 1. Analizziamo passo passo il lavoro che fa questa procedura e la sua importanza.

Per prima cosa occupiamoci di nascondere i messaggi di sistema con SET TALK OFF e SET SAFETY OFF che potrebbero in qualche modo allarmare inutilmente l'utente.Poi provvediamo alla gestione delle eccezioni .
Alcuni errori che sorgono durante questa attività, infatti, non sono da considerare come tali, ma solo dei fault che sono opportunamente da mascherare in modo da far rientrare il codice sulla strada dell'esecuzione regolare.
Le seguenti eccezioni intercettate dalla potente trappola ON ERROR non sono, infatti, da classificare come veri e propri errori bloccanti:

Error 19 si presenta quando l'indice non è allineato con la relativa tabella, ma questa è una delle situazioni che andiamo a bonificare per cui occorre ignorare questo errore;
Error 1558 si verifica quando la tabella non è legata ad un database, anche in questo caso occorre ignorare tale errore in quanto potremmo essere in una situazione in cui qualche legame si sia perso.
Error 1707 quando associamo di nuovo la tabella al database, l'indice composto (CDX) relativo sicuramente non è presente per cui questo errore viene quasi sicuramente generato.

Una volta impostata la gestione intelligente delle eccezioni possiamo procedere allo smembramento del database ed alla sua ricostruzione.
Per prima cosa cancelliamo gli indici contraddistinti dal suffisso CDX, con l'istruzione DELETE FILE.
Sganciamo poi le tabelle dal database con l'istruzione FREE TABLE ed infine cancelliamo il database con DELETE DATABASE. che essendo di fatto una tabella abbiamo intenzione di ricreare inizializzandola opportunamente. Tutte queste operazioni sono mere azioni su un insieme dei file gestiti dal File System corrente.
Nella seconda parte, invece, procediamo alla ricostruzione del Database di Visual Foxpro. Creiamo, quindi, il database con CREATE DATABASE. Sostanzialmente creiamo, come già detto, una tabella che ha come suffisso DBC. Popoliamo, poi, il Database Container con le tabelle mediante il comando ADD TABLE.
Non ci rimane altro che provvedere alla ricostruzione degli indici associati alle tabelle con l'istruzione INDEX ON.
A questo punto abbiamo ricostruito interamente il nostro Database con la certezza che tutta la struttura sia ben definita e senza problemi.
Per stare comunque più tranquilli eseguiamo poi il comando VALIDATE DATABASE che controlla che i path delle tabelle e dei relativi indici siano corretti, nonché i links di collegamento reciproco.
Questa istruzione non può essere eseguita a codice con l'opzione RECOVER, cosa che può essere fatta nella finestra di comando dell'ambiente di sviluppo di Visual Foxpro. Questa opzione è molto utile soprattutto per ripristinare l'integrità fisica del Database in situazioni più difficili, ma quasi annullate da questo trattamento software.


Il Wizard Database


L'ambiente di sviluppo fornisce un wizard che a partire da un Database visto dal Database Designer genera il codice per la sua ricostruzione.
Come si può vedere dal Listato 2, in esso, anche se completo, non troviamo quelle accortezze necessarie a rendere un database più affidabile. Lo scopo del wizard, infatti, è quello di aiutare lo sviluppatore a ricostruire un Database senza ripetere visualmente tutte le operazioni.


VFP e .NET


La facilità di manipolazione dei dati di Foxpro porta sicuramente a considerarlo anche in scenari in cui entra in gioco Visual Studio.NET. La potenza dei cursori di Foxpro che permettono elaborazioni complesse sulla base di dati potrebbe essere racchiusa in un oggetto COM intermedio tra il front-end e il contenitore dei dati vedi figura 5.
Tutta questa struttura ha bisogno di una robustezza del database che deve essere aumentata con gli opportuni accorgimenti di cui abbiamo parlato che è possibile integrare nell'oggetto COM.


Fig 5: Visual Foxpro e .NET
E' chiaro che con ADO.NET possiamo avere la stessa struttura avendo come back-end oltre cha una Data Base Foxpro anche SQL Server o Oracle, ma qui stiamo considerando soluzioni software che fanno uso di strumenti di un certo livello economico e magari con analisi dei dati più immediate e flessibili.

Conclusioni
Integrare in una soluzione software accorgimenti per mantenere l'integrità fisica dei dati è, a mio avviso, uno degli aspetti più importanti da considerare. Non si può, come nel caso di sistemi di gestione dei dati di fascia media delegare tutto al sistema di gestione incorporato nello strumento di sviluppo. Occorre valutare la soluzione informatica nel suo insieme cercando di prevenire il più possibile con meccanismi hardware e software in modo da renderla il più possibile tollerante ai malfunzionamenti. E' su questo terreno che si nota il vero valore aggiunto e la professionalità di applicazione software.

Listato 1
public m.InfoBasePath
m.InfoBasePath ="c:\…\databasemanagement\"
= RebuildInfoBase ( m.InfoBasePath )
return

PROCEDURE RebuildInfoBase ( m.xiInfoBasePath )
*--
* Purpose > Rebuild Info-Base and Index
*--
*-- Settings
      SET SAFETY OFF
      SET TALK OFF
*-- Error Handler Settings
      LOCAL M.EH_Active, M.LocError
      M.EH_Active = ON("ERROR")
      ON ERROR DO SetErrorMonitor && M.LocError = .T.
*-- Work Area Initializing
      CLOSE TABLES ALL
      CLOSE DATABASES ALL
      CLOSE ALL
*-- Base Informativa Fondamentale
      *-- Parte 1
            DELETE FILE (ALLTRIM(m.xiInfoBasePath)+"table1.CDX") RECYCLE
            DELETE FILE (ALLTRIM(m.xiInfoBasePath)+"table2.CDX") RECYCLE
            FREE TABLE ( ALLTRIM(m.xiInfoBasePath)+"table1.DBF" )
            FREE TABLE ( ALLTRIM(m.xiInfoBasePath)+"table2.DBF" )
            DELETE DATABASE (ALLTRIM(m.xiInfoBasePath)+"database.DBC")
      *-- Parte 2
            CREATE DATABASE (ALLTRIM(m.xiInfoBasePath)+"database.DBC")
            OPEN DATABASE (ALLTRIM(m.xiInfoBasePath)+"database.DBC") EXCLUSIVE
            SET DATABASE TO (ALLTRIM(m.xiInfoBasePath)+"database.DBC")
            ADD TABLE (ALLTRIM(m.xiInfoBasePath)+"table1.DBF")
            ADD TABLE (ALLTRIM(m.xiInfoBasePath)+"table2.DBF")
            PACK DATABASE 
*-- Building Base Informativa Fondamentale
      SELECT 10
      USE (ALLTRIM(m.xiInfoBasePath)+"TABLE1.DBF") EXCLUSIVE
      pack
      INDEX ON table1.nome1 TAG nome ascending
      SELECT 11
      USE (ALLTRIM(m.xiInfoBasePath)+"TABLE2.DBF") EXCLUSIVE
      pack
      INDEX ON table2.nome2 TAG nome ascending
*-- Physical Integrity
      VALIDATE DATABASE
      CLOSE TABLES
      PACK DATABASE
      CLOSE DATABASE
      COPY FILE (ALLTRIM(m.xiInfoBasePath)+"database.DCX") TO (m.xiInfoBasePath+"IBBK.DCX")
      COPY FILE (ALLTRIM(m.xiInfoBasePath)+"database.DCT") TO (m.xiInfoBasePath+"IBBK.DCT")
      COPY FILE (ALLTRIM(m.xiInfoBasePath)+"database.DBC") TO (m.xiInfoBasePath+"IBBK.DBC")
*-- Error Handler Settings
      IF NOT EMPTY(M.EH_Active)
            ON ERROR &EH_Active
      ELSE
            ON ERROR
      ENDIF
ENDPROC
*
PROCEDURE SetErrorMonitor
public M.EM_NUMBER, M.EM_MSG
M.EM_NUMBER = ERROR()
M.EM_MSG = MESSAGE()
WAIT WINDOW M.EM_MSG+"/ "+ALLTRIM(STR(M.EM_NUMBER)) TIMEOUT 0.8
if not used("excepion")
      select 200
      use ("c:\…\databasemanagement\exception.dbf") exclusive
endif
select exception
append blank
repla exception.ewhen with datetime()
repla exception.enumber with ERROR()
repla exception.emsg with message()
repla exception.ecode with message(1)
ENDPROC

listato 2

* *********************************************************
* *
* * 14-02-2002 DATABASE.DBC 19:43:35
* *
* *********************************************************
* *
* * Description:
* * This program was automatically generated by GENDBC
* * Version 2.26.67
* *
* *********************************************************
CLOSE DATA ALL
CREATE DATABASE 'DATABASE.DBC'
MakeTable_TABLE1()
MakeTable_TABLE2()

FUNCTION MakeTable_TABLE1
***** Table setup for TABLE1 *****
CREATE TABLE 'TABLE1.DBF' NAME 'TABLE1' (NOME1 C(10) NOT NULL)

***** Create each index for TABLE1 *****
SET COLLATE TO 'MACHINE'
INDEX ON NOME1 TAG NOME

***** Change properties for TABLE1 *****
ENDFUNC

FUNCTION MakeTable_TABLE2
***** Table setup for TABLE2 *****
CREATE TABLE 'TABLE2.DBF' NAME 'TABLE2' (NOME2 C(10) NOT NULL)

***** Create each index for TABLE2 *****
SET COLLATE TO 'MACHINE'
INDEX ON NOME2 TAG NOME
***** Change properties for TABLE2 *****
ENDFUNC
FUNCTION DisplayStatus(lcMessage)
WAIT WINDOW NOWAIT lcMessage
ENDFUNC

Bibliografia
[1] Antonio Albano - "Appunti di Documentazione Automatica", Università di Pisa, 1987
[2] Jenny Brown - "VFP in a .NET World", FoxPro Advisor, Ottobre 2001


Riferimenti
[1] www.west-wind.com
[2] www.foxitaly.com

© Articolo: Andrea Nicchi

Andrea Nicchi è laureato in Scienze dell'Informazione e si occupa da anni di soluzioni informatiche sia tradizionali che web-based.

© FoxPro e Visual FoxPro sono un marchi registrati da Microsoft Corporation

 

 

Marzo 2002
 

FoxPro e Visual FoxPro® sono un marchi registrati da Microsoft Corporation

 


dal 22 Giugno 1999
webmaster@foxitaly.com