Skip to content

Commit c2aa400

Browse files
author
Krzysztof
authored
fix(next storage): Force SQLite checkpoint on Pie and up (#582)
1 parent 8ff385a commit c2aa400

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,19 @@
88
package com.reactnativecommunity.asyncstorage;
99

1010
import javax.annotation.Nullable;
11-
11+
import java.io.File;
1212
import java.util.Arrays;
1313
import java.util.Iterator;
14-
1514
import android.content.ContentValues;
15+
import android.content.Context;
1616
import android.database.Cursor;
1717
import android.database.sqlite.SQLiteDatabase;
18+
import android.os.Build;
1819
import android.text.TextUtils;
19-
20+
import android.util.Log;
2021
import com.facebook.react.bridge.ReadableArray;
21-
2222
import org.json.JSONException;
2323
import org.json.JSONObject;
24-
2524
import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.KEY_COLUMN;
2625
import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.TABLE_CATALYST;
2726
import static com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.VALUE_COLUMN;
@@ -142,4 +141,38 @@ private static void deepMergeInto(JSONObject oldJSON, JSONObject newJSON)
142141
}
143142
}
144143
}
144+
/**
145+
* From Pie and up, Android started to use Write-ahead logging (WAL), instead of journal rollback
146+
* for atomic commits and rollbacks.
147+
* Basically, WAL does not write directly to the database file, rather to the supporting WAL file.
148+
* Because of that, migration to the next storage might not be successful, because the content of
149+
* RKStorage might be still in WAL file instead. Committing all data from WAL to db file is called
150+
* a "checkpoint" and is done automatically (by default) when the WAL file reaches a threshold
151+
* size of 1000 pages.
152+
* More here: https://sqlite.org/wal.html
153+
*
154+
* This helper will force checkpoint on RKStorage, if Next storage file does not exists yet.
155+
*/
156+
public static void verifyAndForceSqliteCheckpoint(Context ctx) {
157+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
158+
Log.i("AsyncStorage_Next", "SQLite checkpoint not required on this API version.");
159+
}
160+
161+
File nextStorageFile = ctx.getDatabasePath("AsyncStorage");
162+
File currentStorageFile = ctx.getDatabasePath(ReactDatabaseSupplier.DATABASE_NAME);
163+
boolean isCheckpointRequired = !nextStorageFile.exists() && currentStorageFile.exists();
164+
if (!isCheckpointRequired) {
165+
Log.i("AsyncStorage_Next", "SQLite checkpoint not required.");
166+
return;
167+
}
168+
169+
try {
170+
ReactDatabaseSupplier supplier = ReactDatabaseSupplier.getInstance(ctx);
171+
supplier.get().rawQuery("PRAGMA wal_checkpoint", null).close();
172+
supplier.closeDatabase();
173+
Log.i("AsyncStorage_Next", "Forcing SQLite checkpoint successful.");
174+
} catch (Exception e) {
175+
Log.w("AsyncStorage_Next", "Could not force checkpoint on RKStorage, the Next storage might not migrate the data properly: " + e.getMessage());
176+
}
177+
}
145178
}

android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
2929
Class storageClass = Class.forName("com.reactnativecommunity.asyncstorage.next.StorageModule");
3030
NativeModule inst = (NativeModule) storageClass.getDeclaredConstructor(new Class[]{ReactContext.class}).newInstance(reactContext);
3131
moduleList.add(inst);
32+
AsyncLocalStorageUtil.verifyAndForceSqliteCheckpoint(reactContext);
3233
} catch (Exception e) {
3334
String message = "Something went wrong when initializing module:"
3435
+ "\n"

android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.reactnativecommunity.asyncstorage.next
22

33
import android.content.Context
4+
import android.util.Log
45
import androidx.room.ColumnInfo
56
import androidx.room.Dao
67
import androidx.room.Database
@@ -100,6 +101,7 @@ private object MIGRATION_TO_NEXT : Migration(1, 2) {
100101
FROM $oldTableName;
101102
""".trimIndent()
102103
)
104+
Log.e("AsyncStorage_Next", "Migration to Next storage completed.")
103105
}
104106
}
105107

0 commit comments

Comments
 (0)