FMDatabasePool.m 5.7 KB

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