ccgus / fmdb

A Cocoa / Objective-C wrapper around SQLite
Other
13.84k stars 2.76k forks source link

[logging] BUG IN CLIENT OF sqlite3.dylib: illegal multi-threaded access to database connection #724

Open edsgershao opened 5 years ago

edsgershao commented 5 years ago
(lldb) bt all
* thread #1, queue = 'fmdb.<FMDatabaseQueue: 0x6000003fd5f0>', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    frame #0: 0x000000010f4accc5 libsqlite3.dylib`sqlite3MutexMisuseAssert + 117
    frame #1: 0x000000010f4acb16 libsqlite3.dylib`checkMutexEnter + 38
    frame #2: 0x000000010f4900a3 libsqlite3.dylib`sqlite3LockAndPrepare + 211
    frame #3: 0x000000010f48196b libsqlite3.dylib`sqlite3_prepare_v2 + 43
  * frame #4: 0x000000010a3f0001 MicroVideo`-[FMDatabase executeQuery:withArgumentsInArray:orDictionary:orVAList:](self=0x0000600002994c60, _cmd="executeQuery:withArgumentsInArray:orDictionary:orVAList:", sql=@"SELECT * FROM send_packet", arrayArgs=0x0000000000000000, dictionaryArgs=0x0000000000000000, args=0x00007ffee5d6e900) at FMDatabase.m:833
    frame #5: 0x000000010a3f0dba MicroVideo`-[FMDatabase executeQuery:](self=0x0000600002994c60, _cmd="executeQuery:", sql=@"SELECT * FROM send_packet") at FMDatabase.m:953
    frame #6: 0x000000010aa6c12a MicroVideo`__29-[MFSendPacketDao getPackets]_block_invoke(.block_descriptor=0x00007ffee5d6ec90, db=0x0000600002994c60) at MFSendPacketDao.m:62
    frame #7: 0x000000010a3faa9d MicroVideo`__30-[FMDatabaseQueue inDatabase:]_block_invoke(.block_descriptor=0x00007ffee5d6ebf0) at FMDatabaseQueue.m:194
    frame #8: 0x0000000118109602 libdispatch.dylib`_dispatch_client_callout + 8
    frame #9: 0x0000000118117653 libdispatch.dylib`_dispatch_lane_barrier_sync_invoke_and_complete + 132
    frame #10: 0x000000010a3fa9c7 MicroVideo`-[FMDatabaseQueue inDatabase:](self=0x00006000003fd5f0, _cmd="inDatabase:", block=0x000000010aa6c0a0) at FMDatabaseQueue.m:190
    frame #11: 0x000000010aa6bf61 MicroVideo`-[MFSendPacketDao getPackets](self=0x0000600000f93590, _cmd="getPackets") at MFSendPacketDao.m:60
    frame #12: 0x000000010aa7b75c MicroVideo`-[MFSendPacketPolicy pullOfflineMessageFinished](self=0x0000600000dd4e40, _cmd="pullOfflineMessageFinished") at MFSendPacketPolicy.m:469
    frame #13: 0x000000010aa331e4 MicroVideo`__49-[MFOfflineMessageHandler handleOfflinePacketIQ:]_block_invoke.81(.block_descriptor=0x00006000002049c0) at MFOfflineMessageHandler.m:116
    frame #14: 0x0000000118108595 libdispatch.dylib`_dispatch_call_block_and_release + 12
    frame #15: 0x0000000118109602 libdispatch.dylib`_dispatch_client_callout + 8
    frame #16: 0x000000011811699a libdispatch.dylib`_dispatch_main_queue_callback_4CF + 1541
    frame #17: 0x00000001112263e9 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    frame #18: 0x0000000111220a76 CoreFoundation`__CFRunLoopRun + 2342
    frame #19: 0x000000011121fe11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #20: 0x000000011917f1dd GraphicsServices`GSEventRunModal + 62
    frame #21: 0x000000011f45081d UIKitCore`UIApplicationMain + 140
    frame #22: 0x000000010a31d580 MicroVideo`main(argc=1, argv=0x00007ffee5d6ffa8) at main.m:14
    frame #23: 0x000000011817f575 libdyld.dylib`start + 1
    frame #24: 0x000000011817f575 libdyld.dylib`start + 1
  thread #3, queue = 'mfkit.longconnection.callback.serial'
    frame #0: 0x00000001184a4bf2 libsystem_kernel.dylib`kevent_id + 10
    frame #1: 0x00000001181283b9 libdispatch.dylib`_dispatch_kq_poll + 222
    frame #2: 0x0000000118127a4c libdispatch.dylib`_dispatch_event_loop_poke + 524
    frame #3: 0x000000010b6f6b93 MicroVideo`+[BLYLogger queueLogMessage:] + 184
    frame #4: 0x000000010b6f6ab0 MicroVideo`+[BLYLogger log:level:file:function:line:tag:] + 383
    frame #5: 0x000000010b701d1b MicroVideo`+[BuglyLog level:tag:log:] + 325
    frame #6: 0x000000010a179455 MicroVideo`__27-[MFLogModuleWrapper setup]_block_invoke.166(.block_descriptor=0x000000010cdf7730, message=@"Error:未定义的接收格式, packet.businessType=security, packet.businessName=second", logLevel=XlogLevelError, moduleName="/Users/shaorongjie/Documents/git_lab/bgzs/ios-MicroVideo/Pods/MFKit/MFKit/Classes/Connection/LongConnection/Receive/MFReceivePacketHandler.m", funcName="-[MFReceivePacketHandler batchCallbackToBusiness:dao:]_block_invoke", lineNumber=545) at MFLogModuleWrapper.m:183
    frame #7: 0x000000010b53cb37 MicroVideo`::+[Xlog logWithLevel:moduleName:fileName:lineNumber:funcName:message:](self=Xlog, _cmd="logWithLevel:moduleName:fileName:lineNumber:funcName:message:", logLevel=XlogLevelError, moduleName="/Users/shaorongjie/Documents/git_lab/bgzs/ios-MicroVideo/Pods/MFKit/MFKit/Classes/Connection/LongConnection/Receive/MFReceivePacketHandler.m", fileName="MFReceivePacketHandler.m", lineNumber=545, funcName="-[MFReceivePacketHandler batchCallbackToBusiness:dao:]_block_invoke", message="Error:未定义的接收格式, packet.businessType=security, packet.businessName=second") at Xlog.mm:91
    frame #8: 0x000000010aa59c50 MicroVideo`__54-[MFReceivePacketHandler batchCallbackToBusiness:dao:]_block_invoke(.block_descriptor=0x0000600001869e40) at MFReceivePacketHandler.m:545
    frame #9: 0x0000000118108595 libdispatch.dylib`_dispatch_call_block_and_release + 12
    frame #10: 0x0000000118109602 libdispatch.dylib`_dispatch_client_callout + 8
    frame #11: 0x0000000118110b0b libdispatch.dylib`_dispatch_lane_serial_drain + 791
    frame #12: 0x0000000118111784 libdispatch.dylib`_dispatch_lane_invoke + 428
    frame #13: 0x000000011811b89a libdispatch.dylib`_dispatch_workloop_worker_thread + 733
    frame #14: 0x00000001184f960b libsystem_pthread.dylib`_pthread_wqthread + 409
    frame #15: 0x00000001184f9405 libsystem_pthread.dylib`start_wqthread + 13
  thread #4, name = 'JavaScriptCore bmalloc scavenger'
    frame #0: 0x00000001184a67de libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00000001184fd593 libsystem_pthread.dylib`_pthread_cond_wait + 724
    frame #2: 0x000000010f3ba78a libc++.1.dylib`std::__1::condition_variable::wait(std::__1::unique_lock<std::__1::mutex>&) + 18
    frame #3: 0x0000000113864842 JavaScriptCore`void std::__1::condition_variable_any::wait<std::__1::unique_lock<bmalloc::Mutex> >(std::__1::unique_lock<bmalloc::Mutex>&) + 82
    frame #4: 0x0000000113868b6b JavaScriptCore`bmalloc::Scavenger::threadRunLoop() + 139
    frame #5: 0x00000001138682d9 JavaScriptCore`bmalloc::Scavenger::threadEntryPoint(bmalloc::Scavenger*) + 9
    frame #6: 0x0000000113869d37 JavaScriptCore`void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(bmalloc::Scavenger*), bmalloc::Scavenger*> >(void*) + 39
    frame #7: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #8: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #9: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #5, name = 'WebThread'
    frame #0: 0x00000001184a317a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00000001184a36d0 libsystem_kernel.dylib`mach_msg + 60
    frame #2: 0x00000001112261b4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x00000001112207e9 CoreFoundation`__CFRunLoopRun + 1689
    frame #4: 0x000000011121fe11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #5: 0x0000000121a1cd35 WebCore`RunWebThread(void*) + 565
    frame #6: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #7: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #8: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #8, name = 'com.apple.uikit.eventfetch-thread'
    frame #0: 0x00000001184a317a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00000001184a36d0 libsystem_kernel.dylib`mach_msg + 60
    frame #2: 0x00000001112261b4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x00000001112207e9 CoreFoundation`__CFRunLoopRun + 1689
    frame #4: 0x000000011121fe11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #5: 0x00000001127af322 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 277
    frame #6: 0x00000001127af534 Foundation`-[NSRunLoop(NSRunLoop) runUntilDate:] + 143
    frame #7: 0x000000011f547bcb UIKitCore`-[UIEventFetcher threadMain] + 118
    frame #8: 0x00000001127c4732 Foundation`__NSThread__start__ + 1221
    frame #9: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #10: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #11: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #10, name = 'AVAudioSession Notify Thread'
    frame #0: 0x00000001184a317a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00000001184a36d0 libsystem_kernel.dylib`mach_msg + 60
    frame #2: 0x00000001112261b4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x00000001112207e9 CoreFoundation`__CFRunLoopRun + 1689
    frame #4: 0x000000011121fe11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #5: 0x00000001188f7f2e AVFAudio`GenericRunLoopThread::Entry(void*) + 158
    frame #6: 0x00000001189155d1 AVFAudio`CAPThread::Entry(CAPThread*) + 77
    frame #7: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #8: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #9: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #12
    frame #0: 0x00000001184a67de libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00000001184fd593 libsystem_pthread.dylib`_pthread_cond_wait + 724
    frame #2: 0x000000010c71f906 MicroVideo`::wait() at condition.h:73 [opt]
    frame #3: 0x000000010c71f7db MicroVideo`::wait() at condition.h:94 [opt]
    frame #4: 0x000000010c71da2b MicroVideo`::__async_log_thread() at appender.cc:516 [opt]
    frame #5: 0x000000010c7207fe MicroVideo`::start_routine() at thread.h:413 [opt]
    frame #6: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #7: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #8: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #13, name = 'com.apple.CFSocket.private'
    frame #0: 0x00000001184aa5aa libsystem_kernel.dylib`__select + 10
    frame #1: 0x000000011122f3ce CoreFoundation`__CFSocketManager + 670
    frame #2: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #3: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #4: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #15
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #17, name = 'MainRunloopMonitor'
    frame #0: 0x00000001184a31ce libsystem_kernel.dylib`semaphore_timedwait_trap + 10
    frame #1: 0x0000000118109d78 libdispatch.dylib`_dispatch_sema4_timedwait + 76
    frame #2: 0x000000011810a49e libdispatch.dylib`_dispatch_semaphore_wait_slow + 58
    frame #3: 0x000000010b723998 MicroVideo`-[BLYMainRunloopMonitorManager monitorThreadRun] + 207
    frame #4: 0x00000001127c4732 Foundation`__NSThread__start__ + 1221
    frame #5: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #6: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #7: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #18, name = 'GCDAsyncSocket-CFStream'
    frame #0: 0x00000001184a317a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00000001184a36d0 libsystem_kernel.dylib`mach_msg + 60
    frame #2: 0x00000001112261b4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x00000001112207e9 CoreFoundation`__CFRunLoopRun + 1689
    frame #4: 0x000000011121fe11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #5: 0x00000001127af322 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 277
    frame #6: 0x000000010b0c40f9 MicroVideo`+[WXOMTAGCDAsyncSocket cfstreamThread] + 334
    frame #7: 0x00000001127c4732 Foundation`__NSThread__start__ + 1221
    frame #8: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #9: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #10: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #19, name = 'com.apple.NSURLConnectionLoader'
    frame #0: 0x00000001184a317a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00000001184a36d0 libsystem_kernel.dylib`mach_msg + 60
    frame #2: 0x00000001112261b4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x00000001112207e9 CoreFoundation`__CFRunLoopRun + 1689
    frame #4: 0x000000011121fe11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #5: 0x0000000110598939 CFNetwork`-[__CoreSchedulingSetRunnable runForever] + 195
    frame #6: 0x00000001127c4732 Foundation`__NSThread__start__ + 1221
    frame #7: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #8: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #9: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #22, queue = 'com.apple.CFNetwork.addPersistCacheToStorageDaemon'
    frame #0: 0x00000001184e6913 libsystem_platform.dylib`_platform_memset$VARIANT$Haswell + 19
    frame #1: 0x000000011122762a CoreFoundation`_CFRuntimeCreateInstance + 346
    frame #2: 0x00000001113198e5 CoreFoundation`CFBasicHashCreateCopy + 373
    frame #3: 0x00000001111e2551 CoreFoundation`CFDictionaryCreateMutableCopy + 145
    frame #4: 0x0000000110413aef CFNetwork`HTTPMessage::copyHeadersWithShadowedArrayValues() + 195
    frame #5: 0x00000001103f40be CFNetwork`URLRequest::createArchiveList(__CFAllocator const*, long*, void const***, long*, __CFDictionary const**) const + 1146
    frame #6: 0x00000001103f4a0e CFNetwork`URLRequest::copyPropertyList(__CFAllocator const*, __CFDictionary const**) const + 78
    frame #7: 0x00000001103bc891 CFNetwork`___ZN12__CFURLCache23CreateAndStoreCacheNodeEP16__CFURLCacheNodePK20_CFCachedURLResponsePK10__CFStringPK13_CFURLRequestPKvbRb_block_invoke + 1314
    frame #8: 0x0000000118108595 libdispatch.dylib`_dispatch_call_block_and_release + 12
    frame #9: 0x0000000118109602 libdispatch.dylib`_dispatch_client_callout + 8
    frame #10: 0x0000000118110b0b libdispatch.dylib`_dispatch_lane_serial_drain + 791
    frame #11: 0x0000000118111784 libdispatch.dylib`_dispatch_lane_invoke + 428
    frame #12: 0x000000011811b89a libdispatch.dylib`_dispatch_workloop_worker_thread + 733
    frame #13: 0x00000001184f960b libsystem_pthread.dylib`_pthread_wqthread + 409
    frame #14: 0x00000001184f9405 libsystem_pthread.dylib`start_wqthread + 13
  thread #23
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #24
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #25, name = 'GCDAsyncSocket-CFStream'
    frame #0: 0x00000001184a317a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x00000001184a36d0 libsystem_kernel.dylib`mach_msg + 60
    frame #2: 0x00000001112261b4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x00000001112207e9 CoreFoundation`__CFRunLoopRun + 1689
    frame #4: 0x000000011121fe11 CoreFoundation`CFRunLoopRunSpecific + 625
    frame #5: 0x00000001127af322 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 277
    frame #6: 0x000000010a9cdbbc MicroVideo`+[GCDAsyncSocket cfstreamThread](self=GCDAsyncSocket, _cmd="cfstreamThread") at GCDAsyncSocket.m:6906
    frame #7: 0x00000001127c4732 Foundation`__NSThread__start__ + 1221
    frame #8: 0x00000001184fa305 libsystem_pthread.dylib`_pthread_body + 126
    frame #9: 0x00000001184fd26f libsystem_pthread.dylib`_pthread_start + 70
    frame #10: 0x00000001184f9415 libsystem_pthread.dylib`thread_start + 13
  thread #26
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #27
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #28
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #29, queue = 'com.chat.received.serial'
    frame #0: 0x00000001162c7d9c libobjc.A.dylib`objc_msgSend + 28
    frame #1: 0x000000010b57b0a0 MicroVideo`+[_YYModelPropertyMeta metaWithClassInfo:propertyInfo:generic:] [inlined] YYClassGetNSType(cls=NSDictionary) at NSObject+YYModel.m:49
    frame #2: 0x000000010b57ad95 MicroVideo`+[_YYModelPropertyMeta metaWithClassInfo:propertyInfo:generic:](self=_YYModelPropertyMeta, _cmd="metaWithClassInfo:propertyInfo:generic:", classInfo=0x0000600002d1b2a0, propertyInfo=0x0000600002d1e490, generic=0x0000000000000000) at NSObject+YYModel.m:368
    frame #3: 0x000000010b57c316 MicroVideo`-[_YYModelMeta initWithClass:](self=0x0000600002d1b250, _cmd="initWithClass:", cls=MFReceivedPacket) at NSObject+YYModel.m:532
    frame #4: 0x000000010b57e342 MicroVideo`+[_YYModelMeta metaWithClass:](self=_YYModelMeta, _cmd="metaWithClass:", cls=MFReceivedPacket) at NSObject+YYModel.m:641
    frame #5: 0x000000010b583dd6 MicroVideo`ModelDescription(model=0x00006000029cfa20) at NSObject+YYModel.m:1306
    frame #6: 0x000000010b583c69 MicroVideo`-[NSObject(self=0x00006000029cfa20, _cmd="yy_modelDescription") yy_modelDescription] at NSObject+YYModel.m:1768
    frame #7: 0x000000010a84436b MicroVideo`-[MFMessageController didReceivedReadOrDeliveredTagPacket:](self=0x00006000003dd9e0, _cmd="didReceivedReadOrDeliveredTagPacket:", packet=0x00006000029cfa20) at MFMessageController.m:1385
    frame #8: 0x000000010a830c0a MicroVideo`__52-[MFMessageController registerObserveReceivedPacket]_block_invoke_2(.block_descriptor=0x00006000017b43c0) at MFMessageController.m:88
    frame #9: 0x0000000118108595 libdispatch.dylib`_dispatch_call_block_and_release + 12
    frame #10: 0x0000000118109602 libdispatch.dylib`_dispatch_client_callout + 8
    frame #11: 0x0000000118110b0b libdispatch.dylib`_dispatch_lane_serial_drain + 791
    frame #12: 0x0000000118111784 libdispatch.dylib`_dispatch_lane_invoke + 428
    frame #13: 0x000000011811b89a libdispatch.dylib`_dispatch_workloop_worker_thread + 733
    frame #14: 0x00000001184f960b libsystem_pthread.dylib`_pthread_wqthread + 409
    frame #15: 0x00000001184f9405 libsystem_pthread.dylib`start_wqthread + 13
  thread #30
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #31
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #32
    frame #0: 0x00000001184f93f8 libsystem_pthread.dylib`start_wqthread
  thread #33
    frame #0: 0x000000010f14e796 libBacktraceRecording.dylib`pthread_introspection_hook
    frame #1: 0x00000001184f98b2 libsystem_pthread.dylib`_pthread_wqthread_setup + 413
    frame #2: 0x00000001184f949d libsystem_pthread.dylib`_pthread_wqthread + 43
    frame #3: 0x00000001184f9405 libsystem_pthread.dylib`start_wqthread + 13

