PDA

View Full Version : [c] File system associativo con metadati


braian
10-02-2008, 21:22
Il problema
Si vuole realizzare un file system associativo che consenta di accedere in maniera più flessibile a un insieme di file memorizzato su
disco. Per ogni file, vengono memorizzati anche dei metadati, che ne specificano alcune proprietà arbitrarie. Per esempio, un
documento di testo potrebbe avere metadati per nome dell'autore, argomento, set di caratteri usato, numero di pagine, ecc.; un file
sorgente potrebbe invece avere metadati per nome dell'autore, funzionalità implementate, numero di revisione, nome del sistema a
cui appartiene, versione del linguaggio di programmazione usato, esito dei test, IDE usata, ecc.
Un elemento di metadati è una coppia (chiave, valore) in cui la chiave è un identificatore (nel senso classico di un carattere alfabetico
seguito da una sequenza di caratteri alfanumerici), mentre il valore può essere una stringa, un numero (floating point), o una data/ora.
Scopo del file system associativo è consentire di memorizzare su memoria permanente, oltre ai dati contenuti in un file, i meta-dati
relativi, ed effettuare ricerche efficienti di un file basate sui valori dei metadati

Realizzazione
Il file system associativo deve fornire una serie di funzioni di libreria che mimino quelle della libreria standard di I/O, con l'aggiunta
di opportuni parametri per assegnare i metadati a un file, modificarli, cancellarli, ed effettuare ricerche. Queste ultime possono essere
di tre tipi: per uguaglianza o per sottostringa sulle chiavi di tipo stringa, per confronto numerico sulle chiavi di tipo numerico o
data/ora (minore, minore uguale, uguale, maggiore o uguale, maggiore). La progettazione di questa API è parte dello sviluppo.


La mia idea è quella di creare una struttura dati a llist di questo tipo:

union valore
{
char* stringa;
float numero;
int data;
};

struct metadato
{
char* chiave;
union valore val;
int tipoval;
struct metadato* next;
};

struct filemem
{
char* nomefile;
struct metadato* first;
struct filemem * next;
};



Oltre a questo pensavo di effettuare la serializzazione dei dati su file per consentire il ripristino della struttura con una funzione start() all'avvio del sistema operativo.
Per la creazione di file ho pensato a una soluzione di questo tipo:



int createf(const char *path,const char *mode,char* fmt,...) //funzione con numero di parametri variabile, i primi 2 servono per la fopen, il terzo è una stringa di formato per i parametri variabili. E'un errore nn passare la stringa di formato, al limite passarla vuota per non inserire metadati. Eventuali parametri in più rispetto a quelli specificati nella stringa di formato vengono ignorati.
{
va_list ap; //il puntatore a argomento
FILE* file; //il file da creare o modificare
FILE* filesave=fopen("save.sav","a"); //il file di salvataggio delle associazioni
int close;
int lung;
char* stringa;
char* sval;
float fval;
struct tm * t;
time_t tx;

int scritti;

if ((file=fopen(path, mode))==NULL)
{
printf("errore1");
}
scritti=fprintf(filesave,"%s,",path);
if (scritti<0)
{
printf("errore 10");//trattamento errore
}
va_start(ap,fmt);
while(*fmt!='\0')
{
if(isalpha(*fmt)!=0)
{
lung=strcspn(fmt," ");
char *str=malloc(sizeof(char)*lung+1);
stringa=strncpy(str,fmt,lung);
stringa[lung]='\0';
if(fputs(stringa,filesave)==EOF) //scrive il nome del metadato
{
printf("errore2");//gestione errore in fputs
}
fputc(',',filesave);
fmt=fmt+lung; //fmt punta al successivo formato di tipo metadato(%s,%n..)
if(isspace(*fmt)==0)
{
printf("errore3");//trattamento errore, non c'è lo spazio dopo il nome di metadato
}
fmt++;
if(*fmt=='%')
{
fmt++;
switch(*fmt)
{
case 's':
sval=va_arg(ap,char*);
scritti=fprintf(filesave,"\%s,%s,",sval);
if (scritti<0)
{
printf("errore 11");
}
fmt++;
break;
case 'n':
fval=va_arg(ap,double);
scritti=fprintf(filesave,"%f,",fval);
if (scritti<0)
{
printf("errore 12");
}
fmt++;
break;
case 'd':
t=va_arg(ap,struct tm*);
tx=mktime(t);
if (tx == (time_t) (-1))
{
printf ("Errore! %ld\n", (long int) tx); //trattamento errore data da rivedere
}
scritti=fprintf(filesave,"%d/%d/%d,",t->tm_mday,t->tm_mon+1,t->tm_year+1900);
if (scritti<0)
{
printf("errore 14");
}
fmt++;
break;
default :
printf("errore4");//trattamento errore formato sconosciuto
break;
}
}
else
{
printf("errore5");//gestione errore, non c'è % dopo il nome del metadato e lo spazio
}

}

}
scritti=fprintf(filesave,"\n");
if (scritti<0)
{
printf("errore15");
}
close=fclose(filesave);
if (close==EOF)
{
//trattamento errore
}
va_end(ap);
return 0;

}



