Bug fix for issue #307 - Memory corruption
This commit is contained in:
parent
8688746cc6
commit
6f1a844d6c
@ -124,8 +124,8 @@ static NSString *const ext_key_class = @"class";
|
||||
/**
|
||||
* YapDatabaseConnection uses these methods to recycle sqlite3 instances using the connection pool.
|
||||
**/
|
||||
- (BOOL)connectionPoolEnqueue:(sqlite3 *)aDb;
|
||||
- (sqlite3 *)connectionPoolDequeue;
|
||||
- (BOOL)connectionPoolEnqueue:(sqlite3 *)aDb main_file:(yap_file *)main_file wal_file:(yap_file *)wal_file;
|
||||
- (BOOL)connectionPoolDequeue:(sqlite3 **)aDb main_file:(yap_file **)main_file wal_file:(yap_file **)wal_file;
|
||||
|
||||
/**
|
||||
* These methods are only accessible from within the snapshotQueue.
|
||||
|
||||
@ -29,12 +29,20 @@
|
||||
#endif
|
||||
#pragma unused(ydbLogLevel)
|
||||
|
||||
/**
|
||||
* YapDatabaseClosedNotification & corresponding keys.
|
||||
**/
|
||||
|
||||
NSString *const YapDatabaseClosedNotification = @"YapDatabaseClosedNotification";
|
||||
|
||||
NSString *const YapDatabasePathKey = @"databasePath";
|
||||
NSString *const YapDatabasePathWalKey = @"databasePath_wal";
|
||||
NSString *const YapDatabasePathShmKey = @"databasePath_shm";
|
||||
|
||||
/**
|
||||
* YapDatabaseModifiedNotification & corresponding keys.
|
||||
**/
|
||||
|
||||
NSString *const YapDatabaseModifiedNotification = @"YapDatabaseModifiedNotification";
|
||||
NSString *const YapDatabaseModifiedExternallyNotification = @"YapDatabaseModifiedExternallyNotification";
|
||||
|
||||
@ -57,6 +65,14 @@ NSString *const YapDatabaseExtensionsOrderKey = @"extensionsOrder";
|
||||
NSString *const YapDatabaseExtensionDependenciesKey = @"extensionDependencies";
|
||||
NSString *const YapDatabaseNotificationKey = @"notification";
|
||||
|
||||
/**
|
||||
* ConnectionPool value dictionary keys.
|
||||
**/
|
||||
|
||||
static NSString *const YDBConnectionPoolValueKey_db = @"db";
|
||||
static NSString *const YDBConnectionPoolValueKey_main_file = @"main_file";
|
||||
static NSString *const YDBConnectionPoolValueKey_wal_file = @"wal_file";
|
||||
|
||||
/**
|
||||
* The database version is stored (via pragma user_version) to sqlite.
|
||||
* It is used to represent the version of the userlying architecture of YapDatabase.
|
||||
@ -522,6 +538,13 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Configure VFS shim (for database connections).
|
||||
|
||||
yap_vfs_shim_name = [NSString stringWithFormat:@"yap_vfs_shim_%@", [[NSUUID UUID] UUIDString]];
|
||||
yap_vfs_shim_register([yap_vfs_shim_name UTF8String], NULL, &yap_vfs_shim);
|
||||
|
||||
// Initialize variables
|
||||
|
||||
internalQueue = dispatch_queue_create("YapDatabase-Internal", NULL);
|
||||
checkpointQueue = dispatch_queue_create("YapDatabase-Checkpoint", NULL);
|
||||
snapshotQueue = dispatch_queue_create("YapDatabase-Snapshot", NULL);
|
||||
@ -572,6 +595,7 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
dispatch_queue_set_specific(writeQueue, IsOnWriteQueueKey, IsOnWriteQueueKey, NULL);
|
||||
|
||||
// Complete database setup in the background
|
||||
|
||||
dispatch_async(snapshotQueue, ^{ @autoreleasepool {
|
||||
|
||||
[self upgradeTable];
|
||||
@ -779,11 +803,6 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
|
||||
sqlite3_wal_autocheckpoint(db, 0);
|
||||
|
||||
// Configure VFS shim (for database connections).
|
||||
|
||||
yap_vfs_shim_name = [NSString stringWithFormat:@"yap_vfs_shim_%@", [[NSUUID UUID] UUIDString]];
|
||||
yap_vfs_shim_register([yap_vfs_shim_name UTF8String], NULL, &yap_vfs_shim);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -2467,7 +2486,7 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
* Returns NO if the instance was not added to the pool.
|
||||
* If so, the YapDatabaseConnection must close the instance.
|
||||
**/
|
||||
- (BOOL)connectionPoolEnqueue:(sqlite3 *)aDb
|
||||
- (BOOL)connectionPoolEnqueue:(sqlite3 *)aDb main_file:(yap_file *)main_file wal_file:(yap_file *)wal_file
|
||||
{
|
||||
__block BOOL result = NO;
|
||||
|
||||
@ -2483,7 +2502,13 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
|
||||
YDBLogVerbose(@"Enqueuing connection to pool: %p", aDb);
|
||||
|
||||
[connectionPoolValues addObject:[NSValue valueWithPointer:(const void *)aDb]];
|
||||
NSDictionary *value = @{
|
||||
YDBConnectionPoolValueKey_db : [NSValue valueWithPointer:(const void *)aDb],
|
||||
YDBConnectionPoolValueKey_main_file : [NSValue valueWithPointer:(const void *)main_file],
|
||||
YDBConnectionPoolValueKey_wal_file : [NSValue valueWithPointer:(const void *)wal_file],
|
||||
};
|
||||
|
||||
[connectionPoolValues addObject:value];
|
||||
[connectionPoolDates addObject:[NSDate date]];
|
||||
|
||||
result = YES;
|
||||
@ -2502,15 +2527,25 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
* Retrieves a connection from the connection pool if available.
|
||||
* Returns NULL if no connections are available.
|
||||
**/
|
||||
- (sqlite3 *)connectionPoolDequeue
|
||||
- (BOOL)connectionPoolDequeue:(sqlite3 **)pDb main_file:(yap_file **)pMainFile wal_file:(yap_file **)pWalFile
|
||||
{
|
||||
NSParameterAssert(pDb != NULL);
|
||||
NSParameterAssert(pMainFile != NULL);
|
||||
NSParameterAssert(pWalFile != NULL);
|
||||
|
||||
__block sqlite3 *aDb = NULL;
|
||||
__block yap_file *main_file = NULL;
|
||||
__block yap_file *wal_file = NULL;
|
||||
|
||||
dispatch_sync(internalQueue, ^{
|
||||
|
||||
if ([connectionPoolValues count] > 0)
|
||||
{
|
||||
aDb = (sqlite3 *)[[connectionPoolValues objectAtIndex:0] pointerValue];
|
||||
NSDictionary *value = [connectionPoolValues objectAtIndex:0];
|
||||
|
||||
aDb = (sqlite3 *)[[value objectForKey:YDBConnectionPoolValueKey_db] pointerValue];
|
||||
main_file = (yap_file *)[[value objectForKey:YDBConnectionPoolValueKey_main_file] pointerValue];
|
||||
wal_file = (yap_file *)[[value objectForKey:YDBConnectionPoolValueKey_wal_file] pointerValue];
|
||||
|
||||
YDBLogVerbose(@"Dequeuing connection from pool: %p", aDb);
|
||||
|
||||
@ -2521,7 +2556,11 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
}
|
||||
});
|
||||
|
||||
return aDb;
|
||||
*pDb = aDb;
|
||||
*pMainFile = main_file;
|
||||
*pWalFile = wal_file;
|
||||
|
||||
return (aDb != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2595,7 +2634,9 @@ static int connectionBusyHandler(void *ptr, int count) {
|
||||
|
||||
if ((interval >= connectionPoolLifetime) || (interval < 0))
|
||||
{
|
||||
sqlite3 *aDb = (sqlite3 *)[[connectionPoolValues objectAtIndex:0] pointerValue];
|
||||
NSDictionary *value = [connectionPoolValues objectAtIndex:0];
|
||||
|
||||
sqlite3 *aDb = (sqlite3 *)[[value objectForKey:YDBConnectionPoolValueKey_db] pointerValue];;
|
||||
|
||||
YDBLogVerbose(@"Closing connection from pool: %p", aDb);
|
||||
|
||||
|
||||
@ -255,8 +255,21 @@ static int connectionBusyHandler(void *ptr, int count)
|
||||
|
||||
lock = OS_SPINLOCK_INIT;
|
||||
|
||||
db = [database connectionPoolDequeue];
|
||||
if (db == NULL)
|
||||
BOOL recycled = [database connectionPoolDequeue:&db main_file:&main_file wal_file:&wal_file];
|
||||
if (recycled)
|
||||
{
|
||||
// Update pointer values
|
||||
|
||||
if (main_file) {
|
||||
main_file->yap_database_connection = (__bridge void *)self;
|
||||
}
|
||||
if (wal_file) {
|
||||
wal_file->yap_database_connection = (__bridge void *)self;
|
||||
}
|
||||
|
||||
sqlite3_busy_handler(db, connectionBusyHandler, (__bridge void *)self);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open the database connection.
|
||||
//
|
||||
@ -343,7 +356,7 @@ static int connectionBusyHandler(void *ptr, int count)
|
||||
//
|
||||
// Note: In all my testing, I've only seen the busy_handler called once per db.
|
||||
|
||||
sqlite3_busy_handler(db, connectionBusyHandler, (__bridge void *)(self));
|
||||
sqlite3_busy_handler(db, connectionBusyHandler, (__bridge void *)self);
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
// Configure SQLCipher encryption (if needed)
|
||||
@ -417,7 +430,7 @@ static int connectionBusyHandler(void *ptr, int count)
|
||||
wal_file->xNotifyDidRead = NULL;
|
||||
}
|
||||
|
||||
if (![database connectionPoolEnqueue:db])
|
||||
if (![database connectionPoolEnqueue:db main_file:main_file wal_file:wal_file])
|
||||
{
|
||||
int status = sqlite3_close(db);
|
||||
if (status != SQLITE_OK)
|
||||
@ -427,6 +440,8 @@ static int connectionBusyHandler(void *ptr, int count)
|
||||
}
|
||||
|
||||
db = NULL;
|
||||
main_file = NULL;
|
||||
wal_file = NULL;
|
||||
}
|
||||
|
||||
[database removeConnection:self];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user