Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FMDB crashes in iOS7 #187

Open
avalanched opened this issue Sep 28, 2013 · 7 comments
Open

FMDB crashes in iOS7 #187

avalanched opened this issue Sep 28, 2013 · 7 comments

Comments

@avalanched
Copy link

I couldn't reproduce this issue but apple did during the review process.
And my app got rejected.

I have no clue why this happened

Application Specific Information:
EventGuide[331] has active assertions beyond permitted time:
{(
<BKProcessAssertion: 0x15e90c60> identifier: Suspending process: EventGuide[331] permittedBackgroundDuration: 10.000000 reason: suspend owner pid:29 preventSuspend preventThrottleDownCPU preventThrottleDownUI preventSuspendOnSleep
)}

Elapsed total CPU time (seconds): 13.100 (user 13.100, system 0.000), 60% CPU
Elapsed application CPU time (seconds): 1.330, 6% CPU

Thread 0 name: Dispatch queue: fmdb.<FMDatabaseQueue: 0x1558f2f0>
Thread 0:
0 libsystem_kernel.dylib 0x3b32c664 fsync + 8
1 libsqlite3.dylib 0x3b05b73c 0x3b01b000 + 263996
2 libsqlite3.dylib 0x3b05b658 0x3b01b000 + 263768
3 libsqlite3.dylib 0x3b051004 0x3b01b000 + 221188
4 libsqlite3.dylib 0x3b032638 0x3b01b000 + 95800
5 libsqlite3.dylib 0x3b04da9c 0x3b01b000 + 207516
6 libsqlite3.dylib 0x3b043e2c sqlite3_step + 404
7 EventGuide 0x00099e0c -[FMDatabase executeUpdate:error:withArgumentsInArray:orDictionary:orVAList:] + 1284
8 EventGuide 0x0009a090 -[FMDatabase executeUpdate:withArgumentsInArray:] + 32
9 EventGuide 0x000718ec +EMCSQLiteHelper updateGenericForTable:withDict:andDatabase:
10 EventGuide 0x00070882 +EMCSQLiteHelper executeUpdateForTable:withArray:andDatabase:
11 EventGuide 0x00070644 41+[EMCSQLiteHelper updateWith:completion:]_block_invoke (EMCSQLiteHelper.m:148)
12 EventGuide 0x0009c254 __30-[FMDatabaseQueue inDatabase:]_block_invoke + 32
13 libdispatch.dylib 0x3b261d64 _dispatch_client_callout + 20
14 libdispatch.dylib 0x3b267bea _dispatch_barrier_sync_f_invoke + 22
15 EventGuide 0x0009c218 -[FMDatabaseQueue inDatabase:] + 96
16 EventGuide 0x000704ce +EMCSQLiteHelper updateWith:completion:
17 EventGuide 0x000286f2 __37-[EMCStartViewController viewDidLoad]_block_invoke (EMCStartViewController.m:90)
18 EventGuide 0x0007b6a4 __74+[AFJSONRequestOperation JSONRequestOperationWithRequest:success:failure:]_block_invoke + 96
19 libdispatch.dylib 0x3b261d78 _dispatch_call_block_and_release + 8
20 libdispatch.dylib 0x3b261d64 _dispatch_client_callout + 20
21 libdispatch.dylib 0x3b2687bc _dispatch_main_queue_callback_4CF$VARIANT$mp + 264
22 CoreFoundation 0x305d581c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
+ 4
23 CoreFoundation 0x305d40f0 __CFRunLoopRun + 1296
24 CoreFoundation 0x3053ece2 CFRunLoopRunSpecific + 518
25 CoreFoundation 0x3053eac6 CFRunLoopRunInMode + 102
26 GraphicsServices 0x3521927e GSEventRunModal + 134
27 UIKit 0x32de0a3c UIApplicationMain + 1132
28 EventGuide 0x0002206e main (main.m:16)
29 EventGuide 0x00022024 start + 36

@ccgus
Copy link
Owner

ccgus commented Sep 28, 2013

If you can reproduce it as described here:
https://github.com/ccgus/fmdb/#reporting-bugs

I'll take a look at it. Otherwise there's nothing to go on.

@scottcc
Copy link