In questa funzione ho tralasciato però il fatto di aggiornare subito la mia struttura dati. Comunque si capisce in che modo vorrei salvare su file i dati della struttura. Altro problema che mi si presenta è quello che se nella stringa di formato o negli argomenti passati alla mia funzione si verifica un errore a quel punto avrei già scritto parte degli argomenti sul file. Quindi mi viene da pensare che sarebbe meglio crearmi prima la variabile struct filemem per memorizzare il file mentre lo elaboro ed eventualmente cancellarla in caso di errore dopo di che salvare eventualmente su file.
Mi chiedo poi se un approccio del genere sia giusto o sia meglio creare una "pipe" dalla mia funzione direttamente a una fprintf e poi rileggere da file e ricreare la struttura con una fscanf (sempre che questo si possa fare).


HELP

gugoXX
11-02-2008, 00:10
La struttura dati direi che va bene.
In C non penso si possa fare tanto di meglio. Qui si inizia a capire che le classi e l'ereditarieta' potrebbero aiutare parecchio.
In pratica ti si sta chiedendo di realizzare un mini-database.

Per quanto riguarda la scrittura su file, non sono riuscito a capire se conti di avere un file per i "File" e uno per i "Metadati". Io almeno farei cosi'.
Il gestirli separatemente avrebbe vantaggi tipo la gestione indipendente dell'entita' "File" e della relazione "Metadato".

Il nome del file sarebbe la chiave primaria di ciascun file.
La coppia "Nome de file" + "Nome del metadato" sarebbe invece la chiave primaria di ciascun metadato.

Il file dei "File" avrebbe quindi l'elenco di ciascun file, ciascuno con la chiave (nome) e le sue caratteristiche richieste (ma ce ne sono?)
Il file dei "Metadati" avrebbe l'elenco dei metadati. Ciascuno con la chiave (nome del file, nome del metadato) e a seguire su ciascuna riga ci sarebbero le caratteristiche del metadato, nel formato che si preferisce.
Un opportuno campo (basta un carattere) iniziale su ciascuna riga potrebbe stare ad indicare se la riga e' cancellata o meno (cosi' cancelliamo in fretta).
L'inserimento dovrebbe essere facile (occhio alle violazioni di chiave), sempre in coda al file.
La cancellazione pure.
Per l'aggiornamento procederei con una cancellazione e poi un nuovo inserimento.
Gli inserimenti proporrei di farli piu' atomici possibile. Scrivi la riga in un opportuno buffer di memoria, e poi la salvi tutta insieme in un comando solo.
Questo ti consiglio di farlo indipendentemente dalla soluzione.

Se ti piace si puo' proseguire, senno' cerca pure tranquillamente un'altra strada. Come detto programmare e' un processo creativo, nulla e' legge.
Ci sono pero' dipinti belli e dipinti brutti. Questo non mi sembra tanto brutto.

_____________


PS: Mi e' venuto in mente un modo "cattivo" per barare malamente.
Se e' un esercizio pero' conta che i prof. normalmente non apprezzano chi bara. Se pero' l'apprezzano e' li' che prendi la lode.

braian
11-02-2008, 00:41
Intanto grazie per la risposta, per la serializzazione avrei pensato di utilizzare un solo file di salvataggio per gestire file e metadati insieme.
Questo anche perchè le uniche informazioni che devo salvare riguardanti i file sono appunto i metadati.

Da quello che mi dici e come pensavo dovrei prima memorizzare tutti i nomi e tipi di metadati in una stringa fino ad avere controllato la correttezza della stringa di formato e i reltivi argomenti prima di copiare su file in modo da non scrivere prima di trovare errori (ATOMICITA') o comunque in altro modo simile.

Vorrei piuttosto sapere se possible cosa ne pensi della funzione in se, nel senso se ti pare giusto che effettui io controlli sulla stringa di formato e argomenti come faccio oppure se vedi possibile in qualche altro modo che al momento vedo oscuro, di creare una pipe tra la mia funzione e una fprintf per scrivere direttamente i dati su file e utilizzare una fscanf per ricaricarli.
Il tutto in modo da ripulire un po' il codice da variabili e per far gestire eventuali errori direttamente dalle suddette funzioni

:)

