motion-yapper 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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