Лучшее обнаружение повреждения 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, а также на Stackru. Я знаю, что, например, принудительное закрытие приложения может нанести вред БД. Я просто хотел бы знать, возможно ли реализовать быструю и более надежную проверку целостности БД.

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

1 ответ

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

Другие вопросы по тегам