2013-05-31 15:31:40 -07:00
//
// 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 = 0 x00 ;
FMDBRelease ( _path ) ;
FMDBRelease ( _databaseInPool ) ;
FMDBRelease ( _databaseOutPool ) ;
if ( _lockQueue ) {
FMDBDispatchQueueRelease ( _lockQueue ) ;
_lockQueue = 0 x00 ;
}
# 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 : ^ ( ) {
2020-08-27 15:08:46 -07:00
if ( [ self -> _databaseInPool containsObject : db ] ) {
2013-05-31 15:31:40 -07:00
[ [ NSException exceptionWithName : @ "Database already in pool" reason : @ "The FMDatabase being put back into the pool is already present in the pool" userInfo : nil ] raise ] ;
}
2020-08-27 15:08:46 -07:00
[ self -> _databaseInPool addObject : db ] ;
[ self -> _databaseOutPool removeObject : db ] ;
2013-05-31 15:31:40 -07:00
} ] ;
}
- ( FMDatabase * ) db {
__block FMDatabase * db ;
[ self executeLocked : ^ ( ) {
2020-08-27 15:08:46 -07:00
db = [ self -> _databaseInPool lastObject ] ;
2013-05-31 15:31:40 -07:00
if ( db ) {
2020-08-27 15:08:46 -07:00
[ self -> _databaseOutPool addObject : db ] ;
[ self -> _databaseInPool removeLastObject ] ;
2013-05-31 15:31:40 -07:00
}
else {
2020-08-27 15:08:46 -07:00
if ( self -> _maximumNumberOfDatabasesToCreate ) {
NSUInteger currentCount = [ self -> _databaseOutPool count ] + [ self -> _databaseInPool count ] ;
2013-05-31 15:31:40 -07:00
2020-08-27 15:08:46 -07:00
if ( currentCount >= self -> _maximumNumberOfDatabasesToCreate ) {
2013-05-31 15:31:40 -07:00
NSLog ( @ "Maximum number of databases (%ld) has already been reached!" , ( long ) currentCount ) ;
return ;
}
}
2020-08-27 15:08:46 -07:00
db = [ FMDatabase databaseWithPath : self -> _path ] ;
2013-05-31 15:31:40 -07:00
}
// This ensures that the db is opened before returning
if ( [ db open ] ) {
2020-08-27 15:08:46 -07:00
if ( [ self -> _delegate respondsToSelector : @ selector ( databasePool : shouldAddDatabaseToPool : ) ] && ! [ self -> _delegate databasePool : self shouldAddDatabaseToPool : db ] ) {
2013-05-31 15:31:40 -07:00
[ db close ] ;
db = 0 x00 ;
}
else {
// It should not get added in the pool twice if lastObject was found
2020-08-27 15:08:46 -07:00
if ( ! [ self -> _databaseOutPool containsObject : db ] ) {
[ self -> _databaseOutPool addObject : db ] ;
2013-05-31 15:31:40 -07:00
}
}
}
else {
2020-08-27 15:08:46 -07:00
NSLog ( @ "Could not open up the database at path %@" , self -> _path ) ;
2013-05-31 15:31:40 -07:00
db = 0 x00 ;
}
} ] ;
return db ;
}
- ( NSUInteger ) countOfCheckedInDatabases {
__block NSUInteger count ;
[ self executeLocked : ^ ( ) {
2020-08-27 15:08:46 -07:00
count = [ self -> _databaseInPool count ] ;
2013-05-31 15:31:40 -07:00
} ] ;
return count ;
}
- ( NSUInteger ) countOfCheckedOutDatabases {
__block NSUInteger count ;
[ self executeLocked : ^ ( ) {
2020-08-27 15:08:46 -07:00
count = [ self -> _databaseOutPool count ] ;
2013-05-31 15:31:40 -07:00
} ] ;
return count ;
}
- ( NSUInteger ) countOfOpenDatabases {
__block NSUInteger count ;
[ self executeLocked : ^ ( ) {
2020-08-27 15:08:46 -07:00
count = [ self -> _databaseOutPool count ] + [ self -> _databaseInPool count ] ;
2013-05-31 15:31:40 -07:00
} ] ;
return count ;
}
- ( void ) releaseAllDatabases {
[ self executeLocked : ^ ( ) {
2020-08-27 15:08:46 -07:00
[ self -> _databaseOutPool removeAllObjects ] ;
[ self -> _databaseInPool removeAllObjects ] ;
2013-05-31 15:31:40 -07:00
} ] ;
}
- ( 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 = 0 x00 ;
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