Browse Source

Bug fixes, doc updates

August Mueller 14 years ago
parent
commit
dfd8fb99ed
6 changed files with 132 additions and 63 deletions
  1. 4 4
      README.markdown
  2. 5 3
      src/FMDatabase.h
  3. 34 35
      src/FMDatabase.m
  4. 2 0
      src/FMDatabasePool.h
  5. 25 3
      src/FMDatabasePool.m
  6. 62 18
      src/fmdb.m

+ 4 - 4
README.markdown

@@ -114,7 +114,7 @@ Internally, the `-execute*WithFormat:` methods are properly boxing things for yo
 
 ## Using FMDatabasePool and Thread Safety.
 
-**Note:** This is preliminary and subject to change.  Consider it experimental, but feel free to try it out and give me feedback.  I'm also not a fan of the method names I've added (pullFromPool, pushTowardsPool, useDatabase:, useTransaction:) - if you've got better ideas of a name, let me know.
+**Note:** This is preliminary and subject to change.  Consider it experimental, but feel free to try it out and give me feedback.  I'm also not a fan of the method names I've added (useDatabase:, useTransaction:) - if you've got better ideas of a name, let me know.
 
 Using a single instance of FMDatabase from multiple threads at once is not supported.  Bad things will eventually happen and you'll eventually get something to crash, or maybe get an exception, or maybe meteorites will fall out of the sky and hit your Mac Pro.  *This would suck*.
 
@@ -143,14 +143,14 @@ When the result set is exhausted or [rs close] is called, the result set will te
 
 If you'd rather use multiple queries without having to call [pool db] each time, you can grab a database instance, tell it to stay out of the pool, and then tell it to go back in the pool when you're done:
 
-	FMDatabase *db = [[pool db] pullFromPool];
+	FMDatabase *db = [[pool db] popFromPool];
 	[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
 	[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
 	[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
 	// put the database back in the pool.
-	[db pushTowardsPool];
+	[db pushToPool];
 
 Alternatively, you can use this nifty block based approach:
 
@@ -189,7 +189,7 @@ If you check out a database, but never execute a statement or query, **you need
 	// lala, don't do anything with the database
 	// oh look, I BETTER PUT THE DB BACK IN THE POOL OR ELSE IT IS GOING TO LEAK:
-	[db pushTowardsPool];
+	[db pushToPool];
 	
 	
 

+ 5 - 3
src/FMDatabase.h

@@ -15,12 +15,14 @@
     BOOL                _shouldCacheStatements;
     BOOL                _inUse;
     int                 _busyRetryTimeout;
-    NSInteger           _keepOutOfPoolCount;
+    
+    
     
     NSMutableDictionary *_cachedStatements;
 	NSMutableSet        *_openResultSets;
     
     FMDatabasePool      *_pool;
+    NSInteger           _poolPopCount;
 }
 
 
@@ -84,8 +86,8 @@
 
 - (int)changes;
 
-- (FMDatabase*)pullFromPool;
-- (void)pushTowardsPool;
+- (FMDatabase*)popFromPool;
+- (void)pushToPool;
 
 
 @end

+ 34 - 35
src/FMDatabase.m

@@ -3,7 +3,7 @@
 
 @interface FMDatabase ()
 
-- (void)pushInPoolIfClose;
+- (void)checkPoolPushBack;
 - (BOOL)inUse;
 - (void)setInUse:(BOOL)b;
 
@@ -176,8 +176,7 @@ - (void)resultSetDidClose:(FMResultSet *)resultSet {
     
     [_openResultSets removeObject:setValue];
     
-    [self pushInPoolIfClose];
-    
+    [self checkPoolPushBack];
 }
 
 - (FMStatement*)cachedStatementForQuery:(NSString*)query {
@@ -295,11 +294,11 @@ - (sqlite_int64)lastInsertRowId {
         return NO;
     }
     
-    [self setInUse:YES];
+    _inUse = YES;
     
     sqlite_int64 ret = sqlite3_last_insert_rowid(_db);
     
-    [self setInUse:NO];
+    _inUse = NO;
     
     return ret;
 }
@@ -310,11 +309,11 @@ - (int)changes {
         return 0;
     }
     
-    [self setInUse:YES];
+    _inUse = YES;
     
     int ret = sqlite3_changes(_db);
     
-    [self setInUse:NO];
+    _inUse = NO;
     
     return ret;
 }
@@ -361,7 +360,7 @@ - (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt {
     }
 }
 
-- (void)_extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments {
+- (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments {
     
     NSUInteger length = [sql length];
     unichar last = '\0';
@@ -474,8 +473,8 @@ - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arr
     }
     
     if (_inUse) {
-        [self pushTowardsPool];
         [self warnInUse];
+        [self checkPoolPushBack];
         return 0x00;
     }
     
@@ -512,7 +511,7 @@ - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arr
                     NSLog(@"Database busy");
                     sqlite3_finalize(pStmt);
                     [self setInUse:NO];
-                    [self pushTowardsPool];
+                    [self checkPoolPushBack];
                     return nil;
                 }
             }
@@ -530,7 +529,7 @@ - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arr
                 
                 sqlite3_finalize(pStmt);
                 [self setInUse:NO];
-                [self pushTowardsPool];
+                [self checkPoolPushBack];
                 return nil;
             }
         }
