lunedì 26 settembre 2011

SQLite con Built-in di compressione online


Questo un mod sperimentale di Sqlite con il supporto integrato di compressione online. Progettazione e realizzazione sono discussi, limite ei parametri di riferimento forniti e il codice sorgente così come DLL predefiniti sono inclusi .

Fondo

Sia Sqlite e MySql supporto compresso (e criptati) dei database. Beh, più o meno. Supporto a SQLite è limitato a database di sola lettura che sono compressi in linea, mentre il supporto di MySQL è limitato a comprimere le stringhe (per quanto posso dire.)
Mentre si lavora su WikiDesk , un progetto del browser Wikipedia, sapevo che il database potrebbe facilmente crescere fino a 100 gigabytes. Il database di scelta qui è Sqlite a causa della sua compattezza e la mobilità. Gli inglesi discarica Wikipedia è già nella gamma di 100s a 1000s dei concerti (a seconda del tipo di discarica). WikiDesk non solo supporta diversi linguaggi di Wikipedia, ma anche progetti diversi, come Wikinotizie, Wikibooks e Wikizionario, tra i tanti disponibili in tutte le lingue, tutte nello stesso database. Teoricamente, si possono importare tutti i contenuti possibili Wiki in un unico database.
L'opportunità di comprimere questo altamente ridondante wiki-codice misto con testo Unicode è stato più o meno evidente. Così è stato ragionevole presumere altri devono avere avuto un caso simile e aggiunto il supporto per la compressione Sqlite. La mia ricerca ha dato solo i casi di cui sopra.
Una parte di me era felice di aver trovato nessun progetto precedente. Ero più che felice di roll-up le maniche e arriva a hacking.

Design Survey

Ci sono molti modi per andare sulla progettazione di un file di database compresso. Il mio scopo principale, tuttavia, era di avere completamente trasparente, supporto online e la compressione in tempo reale. Quindi il progetto deve accogliere gli aggiornamenti e le cancellazioni così come qualsiasi altra operazione di modifica supportate da SQLite.
Un approccio più ovvio è quello usato da MySql, vale a dire comprimere i campi in modo indipendente. Questo è semplice e relativamente parlando dritto in avanti. Tuttavia che sarebbe dire che LIKE non potrebbe essere utilizzato su campi stringa compressa. Raccolta e smistamento e altre caratteristiche sarà assente pure. Infatti i campi in questione non poteva essere TESTO affatto. Inoltre, si doveva comprimere esplicitamente campi, ricordatevi che è compresso e ricordatevi di decomprimere prima di utilizzarli. Ho pensato molto limitato e, probabilmente, non sarebbe valsa la pena.Un altro approccio è quello di fare questo su un livello basso, tale che sarebbe trasparente al chiamante. Tale estensione di Sqlite esiste , ma questo non produrrà grandi vantaggi in piccoli campi. Ho il sospetto che la compressione NTFS darebbe risultati migliori.
NTFS è dotato di supporto alla compressione. Era vale la pena di provarla. In una discarica inglese SimpleWiki ho potuto comprimere il file di database fino a circa il 57% della sua dimensione originale (vedi riferimento sotto). Abbastanza decente. Tuttavia non ho potuto controllo a tutti. Non ho potuto impostare la dimensione del blocco, il livello di compressione o nulla risparmiare per attivare e disattivare esso. Inoltre, l'utente potrebbe disabilitare e perdere tutti i benefici. A livello di database di compressione è più promettente. Un risultato simile può essere ottenuto utilizzandoFuseCompress o compFUSEd (su Linux), anche se, l'utente deve installare un file system per primo.
Uno dei maggiori problemi con i file del database, per quanto riguarda la compressione online è interessato, è che il database logico-struttura tipicamente memorizza i puntatori ai file di offset, in modo che vi sia uno-a-uno tra il fisico e logico-strutture. Questo è ragionevole come il database è in realtà un datastructure grande e complessa su disco (al contrario di memoria.) I nodi btree o rtree sono tipicamente indici pagina, in cui tutte le pagine hanno un predefinito, a livello di database dimensione fissa. Interrompere questa struttura renderebbe il file danneggiato. Lo scopo della dimensione fissa pagine è quello di semplificare l'assegnazione e gestione degli spazi. Questo schema è utilizzato anche da memoria e disco-manager.
Se si comprime una pagina nel database, la pagina sarebbe ora contiene due regioni: dati e spazio libero. Per utilizzare il free-spazio, si potrebbe scrivere una parte della pagina successiva in spazio libero, e il restante nella pagina successiva, e così via per tutte le pagine. Ma allora avremmo dovuto tenere traccia di frammenti di ciascuna pagina in qualche modo. Per evitare questo, possiamo lasciare il libero spazio inutilizzato, ma poi ci saremmo più spazio su disco netta salvato, come il libero spazio sarebbe ancora da assegnare su disco.
Ho potuto memorizzare il nuovi indici e gli offset in qualche tabella di allocazione aggiunte al file. Ma avrei dovuto fare un sacco di dati in movimento, riallocazione, (de) frammentazione e quant'altro solo per tenere traccia degli intervalli liberi e così via. Ovviamente questo approccio è stato abbastanza complicato e prenderebbe design molto più coinvolti e la codifica. Inoltre, Sqlite pagina-dimensioni sono molteplici di dimensione del settore del disco per atomicità. Ho dovuto avere molta familiarità con la progettazione e realizzazione Sqlite di imbarcarsi in un progetto abbastanza grande, se volevo finito e funzionante.
Il motto 'essere pigro' sembra funzionare bene per i programmatori che sono orientati all'efficienza e odio lavoro ripetitivo e soggetto a errori. Quale sarebbe l'approccio più semplice che potrebbe funzionare? Tornando a NTFS si può imparare una lezione o due sulla compressione trasparente. Il segreto è che NTFS può semplicemente allocare ogni inode libero sul disco, scrivere i dati compressi ad esso e aggiornare la tabella indice. Inode sono liste collegate, quindi è molto facile da inserire / rimuovere e modificare la catena. I file, invece, sono array di byte astratto dalla struttura del disco.Spostamento bit in giro di un array è molto più complicato e lungo rispetto all'aggiornamento nodi di una lista collegata.
Ciò che serve è il vantaggio di un file-system applicato a livello di file.
Che cosa se potessimo dire al file-system che queste spazio libero regioni del file sono veramente inutilizzati? NTFS supporta file sparsi in aggiunta al file compressi. Questo potrebbe essere usato a nostro vantaggio. Tutti dovremmo fare è segnare il libero spazio in ogni pagina come inutilizzato e il file system li renderà disponibili ad altri file presenti sul disco, riducendo lo spazio su disco utilizzato netta del database.

