FMDatabasePool.m 5.4 KB

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