Our production RN sessions (Android and iOS) had schema migration block DB initialization: "Collection migration failed" and our app-level "Database initialization timed out". The native error was expo-sqlite finalizeAsync with SQLITE_LOCKED (code 6).
Version: RxDB/Premium Version 17.3.0
Our app migrates collections sequentially, but finalization appears concurrent:
- RxDB shares one SQLite connection per DB:
|
export const DATABASE_STATE_BY_NAME: Map<string, DatabaseState> = new Map(); |
|
export const RX_STORAGE_NAME_SQLITE = 'sqlite'; |
|
|
|
|
|
/** |
|
* @link https://www.sqlite.org/inmemorydb.html |
|
*/ |
|
export const SQLITE_IN_MEMORY_DB_NAME = ':memory:'; |
|
|
|
export function getDatabaseConnection( |
|
sqliteBasics: SQLiteBasics<any>, |
|
databaseName: string |
|
): Promise<SQLiteDatabaseClass> { |
|
let state = DATABASE_STATE_BY_NAME.get(databaseName); |
|
if (!state) { |
|
state = { |
|
database: sqliteBasics.open(databaseName), |
|
sqliteBasics, |
|
openConnections: 1 |
|
}; |
|
DATABASE_STATE_BY_NAME.set(databaseName, state); |
|
} else { |
|
if (state.sqliteBasics !== sqliteBasics && databaseName !== SQLITE_IN_MEMORY_DB_NAME) { |
|
throw new Error('opened db with different creator method ' + databaseName + ' ' + state.sqliteBasics.debugId + ' ' + sqliteBasics.debugId); |
|
} |
|
state.openConnections = state.openConnections + 1; |
|
} |
|
return state.database; |
|
} |
- The Expo adapter forwards all/run directly:
|
export function getSQLiteBasicsExpoSQLiteAsync( |
|
openDB: any, |
|
options?: any, |
|
directory?: any |
|
): SQLiteBasics<any> { |
|
return { |
|
open: async (name: string) => { |
|
return await openDB(name, options, directory); |
|
}, |
|
all: async (db: any, queryWithParams: SQLiteQueryWithParams) => { |
|
const result = await db.getAllAsync( |
|
queryWithParams.query, |
|
queryWithParams.params |
|
); |
|
return result as any; |
|
}, |
|
run: async (db: any, queryWithParams: SQLiteQueryWithParams) => { |
|
const ret = await db.runAsync( |
|
queryWithParams.query, |
|
queryWithParams.params |
|
); |
|
return ret as any; |
|
}, |
|
async setPragma(db, key, value) { |
|
await db.execAsync('PRAGMA ' + key + ' = ' + value); |
|
}, |
|
close: async (db: any) => { |
|
return await db.closeAsync(); |
|
}, |
|
journalMode: '', |
|
}; |
- Migration cleanup concurrently calls oldStorage.remove() and metaStorage.remove(), then cancels replication:
|
await awaitRxStorageReplicationFirstInSync(replicationState); |
|
await awaitRxStorageReplicationInSync(replicationState); |
|
|
|
await this.updateStatusQueue; |
|
if (hasError) { |
|
await cancelRxStorageReplication(replicationState); |
|
await replicationMetaStorageInstance.close(); |
|
throw hasError; |
|
} |
|
|
|
// cleanup old storages |
|
await Promise.all([ |
|
oldStorage.remove(), |
|
replicationMetaStorageInstance.remove() |
|
]); |
|
|
|
await cancelRxStorageReplication(replicationState); |
|
} |
In our reproduction, serializing SQLiteBasics operations per connection prevents the lock. We'd prefer an upstream-supported solution over a broad wrapper.
Our production RN sessions (Android and iOS) had schema migration block DB initialization: "Collection migration failed" and our app-level "Database initialization timed out". The native error was expo-sqlite finalizeAsync with SQLITE_LOCKED (code 6).
Version: RxDB/Premium Version 17.3.0
Our app migrates collections sequentially, but finalization appears concurrent:
rxdb/src/plugins/storage-sqlite/sqlite-helpers.ts
Lines 22 to 50 in 7b916f6
rxdb/src/plugins/storage-sqlite/sqlite-basics-helpers.ts
Lines 408 to 438 in 7b916f6
rxdb/src/plugins/migration-schema/rx-migration-state.ts
Lines 493 to 510 in 7b916f6
In our reproduction, serializing SQLiteBasics operations per connection prevents the lock. We'd prefer an upstream-supported solution over a broad wrapper.