Sometimes I met a crash like this. Xcode console output "2019-01-04 15:39:47.679076+0800 MicroVideo[64613:1974582] [logging] BUG IN CLIENT OF sqlite3.dylib: illegal multi-threaded access to database connection". It seems that multi-threaded access sqlite database . I followed FMDB thread safety rule to code, but it's strange to crash . I don't know why. Can somebody give advices ?Any suggestions will be nice.

edsgershao commented 5 years ago

I have check my code, all database operation use FMDBQueue inDatabase or inTransaction, and only create one FMDatabaseQueue when single instance create time.

CarlosLadd commented 5 years ago

I have check my code, all database operation use FMDBQueue inDatabase or inTransaction, and only create one FMDatabaseQueue when single instance create time.

I have many transaction in my app and the FMDBQueue object is initialize in a singleton and never I seen this error. Can you explain more about where your object FMDBQueue is declared and used?

edsgershao commented 5 years ago

I initialize database and FMDatabaseQueue in a singleton.

@interface MFNetworkDBManager()
@property(nonatomic, strong) FMDatabase *database;
@end

@implementation MFNetworkDBManager

/**
create database singleton
 @return database singleton
 */
+ (instancetype)shareInstance {
    static id sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *cachesDir = [paths objectAtIndex:0];
        NSString *dbDir = [cachesDir stringByAppendingPathComponent:@"longconnectionservice.db"];
        _database = [FMDatabase databaseWithPath:dbDir];
        _databaseQueue = [FMDatabaseQueue databaseQueueWithPath:dbDir];
        [_databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
            NSString *createSendPacketTableSql = @"CREATE TABLE IF NOT EXISTS send_packet (packetId TEXT PRIMARY KEY, businessType TEXT, businessName TEXT, businessId TEXT, companyId TEXT, fromPerson TEXT, toPerson TEXT, data TEXT, extend TEXT)";
            BOOL success = [db executeUpdate:createSendPacketTableSql];
            NSString *createReceivePacketTableSql = @"CREATE TABLE IF NOT EXISTS receive_packet (packetId TEXT PRIMARY KEY, businessType TEXT, businessName TEXT, businessId TEXT, companyId TEXT, fromPerson TEXT, toPerson TEXT, data TEXT, extend TEXT)";
            success = [db executeUpdate:createReceivePacketTableSql];
            NSString *createReceiveInfoTableSql = @"CREATE TABLE IF NOT EXISTS receive_info (packetId TEXT PRIMARY KEY, receiveTime double)";
            success = [db executeUpdate:createReceiveInfoTableSql];
            NSLog(@"success = %d", success);
        }];
    }
    return self;
}
@end

