最初に、いくつかの背景:
私のAndroidアプリには、4 列の行がたくさんある DB テーブルがあります。サーバーに要求を送信し、サーバーはこれら 4 つの値がすべて「有効」である場合にのみ応答します。何千人ものユーザーのうちの数人が、何かがうまくいかないと報告しました (サーバーから結果が得られないため) - 問題の原因を突き止めようとしていたところ、考えられる唯一の原因は検出されていない DB の破損。
ACRA ログに SQL エラーのメッセージがいくつかありますが、これらはファイルが破損しているためにアプリケーションがファイルを開くことができないというものでした。それは私にいくつかの手がかりを与えましたが、これが問題であるとはまだ確信していませんでした. そこで、DB ファイル内のランダムなバイトを変更し、SQLite がそれをどのように処理するかをチェックする非常に単純な Python スクリプトを作成しました。
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
一般に、整合性チェックで検出されなかった変更の半分でクエリの実行が失敗したことを見るのは興味深いことですが、私にとって最も興味深いことは、DB 内のランダムなバイトがスワップされ、一部のユーザーにとってアプリケーションが役に立たなくなる可能性があることです。
SQLite Web サイトと StackOverflow で破損の考えられる原因について読んだことがあります。たとえば、アプリケーションを強制的に閉じると、DB に害を及ぼす可能性があることを知っています。高速で堅牢な DB 整合性チェックを実装できるかどうかを知りたいだけです。
起動時に (オートコンプリートのために) テーブル全体の 1 つの列からデータを読み取っているので、すべての値からハッシュを計算することを考えました。整合性チェックを行っていますが、もっとシンプルで高速で優れた解決策があるかもしれません。