@@ -563,7 +562,7 @@ - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arr
         NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)");
         sqlite3_finalize(pStmt);
         [self setInUse:NO];
-        [self pushTowardsPool];
+        [self checkPoolPushBack];
         return nil;
     }
     
@@ -610,7 +609,7 @@ - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... {
     
     NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]];
     NSMutableArray *arguments = [NSMutableArray array];
-    [self _extractSQL:format argumentsList:args intoString:sql arguments:arguments];    
+    [self extractSQL:format argumentsList:args intoString:sql arguments:arguments];    
     
     va_end(args);
     
@@ -624,12 +623,12 @@ - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)ar
 - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orVAList:(va_list)args {
     
     if (![self databaseExists]) {
-        [self pushTowardsPool];
+        [self checkPoolPushBack];
         return NO;
     }
     
     if (_inUse) {
-        [self pushTowardsPool];
+        [self checkPoolPushBack];
         [self warnInUse];
         return NO;
     }
@@ -666,7 +665,7 @@ - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArra
                     NSLog(@"Database busy");
                     sqlite3_finalize(pStmt);
                     [self setInUse:NO];
-                    [self pushTowardsPool];
+                    [self checkPoolPushBack];
                     return NO;
                 }
             }
@@ -689,7 +688,7 @@ - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArra
                 }
                 
                 [self setInUse:NO];
-                [self pushTowardsPool];
+                [self checkPoolPushBack];
                 return NO;
             }
         }
@@ -722,7 +721,7 @@ - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArra
         NSLog(@"Error: the bind count is not correct for the # of variables (%@) (executeUpdate)", sql);
         sqlite3_finalize(pStmt);
         [self setInUse:NO];
-        [self pushTowardsPool];
+        [self checkPoolPushBack];
         return NO;
     }
     
@@ -798,7 +797,7 @@ - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArra
     }
     
     [self setInUse:NO];
-    [self pushTowardsPool];
+    [self checkPoolPushBack];
     return (rc == SQLITE_OK);
 }
 
@@ -824,7 +823,7 @@ - (BOOL)executeUpdateWithFormat:(NSString*)format, ... {
     NSMutableString *sql      = [NSMutableString stringWithCapacity:[format length]];
     NSMutableArray *arguments = [NSMutableArray array];
     
-    [self _extractSQL:format argumentsList:args intoString:sql arguments:arguments];    
+    [self extractSQL:format argumentsList:args intoString:sql arguments:arguments];    
     
     va_end(args);
     
@@ -847,7 +846,7 @@ - (BOOL)rollback {
         _inTransaction = NO;
     }
     
-    [self pushInPoolIfClose];
+    [self pushToPool];
     
     return b;
 }
@@ -858,7 +857,7 @@ - (BOOL)commit {
         _inTransaction = NO;
     }
     
-    [self pushInPoolIfClose];
+    [self pushToPool];
     
     return b;
 }