scottcc commented May 18, 2014

Just curious here, as we're doing our own work with FMDB and want to ensure we have this case covered. Is this not the watchdog stating: "Hey, you went into the background and while you did spin up a background task to handle it, you took longer than the 10 minutes the system will let you run in the background. Headshot." Curious to know if anyone else has handled doing background handlers in conjunction with FMDB and how they write the "will be killed" block that is passed in (i.e., does one rollback the tx on the database and get out?).

@robertmryan
Copy link
Collaborator

@avalanched Just to clarify, what sort of background operation is this? Are you using beginBackgroundTaskWithExpirationHandler to complete some task that you started in foreground? If so, did you call endBackgroundTask in the expiration handler? (I know, it sounds weird to call endBackgroundTask in the expirationHandler, but if you don't, rather than suspending your app, it will kill your app.)

@scottcc I don't believe you need to do anything, as if the app is killed before the changes are committed, the database should be preserved fine. If you have series of updates that must be committed together, just make sure to wrap them in a transaction, and you should be good.

@scottcc
Copy link

scottcc commented May 20, 2014

@robertmryan Thanks - I was wondering what kind of ExpirationHandler I should set, given that I know I will be wrapping much (if not all) FMDB write functions in their own beginBackgroundTaskWithExpirationHandler. Ie, the first line of the callback from FMDB that passes me the opened FMDatabase *db, I'd set the backgroundTask, and presumably pass in an expirationHandler that does [tx rollback]; [db close]. I know that the new .wal/.shm defaults of sqlite might live on, and Core Data goes on at length that you should protect saves happening on a background thread as they're not guaranteed to let 'go', so to speak.

@robertmryan
Copy link
Collaborator

@scottcc I see the appeal of that idea, but I'm unclear as to how you could do a rollback of the transaction that is presumably still underway on a different thread.

I might be inclined to set a BOOL property to indicate whether the background task had expired:

@property (atomic) UIBackgroundTaskIdentifier task;
@property (atomic) BOOL backgroundTaskExpired;

And then my FMDatabaseQueue transaction would do something like:

UIApplication *app = [UIApplication sharedApplication];

self.task = [app beginBackgroundTaskWithExpirationHandler:^{

    // tell transaction that the background task is canceled

    self.backgroundTaskExpired = YES;

    // usually, I'd have this completion handler end the task so the app is not summarily killed
    // but in this case, we are taking care of this after the transaction is canceled
    //
    // if (self.task != UIBackgroundTaskInvalid) {
    //     [app endBackgroundTask:self.task];
    //     self.task = UIBackgroundTaskInvalid;
    // }
}];

[self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {

    BOOL doneInserting = NO;

    while (!doneInserting) {
        if (self.backgroundTaskExpired) {
            *rollback = YES;
            return;
        }

        // do a single insert here and then we'll loop for the next one,
        // effectively ensuring we check `backgroundTaskExpired` frequently
    }
}];

// if the task hasn't been ended yet, do so here

if (self.task != UIBackgroundTaskInvalid) {
    [app endBackgroundTask:self.task];
    self.task = UIBackgroundTaskInvalid;
}

Perhaps others have better suggestions, but that's what I'd be inclined to try.

Doing a little testing on the device (and don't do this with the debugger, as that alters the behavior), it appears that you have a few seconds after the expiration handler being called and where the app is killed if you fail to call endBackgroundTask. So, as long as you're checking the backgroundTaskExpired variable more frequently than that, you should be good.

@scottcc
Copy link

scottcc commented Jun 11, 2014

Thanks @robertmryan - very helpful. Last question - do you guys recommend altering the shm/wal mode at all? We're thinking we'd probably use read only for access by the app. When updates come in, we are considering taking a copy, performing writes on that, and swapping it back. Not sure whether SQLITE_OPEN_DELETEONCLOSE achieves this or whether the older SQLITE_OPEN_EXCLUSIVE is necessary. Welcome your thoughts there.

@robertmryan
Copy link
Collaborator

@scottcc I don't personally see any need for any of that, as I think the above achieves what you need. But perhaps others have opinions on this topic. Perhaps this would be a good question to post on a forum like Stack Overflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants