diff --git a/app/src/main/java/eu/faircode/email/DB.java b/app/src/main/java/eu/faircode/email/DB.java index af9a94bc7b..850da9aabb 100644 --- a/app/src/main/java/eu/faircode/email/DB.java +++ b/app/src/main/java/eu/faircode/email/DB.java @@ -6,6 +6,7 @@ import android.app.ActivityManager; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabaseCorruptException; import android.net.Uri; import android.os.Build; import android.text.TextUtils; @@ -142,16 +143,39 @@ public abstract class DB extends RoomDatabase { @Override public void init(@NonNull DatabaseConfiguration configuration) { - // https://www.sqlite.org/pragma.html#pragma_wal_autocheckpoint - if (BuildConfig.DEBUG) { - File dbfile = configuration.context.getDatabasePath(DB_NAME); - if (dbfile.exists()) { - try (SQLiteDatabase db = SQLiteDatabase.openDatabase(dbfile.getPath(), null, SQLiteDatabase.OPEN_READWRITE)) { - Log.i("Set PRAGMA wal_autocheckpoint=" + DB_CHECKPOINT); - try (Cursor cursor = db.rawQuery("PRAGMA wal_autocheckpoint=" + DB_CHECKPOINT + ";", null)) { - cursor.moveToNext(); // required + File dbfile = configuration.context.getDatabasePath(DB_NAME); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(configuration.context); + boolean sqlite_integrity_check = prefs.getBoolean("sqlite_integrity_check", true); + + // https://www.sqlite.org/pragma.html#pragma_integrity_check + if (sqlite_integrity_check && dbfile.exists()) { + String check = (Helper.isRedmiNote() || Helper.isOnePlus() || BuildConfig.DEBUG + ? "integrity_check" : "quick_check"); + try (SQLiteDatabase db = SQLiteDatabase.openDatabase(dbfile.getPath(), null, SQLiteDatabase.OPEN_READWRITE)) { + Log.i("PRAGMA " + check); + try (Cursor cursor = db.rawQuery("PRAGMA " + check + ";", null)) { + while (cursor.moveToNext()) { + String line = cursor.getString(0); + if ("ok".equals(line)) + Log.i("PRAGMA " + check + "=" + line); + else + Log.e("PRAGMA " + check + "=" + line); } } + } catch (SQLiteDatabaseCorruptException ex) { + Log.e(ex); + dbfile.delete(); + } + } + + // https://www.sqlite.org/pragma.html#pragma_wal_autocheckpoint + if (BuildConfig.DEBUG && dbfile.exists()) { + try (SQLiteDatabase db = SQLiteDatabase.openDatabase(dbfile.getPath(), null, SQLiteDatabase.OPEN_READWRITE)) { + Log.i("Set PRAGMA wal_autocheckpoint=" + DB_CHECKPOINT); + try (Cursor cursor = db.rawQuery("PRAGMA wal_autocheckpoint=" + DB_CHECKPOINT + ";", null)) { + cursor.moveToNext(); // required + } } } diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java index 758b82af66..673e67c09b 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java @@ -164,6 +164,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc private TextView tvRoomQueryThreads; private SeekBar sbRoomQueryThreads; private ImageButton ibRoom; + private SwitchCompat swIntegrity; private SwitchCompat swWal; private SwitchCompat swCheckpoints; private SwitchCompat swAnalyze; @@ -238,8 +239,8 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc "watchdog", "experiments", "main_log", "protocol", "log_level", "debug", "leak_canary", "test1", "test2", "test3", "test4", "test5", "work_manager", // "external_storage", - "query_threads", "wal", - "sqlite_checkpoints", "sqlite_analyze", "sqlite_auto_vacuum", "sqlite_sync_extra", "sqlite_cache", + "query_threads", + "sqlite_integrity_check", "wal", "sqlite_checkpoints", "sqlite_analyze", "sqlite_auto_vacuum", "sqlite_sync_extra", "sqlite_cache", "chunk_size", "thread_range", "undo_manager", "webview_legacy", "browser_zoom", "fake_dark", "show_recent", @@ -363,6 +364,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc tvRoomQueryThreads = view.findViewById(R.id.tvRoomQueryThreads); sbRoomQueryThreads = view.findViewById(R.id.sbRoomQueryThreads); ibRoom = view.findViewById(R.id.ibRoom); + swIntegrity = view.findViewById(R.id.swIntegrity); swWal = view.findViewById(R.id.swWal); swCheckpoints = view.findViewById(R.id.swCheckpoints); swAnalyze = view.findViewById(R.id.swAnalyze); @@ -1097,6 +1099,17 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc } }); + swIntegrity.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton v, boolean checked) { + prefs.edit() + .putBoolean("sqlite_integrity_check", checked) + .remove("debug") + .commit(); + ApplicationEx.restart(v.getContext(), "sqlite_integrity_check"); + } + }); + swWal.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @@ -1975,6 +1988,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc tvRoomQueryThreads.setText(getString(R.string.title_advanced_room_query_threads, NF.format(query_threads))); sbRoomQueryThreads.setProgress(query_threads); + swIntegrity.setChecked(prefs.getBoolean("sqlite_integrity_check", true)); swWal.setChecked(prefs.getBoolean("wal", true)); swCheckpoints.setChecked(prefs.getBoolean("sqlite_checkpoints", true)); swAnalyze.setChecked(prefs.getBoolean("sqlite_analyze", true)); diff --git a/app/src/main/res/layout/fragment_options_misc.xml b/app/src/main/res/layout/fragment_options_misc.xml index 53cd692ac2..df38d74da9 100644 --- a/app/src/main/res/layout/fragment_options_misc.xml +++ b/app/src/main/res/layout/fragment_options_misc.xml @@ -1025,6 +1025,18 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/ibRoom" /> + + Initialize work manager Use external storage ROOM query threads: %1$s + sqlite integrity check sqlite WAL sqlite checkpoints sqlite analyze