123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- //
- // FMDatabasePool.m
- // fmdb
- //
- // Created by August Mueller on 6/22/11.
- // Copyright 2011 Flying Meat Inc. All rights reserved.
- //
- #import "FMDatabasePool.h"
- #import "FMDatabase.h"
- @interface FMDatabasePool()
- - (void)pushDatabaseBackInPool:(FMDatabase*)db;
- - (FMDatabase*)db;
- @end
- @implementation FMDatabasePool
- @synthesize path=_path;
- @synthesize delegate=_delegate;
- @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate;
- + (id)databasePoolWithPath:(NSString*)aPath {
- return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]);
- }
- - (id)initWithPath:(NSString*)aPath {
-
- self = [super init];
-
- if (self != nil) {
- _path = [aPath copy];
- _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
- _databaseInPool = FMDBReturnRetained([NSMutableArray array]);
- _databaseOutPool = FMDBReturnRetained([NSMutableArray array]);
- }
-
- return self;
- }
- - (void)dealloc {
-
- _delegate = 0x00;
- FMDBRelease(_path);
- FMDBRelease(_databaseInPool);
- FMDBRelease(_databaseOutPool);
-
- if (_lockQueue) {
- FMDBDispatchQueueRelease(_lockQueue);
- _lockQueue = 0x00;
- }
- #if ! __has_feature(objc_arc)
- [super dealloc];
- #endif
- }
- - (void)executeLocked:(void (^)(void))aBlock {
- dispatch_sync(_lockQueue, aBlock);
- }
- - (void)pushDatabaseBackInPool:(FMDatabase*)db {
-
- if (!db) { // db can be null if we set an upper bound on the # of databases to create.
- return;
- }
-
- [self executeLocked:^() {
-
- if ([_databaseInPool containsObject:db]) {
- [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise];
- }
-
- [_databaseInPool addObject:db];
- [_databaseOutPool removeObject:db];
-
- }];
- }
- - (FMDatabase*)db {
-
- __block FMDatabase *db;
-
- [self executeLocked:^() {
- db = [_databaseInPool lastObject];
-
- if (db) {
- [_databaseOutPool addObject:db];
- [_databaseInPool removeLastObject];
- }
- else {
-
- if (_maximumNumberOfDatabasesToCreate) {
- NSUInteger currentCount = [_databaseOutPool count] + [_databaseInPool count];
-
- if (currentCount >= _maximumNumberOfDatabasesToCreate) {
- NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount);
- return;
- }
- }
-
- db = [FMDatabase databaseWithPath:_path];
- }
-
- //This ensures that the db is opened before returning
- if ([db open]) {
- if ([_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![_delegate databasePool:self shouldAddDatabaseToPool:db]) {
- [db close];
- db = 0x00;
- }
- else {
- //It should not get added in the pool twice if lastObject was found
- if (![_databaseOutPool containsObject:db]) {
- [_databaseOutPool addObject:db];
- }
- }
- }
- else {
- NSLog(@"Could not open up the database at path %@", _path);
- db = 0x00;
- }
- }];
-
- return db;
- }
- - (NSUInteger)countOfCheckedInDatabases {
-
- __block NSUInteger count;
-
- [self executeLocked:^() {
- count = [_databaseInPool count];
- }];
-
- return count;
- }
- - (NSUInteger)countOfCheckedOutDatabases {
-
- __block NSUInteger count;
-
- [self executeLocked:^() {
- count = [_databaseOutPool count];
- }];
-
- return count;
- }
- - (NSUInteger)countOfOpenDatabases {
- __block NSUInteger count;
-
- [self executeLocked:^() {
- count = [_databaseOutPool count] + [_databaseInPool count];
- }];
-
- return count;
- }
- - (void)releaseAllDatabases {
- [self executeLocked:^() {
- [_databaseOutPool removeAllObjects];
- [_databaseInPool removeAllObjects];
- }];
- }
- - (void)inDatabase:(void (^)(FMDatabase *db))block {
-
- FMDatabase *db = [self db];
-
- block(db);
-
- [self pushDatabaseBackInPool:db];
- }
- - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
-
- BOOL shouldRollback = NO;
-
- FMDatabase *db = [self db];
-
- if (useDeferred) {
- [db beginDeferredTransaction];
- }
- else {
- [db beginTransaction];
- }
-
-
- block(db, &shouldRollback);
-
- if (shouldRollback) {
- [db rollback];
- }
- else {
- [db commit];
- }
-
- [self pushDatabaseBackInPool:db];
- }
- - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
- [self beginTransaction:YES withBlock:block];
- }
- - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
- [self beginTransaction:NO withBlock:block];
- }
- #if SQLITE_VERSION_NUMBER >= 3007000
- - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
-
- static unsigned long savePointIdx = 0;
-
- NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
-
- BOOL shouldRollback = NO;
-
- FMDatabase *db = [self db];
-
- NSError *err = 0x00;
-
- if (![db startSavePointWithName:name error:&err]) {
- [self pushDatabaseBackInPool:db];
- return err;
- }
-
- block(db, &shouldRollback);
-
- if (shouldRollback) {
- [db rollbackToSavePointWithName:name error:&err];
- }
- else {
- [db releaseSavePointWithName:name error:&err];
- }
-
- [self pushDatabaseBackInPool:db];
-
- return err;
- }
- #endif
- @end
|