Il Design

Sqlite supporta pagine di 512-65535 byte. Dal momento che non può spezzare una singola pagina, la più piccola unità di compressione deve essere di almeno 64 Kbyte lungo. Inoltre, la compressione unità di compressione NTFS sembra essere anche 64 Kbyte. Ciò significa che una serie sparsa deve essere almeno grande quanto una compressione unità da deallocato dal disco e segnati come liberi. Questo pone una limitazione evidente dalla quantità di risparmio si possono ottenere utilizzando questo disegno; compressione non risparmierà alcuno spazio su disco a meno che non riduce le dimensioni in multipli di 64 Kbyte. Un multiplo di 64 Kbyte viene utilizzato come unità di compressione, internamente chiamato un pezzo . In effetti, una misura del blocco di 64 Kbyte sarebbe totalmente inutile come non ci potrebbe essere il risparmio a tutti.
Quando i dati vengono scritti è il primo scritto in un buffer di memoria. Questo tampone è utilizzato per tenere traccia delle modifiche al pezzo, è compensato nel file e utilizzare per comprimere i dati. Quando il pezzo ha bisogno di lavaggio i dati vengono prima compressi e compressi i dati scritti sul pezzo offset. Il resto del pezzo è contrassegnato come una regione sparse. NTFS dealloca qualsiasi unità di compressione naturalmente allineati che sono completamente sparse. Unità parzialmente scritte sono fisicamente allocato sul disco e 0 byte valorizzati vengono scritti su disco.
Durante la lettura dei dati, il blocco completo della richiesta di byte-offset viene letto, decompressi e dai dati nel buffer il byte richiesti copiato al chiamante. I byte sono sparse in modo trasparente lettura come valore 0-byte. Questo è fatto da NTFS e ci allevia dal monitoraggio regioni sparse.
Librerie di compressione inizialmente molto veloci sono stati utilizzati per evitare di sacrificare le prestazioni troppo.FastLz, Lz4 e MiniLzo sono stati testati, ma i risultati non sono stati molto promettenti, compressione-saggio. Come tale la build attuale utilizza Zlib .

