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

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


person user1234567    schedule 23.01.2012    source источник
comment
Как было предложено в ответе на этот вопрос: stackoverflow.com/ questions/11490250/ Вы можете кодировать свои данные, используя прямое исправление ошибок. Может быть, не проще и не быстрее (хэш кажется разумным и простым решением), а может и лучше. У вас действительно будет шанс исправить ошибки, а не просто обнаружить их.   -  person bsa    schedule 31.01.2016
comment
Этот вопрос немного устарел, но я хотел упомянуть в этом ответе упоминается использование PRAGMA quick_check;, которое, по-видимому, выполняет какое-то сканирование по данным (?). Мне любопытно, какие результаты это даст в приведенном выше тестовом примере, но я не уверен, как вы его интегрируете. EDIT: документация говорит, что quick_check является более быстрой версией identity_check. А.   -  person i336_    schedule 26.03.2016


Ответы (1)


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

person dnet    schedule 01.01.2013