Лучшее обнаружение повреждений SQLite

Сначала немного предыстории:

В моем приложении Android есть таблица БД с большим количеством строк с четырьмя столбцами. Он отправляет запросы на сервер, и сервер отвечает только тогда, когда все эти четыре значения являются «действительными».Несколько из тысяч пользователей сообщили, что у них что-то не работает (поскольку какое-то время они не получают результаты с сервера) - я пытался выяснить, что вызывает проблему, и оказалось, что единственной возможной причиной является Повреждение БД, которое не обнаруживается.

В журналах ACRA было несколько сообщений с ошибками SQL, но они были о том, что приложение не может открыть файл из-за его повреждения. Это дало мне некоторую подсказку, но я все еще не был уверен, что это проблема. Итак, я создал очень простой скрипт Python, который изменяет случайные байты в файле БД и проверяет, как SQLite будет с этим справляться:

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'

Результаты показали, что «редактировать» данные таблицы таким способом вполне возможно:

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

Обычно это Интересно видеть, что выполнение запроса завершилось неудачно для половины модификаций, которые не были обнаружены проверкой целостности, но наиболее интересным для меня является то, что что-то может менять случайные байты в моей БД, делая мое приложение бесполезным для части моих пользователей.

Я читал о возможных причинах повреждения на веб-сайте SQLite, а также на StackOverflow, я знаю, например, что принудительное закрытие приложения может нанести вред БД. Я просто хотел бы знать, можно ли реализовать быструю и более надежную проверку целостности БД.

Я читаю данные из одного столбца всей таблицы при запуске (для автозаполнения), поэтому я подумал о том, чтобы вычислить некоторый хэш из всех значений - я думаю, это сработает неплохо, поскольку некоторые хеш-функции разработаны просто для проверки целостности, но, возможно, есть более простое, быстрое и лучшее решение - я спрашиваю вас, знаете ли вы.

6
задан user1234567 23 January 2012 в 15:17
поделиться