and used in follow classes

#import "MFSendPacketDao.h"
#import "MFSendPacketTable.h"
#import "MFJSONSerialization.h"
#import "MFNetworkDBManager.h"
#import "LKDBHelper.h"

static NSString * const tableName = @"send_packet";
@implementation MFSendPacketDao
#pragma mark - public
- (BOOL) insertPacket:(MFSendPacket *) packet {
    __block BOOL insertSuccess = NO;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO %@(packetId, businessType, businessName, businessId, companyId, fromPerson, toPerson, data, extend) VALUES(?,?,?,?,?,?, ?,?, ?)", tableName];
        NSString *extend = [MFJSONSerialization dictionaryToJsonString:packet.extendAttibute];
        insertSuccess = [db executeUpdate:insertSql, packet.packetId, packet.businessType, packet.businessName, packet.businessId, packet.companyId, packet.from, packet.to, packet.data, extend];
    }];
    return insertSuccess;
}

- (BOOL) deletePacket:(MFSendPacket *) packet {
    __block BOOL deleteSuccess = NO;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *deleteSql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE packetId = ?", tableName];
        deleteSuccess = [db executeUpdate:deleteSql, packet.packetId];
    }];
    return deleteSuccess;
}

- (NSArray<MFSendPacket *> *) getPackets {
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    __block NSMutableArray<MFSendPacket *> *packets = [[NSMutableArray<MFSendPacket *> alloc] init];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *selectSql = [NSString stringWithFormat:@"SELECT * FROM %@", tableName];
        FMResultSet *rs = [db executeQuery:selectSql];
        while ([rs next]) {
            MFSendPacket *sendPacket = [[MFSendPacket alloc] init];
            sendPacket.packetId = [rs stringForColumn:@"packetId"];
            sendPacket.businessType = [rs stringForColumn:@"businessType"];
            sendPacket.businessName = [rs stringForColumn:@"businessName"];
            sendPacket.businessId = [rs stringForColumn:@"businessId"];
            sendPacket.companyId = [rs stringForColumn:@"companyId"];
            sendPacket.from = [rs stringForColumn:@"fromPerson"];
            sendPacket.to = [rs stringForColumn:@"toPerson"];
            sendPacket.data = [rs stringForColumn:@"data"];
            NSString *extend = [rs stringForColumn:@"extend"];
            sendPacket.extendAttibute = [MFJSONSerialization jsonStringToDictionary:extend];
            sendPacket.sendPacketType = TYPE_MUST_ARRIVED;
            [packets addObject:sendPacket];
        }
        [rs close];
    }];
    return packets;
}

