Problems with Core Data Migration Manager and journal_mode WAL
Recently for a major update of an app I’m working on, I had to use a Core Data Migration Manager
for the first time.
I run into a weird problem with some pragma statements set in the underlying SQLite database, so I’d like
to offer a workaround in case someone else runs into this issue in the future.
The setup
Here’s the setup of the Core Data stack in our app:
It’s nothing fancy: the stock Core Data initialization you get with the Xcode template, plus the two options
that are commented out (NSMigratePersistentStoresAutomaticallyOption and
NSInferMappingModelAutomaticallyOption) to enable migrations, and a setting to put SQLite in
journal_mode = WAL.
I’m not really sure I need this journal_mode set, but since our app started using MagicalRecord,
that’s the way it was setup. Here’s the relevant SQLite documentation on journal
modes, so you can make an informed decision.
The problem
When you use a Migration Manager, Core Data will create a new database for you,
and start copying the entities one by one from the old DB to the new one.
As we are using journal_mode = WAL, there’s an additional file besides DB.sqlite called DB.sqlite-wal.
From what I can tell, the problem seems to be that Core Data creates a temporary DB, inserts everything
there, and when it renames it to the original name, the -wal file is kept as a leftover from the old
version. The problem is that you end up with an inconsistent DB.
Workaround
As I’m not sure I want WAL enabled, I decided to keep the setting and implement a workaround. It’s simple:
Detect if you need a migration.
If you do, set the journal_mode to DELETE.
Initialize the NSPersistentStoreCoordinator, so it triggers the migrations.
After a successful initialization, recreate the NSPersistentStoreCoordinator with journal_mode set to
WAL, as it was.