motion-yapper 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -1
  4. data/lib/yapper.rb +3 -3
  5. data/lib/yapper/db.rb +61 -4
  6. data/lib/yapper/document/persistence.rb +4 -0
  7. data/lib/yapper/document/selection.rb +13 -0
  8. data/lib/yapper/version.rb +1 -1
  9. data/motion-yapper.gemspec +1 -1
  10. data/spec/integration/search_spec.rb +111 -0
  11. data/vendor/Podfile.lock +11 -7
  12. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.bridgesupport +16 -2
  13. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.h +10 -7
  14. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.m +20 -2
  15. metadata +19 -297
  16. data/vendor/Pods/.build/libPods-CocoaLumberjack.a +0 -0
  17. data/vendor/Pods/.build/libPods-NSData+MD5Digest.a +0 -0
  18. data/vendor/Pods/.build/libPods-YapDatabase.a +0 -0
  19. data/vendor/Pods/.build/libPods.a +0 -0
  20. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h +0 -41
  21. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h +0 -102
  22. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDContextFilterLogFormatter.h +0 -63
  23. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDDispatchQueueLogFormatter.h +0 -128
  24. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h +0 -369
  25. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog+LOGV.h +0 -99
  26. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog.h +0 -634
  27. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDMultiFormatter.h +0 -30
  28. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h +0 -181
  29. data/vendor/Pods/BuildHeaders/NSData+MD5Digest/NSData+MD5Digest.h +0 -18
  30. data/vendor/Pods/BuildHeaders/YapDatabase/NSDictionary+YapDatabase.h +0 -8
  31. data/vendor/Pods/BuildHeaders/YapDatabase/YapCache.h +0 -91
  32. data/vendor/Pods/BuildHeaders/YapDatabase/YapCollectionKey.h +0 -23
  33. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabase.h +0 -547
  34. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnection.h +0 -449
  35. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnectionState.h +0 -29
  36. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseDefaults.h +0 -37
  37. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtension.h +0 -15
  38. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionConnection.h +0 -11
  39. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionPrivate.h +0 -444
  40. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionTransaction.h +0 -11
  41. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredView.h +0 -81
  42. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewConnection.h +0 -12
  43. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -17
  44. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTransaction.h +0 -39
  45. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTypes.h +0 -32
  46. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearch.h +0 -89
  47. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchConnection.h +0 -32
  48. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchPrivate.h +0 -77
  49. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchSnippetOptions.h +0 -79
  50. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchTransaction.h +0 -68
  51. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseLogging.h +0 -158
  52. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseManager.h +0 -17
  53. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabasePrivate.h +0 -446
  54. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseQuery.h +0 -42
  55. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationship.h +0 -35
  56. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipConnection.h +0 -29
  57. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdge.h +0 -163
  58. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdgePrivate.h +0 -79
  59. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipNode.h +0 -99
  60. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipOptions.h +0 -59
  61. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipPrivate.h +0 -125
  62. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipTransaction.h +0 -384
  63. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndex.h +0 -149
  64. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexConnection.h +0 -33
  65. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +0 -83
  66. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetup.h +0 -33
  67. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetupPrivate.h +0 -18
  68. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexTransaction.h +0 -58
  69. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseStatement.h +0 -13
  70. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseString.h +0 -121
  71. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseTransaction.h +0 -651
  72. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseView.h +0 -127
  73. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChange.h +0 -272
  74. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChangePrivate.h +0 -94
  75. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewConnection.h +0 -116
  76. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappings.h +0 -842
  77. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappingsPrivate.h +0 -72
  78. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewOptions.h +0 -63
  79. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPage.h +0 -36
  80. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPageMetadata.h +0 -27
  81. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPrivate.h +0 -170
  82. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewRangeOptions.h +0 -330
  83. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewRangeOptionsPrivate.h +0 -17
  84. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTransaction.h +0 -498
  85. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTypes.h +0 -99
  86. data/vendor/Pods/BuildHeaders/YapDatabase/YapMemoryTable.h +0 -74
  87. data/vendor/Pods/BuildHeaders/YapDatabase/YapNull.h +0 -17
  88. data/vendor/Pods/BuildHeaders/YapDatabase/YapSet.h +0 -41
  89. data/vendor/Pods/BuildHeaders/YapDatabase/YapTouch.h +0 -15
  90. data/vendor/Pods/CocoaLumberjack/LICENSE.txt +0 -18
  91. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +0 -41
  92. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +0 -100
  93. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +0 -102
  94. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +0 -727
  95. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +0 -369
  96. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +0 -1539
  97. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog+LOGV.h +0 -99
  98. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.h +0 -634
  99. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.m +0 -1208
  100. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +0 -181
  101. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +0 -1520
  102. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDContextFilterLogFormatter.h +0 -63
  103. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDContextFilterLogFormatter.m +0 -191
  104. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDDispatchQueueLogFormatter.h +0 -128
  105. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDDispatchQueueLogFormatter.m +0 -253
  106. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.h +0 -30
  107. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.m +0 -127
  108. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/README.txt +0 -7
  109. data/vendor/Pods/CocoaLumberjack/README.markdown +0 -74
  110. data/vendor/Pods/Headers/CocoaLumberjack/DDASLLogger.h +0 -41
  111. data/vendor/Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h +0 -102
  112. data/vendor/Pods/Headers/CocoaLumberjack/DDContextFilterLogFormatter.h +0 -63
  113. data/vendor/Pods/Headers/CocoaLumberjack/DDDispatchQueueLogFormatter.h +0 -128
  114. data/vendor/Pods/Headers/CocoaLumberjack/DDFileLogger.h +0 -369
  115. data/vendor/Pods/Headers/CocoaLumberjack/DDLog+LOGV.h +0 -99
  116. data/vendor/Pods/Headers/CocoaLumberjack/DDLog.h +0 -634
  117. data/vendor/Pods/Headers/CocoaLumberjack/DDMultiFormatter.h +0 -30
  118. data/vendor/Pods/Headers/CocoaLumberjack/DDTTYLogger.h +0 -181
  119. data/vendor/Pods/Headers/NSData+MD5Digest/NSData+MD5Digest.h +0 -18
  120. data/vendor/Pods/Headers/YapDatabase/YapCollectionKey.h +0 -23
  121. data/vendor/Pods/Headers/YapDatabase/YapDatabase.h +0 -547
  122. data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnection.h +0 -449
  123. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtension.h +0 -15
  124. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionConnection.h +0 -11
  125. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionTransaction.h +0 -11
  126. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredView.h +0 -81
  127. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewConnection.h +0 -12
  128. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTransaction.h +0 -39
  129. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTypes.h +0 -32
  130. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearch.h +0 -89
  131. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchConnection.h +0 -32
  132. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchSnippetOptions.h +0 -79
  133. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchTransaction.h +0 -68
  134. data/vendor/Pods/Headers/YapDatabase/YapDatabaseQuery.h +0 -42
  135. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationship.h +0 -35
  136. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipConnection.h +0 -29
  137. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipEdge.h +0 -163
  138. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipNode.h +0 -99
  139. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipOptions.h +0 -59
  140. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipTransaction.h +0 -384
  141. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndex.h +0 -149
  142. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexConnection.h +0 -33
  143. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexSetup.h +0 -33
  144. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexTransaction.h +0 -58
  145. data/vendor/Pods/Headers/YapDatabase/YapDatabaseTransaction.h +0 -651
  146. data/vendor/Pods/Headers/YapDatabase/YapDatabaseView.h +0 -127
  147. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChange.h +0 -272
  148. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewConnection.h +0 -116
  149. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappings.h +0 -842
  150. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewOptions.h +0 -63
  151. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewRangeOptions.h +0 -330
  152. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTransaction.h +0 -498
  153. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTypes.h +0 -99
  154. data/vendor/Pods/Headers/YapDatabase/YapSet.h +0 -41
  155. data/vendor/Pods/Headers/____Pods-CocoaLumberjack-prefix.h +0 -7
  156. data/vendor/Pods/Headers/____Pods-NSData+MD5Digest-prefix.h +0 -5
  157. data/vendor/Pods/Headers/____Pods-YapDatabase-prefix.h +0 -5
  158. data/vendor/Pods/Headers/____Pods-environment.h +0 -38
  159. data/vendor/Pods/Manifest.lock +0 -22
  160. data/vendor/Pods/NSData+MD5Digest/NSData+MD5Digest/NSData+MD5Digest.h +0 -18
  161. data/vendor/Pods/NSData+MD5Digest/NSData+MD5Digest/NSData+MD5Digest.m +0 -39
  162. data/vendor/Pods/NSData+MD5Digest/README.md +0 -11
  163. data/vendor/Pods/Pods-CocoaLumberjack-Private.xcconfig +0 -5
  164. data/vendor/Pods/Pods-CocoaLumberjack-dummy.m +0 -5
  165. data/vendor/Pods/Pods-CocoaLumberjack-prefix.pch +0 -7
  166. data/vendor/Pods/Pods-CocoaLumberjack.xcconfig +0 -0
  167. data/vendor/Pods/Pods-NSData+MD5Digest-Private.xcconfig +0 -5
  168. data/vendor/Pods/Pods-NSData+MD5Digest-dummy.m +0 -5
  169. data/vendor/Pods/Pods-NSData+MD5Digest-prefix.pch +0 -5
  170. data/vendor/Pods/Pods-NSData+MD5Digest.xcconfig +0 -0
  171. data/vendor/Pods/Pods-YapDatabase-Private.xcconfig +0 -5
  172. data/vendor/Pods/Pods-YapDatabase-dummy.m +0 -5
  173. data/vendor/Pods/Pods-YapDatabase-prefix.pch +0 -5
  174. data/vendor/Pods/Pods-YapDatabase.xcconfig +0 -1
  175. data/vendor/Pods/Pods-acknowledgements.markdown +0 -59
  176. data/vendor/Pods/Pods-acknowledgements.plist +0 -97
  177. data/vendor/Pods/Pods-dummy.m +0 -5
  178. data/vendor/Pods/Pods-environment.h +0 -38
  179. data/vendor/Pods/Pods-resources.sh +0 -68
  180. data/vendor/Pods/Pods.xcconfig +0 -5
  181. data/vendor/Pods/Pods.xcodeproj/project.pbxproj +0 -4807
  182. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-CocoaLumberjack.xcscheme +0 -59
  183. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-NSData+MD5Digest.xcscheme +0 -59
  184. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-YapDatabase.xcscheme +0 -59
  185. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods.xcscheme +0 -59
  186. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/xcschememanagement.plist +0 -31
  187. data/vendor/Pods/YapDatabase/LICENSE.txt +0 -18
  188. data/vendor/Pods/YapDatabase/README.md +0 -32
  189. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/Internal/YapDatabaseFilteredViewPrivate.h +0 -17
  190. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.h +0 -81
  191. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.m +0 -159
  192. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewConnection.h +0 -12
  193. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewConnection.m +0 -41
  194. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.h +0 -39
  195. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.m +0 -1235
  196. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTypes.h +0 -32
  197. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/Internal/YapDatabaseFullTextSearchPrivate.h +0 -77
  198. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearch.h +0 -89
  199. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearch.m +0 -146
  200. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.h +0 -32
  201. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.m +0 -298
  202. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchSnippetOptions.h +0 -79
  203. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchSnippetOptions.m +0 -95
  204. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.h +0 -68
  205. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.m +0 -1403
  206. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/Internal/YapDatabaseExtensionPrivate.h +0 -444
  207. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.h +0 -15
  208. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.m +0 -83
  209. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.h +0 -11
  210. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.m +0 -46
  211. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.h +0 -11
  212. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.m +0 -204
  213. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipEdgePrivate.h +0 -79
  214. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipPrivate.h +0 -125
  215. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.h +0 -35
  216. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.m +0 -129
  217. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.h +0 -29
  218. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.m +0 -802
  219. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.h +0 -163
  220. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.m +0 -408
  221. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipNode.h +0 -99
  222. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.h +0 -59
  223. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.m +0 -29
  224. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.h +0 -384
  225. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.m +0 -5254
  226. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexPrivate.h +0 -83
  227. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexSetupPrivate.h +0 -18
  228. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.h +0 -149
  229. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.m +0 -161
  230. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.h +0 -33
  231. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.m +0 -331
  232. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.h +0 -33
  233. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.m +0 -245
  234. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.h +0 -58
  235. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.m +0 -1269
  236. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewChangePrivate.h +0 -94
  237. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewMappingsPrivate.h +0 -72
  238. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPage.h +0 -36
  239. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPage.mm +0 -296
  240. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPageMetadata.h +0 -27
  241. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPageMetadata.m +0 -28
  242. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPrivate.h +0 -170
  243. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewRangeOptionsPrivate.h +0 -17
  244. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.h +0 -272
  245. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.m +0 -2500
  246. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.h +0 -842
  247. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.m +0 -1714
  248. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewRangeOptions.h +0 -330
  249. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewRangeOptions.m +0 -141
  250. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.h +0 -127
  251. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.m +0 -194
  252. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.h +0 -116
  253. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.m +0 -888
  254. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.h +0 -63
  255. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.m +0 -27
  256. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.h +0 -498
  257. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m +0 -4986
  258. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTypes.h +0 -99
  259. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.h +0 -8
  260. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.m +0 -19
  261. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.h +0 -91
  262. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.m +0 -465
  263. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseConnectionState.h +0 -29
  264. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseConnectionState.m +0 -48
  265. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.h +0 -37
  266. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.m +0 -83
  267. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseLogging.h +0 -158
  268. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseLogging.m +0 -73
  269. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseManager.h +0 -17
  270. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseManager.m +0 -56
  271. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabasePrivate.h +0 -446
  272. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseStatement.h +0 -13
  273. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseStatement.m +0 -26
  274. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseString.h +0 -121
  275. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapMemoryTable.h +0 -74
  276. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapMemoryTable.m +0 -603
  277. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.h +0 -17
  278. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.m +0 -35
  279. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapTouch.h +0 -15
  280. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapTouch.m +0 -31
  281. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.h +0 -23
  282. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.m +0 -199
  283. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapDatabaseQuery.h +0 -42
  284. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapDatabaseQuery.m +0 -96
  285. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapSet.h +0 -41
  286. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapSet.m +0 -82
  287. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.h +0 -547
  288. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.m +0 -2013
  289. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.h +0 -449
  290. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.m +0 -4046
  291. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.h +0 -651
  292. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.m +0 -5602
  293. data/vendor/Pods/build-iPhoneSimulator/Pods.bridgesupport +0 -3172
  294. data/vendor/Pods/build-iPhoneSimulator/libPods.a +0 -0