-(BOOL) isExistsFromDB:(MFSendPacket*) packet {
    __block BOOL isExist = NO;
    MFNetworkDBManager  *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSMutableArray<MFSendPacket *> *packets = [[NSMutableArray<MFSendPacket *> alloc] init];
        NSString *selectSql = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE packetId = ?", tableName];
        FMResultSet *rs = [db executeQuery:selectSql, packet.packetId];
        while ([rs next]) {
            MFSendPacket *sendPacket = [[MFSendPacket alloc] init];
            sendPacket.packetId = [rs stringForColumn:@"packetId"];
            [packets addObject:sendPacket];
        }
        isExist = packets.count > 0;
    }];
    return isExist;
}

- (BOOL) isExistsSameBusinessPacket:(MFSendPacket *) packet {
    __block BOOL isExist = NO;
    MFNetworkDBManager  *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSMutableArray<MFSendPacket *> *packets = [[NSMutableArray<MFSendPacket *> alloc] init];
        NSString *selectSql = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE packetId = ?", tableName];
        FMResultSet *rs = [db executeQuery:selectSql, packet.packetId];
        while ([rs next]) {
            MFSendPacket *sendPacket = [[MFSendPacket alloc] init];
            sendPacket.packetId = [rs stringForColumn:@"packetId"];
            [packets addObject:sendPacket];
        }
        isExist = packets.count > 0;
    }];
    return isExist;
}
@end
#import "MFReceiveInfoDao.h"
#import "MFNetworkDBManager.h"
#import <Xlog/Xlog.h>

