lobotomy
LOBOTOMY PROJECT

hyppocampus
HYPPOCAMPUS PROJECT

Modello di Disposizione dei Metadati: Array Linkato
(v0.4, 04.02.2006)



Abstract
Questo documento presenta una struttura dati, attualmente ancora in fase di perfezionamento, studiata per poter conservare nel filesystem di Hyppocampus tutti i dati (e, soprattutto, i metadati) dei files presenti nel sistema e per agevolarne la ricerca.



Sommario:

Introduzione
Sulla mailing list del progetto Hyppocampus si e' piu' volte dibattuto sul modo migliore di disporre i metadati all'interno del filesystem fisico, in modo da poter effettuare velocemente ricerche, anche incrociate, su una quantita' di dati potenzialmente immensa e poter operare poi sui risultati di tali ricerche delle operazioni di tipo relazionale, tipiche dei database cui Hyppocampus si ispira.
Allo stato attuale esistono due proposte per soddisfare questa necessita': qui ne viene presentata una, al momento quella maggiormente dettagliata, che contempla l'uso di una struttura dati molto particolare, studiata ad hoc per l'esigenza, chiamata informalmente "array linkato". Essa permette di effettuare ricerche sia per metadato che per file, ovvero di reperire sia l'insieme di files cui e' associato un tal metadato con un tal valore sia l'insieme dei metadati associati ad un dato file, in tempi non esageratamente lunghi ma comunque migliorabili.
Si prevede di sperimentare al piu' presto la seguente struttura "sul campo", realizzando cioe' un piccolo programma che agisca secondo le specifiche sotto riportate su un insieme ristretto di informazioni, onde poterne meglio valutare le effettive potenzialita'.

Precondizioni
Prima di iniziare la descrizione della struttura in se', e' bene fornire qualche informazione sui dati che essa dovra' contenere: i files saranno identificati univocamente da un numero, un ID, unsigned a 32 bit: il che vuol dire che potranno esistere fino a 4.294.967.296 diversi files. I metadati saranno raccolti entro un insieme predefinito di tipi, ed ogni tipo sara' identificato a sua volta da 32 bit unsigned (dunque: 4.294.967.296 possibili tipi di metadati) e sara' descritto da un nome utente ("nome file", "larghezza immagine", "album del brano musicale"... Si prevede che tali nomi saranno gestiti con un meccanismo di internazionalizzazione, onde poter associare ad ogni tipo di metadato il suo nome utente nella lingua preferita) e da un tipo di valore (int, char, wchar_t... Indica il modo in cui interpretare i bit che si troveranno nel nodo di definizione di un metadato).
Come forse intuibile, buona parte degli algoritmi di ricerca si fonderanno sulle proprieta' matematiche degli unsigned long long che rappresentano tanto i files quanto i metadati.

Panoramica iniziale
La struttura si compone di un numero prefissato di array (attualmente se ne sono ipotizzati 65536, ovvero 2^16) numerati che contengono ognuno, in modo ordinato, tutti i metadati (di tutti i files) il cui tipo e'
tipo_metadato % numero_totale_array == numero_array
Tali metadati saranno ordinati in modo crescente per tipo, e al loro interno i sottoarray di metadati saranno ordinati in ordine crescente per valore. Da considerare sin da ora che ogni sottoarray di metadati viene preceduto da un "header", ovvero un elemento dell'array facilmente identificabile in quanto header e che contiene utili informazioni sul sottoarray che lo segue.

Ogni array conterra' strutture cosi' definite:

typedef struct NodoArray {
    unsigned long next;
    unsigned long file;
    char flags;
    char value [ 64 ];
};

"next" indica il prossimo metadato specificato per il file cui il metadato si riferisce; "file" l'ID del suddetto file; "flags" e' un array di bits che fornisce maggiori informazioni sul valore del metadato contenuti nel nodo (secondo lo schema di seguito presentato); "value" un insieme di bit che rappresenta il valore del metadato per quel file, oppure, se sfora la dimensione fissata, un indirizzo per un'area del disco appositamente preposta a contenere informazioni che non stanno fisicamente all'interno della struttura dati. Suddetta area speciale deve ancora essere studiata nel dettaglio, e per ora non se ne forniscono ulteriori informazioni.

I flags definiti per il nodo sono: {
    00000001    nel nodo / puntatore
    00000010    un elemento / piu' di un elemento nel valore
    00000100    unused
    00001000    unused
    00010000    unused
    00100000    unused
    01000000    unused
    10000000    unused
}

A questo punto pare evidente che non solo si puo' facilmente (e velocemente) reperire l'insieme di files cui e' associato un certo metadato, ma, ricostruendo la "lista" di metadati che si collegano logicamente tra loro mediante il parametro "next", anche l'insieme di metadati associati ad un certo file.

schemino

Ricerca per metadato
La ricerca per metadato avviene in realta' per "tipo" di metadato: conoscendo quale numero identifica univocamente quel tipo di metadato, lo si puo' cercare nell'array numero tipo_metadato % numero_totale_array. Sapendo che i metadati in tale array sono ordinati innanzitutto per tipo, e' sufficiente proseguire all'interno dell'array sinche' non si incontra il primo elemento che ha appunto tipo == tipo_metadato; ma ricordiamo che ogni sottoarray di metadati e' preceduto da un descrittore, ovvero un elemento speciale all'interno dell'array, che riporta nella struttura, anziche' le informazioni canoniche, i seguenti dati:

