diff --git a/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java b/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java index fe29a269..689901f3 100644 --- a/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java +++ b/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java @@ -8,20 +8,19 @@ package com.reactnativecommunity.asyncstorage; import javax.annotation.Nullable; - +import java.io.File; import java.util.Arrays; import java.util.Iterator; - import android.content.ContentValues; +import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.os.Build; import android.text.TextUtils; - +import android.util.Log; import com.facebook.react.bridge.ReadableArray; - import org.json.JSONException; import org.json.JSONObject; - import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.KEY_COLUMN; import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.TABLE_CATALYST; import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.VALUE_COLUMN; @@ -142,4 +141,38 @@ private static void deepMergeInto(JSONObject oldJSON, JSONObject newJSON) } } } + /** + * From Pie and up, Android started to use Write-ahead logging (WAL), instead of journal rollback + * for atomic commits and rollbacks. + * Basically, WAL does not write directly to the database file, rather to the supporting WAL file. + * Because of that, migration to the next storage might not be successful, because the content of + * RKStorage might be still in WAL file instead. Committing all data from WAL to db file is called + * a "checkpoint" and is done automatically (by default) when the WAL file reaches a threshold + * size of 1000 pages. + * More here: https://sqlite.org/wal.html + * + * This helper will force checkpoint on RKStorage, if Next storage file does not exists yet. + */ + public static void verifyAndForceSqliteCheckpoint(Context ctx) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + Log.i("AsyncStorage_Next", "SQLite checkpoint not required on this API version."); + } + + File nextStorageFile = ctx.getDatabasePath("AsyncStorage"); + File currentStorageFile = ctx.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME); + boolean isCheckpointRequired = !nextStorageFile.exists() && currentStorageFile.exists(); + if (!isCheckpointRequired) { + Log.i("AsyncStorage_Next", "SQLite checkpoint not required."); + return; + } + + try { + ReactDatabaseSupplier supplier = ReactDatabaseSupplier.getInstance(ctx); + supplier.get().rawQuery("PRAGMA wal_checkpoint", null).close(); + supplier.closeDatabase(); + Log.i("AsyncStorage_Next", "Forcing SQLite checkpoint successful."); + } catch (Exception e) { + Log.w("AsyncStorage_Next", "Could not force checkpoint on RKStorage, the Next storage might not migrate the data properly: " + e.getMessage()); + } + } } diff --git a/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java b/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java index c110122c..28a78408 100644 --- a/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java +++ b/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java @@ -29,6 +29,7 @@ public List createNativeModules(ReactApplicationContext reactConte Class storageClass = Class.forName("com.reactnativecommunity.asyncstorage.next.StorageModule"); NativeModule inst = (NativeModule) storageClass.getDeclaredConstructor(new Class[]{ReactContext.class}).newInstance(reactContext); moduleList.add(inst); + AsyncLocalStorageUtil.verifyAndForceSqliteCheckpoint(reactContext); } catch (Exception e) { String message = "Something went wrong when initializing module:" + "\n" diff --git a/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt b/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt index e4bdc866..e8a0c419 100644 --- a/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt +++ b/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt @@ -1,6 +1,7 @@ package com.reactnativecommunity.asyncstorage.next import android.content.Context +import android.util.Log import androidx.room.ColumnInfo import androidx.room.Dao import androidx.room.Database @@ -100,6 +101,7 @@ private object MIGRATION_TO_NEXT : Migration(1, 2) { FROM $oldTableName; """.trimIndent() ) + Log.e("AsyncStorage_Next", "Migration to Next storage completed.") } }