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