Implementazione

Il mod compressione è scritto come un Shim VFS . Questo ha il vantaggio di evitare eventuali modifiche al codice di base Sqlite.
L'abilitazione della compressione deve essere fatta prima di aprire qualsiasi file di database. Una singola funzione è definito come segue:

1.int sqlite3_compress (
2.int traccia,
3.int CompressionLevel
4.)
traccia può essere un valore compreso tra 0 e 7. Quando 0 di analisi è disattivata, valori più grandi attivare l'analisi delle operazioni sempre più di livello inferiore. Log di traccia sono scritte su stderr. -1 Per default.
CompressionLevel può essere un valore compreso tra 1 e 9, dove 1 offre le prestazioni più veloci a spese del rapporto di compressione e 9 dà il meglio di compressione a scapito delle prestazioni. -1 Per impostazione predefinita, che in genere il livello-6.
Per abilitare la compressione di questa funzione si chiama semplicemente prima di chiamare sqlite3_open. Livello di compressione può essere cambiato tra le esecuzioni, ma a meno che un pezzo viene modificato, i dati non saranno ricompresso con il nuovo livello.
Solo nel database principale è compresso. Il giornale o qualsiasi altro file temporanei non vengono compressi.

Limitazioni

Oltre al fatto che il codice si trova in una sperimentale dello Stato, ci sono alcune cose non supportate o addirittura insostenibile da questa mod. In primo luogo solo questo mod in grado di leggere i database compressi. L'originale Sqlite dichiarerà banche dati compressi danneggiati. Tuttavia, questo mod può e deve rilevare banche dati non compressi e la compressione disabilita silenziosamente (ma usatelo a vostro rischio e pericolo.)
Poiché il sostegno di file NTFS sparse è la chiave per raggiungere la compressione, il mod è letteralmente inutile su sistemi non NTFS.
Sqlite è conosciuto per essere abbastanza resistenti di fronte a corruzione dei file. Questo non può più essere sostenuto con lo stesso livello in quanto è con il rilascio ufficiale. Inoltre, corruzioni distruggerebbe i dati molto più di una singola pagina. Con la libreria di compressione e il nuovo codice viene anche il rischio di crash o di essere instabile.
Delle caratteristiche non testato e probabilmente non supportato di Sqlite sono:
  • Backup del database on-line.
  • Multiprocesso lettura / scrittura.
  • Vuoto.
  • Recupero di dati.
  • Shell e strumenti di terze parti.
Prestazioni saggio, non c'è praticamente niente caching implementato al di là della corrente pezzo. Questo è nudo osso caching e c'è un sacco di spazio per miglioramenti delle prestazioni.

Benchmark

L'importazione di una discarica inglese SimpleWiki è stato utilizzato come benchmark. La tabella principale può contenere un auto-incremento di indice, timestamp, il titolo della pagina ed il contenuto della pagina (entrambi Unicode).
Blocchi da 256 Kbyte e Livello-6 di compressione (dimensioni in KByte)

OriginaleSqlite compressa
NTFS Normale204.438 (100%)73.296 (35,85%)
NTFS compressi117.460 (57,45%)57.431 (28,09%)
1024 Chunks Kbyte e Level-9 di compressione (dimensioni in KByte)

OriginaleSqlite compressa
NTFS Normale204.438 (100%)67.712 (33,12%)
NTFS compressi117.460 (57,45%)66.220 (32,39%)
E 'abbastanza ovvio che il risparmio con il Sqlite modificati sono sostanziali rispetto alla compressione NTFS sul file originale. È interessante notare che la compressione NTFS se applicato su un file compresso produce ancora guadagni. Questo è a causa delle inefficienze del Zlib (deflate) compressione (che lo è meno per il livello-6 a 9) e perché NTFS può deallocare a livello di cluster, che sono 4096 byte, in contrapposizione al metodo sparse di compressione unità di 64 Kbytes. Dal momento che il free-regioni sono scritti come zero byte e non sono deallocate a meno che una completa unità Kbyte 64 è completamente azzerato, sembra ragionevole supporre la compressione NTFS è scricchiolio questi zero imbottito regioni e deallocando come è unità è solo 4096 byte.
Va inoltre osservato che, mentre statisticamente dovremmo ottenere una migliore compressione con dimensioni pezzo più grande e più elevati livelli di compressione, questo non è lineare. Infatti, aumentando la dimensione del blocco può portare a ridurre utili netti delle dimensioni del file a causa di 64 Kbyte di compressione unità di NTFS. Cioè, se due pezzi ciascuno potesse salvare una singola unità (64 Kbyte,) raddoppiando la dimensione del blocco (in modo tale che entrambi sarebbero compressi insieme come una volta sola) potrebbe non essere in grado di salvare 128 Kbyte, nel qual caso il risparmio sarebbe ridotto da due unità a un singolo, risultando in un file di 64 Kbyte più grande che abbiamo avuto con l'originale chunk-size. Questo dipende fortemente sia i dati e la compressione, naturalmente.

Performance

Un test sintetico fatto utilizzando testo generato da un alfabeto composto da alfa-numerico simbolo più con lunghezze di <1MB sono stati fatti. Zlib sembra eseguire lentamente su questi dati casuali (anche se il numero di codici possibili è di piccole dimensioni.) Chunk dimensione di 256 Kbyte e la compressione a livello di 6 è stato utilizzato. 50 righe casuali sono generati e inseriti con incrementali Ids (tabella a due colonne,) il 50 righe sono selezionate utilizzando il Ids e dei testi rispetto all'originale, nuovi testi sono generati con lunghezze nuovo, questa volta di lunghezza <2MB e le righeaggiornato . Ancora una volta il 50 righe sono selezionate da Id e rispetto alla aggiornato-originali. Il file di database risultante è 50.686 Kbyte.
Il codice originale Sqlite eseguire il test in 13,3 secondi, mentre utilizzando la compressione di default e non tracciamento (per evitare spese generali) lo stesso test finito in 64,7 secondi (più lento 4.86x) risultante in un file di 41.184 KByte. Entrambi i test eseguito sugli stessi dati generati. Il file era su un RAMDisk per minimizzare l'overhead del disco.
Considerando che i dati sono stati casuali e sintetiche e di inserimento / aggiornamento tasso è stato pari a selezionare i tassi, i risultati sono ragionevoli. In pratica, si legge sono in genere più frequente di quanto scrive. Con il caching corretto questo dovrebbe ridurre il sovraccarico di prestazioni in modo significativo.

Scarica

Il codice detiene il diritto d'autore stesso afferma Sqlite, cioè nessuno . Il codice è sperimentale . Usatelo a vostro rischio e pericolo.
Scaricare il codice e DLL predefiniti . Questa è la versione 3.7.7.1 sqlite3.dll amalgama creato con le impostazioni di default / flags dalla fusione creata da fonti originali dall'originale configurare e rendere i file. Il codice di compressione è aggiunto ed è realizzata con VS2010 Sp1 e staticamente amava le librerie di runtime, in quanto tale, non ha dipendenze.

Costruzione

Per generare il codice, prima scaricare una versione recente Sqlite. La 3.7.7.1 fusione è perfetta. L' ultima Zlib deve anche essere scaricato e installato.
Aggiungere le intestazioni Zlib al percorso comprende, copiare il file vfs_compress.c vicino a fonti di sqlite e costruire.Poi, costruire fusione sqlite3.c (o le fonti originali) e collegare i binari di sqlite3, vfs_compress e Zlib per creare l'eseguibile.

Progetti per il futuro

Una buona percentuale delle prove ufficiali Sqlite superare con successo. Ma la corruzione e il formato-validare i test ovviamente fallire. L'aumento dei casi supportato è l'obiettivo primario, a questo punto. Ottenere il mod a "stabile, con nota-limitazione" sarebbe stato un traguardo importante. Il miglioramento delle prestazioni è un altro obiettivo che non è molto difficile da raggiungere. Avere la possibilità di abilitare / disabilitare la compressione su un qualsiasi database è anche utile e aggiungere più protezione dagli abusi. Sarebbe anche interessante per tentare di supporto di compressione senza supporto NTFS sparse file. Questo, mentre molto più complicato, possono funzionare su qualsiasi sistema e non su NTFS da solo.
Come bonus, è quasi banale per aggiungere la crittografia sulla parte superiore del sottosistema di compressione.

Nessun commento:

Posta un commento

Nota. Solo i membri di questo blog possono postare un commento.