2012-01-23 14 views
6

In un primo momento, alcuni retroscena:Meglio rilevazione corruzione SQLite

mio Android applicazione ha tabella DB con un sacco di righe a quattro colonne. Invia richieste al server e il server risponde solo quando tutti questi quattro valori sono "validi". Alcuni dei migliaia di utenti hanno riferito che qualcosa non funziona per loro (poiché da un po 'non ottengono i risultati dal server) - Stavo cercando di capire che cosa causa il problema e si è scoperto che l'unica causa possibile è il Corruzione del DB che non viene rilevata.

Nei registri ACRA ho alcuni messaggi con errori SQL, ma questi riguardavano l'impossibilità dell'applicazione di aprire il file a causa del danneggiamento. Questo mi ha dato qualche indizio, ma non ero ancora convinto che questo fosse il problema. Così, ho creato un semplice script Python che cambia byte casuali nel file DB e controlli come SQLite tratterà che:

import random 
import array 
import sqlite3 

db = array.array('B') 
db.fromstring(open('db').read()) 

ta = [x for x in sqlite3.connect('db').execute('SELECT * FROM table ORDER BY _id')] 

results = [0,0,0,0] 
tries = 1000 

for i in xrange(0,tries): 
    work = db[:] 
    while work == db: 
     for j in xrange(0,random.randint(1,5)): 
      work[random.randint(1,len(db))-1] = random.randint(0,255) 

    work.tofile(open('outdb','w')) 

    try: 
     c = sqlite3.connect('outdb') 
     results[0] += 1 

     for r in c.execute('PRAGMA integrity_check;'): 
     results[1] += 1 if (r[0] == 'ok') else 0 
    except: 
     continue  

    try: 
     results[3] += 1 if [x for x in c.execute('SELECT * FROM table ORDER BY _id')] != ta else 0 
     results[2] += 1 
    except: 
     c.close() 
     continue 

print 'Results for '+str(tries)+' tests:' 
print 'Creating connection failed '+str(tries-results[0])+ ' times' 
print 'Integrity check failed '+str(results[0]-results[1])+ ' times' 
print 'Running a SELECT * query failed '+str(results[1]-results[2])+ ' times' 
print 'Data was succesfully altered '+str(results[3])+ ' times' 

I risultati hanno mostrato che "modifica" i dati della tabella in questo modo è del tutto possibile:

Results for 1000 tests: 
Creating connection failed 0 times 
Integrity check failed 503 times 
Running a SELECT * query failed 289 times 
Data was succesfully altered 193 times 

E 'generalmente interessante vedere che l'esecuzione di una query non riuscito per la metà delle modifiche che non è stata individuata dal controllo di integrità, ma la cosa più interessante per me è che qualcosa possa scambiare byte casuali nel mio DB rendendo la mia domanda inutile per una parte dei miei utenti.

Ho letto su possibili cause di corruzione sul sito Web SQLite e anche su StackOverflow, so che ad es. costringere l'applicazione a chiudere può danneggiare il DB. Vorrei solo sapere se è possibile implementare un controllo dell'integrità dei DB veloce e più robusto.

Sto leggendo i dati da una colonna dell'intera tabella all'avvio (per il completamento automatico), quindi ho pensato di calcolare un hash da tutti i valori - Penso che questo funzionerebbe abbastanza bene, dal momento che alcune funzioni di hash sono progettato solo per fare controlli di integrità, ma forse c'è una soluzione più semplice, più veloce e migliore - ti chiedo quindi, se ne conosci qualcuno.

+0

Come suggerito nella risposta a questa domanda: http://stackoverflow.com/questions/11490250/does-sqlite-checksum-its-data È possibile codificare i dati utilizzando la correzione degli errori in avanti. Forse non più semplice o più veloce (un hash sembra una soluzione ragionevole e semplice), ma forse meglio. Avresti davvero la possibilità di correggere gli errori, non solo di individuarli. – bsa

+0

Questa domanda è un po 'vecchia, ma volevo menzionare [questa risposta] (http://stackoverflow.com/questions/12418600/how-do-you-determine-if-an-sqlite-or-sqback-is- corrupt-in-java) menziona l'uso di 'PRAGMA quick_check;' che apparentemente esegue una sorta di scansione * sui dati (?) *. Sono curioso di sapere che tipo di risultati ciò darebbe nella prova precedente, ma non sono sicuro di come lo integreresti. ** EDIT: [la documentazione] (http://www.sqlite.org/pragma.html#pragma_integrity_check) dice 'quick_check' è una versione più veloce di' identity_check'. ** Ah. –

risposta

1

Non conosco nessuna funzione SQLite come questa, quindi direi che calcolare un hash è la soluzione più semplice, dare un'occhiata alla classe MessageDigest per iniziare.