@@ -1,2013 +0,0 @@
1
- #import "YapDatabase.h"
2
- #import "YapDatabasePrivate.h"
3
- #import "YapDatabaseExtensionPrivate.h"
4
- #import "YapCollectionKey.h"
5
- #import "YapDatabaseManager.h"
6
- #import "YapDatabaseConnectionState.h"
7
- #import "YapDatabaseLogging.h"
8
-
9
- #import "sqlite3.h"
10
-
11
- #import <libkern/OSAtomic.h>
12
-
13
- #if ! __has_feature(objc_arc)
14
- #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
15
- #endif
16
-
17
- /**
18
- * Define log level for this file: OFF, ERROR, WARN, INFO, VERBOSE
19
- * See YapDatabaseLogging.h for more information.
20
- **/
21
- #if DEBUG
22
- static const int ydbLogLevel = YDB_LOG_LEVEL_INFO;
23
- #else
24
- static const int ydbLogLevel = YDB_LOG_LEVEL_WARN;
25
- #endif
26
-
27
- NSString *const YapDatabaseModifiedNotification = @"YapDatabaseModifiedNotification";
28
-
29
- NSString *const YapDatabaseSnapshotKey = @"snapshot";
30
- NSString *const YapDatabaseConnectionKey = @"connection";
31
- NSString *const YapDatabaseExtensionsKey = @"extensions";
32
- NSString *const YapDatabaseCustomKey = @"custom";
33
-
34
- NSString *const YapDatabaseObjectChangesKey = @"objectChanges";
35
- NSString *const YapDatabaseMetadataChangesKey = @"metadataChanges";
36
- NSString *const YapDatabaseRemovedKeysKey = @"removedKeys";
37
- NSString *const YapDatabaseRemovedCollectionsKey = @"removedCollections";
38
- NSString *const YapDatabaseRemovedRowidsKey = @"removedRowids";
39
- NSString *const YapDatabaseAllKeysRemovedKey = @"allKeysRemoved";
40
-
41
- NSString *const YapDatabaseRegisteredExtensionsKey = @"registeredExtensions";
42
- NSString *const YapDatabaseRegisteredTablesKey = @"registeredTables";
43
- NSString *const YapDatabaseExtensionsOrderKey = @"extensionsOrder";
44
- NSString *const YapDatabaseExtensionDependenciesKey = @"extensionDependencies";
45
- NSString *const YapDatabaseNotificationKey = @"notification";
46
-
47
- /**
48
- * The database version is stored (via pragma user_version) to sqlite.
49
- * It is used to represent the version of the userlying architecture of YapDatabase.
50
- * In the event of future changes to the sqlite underpinnings of YapDatabase,
51
- * the version can be consulted to allow for proper on-the-fly upgrades.
52
- * For more information, see the upgradeTable method.
53
- **/
54
- #define YAP_DATABASE_CURRENT_VERION 3
55
-
56
- /**
57
- * Default values
58
- **/
59
- #define DEFAULT_MAX_CONNECTION_POOL_COUNT 5 // connections
60
- #define DEFAULT_CONNECTION_POOL_LIFETIME 90.0 // seconds
61
-
62
-
63
- @implementation YapDatabase
64
-
65
- /**
66
- * The default serializer & deserializer use NSCoding (NSKeyedArchiver & NSKeyedUnarchiver).
67
- * Thus the objects need only support the NSCoding protocol.
68
- **/
69
- + (YapDatabaseSerializer)defaultSerializer
70
- {
71
- return ^ NSData* (NSString *collection, NSString *key, id object){
72
- return [NSKeyedArchiver archivedDataWithRootObject:object];
73
- };
74
- }
75
-
76
- /**
77
- * The default serializer & deserializer use NSCoding (NSKeyedArchiver & NSKeyedUnarchiver).
78
- * Thus the objects need only support the NSCoding protocol.
79
- **/
80
- + (YapDatabaseDeserializer)defaultDeserializer
81
- {
82
- return ^ id (NSString *collection, NSString *key, NSData *data){
83
- return [NSKeyedUnarchiver unarchiveObjectWithData:data];
84
- };
85
- }
86
-
87
- /**
88
- * Property lists ONLY support the following: NSData, NSString, NSArray, NSDictionary, NSDate, and NSNumber.
89
- * Property lists are highly optimized and are used extensively by Apple.
90
- *
91
- * Property lists make a good fit when your existing code already uses them,
92
- * such as replacing NSUserDefaults with a database.
93
- **/
94
- + (YapDatabaseSerializer)propertyListSerializer
95
- {
96
- return ^ NSData* (NSString *collection, NSString *key, id object){
97
- return [NSPropertyListSerialization dataWithPropertyList:object
98
- format:NSPropertyListBinaryFormat_v1_0
99
- options:NSPropertyListImmutable
100
- error:NULL];
101
- };
102
- }
103
-
104
- /**
105
- * Property lists ONLY support the following: NSData, NSString, NSArray, NSDictionary, NSDate, and NSNumber.
106
- * Property lists are highly optimized and are used extensively by Apple.
107
- *
108
- * Property lists make a good fit when your existing code already uses them,
109
- * such as replacing NSUserDefaults with a database.
110
- **/
111
- + (YapDatabaseDeserializer)propertyListDeserializer
112
- {
113
- return ^ id (NSString *collection, NSString *key, NSData *data){
114
- return [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error:NULL];
115
- };
116
- }
117
-
118
- /**
119
- * A FASTER serializer than the default, if serializing ONLY a NSDate object.
120
- * You may want to use timestampSerializer & timestampDeserializer if your metadata is simply an NSDate.
121
- **/
122
- + (YapDatabaseSerializer)timestampSerializer
123
- {
124
- return ^ NSData* (NSString *collection, NSString *key, id object) {
125
-
126
- if ([object isKindOfClass:[NSDate class]])
127
- {
128
- NSTimeInterval timestamp = [(NSDate *)object timeIntervalSinceReferenceDate];
129
-
130
- return [[NSData alloc] initWithBytes:(void *)&timestamp length:sizeof(NSTimeInterval)];
131
- }
132
- else
133
- {
134
- return [NSKeyedArchiver archivedDataWithRootObject:object];
135
- }
136
- };
137
- }
138
-
139
- /**
140
- * A FASTER deserializer than the default, if deserializing data from timestampSerializer.
141
- * You may want to use timestampSerializer & timestampDeserializer if your metadata is simply an NSDate.
142
- **/
143
- + (YapDatabaseDeserializer)timestampDeserializer
144
- {
145
- return ^ id (NSString *collection, NSString *key, NSData *data) {
146
-
147
- if ([data length] == sizeof(NSTimeInterval))
148
- {
149
- NSTimeInterval timestamp;
150
- memcpy((void *)&timestamp, [data bytes], sizeof(NSTimeInterval));
151
-
152
- return [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:timestamp];
153
- }
154
- else
155
- {
156
- return [NSKeyedUnarchiver unarchiveObjectWithData:data];
157
- }
158
- };
159
- }
160
-
161
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
162
- #pragma mark Properties
163
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
164
-
165
- @synthesize databasePath;
166
-
167
- @synthesize objectSerializer = objectSerializer;
168
- @synthesize objectDeserializer = objectDeserializer;
169
- @synthesize metadataSerializer = metadataSerializer;
170
- @synthesize metadataDeserializer = metadataDeserializer;
171
- @synthesize objectSanitizer = objectSanitizer;
172
- @synthesize metadataSanitizer = metadataSanitizer;
173
-
174
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
175
- #pragma mark Init
176
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
177
-
178
- - (id)initWithPath:(NSString *)inPath
179
- {
180
- return [self initWithPath:inPath
181
- objectSerializer:NULL
182
- objectDeserializer:NULL
183
- metadataSerializer:NULL
184
- metadataDeserializer:NULL
185
- objectSanitizer:NULL
186
- metadataSanitizer:NULL];
187
- }
188
-
189
- - (id)initWithPath:(NSString *)inPath
190
- serializer:(YapDatabaseSerializer)inSerializer
191
- deserializer:(YapDatabaseDeserializer)inDeserializer
192
- {
193
- return [self initWithPath:inPath
194
- objectSerializer:inSerializer
195
- objectDeserializer:inDeserializer
196
- metadataSerializer:inSerializer
197
- metadataDeserializer:inDeserializer
198
- objectSanitizer:NULL
199
- metadataSanitizer:NULL];
200
- }
201
-
202
- - (id)initWithPath:(NSString *)inPath
203
- serializer:(YapDatabaseSerializer)inSerializer
204
- deserializer:(YapDatabaseDeserializer)inDeserializer
205
- sanitizer:(YapDatabaseSanitizer)inSanitizer
206
- {
207
- return [self initWithPath:inPath
208
- objectSerializer:inSerializer
209
- objectDeserializer:inDeserializer
210
- metadataSerializer:inSerializer
211
- metadataDeserializer:inDeserializer
212
- objectSanitizer:inSanitizer
213
- metadataSanitizer:inSanitizer];
214
- }
215
-
216
- - (id)initWithPath:(NSString *)inPath objectSerializer:(YapDatabaseSerializer)inObjectSerializer
217
- objectDeserializer:(YapDatabaseDeserializer)inObjectDeserializer
218
- metadataSerializer:(YapDatabaseSerializer)inMetadataSerializer
219
- metadataDeserializer:(YapDatabaseDeserializer)inMetadataDeserializer
220
- {
221
- return [self initWithPath:inPath
222
- objectSerializer:inObjectSerializer
223
- objectDeserializer:inObjectDeserializer
224
- metadataSerializer:inMetadataSerializer
225
- metadataDeserializer:inMetadataDeserializer
226
- objectSanitizer:NULL
227
- metadataSanitizer:NULL];
228
- }
229
-
230
- - (id)initWithPath:(NSString *)inPath objectSerializer:(YapDatabaseSerializer)inObjectSerializer
231
- objectDeserializer:(YapDatabaseDeserializer)inObjectDeserializer
232
- metadataSerializer:(YapDatabaseSerializer)inMetadataSerializer
233
- metadataDeserializer:(YapDatabaseDeserializer)inMetadataDeserializer
234
- objectSanitizer:(YapDatabaseSanitizer)inObjectSanitizer
235
- metadataSanitizer:(YapDatabaseSanitizer)inMetadataSanitizer;
236
- {
237
- // First, standardize path.
238
- // This allows clients to be lazy when passing paths.
239
- NSString *path = [inPath stringByStandardizingPath];
240
-
241
- // Ensure there is only a single database instance per file.
242
- // However, clients may create as many connections as desired.
243
- if (![YapDatabaseManager registerDatabaseForPath:path])
244
- {
245
- YDBLogError(@"Only a single database instance is allowed per file. "
246
- @"For concurrency you create multiple connections from a single database instance.");
247
- return nil;
248
- }
249
-
250
- if ((self = [super init]))
251
- {
252
- databasePath = path;
253
-
254
- BOOL(^openConfigCreate)(void) = ^BOOL (void) { @autoreleasepool {
255
-
256
- BOOL result = YES;
257
-
258
- if (result) result = [self openDatabase];
259
- if (result) result = [self configureDatabase];
260
- if (result) result = [self createTables];
261
-
262
- if (!result && db)
263
- {
264
- sqlite3_close(db);
265
- db = NULL;
266
- }
267
-
268
- return result;
269
- }};
270
-
271
- BOOL result = openConfigCreate();
272
- if (!result)
273
- {
274
- // There are a few reasons why the database might not open.
275
- // One possibility is if the database file gets corrupt.
276
- // In the event of a problem, we simply delete the database file.
277
- // This isn't a big deal since we can just redownload the data.
278
-
279
- // Delete the (possibly corrupt) database file.
280
- [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
281
-
282
- // Then try opening a database again.
283
-
284
- result = openConfigCreate();
285
-
286
- if (result) {
287
- YDBLogInfo(@"Database corruption resolved (name=%@)", [path lastPathComponent]);
288
- }
289
- else {
290
- YDBLogError(@"Database corruption unresolved (name=%@)", [path lastPathComponent]);
291
- }
292
- }
293
- if (!result)
294
- {
295
- return nil;
296
- }
297
-
298
- internalQueue = dispatch_queue_create("YapDatabase-Internal", NULL);
299
- checkpointQueue = dispatch_queue_create("YapDatabase-Checkpoint", NULL);
300
- snapshotQueue = dispatch_queue_create("YapDatabase-Snapshot", NULL);
301
- writeQueue = dispatch_queue_create("YapDatabase-Write", NULL);
302
-
303
- changesets = [[NSMutableArray alloc] init];
304
- connectionStates = [[NSMutableArray alloc] init];
305
-
306
- defaults = [[YapDatabaseDefaults alloc] init];
307
-
308
- registeredExtensions = [[NSDictionary alloc] init];
309
- registeredTables = [[NSDictionary alloc] init];
310
-
311
- extensionDependencies = [[NSDictionary alloc] init];
312
- extensionsOrder = [[NSArray alloc] init];
313
-
314
- maxConnectionPoolCount = DEFAULT_MAX_CONNECTION_POOL_COUNT;
315
- connectionPoolLifetime = DEFAULT_CONNECTION_POOL_LIFETIME;
316
-
317
- YapDatabaseSerializer defaultSerializer = nil;
318
- YapDatabaseDeserializer defaultDeserializer = nil;
319
-
320
- if (!inObjectSerializer || !inMetadataSerializer)
321
- defaultSerializer = [[self class] defaultSerializer];
322
-
323
- if (!inObjectDeserializer || !inMetadataDeserializer)
324
- defaultDeserializer = [[self class] defaultDeserializer];
325
-
326
- objectSerializer = inObjectSerializer ? inObjectSerializer : defaultSerializer;
327
- objectDeserializer = inObjectDeserializer ? inObjectDeserializer : defaultDeserializer;
328
-
329
- metadataSerializer = inMetadataSerializer ? inMetadataSerializer : defaultSerializer;
330
- metadataDeserializer = inMetadataDeserializer ? inMetadataDeserializer : defaultDeserializer;
331
-
332
- objectSanitizer = inObjectSanitizer;
333
- metadataSanitizer = inMetadataSanitizer;
334
-
335
- // Mark the queues so we can identify them.
336
- // There are several methods whose use is restricted to within a certain queue.
337
-
338
- IsOnSnapshotQueueKey = &IsOnSnapshotQueueKey;
339
- dispatch_queue_set_specific(snapshotQueue, IsOnSnapshotQueueKey, IsOnSnapshotQueueKey, NULL);
340
-
341
- IsOnWriteQueueKey = &IsOnWriteQueueKey;
342
- dispatch_queue_set_specific(writeQueue, IsOnWriteQueueKey, IsOnWriteQueueKey, NULL);
343
-
344
- // Complete database setup in the background
345
- dispatch_async(snapshotQueue, ^{ @autoreleasepool {
346
-
347
- [self upgradeTable];
348
- [self prepare];
349
- }});
350
- }
351
- return self;
352
- }
353
-
354
- - (void)dealloc
355
- {
356
- YDBLogVerbose(@"Dealloc <%@ %p: databaseName=%@>", [self class], self, [databasePath lastPathComponent]);
357
-
358
- while ([connectionPoolValues count] > 0)
359
- {
360
- sqlite3 *aDb = (sqlite3 *)[[connectionPoolValues objectAtIndex:0] pointerValue];
361
-
362
- int status = sqlite3_close(aDb);
363
- if (status != SQLITE_OK)
364
- {
365
- YDBLogError(@"Error in sqlite_close: %d %s", status, sqlite3_errmsg(aDb));
366
- }
367
-
368
- [connectionPoolValues removeObjectAtIndex:0];
369
- [connectionPoolDates removeObjectAtIndex:0];
370
- }
371
-
372
- if (connectionPoolTimer)
373
- dispatch_source_cancel(connectionPoolTimer);
374
-
375
- if (db) {
376
- sqlite3_close(db);
377
- db = NULL;
378
- }
379
-
380
- [YapDatabaseManager deregisterDatabaseForPath:databasePath];
381
-
382
- #if !OS_OBJECT_USE_OBJC
383
- if (internalQueue)
384
- dispatch_release(internalQueue);
385
- if (snapshotQueue)
386
- dispatch_release(snapshotQueue);
387
- if (writeQueue)
388
- dispatch_release(writeQueue);
389
- if (checkpointQueue)
390
- dispatch_release(checkpointQueue);
391
- #endif
392
- }
393
-
394
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
395
- #pragma mark Setup
396
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
397
-
398
- /**
399
- * Attempts to open (or create & open) the database connection.
400
- **/
401
- - (BOOL)openDatabase
402
- {
403
- // Open the database connection.
404
- //
405
- // We use SQLITE_OPEN_NOMUTEX to use the multi-thread threading mode,
406
- // as we will be serializing access to the connection externally.
407
-
408
- int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE;
409
-
410
- int status = sqlite3_open_v2([databasePath UTF8String], &db, flags, NULL);
411
- if (status != SQLITE_OK)
412
- {
413
- // There are a few reasons why the database might not open.
414
- // One possibility is if the database file gets corrupt.
415
- // In the event of a problem, we simply delete the database file.
416
- // This isn't a big deal since we can just redownload the data.
417
-
418
- // Sometimes the open function returns a db to allow us to query it for the error message
419
- if (db) {
420
- YDBLogWarn(@"Error opening database: %d %s", status, sqlite3_errmsg(db));
421
- }
422
- else {
423
- YDBLogError(@"Error opening database: %d", status);
424
- }
425
-
426
- return NO;
427
- }
428
-
429
- return YES;
430
- }
431
-
432
- /**
433
- * Configures the database connection.
434
- * This mainly means enabling WAL mode, and configuring the auto-checkpoint.
435
- **/
436
- - (BOOL)configureDatabase
437
- {
438
- int status;
439
-
440
- status = sqlite3_exec(db, "PRAGMA legacy_file_format = 0;", NULL, NULL, NULL);
441
- if (status != SQLITE_OK)
442
- {
443
- YDBLogError(@"Error setting legacy_file_format: %d %s", status, sqlite3_errmsg(db));
444
- return NO;
445
- }
446
-
447
- status = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL);
448
- if (status != SQLITE_OK)
449
- {
450
- YDBLogError(@"Error setting journal_mode: %d %s", status, sqlite3_errmsg(db));
451
- return NO;
452
- }
453
-
454
- // Disable autocheckpointing.
455
- //
456
- // YapDatabase has its own optimized checkpointing algorithm built-in.
457
- // It knows the state of every active connection for the database,
458
- // so it can invoke the checkpoint methods at the precise time in which a checkpoint can be most effective.
459
-
460
- sqlite3_wal_autocheckpoint(db, 0);
461
-
462
- return YES;
463
- }
464
-
465
- /**
466
- * Creates the database tables we need:
467
- *
468
- * - yap2 : stores snapshot and metadata for extensions
469
- * - database2 : stores collection/key/value/metadata rows
470
- **/
471
- - (BOOL)createTables
472
- {
473
- int status;
474
-
475
- char *createYapTableStatement =
476
- "CREATE TABLE IF NOT EXISTS \"yap2\""
477
- " (\"extension\" CHAR NOT NULL, "
478
- " \"key\" CHAR NOT NULL, "
479
- " \"data\" BLOB, "
480
- " PRIMARY KEY (\"extension\", \"key\")"
481
- " );";
482
-
483
- status = sqlite3_exec(db, createYapTableStatement, NULL, NULL, NULL);
484
- if (status != SQLITE_OK)
485
- {
486
- YDBLogError(@"Failed creating 'yap2' table: %d %s", status, sqlite3_errmsg(db));
487
- return NO;
488
- }
489
-
490
- char *createDatabaseTableStatement =
491
- "CREATE TABLE IF NOT EXISTS \"database2\""
492
- " (\"rowid\" INTEGER PRIMARY KEY,"
493
- " \"collection\" CHAR NOT NULL,"
494
- " \"key\" CHAR NOT NULL,"
495
- " \"data\" BLOB,"
496
- " \"metadata\" BLOB"
497
- " );";
498
-
499
- status = sqlite3_exec(db, createDatabaseTableStatement, NULL, NULL, NULL);
500
- if (status != SQLITE_OK)
501
- {
502
- YDBLogError(@"Failed creating 'database2' table: %d %s", status, sqlite3_errmsg(db));
503
- return NO;
504
- }
505
-
506
- char *createIndexStatement =
507
- "CREATE UNIQUE INDEX IF NOT EXISTS \"true_primary_key\" ON \"database2\" ( \"collection\", \"key\" );";
508
-
509
- status = sqlite3_exec(db, createIndexStatement, NULL, NULL, NULL);
510
- if (status != SQLITE_OK)
511
- {
512
- YDBLogError(@"Failed creating index on 'database' table: %d %s", status, sqlite3_errmsg(db));
513
- return NO;
514
- }
515
-
516
- return YES;
517
- }
518
-
519
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
520
- #pragma mark Utilities
521
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
522
-
523
- /**
524
- * Returns whether or not the given table exists.
525
- **/
526
- - (BOOL)tableExists:(NSString *)tableName using:(sqlite3 *)aDb
527
- {
528
- if (tableName == nil) return NO;
529
-
530
- sqlite3_stmt *statement;
531
- char *stmt = "SELECT count(*) FROM sqlite_master WHERE type = 'table' AND name = ?";
532
-
533
- int status = sqlite3_prepare_v2(aDb, stmt, (int)strlen(stmt)+1, &statement, NULL);
534
- if (status != SQLITE_OK)
535
- {
536
- YDBLogError(@"%@: Error creating statement! %d %s", THIS_METHOD, status, sqlite3_errmsg(aDb));
537
- return NO;
538
- }
539
-
540
- BOOL result = NO;
541
-
542
- sqlite3_bind_text(statement, 1, [tableName UTF8String], -1, SQLITE_TRANSIENT);
543
-
544
- status = sqlite3_step(statement);
545
- if (status == SQLITE_ROW)
546
- {
547
- int count = sqlite3_column_int(statement, 1);
548
-
549
- result = (count > 0);
550
- }
551
- else if (status == SQLITE_ERROR)
552
- {
553
- YDBLogError(@"%@: Error executing statement! %d %s", THIS_METHOD, status, sqlite3_errmsg(aDb));
554
- }
555
-
556
- sqlite3_finalize(statement);
557
- statement = NULL;
558
-
559
- return result;
560
- }
561
-
562
- /**
563
- * Extracts and returns column names from the given table in the database.
564
- **/
565
- - (NSArray *)columnNamesForTable:(NSString *)tableName using:(sqlite3 *)aDb
566
- {
567
- if (tableName == nil) return nil;
568
-
569
- sqlite3_stmt *statement;
570
- NSString *pragma = [NSString stringWithFormat:@"PRAGMA table_info('%@');", tableName];
571
-
572
- int status = sqlite3_prepare_v2(aDb, [pragma UTF8String], -1, &statement, NULL);
573
- if (status != SQLITE_OK)
574
- {
575
- YDBLogError(@"%@: Error creating statement! %d %s", THIS_METHOD, status, sqlite3_errmsg(aDb));
576
- return nil;
577
- }
578
-
579
- NSMutableArray *tableColumnNames = [NSMutableArray array];
580
-
581
- while ((status = sqlite3_step(statement)) == SQLITE_ROW)
582
- {
583
- const unsigned char *text = sqlite3_column_text(statement, 1);
584
- int textSize = sqlite3_column_bytes(statement, 1);
585
-
586
- NSString *columnName = [[NSString alloc] initWithBytes:text length:textSize encoding:NSUTF8StringEncoding];
587
- if (columnName)
588
- {
589
- [tableColumnNames addObject:columnName];
590
- }
591
- }
592
-
593
- if (status != SQLITE_DONE)
594
- {
595
- YDBLogError(@"%@: Error executing statement! %d %s", THIS_METHOD, status, sqlite3_errmsg(aDb));
596
- }
597
-
598
- sqlite3_finalize(statement);
599
- statement = NULL;
600
-
601
- return tableColumnNames;
602
- }
603
-
604
- /**
605
- * Extracts and returns column names & affinity for the given table in the database.
606
- * The dictionary format is:
607
- *
608
- * key:(NSString *)columnName -> value:(NSString *)affinity
609
- **/
610
- - (NSDictionary *)columnNamesAndAffinityForTable:(NSString *)tableName using:(sqlite3 *)aDb
611
- {
612
- if (tableName == nil) return nil;
613
-
614
- sqlite3_stmt *statement;
615
- NSString *pragma = [NSString stringWithFormat:@"PRAGMA table_info('%@');", tableName];
616
-
617
- int status = sqlite3_prepare_v2(aDb, [pragma UTF8String], -1, &statement, NULL);
618
- if (status != SQLITE_OK)
619
- {
620
- YDBLogError(@"%@: Error creating statement! %d %s", THIS_METHOD, status, sqlite3_errmsg(aDb));
621
- return nil;
622
- }
623
-
624
- NSMutableDictionary *columns = [NSMutableDictionary dictionary];
625
-
626
- while ((status = sqlite3_step(statement)) == SQLITE_ROW)
627
- {
628
- // cid|name|type|notnull|dflt|value|pk
629
-
630
- const unsigned char *_name = sqlite3_column_text(statement, 1);
631
- int _nameSize = sqlite3_column_bytes(statement, 1);
632
-
633
- const unsigned char *_type = sqlite3_column_text(statement, 2);
634
- int _typeSize = sqlite3_column_bytes(statement, 2);
635
-
636
- NSString *name = [[NSString alloc] initWithBytes:_name length:_nameSize encoding:NSUTF8StringEncoding];
637
- NSString *affinity = [[NSString alloc] initWithBytes:_type length:_typeSize encoding:NSUTF8StringEncoding];
638
-
639
- if (name && affinity)
640
- {
641
- [columns setObject:affinity forKey:name];
642
- }
643
- }
644
-
645
- if (status != SQLITE_DONE)
646
- {
647
- YDBLogError(@"%@: Error executing statement! %d %s", THIS_METHOD, status, sqlite3_errmsg(aDb));
648
- }
649
-
650
- sqlite3_finalize(statement);
651
- statement = NULL;
652
-
653
- return columns;
654
- }
655
-
656
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
657
- #pragma mark Upgrade
658
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
659
-
660
- /**
661
- * Gets the version of the table.
662
- * This is used to perform the various upgrade paths.
663
- **/
664
- - (BOOL)get_user_version:(int *)user_version_ptr
665
- {
666
- sqlite3_stmt *pragmaStatement;
667
- int status;
668
- int user_version;
669
-
670
- char *stmt = "PRAGMA user_version;";
671
-
672
- status = sqlite3_prepare_v2(db, stmt, (int)strlen(stmt)+1, &pragmaStatement, NULL);
673
- if (status != SQLITE_OK)
674
- {
675
- YDBLogError(@"Error creating pragma user_version statement! %d %s", status, sqlite3_errmsg(db));
676
- return NO;
677
- }
678
-
679
- status = sqlite3_step(pragmaStatement);
680
- if (status == SQLITE_ROW)
681
- {
682
- user_version = sqlite3_column_int(pragmaStatement, 0);
683
- }
684
- else
685
- {
686
- YDBLogError(@"Error fetching user_version: %d %s", status, sqlite3_errmsg(db));
687
- return NO;
688
- }
689
-
690
- sqlite3_finalize(pragmaStatement);
691
- pragmaStatement = NULL;
692
-
693
- // If user_version is zero, then this is a new database
694
-
695
- if (user_version == 0)
696
- {
697
- user_version = YAP_DATABASE_CURRENT_VERION;
698
- [self set_user_version:user_version];
699
- }
700
-
701
- if (user_version_ptr)
702
- *user_version_ptr = user_version;
703
- return YES;
704
- }
705
-
706
- /**
707
- * Sets the version of the table.
708
- * The version is used to check and perform upgrade logic if needed.
709
- **/
710
- - (BOOL)set_user_version:(int)user_version
711
- {
712
- NSString *query = [NSString stringWithFormat:@"PRAGMA user_version = %d;", user_version];
713
-
714
- int status = sqlite3_exec(db, [query UTF8String], NULL, NULL, NULL);
715
- if (status != SQLITE_OK)
716
- {
717
- YDBLogError(@"Error setting user_version: %d %s", status, sqlite3_errmsg(db));
718
- return NO;
719
- }
720
-
721
- return YES;
722
- }
723
-
724
- - (BOOL)upgradeTable_1_2
725
- {
726
- // In version 1, we used a table named "yap" which had {key, data}.
727
- // In version 2, we use a table named "yap2" which has {extension, key, data}
728
-
729
- int status = sqlite3_exec(db, "DROP TABLE IF EXISTS \"yap\"", NULL, NULL, NULL);
730
- if (status != SQLITE_OK)
731
- {
732
- YDBLogError(@"Failed dropping 'yap' table: %d %s", status, sqlite3_errmsg(db));
733
- }
734
-
735
- return YES;
736
- }
737
-
738
- /**
739
- * In version 3 (more commonly known as version 2.1),
740
- * we altered the tables to use INTEGER PRIMARY KEY's so we could pass rowid's to extensions.
741
- *
742
- * This method migrates 'database' to 'database2'.
743
- **/
744
- - (BOOL)upgradeTable_2_3
745
- {
746
- int status;
747
-
748
- char *stmt = "INSERT INTO \"database2\" (\"collection\", \"key\", \"data\", \"metadata\")"
749
- " SELECT \"collection\", \"key\", \"data\", \"metadata\" FROM \"database\";";
750
-
751
- status = sqlite3_exec(db, stmt, NULL, NULL, NULL);
752
- if (status != SQLITE_OK)
753
- {
754
- YDBLogError(@"Error migrating 'database' to 'database2': %d %s", status, sqlite3_errmsg(db));
755
- return NO;
756
- }
757
-
758
- status = sqlite3_exec(db, "DROP TABLE IF EXISTS \"database\"", NULL, NULL, NULL);
759
- if (status != SQLITE_OK)
760
- {
761
- YDBLogError(@"Failed dropping 'database' table: %d %s", status, sqlite3_errmsg(db));
762
- return NO;
763
- }
764
-
765
- return YES;
766
- }
767
-
768
- /**
769
- * Performs upgrade checks, and implements the upgrade "plumbing" by invoking the appropriate upgrade methods.
770
- *
771
- * To add custom upgrade logic, implement a method named "upgradeTable_X_Y",
772
- * where X is the previous version, and Y is the new version.
773
- * For example:
774
- *
775
- * - (BOOL)upgradeTable_1_2 {
776
- * // Upgrades from version 1 to version 2 of YapDatabase.
777
- * // Return YES if successful.
778
- * }
779
- *
780
- * IMPORTANT:
781
- * This is for upgrades of the database schema, and low-level operations of YapDatabase.
782
- * This is NOT for upgrading data within the database (i.e. objects, metadata, or keys).
783
- * Such data upgrades should be performed client side.
784
- *
785
- * This method is run asynchronously on the queue.
786
- **/
787
- - (void)upgradeTable
788
- {
789
- int user_version = 0;
790
- if (![self get_user_version:&user_version]) return;
791
-
792
- while (user_version < YAP_DATABASE_CURRENT_VERION)
793
- {
794
- // Invoke method upgradeTable_X_Y
795
- // where X == current_version, and Y == current_version+1.
796
- //
797
- // Do this until we're up-to-date.
798
-
799
- int new_user_version = user_version + 1;
800
-
801
- NSString *selName = [NSString stringWithFormat:@"upgradeTable_%d_%d", user_version, new_user_version];
802
- SEL sel = NSSelectorFromString(selName);
803
-
804
- if ([self respondsToSelector:sel])
805
- {
806
- YDBLogInfo(@"Upgrading database (%@) from version %d to %d...",
807
- [databasePath lastPathComponent], user_version, new_user_version);
808
-
809
- #pragma clang diagnostic push
810
- #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
811
- if ([self performSelector:sel])
812
- #pragma clang diagnostic pop
813
- {
814
- [self set_user_version:new_user_version];
815
- }
816
- else
817
- {
818
- YDBLogError(@"Error upgrading database (%@)", [databasePath lastPathComponent]);
819
- break;
820
- }
821
- }
822
- else
823
- {
824
- YDBLogWarn(@"Missing upgrade method: %@", selName);
825
- }
826
-
827
- user_version = new_user_version;
828
- }
829
- }
830
-
831
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
832
- #pragma mark Prepare
833
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
834
-
835
- /**
836
- * Optional override hook.
837
- * Don't forget to invoke [super prepare] so super can prepare too.
838
- *
839
- * This method is run asynchronously on the snapshotQueue.
840
- **/
841
- - (void)prepare
842
- {
843
- // Initialize snapshot
844
-
845
- snapshot = 0;
846
-
847
- // Write it to disk (replacing any previous value from last app run)
848
-
849
- [self beginTransaction];
850
- [self writeSnapshot];
851
- [self fetchPreviouslyRegisteredExtensionNames];
852
- [self commitTransaction];
853
- }
854
-
855
- - (void)beginTransaction
856
- {
857
- int status = status = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
858
- if (status != SQLITE_OK)
859
- {
860
- YDBLogError(@"Error in '%@': %d %s", THIS_METHOD, status, sqlite3_errmsg(db));
861
- }
862
- }
863
-
864
- - (void)commitTransaction
865
- {
866
- int status = status = sqlite3_exec(db, "COMMIT TRANSACTION;", NULL, NULL, NULL);
867
- if (status != SQLITE_OK)
868
- {
869
- YDBLogError(@"Error in '%@': %d %s", THIS_METHOD, status, sqlite3_errmsg(db));
870
- }
871
- }
872
-
873
- - (void)writeSnapshot
874
- {
875
- int status;
876
- sqlite3_stmt *statement;
877
-
878
- char *stmt = "INSERT OR REPLACE INTO \"yap2\" (\"extension\", \"key\", \"data\") VALUES (?, ?, ?);";
879
-
880
- status = sqlite3_prepare_v2(db, stmt, (int)strlen(stmt)+1, &statement, NULL);
881
- if (status != SQLITE_OK)
882
- {
883
- YDBLogError(@"%@: Error creating statement: %d %s", THIS_METHOD, status, sqlite3_errmsg(db));
884
- }
885
- else
886
- {
887
- char *extension = "";
888
- sqlite3_bind_text(statement, 1, extension, (int)strlen(extension), SQLITE_STATIC);
889
-
890
- char *key = "snapshot";
891
- sqlite3_bind_text(statement, 2, key, (int)strlen(key), SQLITE_STATIC);
892
-
893
- sqlite3_bind_int64(statement, 3, (sqlite3_int64)snapshot);
894
-
895
- status = sqlite3_step(statement);
896
- if (status != SQLITE_DONE)
897
- {
898
- YDBLogError(@"%@: Error in statement: %d %s", THIS_METHOD, status, sqlite3_errmsg(db));
899
- }
900
-
901
- sqlite3_finalize(statement);
902
- }
903
- }
904
-
905
- - (void)fetchPreviouslyRegisteredExtensionNames
906
- {
907
- int status;
908
- sqlite3_stmt *statement;
909
-
910
- char *stmt = "SELECT DISTINCT \"extension\" FROM \"yap2\";";
911
-
912
- NSMutableArray *extensionNames = [NSMutableArray array];
913
-
914
- status = sqlite3_prepare_v2(db, stmt, (int)strlen(stmt)+1, &statement, NULL);
915
- if (status != SQLITE_OK)
916
- {
917
- YDBLogError(@"%@: Error creating statement: %d %s", THIS_METHOD, status, sqlite3_errmsg(db));
918
- }
919
- else
920
- {
921
- while ((status = sqlite3_step(statement)) == SQLITE_ROW)
922
- {
923
- const unsigned char *text = sqlite3_column_text(statement, 0);
924
- int textSize = sqlite3_column_bytes(statement, 0);
925
-
926
- NSString *extensionName =
927
- [[NSString alloc] initWithBytes:text length:textSize encoding:NSUTF8StringEncoding];
928
-
929
- if ([extensionName length] > 0)
930
- {
931
- [extensionNames addObject:extensionName];
932
- }
933
- }
934
-
935
- if (status != SQLITE_DONE)
936
- {
937
- YDBLogError(@"%@: Error in statement: %d %s", THIS_METHOD, status, sqlite3_errmsg(db));
938
- }
939
-
940
- sqlite3_finalize(statement);
941
- }
942
-
943
- previouslyRegisteredExtensionNames = extensionNames;
944
- }
945
-
946
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
947
- #pragma mark Defaults
948
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
949
-
950
- - (YapDatabaseDefaults *)defaults
951
- {
952
- __block YapDatabaseDefaults *result = nil;
953
-
954
- dispatch_sync(internalQueue, ^{
955
-
956
- result = [defaults copy];
957
- });
958
-
959
- return result;
960
- }
961
-
962
- - (BOOL)defaultObjectCacheEnabled
963
- {
964
- __block BOOL result = NO;
965
-
966
- dispatch_sync(internalQueue, ^{
967
-
968
- result = defaults.objectCacheEnabled;
969
- });
970
-
971
- return result;
972
- }
973
-
974
- - (void)setDefaultObjectCacheEnabled:(BOOL)defaultObjectCacheEnabled
975
- {
976
- dispatch_sync(internalQueue, ^{
977
-
978
- defaults.objectCacheEnabled = defaultObjectCacheEnabled;
979
- });
980
- }
981
-
982
- - (NSUInteger)defaultObjectCacheLimit
983
- {
984
- __block NSUInteger result = NO;
985
-
986
- dispatch_sync(internalQueue, ^{
987
-
988
- result = defaults.objectCacheLimit;
989
- });
990
-
991
- return result;
992
- }
993
-
994
- - (void)setDefaultObjectCacheLimit:(NSUInteger)defaultObjectCacheLimit
995
- {
996
- dispatch_sync(internalQueue, ^{
997
-
998
- defaults.objectCacheLimit = defaultObjectCacheLimit;
999
- });
1000
- }
1001
-
1002
- - (BOOL)defaultMetadataCacheEnabled
1003
- {
1004
- __block BOOL result = NO;
1005
-
1006
- dispatch_sync(internalQueue, ^{
1007
-
1008
- result = defaults.metadataCacheEnabled;
1009
- });
1010
-
1011
- return result;
1012
- }
1013
-
1014
- - (void)setDefaultMetadataCacheEnabled:(BOOL)defaultMetadataCacheEnabled
1015
- {
1016
- dispatch_sync(internalQueue, ^{
1017
-
1018
- defaults.metadataCacheEnabled = defaultMetadataCacheEnabled;
1019
- });
1020
- }
1021
-
1022
- - (NSUInteger)defaultMetadataCacheLimit
1023
- {
1024
- __block NSUInteger result = 0;
1025
-
1026
- dispatch_sync(internalQueue, ^{
1027
-
1028
- result = defaults.metadataCacheLimit;
1029
- });
1030
-
1031
- return result;
1032
- }
1033
-
1034
- - (void)setDefaultMetadataCacheLimit:(NSUInteger)defaultMetadataCacheLimit
1035
- {
1036
- dispatch_sync(internalQueue, ^{
1037
-
1038
- defaults.metadataCacheLimit = defaultMetadataCacheLimit;
1039
- });
1040
- }
1041
-
1042
- - (YapDatabasePolicy)defaultObjectPolicy
1043
- {
1044
- __block YapDatabasePolicy result = YapDatabasePolicyShare;
1045
-
1046
- dispatch_sync(internalQueue, ^{
1047
-
1048
- result = defaults.objectPolicy;
1049
- });
1050
-
1051
- return result;
1052
- }
1053
-
1054
- - (void)setDefaultObjectPolicy:(YapDatabasePolicy)defaultObjectPolicy
1055
- {
1056
- dispatch_sync(internalQueue, ^{
1057
-
1058
- defaults.objectPolicy = defaultObjectPolicy;
1059
- });
1060
- }
1061
-
1062
- - (YapDatabasePolicy)defaultMetadataPolicy
1063
- {
1064
- __block YapDatabasePolicy result = YapDatabasePolicyShare;
1065
-
1066
- dispatch_sync(internalQueue, ^{
1067
-
1068
- result = defaults.metadataPolicy;
1069
- });
1070
-
1071
- return result;
1072
- }
1073
-
1074
- - (void)setDefaultMetadataPolicy:(YapDatabasePolicy)defaultMetadataPolicy
1075
- {
1076
- dispatch_sync(internalQueue, ^{
1077
-
1078
- defaults.metadataPolicy = defaultMetadataPolicy;
1079
- });
1080
- }
1081
-
1082
- #if TARGET_OS_IPHONE
1083
-
1084
- - (YapDatabaseConnectionFlushMemoryFlags)defaultAutoFlushMemoryFlags
1085
- {
1086
- __block int result = YapDatabaseConnectionFlushMemoryFlags_None;
1087
-
1088
- dispatch_sync(internalQueue, ^{
1089
-
1090
- result = defaults.autoFlushMemoryFlags;
1091
- });
1092
-
1093
- return result;
1094
- }
1095
-
1096
- - (void)setDefaultAutoFlushMemoryFlags:(YapDatabaseConnectionFlushMemoryFlags)defaultAutoFlushMemoryFlags
1097
- {
1098
- dispatch_sync(internalQueue, ^{
1099
-
1100
- defaults.autoFlushMemoryFlags = defaultAutoFlushMemoryFlags;
1101
- });
1102
- }
1103
-
1104
- #endif
1105
-
1106
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1107
- #pragma mark Connections
1108
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1109
-
1110
- /**
1111
- * This method is called from newConnection, either above or from a subclass.
1112
- **/
1113
- - (void)addConnection:(YapDatabaseConnection *)connection
1114
- {
1115
- // We can asynchronously add the connection to the state table.
1116
- // This is safe as the connection itself must go through the same queue in order to do anything.
1117
- //
1118
- // The primary motivation in adding the asynchronous functionality is due to the following common use case:
1119
- //
1120
- // YapDatabase *database = [[YapDatabase alloc] initWithPath:path];
1121
- // YapDatabaseConnection *databaseConnection = [database newConnection];
1122
- //
1123
- // The YapDatabase init method is asynchronously preparing itself through the snapshot queue.
1124
- // We'd like to avoid blocking the very next line of code and allow the asynchronous prepare to continue.
1125
-
1126
- dispatch_async(connection->connectionQueue, ^{
1127
-
1128
- dispatch_sync(snapshotQueue, ^{ @autoreleasepool {
1129
-
1130
- // Add the connection to the state table
1131
-
1132
- YapDatabaseConnectionState *state = [[YapDatabaseConnectionState alloc] initWithConnection:connection];
1133
- [connectionStates addObject:state];
1134
-
1135
- YDBLogVerbose(@"Created new connection(%p) for <%@ %p: databaseName=%@, connectionCount=%lu>",
1136
- connection, [self class], self, [databasePath lastPathComponent],
1137
- (unsigned long)[connectionStates count]);
1138
-
1139
- // Invoke the one-time prepare method, so the connection can perform any needed initialization.
1140
- // Be sure to do this within the snapshotQueue, as the prepare method depends on this.
1141
-
1142
- [connection prepare];
1143
- }});
1144
- });
1145
- }
1146
-
1147
- /**
1148
- * This method is called from YapDatabaseConnection's dealloc method.
1149
- **/
1150
- - (void)removeConnection:(YapDatabaseConnection *)connection
1151
- {
1152
- dispatch_block_t block = ^{ @autoreleasepool {
1153
-
1154
- NSUInteger index = 0;
1155
- for (YapDatabaseConnectionState *state in connectionStates)
1156
- {
1157
- if (state->connection == connection)
1158
- {
1159
- [connectionStates removeObjectAtIndex:index];
1160
- break;
1161
- }
1162
-
1163
- index++;
1164
- }
1165
-
1166
- YDBLogVerbose(@"Removed connection(%p) from <%@ %p: databaseName=%@, connectionCount=%lu>",
1167
- connection, [self class], self, [databasePath lastPathComponent],
1168
- (unsigned long)[connectionStates count]);
1169
- }};
1170
-
1171
- // We prefer to invoke this method synchronously.
1172
- //
1173
- // The connection may be the last object retaining the database.
1174
- // It's easier to trace object deallocations when they happen in a predictable order.
1175
-
1176
- if (dispatch_get_specific(IsOnSnapshotQueueKey))
1177
- block();
1178
- else
1179
- dispatch_sync(snapshotQueue, block);
1180
- }
1181
-
1182
- /**
1183
- * This is a public method called to create a new connection.
1184
- **/
1185
- - (YapDatabaseConnection *)newConnection
1186
- {
1187
- YapDatabaseConnection *connection = [[YapDatabaseConnection alloc] initWithDatabase:self];
1188
-
1189
- [self addConnection:connection];
1190
- return connection;
1191
- }
1192
-
1193
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1194
- #pragma mark Extensions
1195
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1196
-
1197
- /**
1198
- * Registers the extension with the database using the given name.
1199
- * After registration everything works automatically using just the extension name.
1200
- *
1201
- * The registration process is equivalent to a readwrite transaction.
1202
- * It involves persisting various information about the extension to the database,
1203
- * as well as possibly populating the extension by enumerating existing rows in the database.
1204
- *
1205
- * @return
1206
- * YES if the extension was properly registered.
1207
- * NO if an error occurred, such as the extensionName is already registered.
1208
- *
1209
- * @see asyncRegisterExtension:withName:completionBlock:
1210
- * @see asyncRegisterExtension:withName:completionBlock:completionQueue:
1211
- **/
1212
- - (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
1213
- {
1214
- __block BOOL ready = NO;
1215
-
1216
- dispatch_sync(writeQueue, ^{ @autoreleasepool {
1217
-
1218
- ready = [self _registerExtension:extension withName:extensionName];
1219
- }});
1220
-
1221
- return ready;
1222
- }
1223
-
1224
- /**
1225
- * Asynchronoulsy starts the extension registration process.
1226
- * After registration everything works automatically using just the extension name.
1227
- *
1228
- * The registration process is equivalent to a readwrite transaction.
1229
- * It involves persisting various information about the extension to the database,
1230
- * as well as possibly populating the extension by enumerating existing rows in the database.
1231
- *
1232
- * An optional completion block may be used.
1233
- * If the extension registration was successful then the ready parameter will be YES.
1234
- *
1235
- * The completionBlock will be invoked on the main thread (dispatch_get_main_queue()).
1236
- **/
1237
- - (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
1238
- withName:(NSString *)extensionName
1239
- completionBlock:(void(^)(BOOL ready))completionBlock
1240
- {
1241
- [self asyncRegisterExtension:extension
1242
- withName:extensionName
1243
- completionBlock:completionBlock
1244
- completionQueue:NULL];
1245
- }
1246
-
1247
- /**
1248
- * Asynchronoulsy starts the extension registration process.
1249
- * After registration everything works automatically using just the extension name.
1250
- *
1251
- * The registration process is equivalent to a readwrite transaction.
1252
- * It involves persisting various information about the extension to the database,
1253
- * as well as possibly populating the extension by enumerating existing rows in the database.
1254
- *
1255
- * An optional completion block may be used.
1256
- * If the extension registration was successful then the ready parameter will be YES.
1257
- *
1258
- * Additionally the dispatch_queue to invoke the completion block may also be specified.
1259
- * If NULL, dispatch_get_main_queue() is automatically used.
1260
- **/
1261
- - (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
1262
- withName:(NSString *)extensionName
1263
- completionBlock:(void(^)(BOOL ready))completionBlock
1264
- completionQueue:(dispatch_queue_t)completionQueue
1265
- {
1266
- if (completionQueue == NULL && completionBlock != NULL)
1267
- completionQueue = dispatch_get_main_queue();
1268
-
1269
- dispatch_async(writeQueue, ^{ @autoreleasepool {
1270
-
1271
- BOOL ready = [self _registerExtension:extension withName:extensionName];
1272
-
1273
- if (completionBlock)
1274
- {
1275
- dispatch_async(completionQueue, ^{ @autoreleasepool {
1276
-
1277
- completionBlock(ready);
1278
- }});
1279
- }
1280
- }});
1281
- }
1282
-
1283
- /**
1284
- *
1285
- **/
1286
- - (void)unregisterExtension:(NSString *)extensionName
1287
- {
1288
- dispatch_sync(writeQueue, ^{ @autoreleasepool {
1289
-
1290
- [self _unregisterExtension:extensionName];
1291
- }});
1292
- }
1293
-
1294
- - (void)asyncUnregisterExtension:(NSString *)extensionName
1295
- completionBlock:(dispatch_block_t)completionBlock
1296
- {
1297
- [self asyncUnregisterExtension:extensionName
1298
- completionBlock:completionBlock
1299
- completionQueue:NULL];
1300
- }
1301
-
1302
- - (void)asyncUnregisterExtension:(NSString *)extensionName
1303
- completionBlock:(dispatch_block_t)completionBlock
1304
- completionQueue:(dispatch_queue_t)completionQueue
1305
- {
1306
- if (completionQueue == NULL && completionBlock != NULL)
1307
- completionQueue = dispatch_get_main_queue();
1308
-
1309
- dispatch_async(writeQueue, ^{ @autoreleasepool {
1310
-
1311
- [self _unregisterExtension:extensionName];
1312
-
1313
- if (completionBlock)
1314
- {
1315
- dispatch_async(completionQueue, ^{ @autoreleasepool {
1316
-
1317
- completionBlock();
1318
- }});
1319
- }
1320
- }});
1321
- }
1322
-
1323
- /**
1324
- * Internal utility method.
1325
- * Handles lazy creation and destruction of short-lived registrationConnection instance.
1326
- *
1327
- * @see _registerExtension:withName:
1328
- * @see _unregisterExtension:
1329
- **/
1330
- - (YapDatabaseConnection *)registrationConnection
1331
- {
1332
- if (registrationConnection == nil)
1333
- {
1334
- registrationConnection = [self newConnection];
1335
- registrationConnection.name = @"YapDatabase_extensionRegistrationConnection";
1336
-
1337
- NSTimeInterval delayInSeconds = 10.0;
1338
- dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
1339
- dispatch_after(popTime, writeQueue, ^(void){
1340
-
1341
- registrationConnection = nil;
1342
- });
1343
- }
1344
-
1345
- return registrationConnection;
1346
- }
1347
-
1348
- /**
1349
- * Internal method that handles extension registration.
1350
- * This method must be invoked on the writeQueue.
1351
- **/
1352
- - (BOOL)_registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
1353
- {
1354
- NSAssert(dispatch_get_specific(IsOnWriteQueueKey), @"Must go through writeQueue.");
1355
-
1356
- // Validate parameters
1357
-
1358
- if (extension == nil)
1359
- {
1360
- YDBLogError(@"Error registering extension: extension parameter is nil");
1361
- return NO;
1362
- }
1363
- if ([extensionName length] == 0)
1364
- {
1365
- YDBLogError(@"Error registering extension: extensionName parameter is nil or empty string");
1366
- return NO;
1367
- }
1368
-
1369
- // Check to ensure extension isn't already registered,
1370
- // or that the extensionName isn't already taken.
1371
-
1372
- NSDictionary *_registeredExtensions = [self registeredExtensions];
1373
-
1374
- if (extension.registeredName != nil)
1375
- {
1376
- YDBLogError(@"Error registering extension: extension is already registered");
1377
- return NO;
1378
- }
1379
- if ([_registeredExtensions objectForKey:extensionName] != nil)
1380
- {
1381
- YDBLogError(@"Error registering extension: extensionName(%@) already registered", extensionName);
1382
- return NO;
1383
- }
1384
-
1385
- // Make sure the extension can be supported
1386
-
1387
- if (![extension supportsDatabase:self withRegisteredExtensions:_registeredExtensions])
1388
- {
1389
- YDBLogError(@"Error registering extension: extension doesn't database type or configuration");
1390
- return NO;
1391
- }
1392
-
1393
- // Attempt registration
1394
-
1395
- BOOL result = [[self registrationConnection] registerExtension:extension withName:extensionName];
1396
- return result;
1397
- }
1398
-
1399
- /**
1400
- * Internal method that handles extension unregistration.
1401
- * This method must be invoked on the writeQueue.
1402
- **/
1403
- - (void)_unregisterExtension:(NSString *)extensionName
1404
- {
1405
- NSAssert(dispatch_get_specific(IsOnWriteQueueKey), @"Must go through writeQueue.");
1406
-
1407
- if ([extensionName length] == 0)
1408
- {
1409
- YDBLogError(@"Error unregistering extension: extensionName parameter is nil or empty string");
1410
- return;
1411
- }
1412
-
1413
- [[self registrationConnection] unregisterExtension:extensionName];
1414
- }
1415
-
1416
- /**
1417
- * Returns the registered extension with the given name.
1418
- **/
1419
- - (id)registeredExtension:(NSString *)extensionName
1420
- {
1421
- // This method is public
1422
-
1423
- __block YapDatabaseExtension *result = nil;
1424
-
1425
- dispatch_block_t block = ^{
1426
-
1427
- result = [registeredExtensions objectForKey:extensionName];
1428
- };
1429
-
1430
- if (dispatch_get_specific(IsOnSnapshotQueueKey))
1431
- block();
1432
- else
1433
- dispatch_sync(snapshotQueue, block);
1434
-
1435
- return result;
1436
- }
1437
-
1438
- /**
1439
- * Returns all currently registered extensions as a dictionary.
1440
- * The key is the registed name (NSString), and the value is the extension (YapDatabaseExtension subclass).
1441
- **/
1442
- - (NSDictionary *)registeredExtensions
1443
- {
1444
- // This method is public
1445
-
1446
- __block NSDictionary *extensionsCopy = nil;
1447
-
1448
- dispatch_block_t block = ^{
1449
-
1450
- extensionsCopy = registeredExtensions;
1451
- };
1452
-
1453
- if (dispatch_get_specific(IsOnSnapshotQueueKey))
1454
- block();
1455
- else
1456
- dispatch_sync(snapshotQueue, block);
1457
-
1458
- return extensionsCopy;
1459
- }
1460
-
1461
- /**
1462
- * This method is only accessible from within the snapshotQueue.
1463
- * Used by [YapDatabaseConnection prepare].
1464
- **/
1465
- - (NSArray *)extensionsOrder
1466
- {
1467
- NSAssert(dispatch_get_specific(IsOnSnapshotQueueKey), @"Must go through snapshotQueue for atomic access.");
1468
-
1469
- return extensionsOrder;
1470
- }
1471
-
1472
- /**
1473
- * This method is only accessible from within the snapshotQueue.
1474
- * Used by [YapDatabaseConnection prepare].
1475
- **/
1476
- - (NSDictionary *)extensionDependencies
1477
- {
1478
- NSAssert(dispatch_get_specific(IsOnSnapshotQueueKey), @"Must go through snapshotQueue for atomic access.");
1479
-
1480
- return extensionDependencies;
1481
- }
1482
-
1483
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1484
- #pragma mark Pooling
1485
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1486
-
1487
- - (NSUInteger)maxConnectionPoolCount
1488
- {
1489
- __block NSUInteger count = 0;
1490
-
1491
- dispatch_sync(internalQueue, ^{
1492
-
1493
- count = maxConnectionPoolCount;
1494
- });
1495
-
1496
- return count;
1497
- }
1498
-
1499
- - (void)setMaxConnectionPoolCount:(NSUInteger)count
1500
- {
1501
- dispatch_sync(internalQueue, ^{
1502
-
1503
- // Update ivar
1504
- maxConnectionPoolCount = count;
1505
-
1506
- // Immediately drop any excess connections
1507
- if ([connectionPoolValues count] > maxConnectionPoolCount)
1508
- {
1509
- do
1510
- {
1511
- sqlite3 *aDb = (sqlite3 *)[[connectionPoolValues objectAtIndex:0] pointerValue];
1512
-
1513
- int status = sqlite3_close(aDb);
1514
- if (status != SQLITE_OK)
1515
- {
1516
- YDBLogError(@"Error in sqlite_close: %d %s", status, sqlite3_errmsg(aDb));
1517
- }
1518
-
1519
- [connectionPoolValues removeObjectAtIndex:0];
1520
- [connectionPoolDates removeObjectAtIndex:0];
1521
-
1522
- } while ([connectionPoolValues count] > maxConnectionPoolCount);
1523
-
1524
- [self resetConnectionPoolTimer];
1525
- }
1526
- });
1527
- }
1528
-
1529
- - (NSTimeInterval)connectionPoolLifetime
1530
- {
1531
- __block NSTimeInterval lifetime = 0;
1532
-
1533
- dispatch_sync(internalQueue, ^{
1534
-
1535
- lifetime = connectionPoolLifetime;
1536
- });
1537
-
1538
- return lifetime;
1539
- }
1540
-
1541
- - (void)setConnectionPoolLifetime:(NSTimeInterval)lifetime
1542
- {
1543
- dispatch_sync(internalQueue, ^{
1544
-
1545
- // Update ivar
1546
- connectionPoolLifetime = lifetime;
1547
-
1548
- // Update timer (if needed)
1549
- [self resetConnectionPoolTimer];
1550
- });
1551
- }
1552
-
1553
- /**
1554
- * Adds the given connection to the connection pool if possible.
1555
- *
1556
- * Returns YES if the instance was added to the pool.
1557
- * If so, the YapDatabaseConnection must not close the instance.
1558
- *
1559
- * Returns NO if the instance was not added to the pool.
1560
- * If so, the YapDatabaseConnection must close the instance.
1561
- **/
1562
- - (BOOL)connectionPoolEnqueue:(sqlite3 *)aDb
1563
- {
1564
- __block BOOL result = NO;
1565
-
1566
- dispatch_sync(internalQueue, ^{
1567
-
1568
- if ([connectionPoolValues count] < maxConnectionPoolCount)
1569
- {
1570
- if (connectionPoolValues == nil)
1571
- {
1572
- connectionPoolValues = [[NSMutableArray alloc] init];
1573
- connectionPoolDates = [[NSMutableArray alloc] init];
1574
- }
1575
-
1576
- YDBLogVerbose(@"Enqueuing connection to pool: %p", aDb);
1577
-
1578
- [connectionPoolValues addObject:[NSValue valueWithPointer:(const void *)aDb]];
1579
- [connectionPoolDates addObject:[NSDate date]];
1580
-
1581
- result = YES;
1582
-
1583
- if ([connectionPoolValues count] == 1)
1584
- {
1585
- [self resetConnectionPoolTimer];
1586
- }
1587
- }
1588
- });
1589
-
1590
- return result;
1591
- }
1592
-
1593
- /**
1594
- * Retrieves a connection from the connection pool if available.
1595
- * Returns NULL if no connections are available.
1596
- **/
1597
- - (sqlite3 *)connectionPoolDequeue
1598
- {
1599
- __block sqlite3 *aDb = NULL;
1600
-
1601
- dispatch_sync(internalQueue, ^{
1602
-
1603
- if ([connectionPoolValues count] > 0)
1604
- {
1605
- aDb = (sqlite3 *)[[connectionPoolValues objectAtIndex:0] pointerValue];
1606
-
1607
- YDBLogVerbose(@"Dequeuing connection from pool: %p", aDb);
1608
-
1609
- [connectionPoolValues removeObjectAtIndex:0];
1610
- [connectionPoolDates removeObjectAtIndex:0];
1611
-
1612
- [self resetConnectionPoolTimer];
1613
- }
1614
- });
1615
-
1616
- return aDb;
1617
- }
1618
-
1619
- /**
1620
- * Internal utility method to handle setting/resetting the timer.
1621
- **/
1622
- - (void)resetConnectionPoolTimer
1623
- {
1624
- YDBLogAutoTrace();
1625
-
1626
- if (connectionPoolLifetime <= 0.0 || [connectionPoolValues count] == 0)
1627
- {
1628
- if (connectionPoolTimer)
1629
- {
1630
- dispatch_source_cancel(connectionPoolTimer);
1631
- connectionPoolTimer = NULL;
1632
- }
1633
-
1634
- return;
1635
- }
1636
-
1637
- BOOL isNewTimer = NO;
1638
-
1639
- if (connectionPoolTimer == NULL)
1640
- {
1641
- connectionPoolTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, internalQueue);
1642
-
1643
- __weak YapDatabase *weakSelf = self;
1644
- dispatch_source_set_event_handler(connectionPoolTimer, ^{ @autoreleasepool {
1645
-
1646
- __strong YapDatabase *strongSelf = weakSelf;
1647
- if (strongSelf)
1648
- {
1649
- [strongSelf handleConnectionPoolTimerFire];
1650
- }
1651
- }});
1652
-
1653
- #if !OS_OBJECT_USE_OBJC
1654
- dispatch_source_t timer = connectionPoolTimer;
1655
- dispatch_source_set_cancel_handler(connectionPoolTimer, ^{
1656
- dispatch_release(timer);
1657
- });
1658
- #endif
1659
-
1660
- isNewTimer = YES;
1661
- }
1662
-
1663
- NSDate *date = [connectionPoolDates objectAtIndex:0];
1664
- NSTimeInterval interval = [date timeIntervalSinceNow] + connectionPoolLifetime;
1665
-
1666
- dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (interval * NSEC_PER_SEC));
1667
- dispatch_source_set_timer(connectionPoolTimer, tt, DISPATCH_TIME_FOREVER, 0);
1668
-
1669
- if (isNewTimer) {
1670
- dispatch_resume(connectionPoolTimer);
1671
- }
1672
- }
1673
-
1674
- /**
1675
- * Internal method to handle removing stale connections from the connection pool.
1676
- **/
1677
- - (void)handleConnectionPoolTimerFire
1678
- {
1679
- YDBLogAutoTrace();
1680
-
1681
- NSDate *now = [NSDate date];
1682
-
1683
- BOOL done = NO;
1684
- while ([connectionPoolValues count] > 0 && !done)
1685
- {
1686
- NSTimeInterval interval = [[connectionPoolDates objectAtIndex:0] timeIntervalSinceDate:now] * -1.0;
1687
-
1688
- if ((interval >= connectionPoolLifetime) || (interval < 0))
1689
- {
1690
- sqlite3 *aDb = (sqlite3 *)[[connectionPoolValues objectAtIndex:0] pointerValue];
1691
-
1692
- YDBLogVerbose(@"Closing connection from pool: %p", aDb);
1693
-
1694
- int status = sqlite3_close(aDb);
1695
- if (status != SQLITE_OK)
1696
- {
1697
- YDBLogError(@"Error in sqlite_close: %d %s", status, sqlite3_errmsg(aDb));
1698
- }
1699
-
1700
- [connectionPoolValues removeObjectAtIndex:0];
1701
- [connectionPoolDates removeObjectAtIndex:0];
1702
- }
1703
- else
1704
- {
1705
- done = YES;
1706
- }
1707
- }
1708
-
1709
- [self resetConnectionPoolTimer];
1710
- }
1711
-
1712
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1713
- #pragma mark Tables
1714
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1715
-
1716
- /**
1717
- * This method is only accessible from within the snapshotQueue.
1718
- * Used by [YapDatabaseConnection prepare].
1719
- **/
1720
- - (NSDictionary *)registeredTables
1721
- {
1722
- NSAssert(dispatch_get_specific(IsOnSnapshotQueueKey), @"Must go through snapshotQueue for atomic access.");
1723
-
1724
- return registeredTables;
1725
- }
1726
-
1727
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1728
- #pragma mark Snapshot Architecture
1729
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1730
-
1731
- /**
1732
- * The snapshot represents when the database was last modified by a read-write transaction.
1733
- * This information isn persisted to the 'yap' database, and is separately held in memory.
1734
- * It serves multiple purposes.
1735
- *
1736
- * First is assists in validation of a connection's cache.
1737
- * When a connection begins a new transaction, it may have items sitting in the cache.
1738
- * However the connection doesn't know if the items are still valid because another connection may have made changes.
1739
- *
1740
- * The snapshot also assists in correcting for a race condition.
1741
- * It order to minimize blocking we allow read-write transactions to commit outside the context
1742
- * of the snapshotQueue. This is because the commit may be a time consuming operation, and we
1743
- * don't want to block read-only transactions during this period. The race condition occurs if a read-only
1744
- * transactions starts in the midst of a read-write commit, and the read-only transaction gets
1745
- * a "yap-level" snapshot that's out of sync with the "sql-level" snapshot. This is easily correctable if caught.
1746
- * Thus we maintain the snapshot in memory, and fetchable via a select query.
1747
- * One represents the "yap-level" snapshot, and the other represents the "sql-level" snapshot.
1748
- *
1749
- * The snapshot is simply a 64-bit integer.
1750
- * It is reset when the YapDatabase instance is initialized,
1751
- * and incremented by each read-write transaction (if changes are actually made).
1752
- **/
1753
- - (uint64_t)snapshot
1754
- {
1755
- if (dispatch_get_specific(IsOnSnapshotQueueKey))
1756
- {
1757
- // Very common case.
1758
- // This method is called on just about every transaction.
1759
- return snapshot;
1760
- }
1761
- else
1762
- {
1763
- // Non-common case.
1764
- // Public access implementation.
1765
- __block uint64_t result = 0;
1766
-
1767
- dispatch_sync(snapshotQueue, ^{
1768
- result = snapshot;
1769
- });
1770
-
1771
- return result;
1772
- }
1773
- }
1774
-
1775
- /**
1776
- * This method is only accessible from within the snapshotQueue.
1777
- *
1778
- * Prior to starting the sqlite commit, the connection must report its changeset to the database.
1779
- * The database will store the changeset, and provide it to other connections if needed (due to a race condition).
1780
- *
1781
- * The following MUST be in the dictionary:
1782
- *
1783
- * - snapshot : NSNumber with the changeset's snapshot
1784
- **/
1785
- - (void)notePendingChanges:(NSDictionary *)pendingChangeset fromConnection:(YapDatabaseConnection *)sender
1786
- {
1787
- NSAssert(dispatch_get_specific(IsOnSnapshotQueueKey), @"Must go through snapshotQueue for atomic access.");
1788
- NSAssert([pendingChangeset objectForKey:YapDatabaseSnapshotKey], @"Missing required change key: snapshot");
1789
-
1790
- // The sender is preparing to start the sqlite commit.
1791
- // We save the changeset in advance to handle possible edge cases.
1792
-
1793
- [changesets addObject:pendingChangeset];
1794
-
1795
- YDBLogVerbose(@"Adding pending changeset %@ for database: %@",
1796
- [[changesets lastObject] objectForKey:YapDatabaseSnapshotKey], self);
1797
- }
1798
-
1799
- /**
1800
- * This method is only accessible from within the snapshotQueue.
1801
- *
1802
- * This method is used if a transaction finds itself in a race condition.
1803
- * It should retrieve the database's pending and/or committed changes,
1804
- * and then process them via [connection noteCommittedChanges:].
1805
- **/
1806
- - (NSArray *)pendingAndCommittedChangesSince:(uint64_t)connectionSnapshot until:(uint64_t)maxSnapshot
1807
- {
1808
- NSAssert(dispatch_get_specific(IsOnSnapshotQueueKey), @"Must go through snapshotQueue for atomic access.");
1809
-
1810
- NSMutableArray *relevantChangesets = [NSMutableArray arrayWithCapacity:[changesets count]];
1811
-
1812
- for (NSDictionary *changeset in changesets)
1813
- {
1814
- uint64_t changesetSnapshot = [[changeset objectForKey:YapDatabaseSnapshotKey] unsignedLongLongValue];
1815
-
1816
- if ((changesetSnapshot > connectionSnapshot) && (changesetSnapshot <= maxSnapshot))
1817
- {
1818
- [relevantChangesets addObject:changeset];
1819
- }
1820
- }
1821
-
1822
- return relevantChangesets;
1823
- }
1824
-
1825
- /**
1826
- * This method is only accessible from within the snapshotQueue.
1827
- *
1828
- * Upon completion of a readwrite transaction, the connection should report it's changeset to the database.
1829
- * The database will then forward the changes to all other connection's.
1830
- *
1831
- * The following MUST be in the dictionary:
1832
- *
1833
- * - snapshot : NSNumber with the changeset's snapshot
1834
- **/
1835
- - (void)noteCommittedChanges:(NSDictionary *)changeset fromConnection:(YapDatabaseConnection *)sender
1836
- {
1837
- NSAssert(dispatch_get_specific(IsOnSnapshotQueueKey), @"Must go through snapshotQueue for atomic access.");
1838
- NSAssert([changeset objectForKey:YapDatabaseSnapshotKey], @"Missing required change key: snapshot");
1839
-
1840
- // The sender has finished the sqlite commit, and all data is now written to disk.
1841
-
1842
- // Update the in-memory snapshot,
1843
- // which represents the most recent snapshot of the last committed readwrite transaction.
1844
-
1845
- snapshot = [[changeset objectForKey:YapDatabaseSnapshotKey] unsignedLongLongValue];
1846
-
1847
- // Update registeredExtensions, if changed.
1848
-
1849
- NSDictionary *newRegisteredExtensions = [changeset objectForKey:YapDatabaseRegisteredExtensionsKey];
1850
- if (newRegisteredExtensions)
1851
- {
1852
- registeredExtensions = newRegisteredExtensions;
1853
- extensionsOrder = [changeset objectForKey:YapDatabaseExtensionsOrderKey];
1854
- extensionDependencies = [changeset objectForKey:YapDatabaseExtensionDependenciesKey];
1855
- }
1856
-
1857
- // Update registeredTables, if changed.
1858
-
1859
- NSDictionary *newRegisteredTables = [changeset objectForKey:YapDatabaseRegisteredTablesKey];
1860
- if (newRegisteredTables)
1861
- {
1862
- registeredTables = newRegisteredTables;
1863
- }
1864
-
1865
- // Forward the changeset to all other connections so they can perform any needed updates.
1866
- // Generally this means updating the in-memory components such as the cache.
1867
-
1868
- dispatch_group_t group = NULL;
1869
-
1870
- for (YapDatabaseConnectionState *state in connectionStates)
1871
- {
1872
- if (state->connection != sender)
1873
- {
1874
- // Create strong reference (state->connection is weak)
1875
- __strong YapDatabaseConnection *connection = state->connection;
1876
-
1877
- if (connection)
1878
- {
1879
- if (group == NULL)
1880
- group = dispatch_group_create();
1881
-
1882
- dispatch_group_async(group, connection->connectionQueue, ^{ @autoreleasepool {
1883
-
1884
- [connection noteCommittedChanges:changeset];
1885
- }});
1886
- }
1887
- }
1888
- }
1889
-
1890
- // Schedule block to be executed once all connections have processed the changes.
1891
-
1892
- BOOL isInternalChangeset = (sender == nil);
1893
-
1894
- dispatch_block_t block = ^{
1895
-
1896
- // All connections have now processed the changes.
1897
- // So we no longer need to retain the changeset in memory.
1898
-
1899
- if (isInternalChangeset)
1900
- {
1901
- YDBLogVerbose(@"Completed internal changeset %@ for database: %@",
1902
- [changeset objectForKey:YapDatabaseSnapshotKey], self);
1903
- }
1904
- else
1905
- {
1906
- YDBLogVerbose(@"Dropping processed changeset %@ for database: %@",
1907
- [changeset objectForKey:YapDatabaseSnapshotKey], self);
1908
-
1909
- [changesets removeObjectAtIndex:0];
1910
- }
1911
-
1912
- #if !OS_OBJECT_USE_OBJC
1913
- if (group)
1914
- dispatch_release(group);
1915
- #endif
1916
- };
1917
-
1918
- if (group)
1919
- dispatch_group_notify(group, snapshotQueue, block);
1920
- else
1921
- block();
1922
- }
1923
-
1924
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1925
- #pragma mark Manual Checkpointing
1926
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1927
-
1928
- /**
1929
- * This method should be called whenever the maximum checkpointable snapshot is incremented.
1930
- * That is, the state of every connection is known to the system.
1931
- * And a snaphot cannot be checkpointed until every connection is at or past that snapshot.
1932
- * Thus, we can know the point at which a snapshot becomes checkpointable,
1933
- * and we can thus optimize the checkpoint invocations such that
1934
- * each invocation is able to checkpoint one or more commits.
1935
- **/
1936
- - (void)asyncCheckpoint:(uint64_t)maxCheckpointableSnapshot
1937
- {
1938
- __weak YapDatabase *weakSelf = self;
1939
-
1940
- dispatch_async(checkpointQueue, ^{ @autoreleasepool {
1941
-
1942
- __strong YapDatabase *strongSelf = weakSelf;
1943
- if (strongSelf == nil) return;
1944
-
1945
- YDBLogVerbose(@"Checkpointing up to snapshot %llu", maxCheckpointableSnapshot);
1946
-
1947
- // We're ready to checkpoint more frames.
1948
- //
1949
- // So we're going to execute a passive checkpoint.
1950
- // That is, without disrupting any connections, we're going to write pages from the WAL into the database.
1951
- // The checkpoint can only write pages from snapshots if all connections are at or beyond the snapshot.
1952
- // Thus, this method is only called by a connection that moves the min snapshot forward.
1953
-
1954
- int frameCount = 0;
1955
- int checkpointCount = 0;
1956
-
1957
- int result = sqlite3_wal_checkpoint_v2(strongSelf->db, "main",
1958
- SQLITE_CHECKPOINT_PASSIVE, &frameCount, &checkpointCount);
1959
-
1960
- // frameCount = total number of frames in the log file
1961
- // checkpointCount = total number of checkpointed frames
1962
- // (including any that were already checkpointed before the function was called)
1963
-
1964
- if (result != SQLITE_OK)
1965
- {
1966
- if (result == SQLITE_BUSY) {
1967
- YDBLogVerbose(@"sqlite3_wal_checkpoint_v2 returned SQLITE_BUSY");
1968
- }
1969
- else {
1970
- YDBLogWarn(@"sqlite3_wal_checkpoint_v2 returned error code: %d", result);
1971
- }
1972
-
1973
- return;// from_block
1974
- }
1975
-
1976
- YDBLogVerbose(@"Post-checkpoint (%llu): frames(%d) checkpointed(%d)",
1977
- maxCheckpointableSnapshot, frameCount, checkpointCount);
1978
-
1979
- // Have we checkpointed the entire WAL yet?
1980
-
1981
- if (frameCount == checkpointCount)
1982
- {
1983
- // We've checkpointed every single frame.
1984
- // This means the next read-write transaction will reset the WAL (instead of appending to it).
1985
- //
1986
- // However, this will get spoiled if there are active read-only transactions that
1987
- // were started before our checkpoint finished, and continue to exist during the next read-write.
1988
- // It's not a big deal if the occasional read-only transaction happens to spoil the WAL reset.
1989
- // In those cases, the WAL generally gets reset shortly thereafter.
1990
- // Long-lived read transactions are a different case entirely.
1991
- // These transactions spoil it every single time, and could potentially cause the WAL to grow indefinitely.
1992
- //
1993
- // The solution is to notify active long-lived connections, and tell them to re-begin their transaction
1994
- // on the same snapshot. But this time the sqlite machinery will read directly from the database,
1995
- // and thus unlock the WAL so it can be reset.
1996
-
1997
- dispatch_async(snapshotQueue, ^{
1998
-
1999
- for (YapDatabaseConnectionState *state in connectionStates)
2000
- {
2001
- if (state->yapLevelSharedReadLock &&
2002
- state->longLivedReadTransaction &&
2003
- state->lastKnownSnapshot == snapshot)
2004
- {
2005
- [state->connection maybeResetLongLivedReadTransaction];
2006
- }
2007
- }
2008
- });
2009
- }
2010
- }});
2011
- }
2012
-
2013
- @end