static NSString * const tableName = @"receive_info";

@implementation MFReceiveInfoDao
- (BOOL) insertReceiveInfo:(MFReceiveInfoTable *) receiveInfo {
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    __block BOOL insertSuccess = NO;
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        //NSString * insertSql = [NSString stringWithFormat:@"INSERT INTO %@(packetId, receiveTime) VALUES(?,?)", tableName];
        //NSNumber *number = [[NSNumber alloc] initWithDouble:receiveInfo.receiveTime];
        //insertSuccess = [db executeUpdate:insertSql, receiveInfo.packetId, number];
        NSString * insertSql = [NSString stringWithFormat:@"INSERT INTO %@(packetId, receiveTime) VALUES('%@', %f)", tableName, receiveInfo.packetId, receiveInfo.receiveTime];
        insertSuccess = [db executeUpdate:insertSql];
    }];
    return insertSuccess;
}

- (BOOL) deleteReceiveInfo:(MFReceiveInfoTable *) receiveInfo {
    __block BOOL deleteSuccess = NO;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *deleteSql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE packetId = ?", tableName];
        deleteSuccess = [db executeUpdate:deleteSql, receiveInfo.packetId];
    }];
    return deleteSuccess;
}

- (BOOL) isExistInDB:(MFReceiveInfoTable *) receiveInfo {
    __block BOOL isExist = NO;
    MFNetworkDBManager  *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *querySql = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE packetId = '%@'", tableName, receiveInfo.packetId];
        FMResultSet* rs = [db executeQuery:querySql];
        NSMutableArray<MFReceiveInfoTable *> *tables = [[NSMutableArray<MFReceiveInfoTable *> alloc] init];
        while ([rs next]) {
            MFReceiveInfoTable *table = [[MFReceiveInfoTable alloc] init];
            table.packetId = [rs stringForColumn:@"packetId"];
            table.receiveTime = [rs doubleForColumn:@"receiveTime"];
            [tables addObject:table];
        }
        isExist = tables.count > 0;
    }];
    return isExist;
}

