2012-01-23 5 views
6

En primer lugar, algunos antecedentes:Mejor detección de la corrupción SQLite

Mi Android aplicación tiene mesa de DB con una gran cantidad de filas de cuatro columnas. Envía solicitudes al servidor y el servidor responde solo cuando todos estos cuatro valores son "válidos". Algunos de los miles de usuarios informaron que algo no funciona para ellos (ya que no están obteniendo los resultados del servidor) - Intenté descubrir qué causaba el problema y resultó que la única causa posible es la Daño de DB que no se detecta.

En los registros de ACRA recibo algunos mensajes con errores de SQL, pero se trata de que la aplicación no puede abrir el archivo porque está dañado. Eso me dio alguna pista, pero todavía no estaba convencido de que este fuera el problema. Por lo tanto, he creado un script de Python muy sencillo que cambia bytes aleatorios en el archivo de base de datos y los controles cómo SQLite se ocupará de que:

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' 

Los resultados mostraron que "la edición de" datos de la tabla de esta manera es muy posible:

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 

por lo general es interesante ver que la ejecución de una consulta falló por medio de las modificaciones que no fue detectado por el control de integridad, pero lo más interesante para mí es que algo puede cambiar bytes aleatorios en mi DB haciendo mi solicitud inútil para una parte de mis usuarios.

He leído sobre posibles causas de corrupción en el sitio web de SQLite y también en StackOverflow, sé que p. forzar el cierre de la aplicación puede dañar el DB. Me gustaría saber si es posible implementar una verificación de integridad de DB rápida y más sólida.

Estoy leyendo los datos de una columna de toda la tabla al inicio (para autocompletar), así que pensé en calcular algunos hash de todos los valores - Creo que esto funcionaría bastante bien, ya que algunas funciones hash son diseñado solo para hacer comprobaciones de integridad, pero tal vez haya una solución más simple, más rápida y mejor. Por lo tanto, se lo pregunto, si conoce alguno.

+0

Como se sugiere en la respuesta a esta pregunta: http://stackoverflow.com/questions/11490250/does-sqlite-checksum-its-data Puede codificar sus datos utilizando la corrección de errores hacia adelante. Tal vez no sea más simple o más rápido (un hash parece una solución razonable y simple), pero quizás sea mejor. De hecho, tendrías la oportunidad de corregir errores, no solo de detectarlos. – bsa

+0

Esta pregunta es un poco antigua, pero quería mencionar [esta respuesta] (http://stackoverflow.com/questions/12418600/how-do-you-determine-if-an-sqlite-or-sqback-is- corrupt-in-java) menciona 'PRAGMA quick_check;' que aparentemente hace algún tipo de escaneo * sobre los datos (?) *. Tengo curiosidad por saber qué tipo de resultados daría en el caso de prueba anterior, pero no estoy seguro de cómo lo integraría. ** EDITAR: [la documentación] (http://www.sqlite.org/pragma.html#pragma_integrity_check) dice 'quick_check' es una versión más rápida de' identity_check'. ** Ah. –

Respuesta

1

No conozco ninguna característica de SQLite como esta, así que diría que el cálculo de un hash es la solución más simple, eche un vistazo a la clase MessageDigest para empezar.

Cuestiones relacionadas