Ned
Ned

Reputation: 6270

SQLite Error 266 on CoreData DB

With my most recent app update, I have started to see very inconsistent SQLite errors when saving my database. These are happening with multiple users, so it is not just the same user crashing repeatedly (though it has happened for the same user multiple times). I am getting error 266, which is SQLITE_IOERR_READ. I haven't found anyone else running into this error, so not sure why I'm getting it.

00:04:18:25  $ -[AppDelegate saveContext] line 328 $ Unresolved error Error Domain=NSCocoaErrorDomain Code=266 "The operation couldn’t be completed. (Cocoa error 266.)" UserInfo=0x1dd141b0 {NSSQLiteErrorDomain=266, NSFilePath=/var/mobile/Applications/[omitted], NSPOSIXErrorDomain=1, NSUnderlyingException=I/O error for database at /var/mobile/Applications/[omitted]. SQLite error code:266, 'not an error' errno:1}, {
* 00:04:18:25  NSFilePath = "/var/mobile/Applications/[omitted].sqlite";
* 00:04:18:25  NSPOSIXErrorDomain = 1;
* 00:04:18:25  NSSQLiteErrorDomain = 266;
* 00:04:18:25  NSUnderlyingException = "I/O error for database at /var/mobile/Applications/[omitted].sqlite. SQLite error code:266, 'not an error' errno:1";
* 00:04:18:25  }

EDIT

Here is the core-data related code (most of it standard boilerplate):

/**
 Returns the managed object context for the application.
 If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
 */
- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }
    return managedObjectContext;
}


/**
 Returns the managed object model for the application.
 If the model doesn't already exist, it is created by merging all of the models found in the application bundle.
 */
- (NSManagedObjectModel *)managedObjectModel {

    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    //managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];

    // See  http://iphonedevelopment.blogspot.com.au/2009/09/core-data-migration-problems.html
    NSString *path = [[NSBundle mainBundle] pathForResource:@"modelDB" ofType:@"momd"];
    NSURL *momURL = [NSURL fileURLWithPath:path];
    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];

    return managedObjectModel;
}


/**
 Returns the persistent store coordinator for the application.
 If the coordinator doesn't already exist, it is created and the application's store added to it.
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }

    NSString *storePath = [[Utils documentsDirectory] stringByAppendingPathComponent: @"modelDB.sqlite"];
    NSURL *storeUrl = [NSURL fileURLWithPath: storePath];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

    // Allow inferred migration from the original version of the application.
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
        // Handle the error.
        CLS_LOG(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    //Turn on complete file protection (encrypts files when phone is locked using device pin)
    NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
    if(![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:storePath error:&error])
    {
        //handle error
    }

    return persistentStoreCoordinator;
}

When a user logs out, this is called to remove the model store:

- (NSPersistentStoreCoordinator *)resetPersistentStore
{
    NSError *error = nil;

    if ([persistentStoreCoordinator persistentStores] == nil)
        return [self persistentStoreCoordinator];

    [managedObjectContext release];
    managedObjectContext = nil;

    //If there are many stores, this could be an issue
    NSPersistentStore *store = [[persistentStoreCoordinator persistentStores] lastObject];

    if (![persistentStoreCoordinator removePersistentStore:store error:&error])
    {
        CLS_LOG(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    // Delete file
    if ([[NSFileManager defaultManager] fileExistsAtPath:store.URL.path]) {
        if (![[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:&error])
        {
            CLS_LOG(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }

    // Delete the reference to non-existing store
    [persistentStoreCoordinator release];
    persistentStoreCoordinator = nil;
    NSPersistentStoreCoordinator *r = [self persistentStoreCoordinator];

    return r;
}

My app has a single store, so I don't think NSPersistentStore *store = [[persistentStoreCoordinator persistentStores] lastObject]; would cause an issue.

Upvotes: 1

Views: 1559

Answers (2)

Daniel
Daniel

Reputation: 9050

A little late to respond, but I noticed that this error almost always occurred when our app had been pushed to the background.

When creating the persistentStoreCoordinator you may need to set the NSPersistentStoreFileProtectionKey option to NSFileProtectionCompleteUntilFirstUserAuthentication instead of NSFileProtectionComplete.

Note that this slightly elevates the security risk so you may want to consider if this is necessary in your app.

Upvotes: 1

Apollo
Apollo

Reputation: 196

Are you sure that the database is correctly opened / closed at everytime? It can be a problem due to a file open while it was uncorrectly closed

Upvotes: 0

Related Questions