- (void) deleteReceiveInfoLessThan:(NSTimeInterval) earlierDate {
    __block BOOL deleteSuccess = NO;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *deleteSql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE receiveTime < ?", tableName];
        deleteSuccess = [db executeUpdate:deleteSql, @(earlierDate)];
    }];
}
@end
#import "MFReceivePacketDao.h"
#import "MFJSONSerialization.h"
#import "MFNetworkDBManager.h"
#import "MFNetworkConstants.h"
#import "MFNetworkErrorCode.h"
#import <Xlog/Xlog.h>
#import <Bugly/Bugly.h>

static NSString * const tableName = @"receive_packet";

@implementation MFReceivePacketDao

#pragma mark - public
- (BOOL) insertPacket:(MFReceivedPacket *) packet {
    __block BOOL insertSuccess = NO;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO %@(packetId, businessType, businessName, businessId, companyId, fromPerson, toPerson, data, extend) VALUES(?,?,?,?,?,?, ?,?, ?)", tableName];
        NSString *extend = [MFJSONSerialization dictionaryToJsonString:packet.extendAttibute];
        insertSuccess = [db executeUpdate:insertSql, packet.packetId, packet.businessType, packet.businessName, packet.businessId, packet.companyId, packet.from, packet.to, packet.data, extend];
        if (!insertSuccess) {
            XLOG_ERROR(@"insert failed packetId = %@, businessType = %@, businessName = %@, businessId = %@, companyId = %@, fromPerson = %@, toPerson = %@, data = %@, extend = %@", packet.packetId, packet.businessType, packet.businessName, packet.businessId, packet.companyId, packet.from, packet.to, packet.data, extend);
        }
    }];
    return insertSuccess;
}

