Nessuna descrizione

AWSFMDatabasePool.m 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //
  2. // FMDatabasePool.m
  3. // fmdb
  4. //
  5. // Created by August Mueller on 6/22/11.
  6. // Copyright 2011 Flying Meat Inc. All rights reserved.
  7. //
  8. #import "AWSFMDatabasePool.h"
  9. #import "AWSFMDatabase.h"
  10. #import "AWSFMDatabase+Private.h"
  11. @interface AWSFMDatabasePool()
  12. - (void)pushDatabaseBackInPool:(AWSFMDatabase*)db;
  13. - (AWSFMDatabase*)db;
  14. @end
  15. @implementation AWSFMDatabasePool
  16. @synthesize path=_path;
  17. @synthesize delegate=_delegate;
  18. @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate;
  19. @synthesize openFlags=_openFlags;
  20. + (instancetype)databasePoolWithPath:(NSString*)aPath {
  21. return AWSFMDBReturnAutoreleased([[self alloc] initWithPath:aPath]);
  22. }
  23. + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags {
  24. return AWSFMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]);
  25. }
  26. - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags {
  27. self = [super init];
  28. if (self != nil) {
  29. _path = [aPath copy];
  30. _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
  31. _databaseInPool = AWSFMDBReturnRetained([NSMutableArray array]);
  32. _databaseOutPool = AWSFMDBReturnRetained([NSMutableArray array]);
  33. _openFlags = openFlags;
  34. }
  35. return self;
  36. }
  37. - (instancetype)initWithPath:(NSString*)aPath
  38. {
  39. // default flags for sqlite3_open
  40. return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
  41. }
  42. - (instancetype)init {
  43. return [self initWithPath:nil];
  44. }
  45. - (void)dealloc {
  46. _delegate = 0x00;
  47. AWSFMDBRelease(_path);
  48. AWSFMDBRelease(_databaseInPool);
  49. AWSFMDBRelease(_databaseOutPool);
  50. if (_lockQueue) {
  51. AWSFMDBDispatchQueueRelease(_lockQueue);
  52. _lockQueue = 0x00;
  53. }
  54. #if ! __has_feature(objc_arc)
  55. [super dealloc];
  56. #endif
  57. }
  58. - (void)executeLocked:(void (^)(void))aBlock {
  59. dispatch_sync(_lockQueue, aBlock);
  60. }
  61. - (void)pushDatabaseBackInPool:(AWSFMDatabase*)db {
  62. if (!db) { // db can be null if we set an upper bound on the # of databases to create.
  63. return;
  64. }
  65. [self executeLocked:^() {
  66. if ([self->_databaseInPool containsObject:db]) {
  67. [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise];
  68. }
  69. [self->_databaseInPool addObject:db];
  70. [self->_databaseOutPool removeObject:db];
  71. }];
  72. }
  73. - (AWSFMDatabase*)db {
  74. __block AWSFMDatabase *db;
  75. [self executeLocked:^() {
  76. db = [self->_databaseInPool lastObject];
  77. BOOL shouldNotifyDelegate = NO;
  78. if (db) {
  79. [self->_databaseOutPool addObject:db];
  80. [self->_databaseInPool removeLastObject];
  81. }
  82. else {
  83. if (self->_maximumNumberOfDatabasesToCreate) {
  84. NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count];
  85. if (currentCount >= self->_maximumNumberOfDatabasesToCreate) {
  86. NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount);
  87. return;
  88. }
  89. }
  90. db = [AWSFMDatabase databaseWithPath:self->_path];
  91. shouldNotifyDelegate = YES;
  92. }
  93. //This ensures that the db is opened before returning
  94. #if SQLITE_VERSION_NUMBER >= 3005000
  95. BOOL success = [db openWithFlags:self->_openFlags];
  96. #else
  97. BOOL success = [db open];
  98. #endif
  99. if (success) {
  100. if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) {
  101. [db close];
  102. db = 0x00;
  103. }
  104. else {
  105. //It should not get added in the pool twice if lastObject was found
  106. if (![self->_databaseOutPool containsObject:db]) {
  107. [self->_databaseOutPool addObject:db];
  108. if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) {
  109. [self->_delegate databasePool:self didAddDatabase:db];
  110. }
  111. }
  112. }
  113. }
  114. else {
  115. NSLog(@"Could not open up the database at path %@", self->_path);
  116. db = 0x00;
  117. }
  118. }];
  119. return db;
  120. }
  121. - (NSUInteger)countOfCheckedInDatabases {
  122. __block NSUInteger count;
  123. [self executeLocked:^() {
  124. count = [self->_databaseInPool count];
  125. }];
  126. return count;
  127. }
  128. - (NSUInteger)countOfCheckedOutDatabases {
  129. __block NSUInteger count;
  130. [self executeLocked:^() {
  131. count = [self->_databaseOutPool count];
  132. }];
  133. return count;
  134. }
  135. - (NSUInteger)countOfOpenDatabases {
  136. __block NSUInteger count;
  137. [self executeLocked:^() {
  138. count = [self->_databaseOutPool count] + [self->_databaseInPool count];
  139. }];
  140. return count;
  141. }
  142. - (void)releaseAllDatabases {
  143. [self executeLocked:^() {
  144. [self->_databaseOutPool removeAllObjects];
  145. [self->_databaseInPool removeAllObjects];
  146. }];
  147. }
  148. - (void)inDatabase:(void (^)(AWSFMDatabase *db))block {
  149. AWSFMDatabase *db = [self db];
  150. block(db);
  151. [self pushDatabaseBackInPool:db];
  152. }
  153. - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(AWSFMDatabase *db, BOOL *rollback))block {
  154. BOOL shouldRollback = NO;
  155. AWSFMDatabase *db = [self db];
  156. if (useDeferred) {
  157. [db beginDeferredTransaction];
  158. }
  159. else {
  160. [db beginTransaction];
  161. }
  162. block(db, &shouldRollback);
  163. if (shouldRollback) {
  164. [db rollback];
  165. }
  166. else {
  167. [db commit];
  168. }
  169. [self pushDatabaseBackInPool:db];
  170. }
  171. - (void)inDeferredTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block {
  172. [self beginTransaction:YES withBlock:block];
  173. }
  174. - (void)inTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block {
  175. [self beginTransaction:NO withBlock:block];
  176. }
  177. - (NSError*)inSavePoint:(void (^)(AWSFMDatabase *db, BOOL *rollback))block {
  178. NSError *err = 0x00;
  179. #if SQLITE_VERSION_NUMBER >= 3007000
  180. static unsigned long savePointIdx = 0;
  181. NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
  182. BOOL shouldRollback = NO;
  183. AWSFMDatabase *db = [self db];
  184. if (![db startSavePointWithName:name error:&err]) {
  185. [self pushDatabaseBackInPool:db];
  186. return err;
  187. }
  188. block(db, &shouldRollback);
  189. if (shouldRollback) {
  190. // We need to rollback and release this savepoint to remove it
  191. [db rollbackToSavePointWithName:name error:&err];
  192. }
  193. [db releaseSavePointWithName:name error:&err];
  194. [self pushDatabaseBackInPool:db];
  195. #endif
  196. return err;
  197. }
  198. @end