8

I have a core data based application that uses Dropbox to backup and restore data. The way I backup is pretty straight forward. I copy the .sqlite file on the user's dropbox.

Now my backup and restore functionality are working fine. The issue is with the .sqlite file itself. It appears that the .sqlite file is incomplete.

I entered about 125 entries in my application and took a backup. The backup appeared in my dropbox but when I use a .sqlite explorer tool to see the contents, I only see records upto 117th entry.

I tried updating the first entry and then again observing .sqlite file but no changes again.

What's even more strange is that the app appears to have recorded all changes. When I add a new entry or update an existing one and restart the app, the newly added data seems to persist. But this newly added data does not appear in my .sqlite file.

I am backing up using this code:

AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSString *filePath = [[[appDelegate applicationDocumentsDirectory] path] stringByAppendingPathComponent:@"MyApp.sqlite"];


if (account) {
    if ([filesystem isShutDown]) {
        filesystem = [[DBFilesystem alloc] initWithAccount:account];
        [DBFilesystem setSharedFilesystem:filesystem];
    }

    DBPath *newPath = [[DBPath root] childPath:[NSString stringWithFormat:@"Backup - %@.sqlite", [NSDate date]]];
    DBFile *file = [[DBFilesystem sharedFilesystem] createFile:newPath error:nil];
    [file writeContentsOfFile:filePath shouldSteal:NO error:nil];
    [filesystem shutDown];

}

I also copied the .sqlite file from the Simulator's folder and tried seeing it in the .sqlite browser. It still exhibits the same behaviour. Any reason why this must be happening?

Gaurav Wadhwani
  • 1,352
  • 2
  • 15
  • 32

1 Answers1

7

Starting with iOS 7 / OS X 10.9, Core Data uses "Write-Ahead Logging" (WAL) as default journaling mode for the underlying SQLite store file. This is explained in

Technical Q&A QA1809: New default journaling mode for Core Data SQLite stores in iOS 7 and OS X Mavericks

With the WAL mode, Core Data keeps the main store file untouched and appends transactions to a -wal file in the same location. After the Core Data context is saved, the -wal file is not deleted, and the data in that file is not merged to the store file either. Therefore, simply making copies of the store file will likely cause data loss and inconsistency.

That should explain why your .sqlite file alone is incomplete. As as solution you can (also explained in that Technical Note):

  • Disable WAL-mode (and use the "old" rollback journaling mode) for the SQLite store by setting the

    @{NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}};
    

    option when adding the persistent store, or

  • Use the

    - (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error
    

    method to make a backup copy of the Core Data store.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • So what would you recommend? Apple recommends your second approach but I don't understand how I could use that with dropbox (it looks tailored for iCloud). If I disable WAL mode now, will I loose the data already entered? And what do you think about creating a zip file with the .sqlite file and the wal file and saving it as backup (and do reverse to restore)? – Gaurav Wadhwani Apr 15 '14 at 17:59
  • @GauravWadhwani: In this answer http://stackoverflow.com/a/21002923/1187415 it is stated that opening the store with journal_mode=DELETE does *not* destroy your data, but I haven't tested it myself. With the second approach you probably have to backup to a separate (single-file) store first which you can then move to the dropbox (but I am not familiar with the dropbox functions). - Sorry, I cannot give you recommendations. Perhaps another answer will come and help more. – Martin R Apr 15 '14 at 18:10
  • @GauravWadhwani - can you please post the resolution. I am having major issues with migratePersistentStore: – Jim Holland Sep 04 '15 at 14:14