- (BOOL) deletePacket:(MFReceivedPacket *) packet {
    if (![self isExistInDB:packet]) {
        return YES;
    }
    __block BOOL deleteSuccess = NO;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *deleteSql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE packetId = ?", tableName];
        deleteSuccess = [db executeUpdate:deleteSql, packet.packetId];
        if (!deleteSuccess) {
            XLOG_ERROR(@"delete failed sql = %@, packetId = %@", deleteSql, packet.packetId);
        }
    }];
    return deleteSuccess;
}

- (NSArray<MFReceivedPacket *> *) getAllPackets {
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    __block NSMutableArray<MFReceivedPacket *> *packets = [[NSMutableArray<MFReceivedPacket *> alloc] init];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *selectSql = [NSString stringWithFormat:@"SELECT * FROM %@", tableName];
        FMResultSet *rs = [db executeQuery:selectSql];
        while ([rs next]) {
            MFReceivedPacket *receivePacket = [[MFReceivedPacket alloc] init];
            receivePacket.packetId = [rs stringForColumn:@"packetId"];
            receivePacket.businessType = [rs stringForColumn:@"businessType"];
            receivePacket.businessName = [rs stringForColumn:@"businessName"];
            receivePacket.businessId = [rs stringForColumn:@"businessId"];
            receivePacket.companyId = [rs stringForColumn:@"companyId"];
            receivePacket.from = [rs stringForColumn:@"fromPerson"];
            receivePacket.to = [rs stringForColumn:@"toPerson"];
            receivePacket.data = [rs stringForColumn:@"data"];
            NSString *extend = [rs stringForColumn:@"extend"];
            receivePacket.extendAttibute = [MFJSONSerialization jsonStringToDictionary:extend];
            [packets addObject:receivePacket];
        }
    }];
    return packets;

}

- (BOOL) isExistInDB:(MFReceivedPacket *) packet {
    __block BOOL isExist = NO;
    MFNetworkDBManager  *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSString *querySql = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE packetId = '%@'", tableName, packet.packetId];
        NSMutableArray<MFReceivedPacket *> *packets = [[NSMutableArray<MFReceivedPacket *> alloc] init];
        FMResultSet *rs = [db executeQuery:querySql];
        while ([rs next]) {
            MFReceivedPacket *receivePacket = [[MFReceivedPacket alloc] init];
            receivePacket.packetId = [rs stringForColumn:@"packetId"];
            receivePacket.businessType = [rs stringForColumn:@"businessType"];
            receivePacket.businessName = [rs stringForColumn:@"businessName"];
            receivePacket.businessId = [rs stringForColumn:@"businessId"];
            receivePacket.companyId = [rs stringForColumn:@"companyId"];
            receivePacket.from = [rs stringForColumn:@"fromPerson"];
            receivePacket.to = [rs stringForColumn:@"toPerson"];
            receivePacket.data = [rs stringForColumn:@"data"];
            NSString *extend = [rs stringForColumn:@"extend"];
            receivePacket.extendAttibute = [MFJSONSerialization jsonStringToDictionary:extend];
            [packets addObject:receivePacket];
        }
        isExist = packets.count > 0;
    }];
    return isExist;
}