@@ -866,7 +865,7 @@ - (BOOL)commit {
 - (BOOL)beginDeferredTransaction {
     
     if (_pool) {
-        [self pullFromPool];
+        [self popFromPool];
     }
     
     BOOL b =  [self executeUpdate:@"BEGIN DEFERRED TRANSACTION;"];
@@ -880,15 +879,14 @@ - (BOOL)beginDeferredTransaction {
 - (BOOL)beginTransaction {
     
     if (_pool) {
-        [self pullFromPool];
+        [self popFromPool];
     }
     
     BOOL b =  [self executeUpdate:@"BEGIN EXCLUSIVE TRANSACTION;"];
     if (b) {
         _inTransaction = YES;
-        
-        
     }
+    
     return b;
 }
 
@@ -917,35 +915,36 @@ - (void)setShouldCacheStatements:(BOOL)value {
     }
 }
 
-- (FMDatabase*)pullFromPool {
+- (FMDatabase*)popFromPool {
     
     if (!_pool) {
         NSLog(@"No FMDatabasePool in place for %@", self);
         return 0x00;
     }
     
-    _keepOutOfPoolCount++;
+    _poolPopCount++;
     
     return self;
 }
 
-- (void)pushTowardsPool {
-    _keepOutOfPoolCount--;
+- (void)pushToPool {
+    _poolPopCount--;
     
-    [self pushInPoolIfClose];
+    [self checkPoolPushBack];
 }
 
-- (void)pushInPoolIfClose {
+- (void)checkPoolPushBack {
     
-    if (_keepOutOfPoolCount <= 0) {
+    if (_poolPopCount <= 0) {
         [_pool pushDatabaseBackInPool:self];
         
-        if (_keepOutOfPoolCount < 0) {
-            _keepOutOfPoolCount = 0;
+        if (_poolPopCount < 0) {
+            _poolPopCount = 0;
         }
     }
 }
 
+
 @end
 
 

+ 2 - 0
src/FMDatabasePool.h

@@ -33,6 +33,8 @@
 - (void)pushDatabaseBackInPool:(FMDatabase*)db;
 - (FMDatabase*)db;
 
+- (NSUInteger)countOfCheckedInDatabases;
+- (NSUInteger)countOfCheckedOutDatabases;
 - (NSUInteger)countOfOpenDatabases;
 - (void)releaseAllDatabases;
 

+ 25 - 3
src/FMDatabasePool.m

@@ -93,8 +93,8 @@ - (FMDatabase*)db {
             }
             
             db = [FMDatabase databaseWithPath:_path];
+            
             if ([db open]) {
-                
                 if ([_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![_delegate databasePool:self shouldAddDatabaseToPool:db]) {
                     [db close];
                     db = 0x00;
@@ -115,6 +115,28 @@ - (FMDatabase*)db {
     return db;
 }
 
+- (NSUInteger)countOfCheckedInDatabases {
+    
+    __block NSInteger count;
+    
+    [self executeLocked:^() {
+        count = [_databaseInPool count];
+    }];
+    
+    return count;
+}
+
+- (NSUInteger)countOfCheckedOutDatabases {
+    
+    __block NSInteger count;
+    
+    [self executeLocked:^() {
+        count = [_databaseOutPool count];
+    }];
+    
+    return count;
+}
+
 - (NSUInteger)countOfOpenDatabases {
     __block NSInteger count;
     
@@ -134,11 +156,11 @@ - (void)releaseAllDatabases {
 
 - (void)useDatabase:(void (^)(FMDatabase *db))block {
     
-    FMDatabase *db = [[self db] pullFromPool];
+    FMDatabase *db = [[self db] popFromPool];
     
     block(db);
     
-    [db pushTowardsPool];
+    [db pushToPool];
 }
 
 - (void)useTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {

+ 62 - 18
src/fmdb.m

@@ -556,10 +556,10 @@ int main (int argc, const char * argv[]) {
     db = [dbPool db];
     FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);
     
-    [db pushTowardsPool];
+    [db pushToPool];
     
-    [[dbPool db] pushTowardsPool];
-    [[dbPool db] pushTowardsPool];
+    [[dbPool db] pushToPool];
+    [[dbPool db] pushToPool];
     
     FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);
     
@@ -567,33 +567,65 @@ int main (int argc, const char * argv[]) {
     
     FMDBQuickCheck([dbPool countOfOpenDatabases] == 0);
     
-    [dbPool useDatabase: ^(FMDatabase *aDb) {
+    [dbPool useDatabase:^(FMDatabase *aDb) {
+        
+        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
+        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
         
         FMDBQuickCheck([aDb tableExists:@"t4"]);
         
+        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
+        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
+        
         FMDBQuickCheck(([aDb executeUpdate:@"insert into easy (a) values (?)", @"hi"]));
         
         // just for fun.
-        FMResultSet *rs2 = [db executeQuery:@"select * from easy"];
+        FMResultSet *rs2 = [aDb executeQuery:@"select * from easy"];
         FMDBQuickCheck([rs2 next]);
         while ([rs2 next]) { ; } // whatevers.
         
         FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
+        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
+        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
     }];
     
     
     FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
     
     
-    db = [[dbPool db] pullFromPool];
+    {
+        
+        db = [[dbPool db] popFromPool];
+        
+        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1]];
+        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:2]];
+        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]];
+        
+        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
+        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
+        
+        [db pushToPool];
+    }
     
-	[db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1]];
-	[db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:2]];
-	[db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]];
     
-    [db pushTowardsPool];
+    {
+        // double pop!
+        db = [[dbPool db] popFromPool];
+        
+        [db popFromPool];
+        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1]];
+        
+        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
+        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
+        
+        [db pushToPool];
+        [db pushToPool];
+        
+        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);
+        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);
+    }
     
-    [[dbPool db] pushTowardsPool];
+    [[dbPool db] pushToPool];
     
     FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
     
@@ -640,25 +672,37 @@ int main (int argc, const char * argv[]) {
     FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
     
     
-    [dbPool useTransaction:^(FMDatabase *db, BOOL *rollback) {
-        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];
-        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];
-        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];
+    [dbPool useTransaction:^(FMDatabase *adb, BOOL *rollback) {
+        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];
+        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];
+        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];
+        
+        FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
+        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
+        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
     }];
     
     
+    FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
+    FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);
+    FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);
+    
+    
     FMResultSet *rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1001]];
     FMDBQuickCheck([rs2 next]);
     FMDBQuickCheck(![rs2 next]);
     
     
-    [dbPool useTransaction:^(FMDatabase *db, BOOL *rollback) {
-        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1004]];
-        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1005]];
+    [dbPool useTransaction:^(FMDatabase *adb, BOOL *rollback) {
+        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1004]];
+        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1005]];
         
         *rollback = YES;
     }];
     
+    FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
+    FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);
+    FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);
     
     rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1004]];
     FMDBQuickCheck(![rs2 next]);