gugoXX
11-02-2008, 00:51
Vorrei piuttosto sapere se possible cosa ne pensi della funzione in se, nel senso se ti pare giusto che effettui io controlli sulla stringa di formato e argomenti come faccio oppure se vedi possibile in qualche altro modo che al momento vedo oscuro, di creare una pipe tra la mia funzione e una fprintf per scrivere direttamente i dati su file e utilizzare una fscanf per ricaricarli.
Il tutto in modo da ripulire un po' il codice da variabili e per far gestire eventuali errori direttamente dalle suddette funzioni

:)

Se non sbaglio esisteva in c qualcosa chiamato ssprintf, ovvero la scrittura di una stringa formattata su una stringa.

Il caricarli con la fscanf subito non l'ho capito.
Ma l'esercizio non consta nel costruire una libreria di supporto ai metadati, ma su file? Non penso che tu possa considerare di averli sia in memoria che su file.
L'esercizio sarebbe quello di scrivere i metadati su file, realizzando le funzioni insert/delete/update
E poi di andarli a cercare e leggere sempre da file quando richiesto... Non mi servirebbe la fscanf subito, o no?
Ma forse ho capito male.

Resta che il metodo "baro" mi ispira sempre di piu'...

braian
11-02-2008, 01:11
Le operazioni fondamentali richieste sono quelle appunto di crazione di file attribuendogli i metadati, di modifica dei metadati associati a un file e di ricerca di file basata su condizioni logiche sui metadati.
Io immaginavo di tenere i dati memorizzati sia su file che su una struttura dati (tutta la struttuta del primo messaggio) per i seguenti motivi:
-il file per la consistenza e quindi il poter ritrovare i metadati associati ai file anche dopo la chiusura e il riavvio del sistema operativo;
-la struttura per velocizzare le operazioni di ricerca che richiedono tempo lineare sui metadati.

Il la fscanf imaginavo che fosse utilizzabile per caricare i dati dal file alla struttura, magari con qualche meccanismo particolare tipo salvare su un altro file, quando trasferisco i dati dalla struttura al file di salvataggio, i tipi di formato contenuti nel file di salvataggio ovvero avere sull' altro file la stringa di formato da passare alla fscanf

:confused:

cosa intendi per metodo baro?

gugoXX
11-02-2008, 08:34
Le operazioni fondamentali richieste sono quelle appunto di crazione di file attribuendogli i metadati, di modifica dei metadati associati a un file e di ricerca di file basata su condizioni logiche sui metadati.
Io immaginavo di tenere i dati memorizzati sia su file che su una struttura dati (tutta la struttuta del primo messaggio) per i seguenti motivi:
-il file per la consistenza e quindi il poter ritrovare i metadati associati ai file anche dopo la chiusura e il riavvio del sistema operativo;
-la struttura per velocizzare le operazioni di ricerca che richiedono tempo lineare sui metadati.

Anche io nella realta' farei cosi'.
Se pensi che l'esercizio lo permetta allora sei a posto.

Il la fscanf imaginavo che fosse utilizzabile per caricare i dati dal file alla struttura
Esatto, ma per cosa detto prima il caricare i dati da file serve solo all'inizio, non ogni volta che scrivi su file.
Per intendere, quando p.es. inserisci, inseirisci sia sul file che sulla liste di strutture in memoria. Nessuna fscanf.

Se sia l'inserimento che l'aggiornamento li fai sempre in append, al fondo del file, non avrai problemi di lunghezza variabile di record.


cosa intendi per metodo baro?
Fatto salvo che la ricerca la fai in memoria, il metodo baro sarebbe quello di creare un file di metatadati per ciascun file fisico.
Es: pippo.txt e' il file, pippo.mtd e' il file associato di metadati.
Niente di nuovo e di inventato... e' gia' stato fatto altre volte in passato.
Ma appunto non so se sia accettabile.

braian
11-02-2008, 09:15
ti ringrazio della pazienza che mi hai dedicato, un ultima cosa, secondo la specifica le funzioni in caso di errore devono stampare su STANDARD ERROR e non su stderr. Che vuol dire?

gugoXX
11-02-2008, 10:00
Non lo so. So cos'e' STDERR, ma non cosa sia STANDARD ERROR, ma come detto sono anni che non scrivo una riga di C puro.
Sotto windows oggi si scrive comunemente sull'event log...

cionci
11-02-2008, 10:23
stderr è l'abbreviazione di standard error...

gugoXX
11-02-2008, 10:30
stderr è l'abbreviazione di standard error...

Si, ma se le specifiche dicono
secondo la specifica le funzioni in caso di errore devono stampare su STANDARD ERROR e non su stderr.
Mi rendono un po' confuso...

cionci
11-02-2008, 10:32
Davvero strano...boh...