Mejor detección de corrupción de SQLite
Al principio, algunos antecedentes:
Mi aplicación de Android tiene una tabla de DB con muchas filas de cuatro columnas. Envía peticiones al servidor y el servidor responde sólo cuando todos estos cuatro valores son "válidos". Algunos de los miles de usuarios informaron que algo no funciona para ellos (desde hace algún tiempo no están recibiendo los resultados del servidor) – estaba tratando de averiguar lo que está causando el problema y resultó que la única causa posible es la DB corrupción que no está siendo detectado.
- SQLITE INSERT con ID manual (clave principal)
- Android sqlite actualización de fila
- Clave Extranjera de SQLite
- Posible obtener detalles de error específicos de Android SQLiteConstraintException?
- ¿Rellenar la base de datos de Android desde el archivo CSV?
En ACRA logs tengo algunos mensajes con errores de SQL, pero se trataba de la aplicación no poder abrir el archivo debido a que está dañado. Eso me dio alguna pista, pero todavía no estaba convencido de que este es el problema. Por lo tanto, he creado un script Python muy simple que cambia los bytes aleatorios en el archivo DB y comprueba cómo SQLite se ocupará de eso:
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 tabla de esta manera es totalmente 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ó en la mitad de las modificaciones que no fueron detectadas por el chequeo de integridad, pero lo más interesante para mí es que algo puede intercambiar bytes aleatorios en mi DB haciendo que mi aplicación sea inútil para una parte de mis usuarios.
He leído sobre las posibles causas de la corrupción en el sitio web de SQLite y también en StackOverflow, sé que por ejemplo forzar la aplicación para cerrar puede hacer un daño a la base de datos. Sólo me gustaría saber si es posible implementar una comprobación rápida y más robusta de la integridad de la base de datos.
Estoy leyendo los datos de una columna de toda la tabla en el inicio (para el autocompletado), así que pensé en calcular un poco de hash de todos los valores – Creo que esto funcionaría muy bien, ya que algunos hash función están diseñados sólo para hacer Cheques de integridad, pero tal vez hay una solución más simple, más rápida y mejor – le pregunto, si usted sabe cualquiera.
- La manera más rápida y eficiente de pre-poblar la base de datos en Android
- Base de datos Sqlite que actualiza una fila Android
- Leer sólo la actualización de la base de datos SQLite en la carpeta de activos para la nueva versión de la aplicación
- ¿Qué hace exactamente la restricción de clave externa "NO ACTION" de SQLite y cómo es diferente de "RESTRICT"?
- Tabla de SQLite con columnas de columna de enteros
- Error al leer la fila 0, columna 0 de una CursorWindow que tiene 0 filas, 64 columnas
- Android - ¿SimpleCursorAdapter permite múltiples diseños como BaseAdapter?
- Cómo eliminar la base de datos en sqlite?
No sé de ninguna característica de SQLite como esto, así que diría que calcular un hash es la solución más simple, echar un vistazo a la clase MessageDigest
para empezar.
- ¿Cómo enviar a "Misceláneo" canal de notificación?
- ¿Cuál es la forma correcta de manejar el ciclo de vida de la actividad con OpenGL?