- (BOOL) batchInsertPackets:(NSArray<MFReceivedPacket*> *) packets {
    if (!packets) {
        return YES;
    }
    if (packets.count <= 0) {
        return YES;
    }
    __block BOOL batchInsertSuccess = YES;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inTransaction:^(FMDatabase * _Nonnull db, BOOL * _Nonnull rollback) {
        BOOL insertSuccess = NO;
        NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO %@(packetId, businessType, businessName, businessId, companyId, fromPerson, toPerson, data, extend) VALUES(?,?,?,?,?,?, ?,?, ?)", tableName];
        for (MFReceivedPacket *packet in packets) {
            NSString *querySql = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE packetId = '%@'", tableName, packet.packetId];
            FMResultSet *rs = [db executeQuery:querySql];
            if (rs.next) {
                XLOG_INFO(@"exist same packetId packet");
            } else {
                NSString *extend = [MFJSONSerialization dictionaryToJsonString:packet.extendAttibute];
                insertSuccess = [db executeUpdate:insertSql, packet.packetId, packet.businessType, packet.businessName, packet.businessId, packet.companyId, packet.from, packet.to, packet.data, extend];
                if (!insertSuccess) {
                    NSString *errorMessage = [NSString stringWithFormat:@"batch insert failed packetId = %@, businessType = %@, businessName = %@, businessId = %@, companyId = %@, fromPerson = %@, toPerson = %@, data = %@, extend = %@", packet.packetId, packet.businessType, packet.businessName, packet.businessId, packet.companyId, packet.from, packet.to, packet.data, extend];
                    NSError *batchInsertError = [NSError errorWithDomain:MFLongConnectionLogicErrorDomain code:MFErrorDatabaseOperationFailed userInfo:@{NSLocalizedDescriptionKey:errorMessage}];
                    [Bugly reportError:batchInsertError];
                    XLOG_ERROR(errorMessage);
                    *rollback = YES;
                    batchInsertSuccess = NO;
                    return;
                }
            }

        }
    }];
    return batchInsertSuccess;
}

- (BOOL) batchDeletePackets:(NSArray<MFReceivedPacket*> *) packets {
    if (!packets) {
        return YES;
    }
    if (packets.count <= 0) {
        return YES;
    }

    __block BOOL batchDeleteSuccess = NO;
    MFNetworkDBManager *mgr = [MFNetworkDBManager shareInstance];
    [mgr.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
        NSMutableString * where = [[NSMutableString alloc] initWithString:@"packetId  IN ("];
        NSInteger count = [packets count];
        for (NSInteger i = 0; i < count; i ++) {
            MFReceivedPacket *receivedPacket = [packets objectAtIndex:i];
            if (i == 0) {
                [where appendFormat:@"'%@'",receivedPacket.packetId];
            } else {
                [where appendFormat:@",'%@'",receivedPacket.packetId];
            }
        }
        [where appendString:@")"];
        NSString *batchDeleteSql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@", tableName, where];
        batchDeleteSuccess = [db executeUpdate:batchDeleteSql];
        if (!batchDeleteSuccess) {
            XLOG_ERROR(@"batch delete failed sql = %@", batchDeleteSql);
        }
    }];
    return batchDeleteSuccess;
}
@end

@CarlosLadd Can you give me a help? Thanks!

CarlosLadd commented 5 years ago

Well, I can't see your FMDatabaseQueue object declaration but is similar like this:

*@property (nonatomic) FMDatabaseQueue databaseQueue;**

Don't use "strong" because we are in a singleton and you need to delete de FMDatabase Object because we don't use anymore. I can't see an error directly but I think in this method there is something wrong:

The "for loop" execute many times "executeQuery" method you need rethink that logic, In your Singleton class you can do a method like this to make sure the object is already exists:

For next step you can invoke the method like this:

[MFNetworkDBManager. shareInstance.execDB inDatabase:^(FMDatabase * _Nonnull db) { // do the magic }];

@edsgershao I hope it helps you :) let me know

edsgershao commented 5 years ago

@CarlosLadd Thanks for your help! I modify it by your advices, can't see this issue any more, I think it may be solved.

CarlosLadd commented 5 years ago

Excellent :) cheers

crmo commented 5 years ago

I also encountered the same problem, close FMResultSet manually may be helpful.

FMResultSet *rs = [db executeQuery:querySql];
if (rs.next) {
     XLOG_INFO(@"exist same packetId packet");
    // close FMResultSet manually
     [rs close];
}