123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- //
- // 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;
- @synthesize openFlags=_openFlags;
- + (instancetype)databasePoolWithPath:(NSString*)aPath {
- return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]);
- }
- + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags {
- return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]);
- }
- - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags {
-
- 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]);
- _openFlags = openFlags;
- }
-
- return self;
- }
- - (instancetype)initWithPath:(NSString*)aPath
- {
- // default flags for sqlite3_open
- return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
- }
- - (instancetype)init {
- return [self initWithPath:nil];
- }
- - (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 ([self->_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];
- }
-
- [self->_databaseInPool addObject:db];
- [self->_databaseOutPool removeObject:db];
-
- }];
- }
- - (FMDatabase*)db {
-
- __block FMDatabase *db;
-
-
- [self executeLocked:^() {
- db = [self->_databaseInPool lastObject];
-
- BOOL shouldNotifyDelegate = NO;
-
- if (db) {
- [self->_databaseOutPool addObject:db];
- [self->_databaseInPool removeLastObject];
- }
- else {
-
- if (self->_maximumNumberOfDatabasesToCreate) {
- NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count];
-
- if (currentCount >= self->_maximumNumberOfDatabasesToCreate) {
- NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount);
- return;
- }
- }
-
- db = [FMDatabase databaseWithPath:self->_path];
- shouldNotifyDelegate = YES;
- }
-
- //This ensures that the db is opened before returning
- #if SQLITE_VERSION_NUMBER >= 3005000
- BOOL success = [db openWithFlags:self->_openFlags];
- #else
- BOOL success = [db open];
- #endif
- if (success) {
- if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) {
- [db close];
- db = 0x00;
- }
- else {
- //It should not get added in the pool twice if lastObject was found
- if (![self->_databaseOutPool containsObject:db]) {
- [self->_databaseOutPool addObject:db];
-
- if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) {
- [self->_delegate databasePool:self didAddDatabase:db];
- }
- }
- }
- }
- else {
- NSLog(@"Could not open up the database at path %@", self->_path);
- db = 0x00;
- }
- }];
-
- return db;
- }
- - (NSUInteger)countOfCheckedInDatabases {
-
- __block NSUInteger count;
-
- [self executeLocked:^() {
- count = [self->_databaseInPool count];
- }];
-
- return count;
- }
- - (NSUInteger)countOfCheckedOutDatabases {
-
- __block NSUInteger count;
-
- [self executeLocked:^() {
- count = [self->_databaseOutPool count];
- }];
-
- return count;
- }
- - (NSUInteger)countOfOpenDatabases {
- __block NSUInteger count;
-
- [self executeLocked:^() {
- count = [self->_databaseOutPool count] + [self->_databaseInPool count];
- }];
-
- return count;
- }
- - (void)releaseAllDatabases {
- [self executeLocked:^() {
- [self->_databaseOutPool removeAllObjects];
- [self->_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) {
- // We need to rollback and release this savepoint to remove it
- [db rollbackToSavePointWithName:name error:&err];
- }
- [db releaseSavePointWithName:name error:&err];
-
- [self pushDatabaseBackInPool:db];
-
- return err;
- }
- #endif
- @end
|