next = 4294967296; // questo permette di identificare subito l'elemento in quanto header di sottoarray
file = tipo_metadato; // l'unsigned long long che rappresenta il tipo di metadato
flags = 00000000; // array di bit che descrivono il tipo di dato permesso per il metadato, descritto sotto
value = numero_di_elementi|numero_blocchi_liberi; // in formato long long, il numero di elementi contenuti nel sottoarray e il numero di blocchi liberi presenti nel sottoarray, prima del prossimo header

flags per l'header {
    00000000    void
    00000001    char
    00000010    short
    00000011    int
    00000100    double
    00000101    float
    00000110    struct
    00000111    enum
    00001000    unsigned
    00010000    long
    00100000    array
    01000000    permessi piu' valori nello stesso nodo
    10000000    ordinati per file (anziche' per valore)
}

In questo modo, e' palese che per avanzare nell'array e' sufficiente saltare da un header all'altro procedendo di
sizeof(NodoArray) * ( *(array_numero_N[posizione_header].value) + (array_numero_N[posizione_header].value[32] )
bytes alla volta, fino a giungere a quello che interessa.
A questo punto, una volta identificato l'inizio del sottoarray, si puo' procedere con una classica ricerca all'interno di dati ordinati per valore.

Ricerca per file
Il parametro distintivo di ogni file e' il suo ID, il quale viene trattato come qualunque altro tipo di metadato: tutti gli ID si troveranno in uno degli array di metadati (possibilmente in testa ad uno di questi, per facilitare l'accesso immediato), ordinati secondo gli stessi criteri. Come accennato, date le proprieta' degli elementi all'interno degli array l'assembramento dei metadati associati ad un file consistera' nella ricerca di ogni singolo metadato, dal quale si passera' al successivo verificando il campo "next" dell'elemento e cercando nel sottoarray previsto il nodo che ha settato nel campo "file" l'ID del file che si sta cercando.
E' evidente che questo tipo di ricerca e' assai sfavorito rispetto alla ricerca per metadato, in quanto consiste a sua volta nella ricerca di piu' metadati, ma, essendo l'obiettivo primario del progetto la manipolazione dei metadati e delle relazioni che intercorrono tra loro, si preferisce sacrificare un poco questo aspetto per garantire veloci tempi di accesso ai singoli metadati.

Accesso ai dati
In Hyppocampus, anche gli indirizzi dei blocchi che compongono i dati contenuti nei files veri e propri sono espressi come metadati, che dunque vanno trattati nello stesso modo di tutti gli altri.
Al contrario di quanto accade con la maggior parte degli attuali filesystem, i blocchi non hanno un dimensionamento fisso, ma la loro dimensione cambia a seconda dello spazio libero che si trova tra un blocco e l'altro, e si tiene traccia della dimensione di ognuno. In questo modo e' molto facile sia allocare contiguamente buona parte dei files che rintracciare in un colpo solo tutti i blocchi che compongono l'elemento desiderato. Cio' pero' implica alcune problematiche nell'indirizzamento dei blocchi, che possono essere (almeno parzialmente) mitigate con l'introduzione dei "gruppi": dividendo l'area del filesystem in parti uguali (suddivisione gia' implicita a causa della molteplicita' degli array dei metadati) e' possibile indicare solo il gruppo in cui e' stato allocato il file, e l'indirizzo dei singoli blocchi puo' essere un offset tra l'inizio del gruppo e il blocco stesso.

accesso blocchi


Da notare che l'array segnato come "dimensione dei blocchi" e' ordinato non per valore ma per file di appartenenza: in questo modo e' garantito il veloce calcolo della dimensione reale del file.
E' facile desumere che questi due array (per le dimensioni e per gli indirizzi dei blocchi) debbano essere gestiti con regole diverse rispetto a tutti gli altri.

Inserzione / rimozione di elementi
E' palese che il maggiore problema con questo tipo di struttura e' l'inserimento di nuovi elementi negli array: essendo tali elementi disposti in modo ordinato, sembra d'obbligo dover traslare una parte dell'array per far posto ad un nuovo elemento che viene prima, compromettendo, e non di poco, i tempi dell'intero sistema.
Per ovviare, almeno parzialmente, a tali inconvenienti, si pensa di generare volontariamente dei "buchi" all'interno degli array, in modo che questi possano ammortizzare gli spostamenti di dati e limitarli a piccole zone della struttura.
Quando verra' aggiunto un metadato si fara' spazio non ad uno ma a piu' elementi (il numero e' ancora da definire, ma probabilmente 5 e' un compromesso, ancora da valutare in via sperimentale), e quando verra' eliminato lo spazio lasciato libero rimarra a disposizione; i nodi non occupati potrebbero essere riconosciuti dal fatto che riportano il valore 0 nel campo "file".
Lasciando delle aree libere all'interno degli array, nel momento in cui ci sia da inserire un nuovo elemento non si dovra' spostare tutto il blocco di array che segue ma il blocco che va dalla posizione assunta dall'elemento al primo nodo disponibile.

buchi array


Disposizione fisica della struttura
Essendo la struttura disposta in realta' su piu' elementi (gli array) e' facile ipotizzare che questi possano essere disposti fisicamente sul disco rigido in modo da allinearsi tra di loro e ai cilindri del disco stesso, guadagnando sul tempo di latenza fisico richiesto per la lettura dei dati.
Questo aspetto deve ancora essere approfondito, e non se ne forniscono qui ulteriori dettagli.

Links


Copyright © 2005 - Roberto -MadBob- Guido