aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/SPMySQLFramework/Source
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2012-03-14 01:16:18 +0000
committerrowanbeentje <rowan@beent.je>2012-03-14 01:16:18 +0000
commit79eff5bf42154da8d7730e0e0159160f68ec4e16 (patch)
tree38db570f7c36fbe2995774fefa627f1b467a9371 /Frameworks/SPMySQLFramework/Source
parentd5e20720cf7f991a691d9a03e7f895211b7c98ad (diff)
downloadsequelpro-79eff5bf42154da8d7730e0e0159160f68ec4e16.tar.gz
sequelpro-79eff5bf42154da8d7730e0e0159160f68ec4e16.tar.bz2
sequelpro-79eff5bf42154da8d7730e0e0159160f68ec4e16.zip
Final feature work on the SPMySQL branch before merging:
- Add a ping keepalive managing object to prevent retain cycles from the NSTimer - Add -[SPMySQLConnection copy] support - Refactor Hans-Jörg Bibiko's database structure retrieval, moving it out of the MySQL framework and building it around a copy of the connection. This reduces the amount of connections-over-time used by Sequel Pro to two constant connections (addressing Issue #1097) and improves robustness. - Use the database structure retrieval connection for faster query cancellation without an extra connection required, if possible
Diffstat (limited to 'Frameworks/SPMySQLFramework/Source')
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.h36
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.m71
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h5
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m15
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.h1
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m10
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h6
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m16
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.h45
-rw-r--r--Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.m127
10 files changed, 295 insertions, 37 deletions
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.h
new file mode 100644
index 00000000..83d055d5
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.h
@@ -0,0 +1,36 @@
+//
+// $Id$
+//
+// Copying.h
+// SPMySQLFramework
+//
+// Created by Rowan Beentje (rowan.beent.je) on March 8, 2012
+// Copyright (c) 2012 Rowan Beentje. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+
+@interface SPMySQLConnection (Copying) <NSCopying>
+
+@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.m
new file mode 100644
index 00000000..c2df2a4b
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Copying.m
@@ -0,0 +1,71 @@
+//
+// $Id$
+//
+// Copying.m
+// SPMySQLFramework
+//
+// Created by Rowan Beentje (rowan.beent.je) on March 8, 2012
+// Copyright (c) 2012 Rowan Beentje. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "Copying.h"
+
+@implementation SPMySQLConnection (Copying)
+
+/**
+ * Provide a copy of the SPMySQLConnection instance.
+ * The copy should inherit the full setup, but will not inherit
+ * the connection state - it will not be connected, and any connection
+ * details such as the selected database/encoding will not be inherited.
+ * Note that any proxy will not be referenced in the new connection, and
+ * should also be set if desired.
+ */
+- (id)copyWithZone:(NSZone *)zone
+{
+ SPMySQLConnection *copy = [[[self class] allocWithZone:zone] init];
+
+ // Synthesized details
+ [copy setDelegate:delegate];
+ [copy setHost:host];
+ [copy setUsername:username];
+ [copy setPassword:password];
+ [copy setPort:port];
+ [copy setUseSocket:useSocket];
+ [copy setSocketPath:socketPath];
+ [copy setUseSSL:useSSL];
+ [copy setSslKeyFilePath:sslKeyFilePath];
+ [copy setSslCertificatePath:sslCertificatePath];
+ [copy setSslCACertificatePath:sslCACertificatePath];
+ [copy setTimeout:timeout];
+ [copy setUseKeepAlive:useKeepAlive];
+ [copy setRetryQueriesOnConnectionFailure:retryQueriesOnConnectionFailure];
+ [copy setDelegateQueryLogging:delegateQueryLogging];
+
+ // Active connection state details, like selected database and encoding, are *not* copied.
+
+ return copy;
+}
+
+@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h
index 3788c653..e84c4ca6 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.h
@@ -40,11 +40,8 @@ typedef struct {
@interface SPMySQLConnection (Ping_and_KeepAlive)
-// Setup functions
-- (void)_initKeepAlivePingTimer;
-
// Keepalive ping initialisation
-- (void)_keepAlive:(NSTimer *)theTimer;
+- (void)_keepAlive;
- (void)_threadedKeepAlive;
// Master ping method
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
index 9e25edcb..3ce0c0cd 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Ping & KeepAlive.m
@@ -38,19 +38,6 @@
@implementation SPMySQLConnection (Ping_and_KeepAlive)
#pragma mark -
-#pragma mark Setup functions
-
-/**
- * Set up the keepalive timer; this should be called on the main
- * thread, to ensure the timer isn't descheduled when child threads
- * terminate.
- */
-- (void)_initKeepAlivePingTimer
-{
- keepAliveTimer = [[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(_keepAlive:) userInfo:nil repeats:YES] retain];
-}
-
-#pragma mark -
#pragma mark Keepalive ping initialisation
/**
@@ -58,7 +45,7 @@
* This method is called every ten seconds and spawns a thread which determines
* whether or not it should perform a ping.
*/
-- (void)_keepAlive:(NSTimer *)theTimer
+- (void)_keepAlive
{
// Do nothing if not connected or if keepalive is disabled
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.h
index 9ab8bc6a..0f086a89 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.h
@@ -61,7 +61,6 @@
// Query cancellation
- (void)cancelCurrentQuery;
-- (BOOL)lastQueryWasCancelled;
- (BOOL)lastQueryWasCancelledUsingReconnect;
@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m
index cb5ce70d..9b54029c 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection Categories/Querying & Preparation.m
@@ -282,7 +282,7 @@
} else {
// Prevent retries if the query was cancelled or not a connection error
- if (lastQueryWasCancelled && ![SPMySQLConnection isErrorIDConnectionError:mysql_errno(mySQLConnection)]) {
+ if (lastQueryWasCancelled || ![SPMySQLConnection isErrorIDConnectionError:mysql_errno(mySQLConnection)]) {
break;
}
}
@@ -549,14 +549,6 @@
}
/**
- * Returns whether the last query was cancelled using cancelCurrentQuery.
- */
-- (BOOL)lastQueryWasCancelled
-{
- return lastQueryWasCancelled;
-}
-
-/**
* If the last query was cancelled, returns whether that query cancellation
* required the connection to be reset or whether the query was successfully
* cancelled leaving the connection intact.
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
index 5d1a5d11..8f3b7f9f 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.h
@@ -30,6 +30,8 @@
//
// More info at <http://code.google.com/p/sequel-pro/>
+@class SPMySQLKeepAliveTimer;
+
@interface SPMySQLConnection : NSObject {
// Delegate
@@ -80,7 +82,7 @@
// Timeout and keep-alive
NSUInteger timeout;
BOOL useKeepAlive;
- NSTimer *keepAliveTimer;
+ SPMySQLKeepAliveTimer *keepAliveTimer;
CGFloat keepAliveInterval;
uint64_t lastKeepAliveTime;
NSUInteger keepAlivePingFailures;
@@ -153,6 +155,8 @@
@property (readwrite, assign) BOOL delegateQueryLogging;
+@property (readwrite, assign) BOOL lastQueryWasCancelled;
+
#pragma mark -
#pragma mark Connection and disconnection
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
index 4968266d..4f1e8a74 100644
--- a/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLConnection.m
@@ -31,6 +31,7 @@
// More info at <http://code.google.com/p/sequel-pro/>
#import "SPMySQL Private APIs.h"
+#import "SPMySQLKeepAliveTimer.h"
#include <mach/mach_time.h>
#include <pthread.h>
#include <SystemConfiguration/SCNetworkReachability.h>
@@ -71,6 +72,7 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
@synthesize mysqlConnectionThreadId;
@synthesize retryQueriesOnConnectionFailure;
@synthesize delegateQueryLogging;
+@synthesize lastQueryWasCancelled;
#pragma mark -
#pragma mark Initialisation and teardown
@@ -161,11 +163,7 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
retryQueriesOnConnectionFailure = YES;
// Start the ping keepalive timer
- if ([NSThread isMainThread]) {
- [self _initKeepAlivePingTimer];
- } else {
- [self performSelectorOnMainThread:@selector(_initKeepAlivePingTimer) withObject:nil waitUntilDone:YES];
- }
+ keepAliveTimer = [[SPMySQLKeepAliveTimer alloc] initWithInterval:10 target:self selector:@selector(_keepAlive)];
}
return self;
@@ -181,6 +179,10 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
// Unset the delegate
[self setDelegate:nil];
+ // Clear the keepalive timer
+ [keepAliveTimer invalidate];
+ [keepAliveTimer release];
+
// Disconnect if appropriate (which should also disconnect any proxy)
[self disconnect];
@@ -196,14 +198,12 @@ const char *SPMySQLSSLPermissibleCiphers = "DHE-RSA-AES256-SHA:AES256-SHA:DHE-RS
}
[connectionLock release], connectionLock = nil;
- [encoding dealloc];
+ [encoding release];
if (previousEncoding) [previousEncoding release], previousEncoding = nil;
if (database) [database release], database = nil;
if (serverVersionString) [serverVersionString release], serverVersionString = nil;
if (queryErrorMessage) [queryErrorMessage release], queryErrorMessage = nil;
- [keepAliveTimer invalidate];
- [keepAliveTimer release];
[delegateDecisionLock release];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.h b/Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.h
new file mode 100644
index 00000000..ebe46bed
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.h
@@ -0,0 +1,45 @@
+//
+// $Id$
+//
+// SPMySQLKeepAliveTimer.h
+// SPMySQLFramework
+//
+// Created by Rowan Beentje (rowan.beent.je) on March 5, 2012
+// Copyright (c) 2012 Rowan Beentje. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+
+@interface SPMySQLKeepAliveTimer : NSObject {
+ id timerTarget;
+ SEL timerSelector;
+ NSTimeInterval timerRepeatInterval;
+
+ NSTimer *wrappedTimer;
+}
+
+- (id)initWithInterval:(NSTimeInterval)anInterval target:(id)aTarget selector:(SEL)aSelector;
+- (void)invalidate;
+
+@end
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.m b/Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.m
new file mode 100644
index 00000000..f9164aff
--- /dev/null
+++ b/Frameworks/SPMySQLFramework/Source/SPMySQLKeepAliveTimer.m
@@ -0,0 +1,127 @@
+//
+// $Id$
+//
+// SPMySQLKeepAliveTimer.m
+// SPMySQLFramework
+//
+// Created by Rowan Beentje (rowan.beent.je) on March 5, 2012
+// Copyright (c) 2012 Rowan Beentje. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+
+#import "SPMySQLKeepAliveTimer.h"
+#import "SPMySQL Private APIs.h"
+
+@interface SPMySQLKeepAliveTimer (Private_API)
+
+- (void)_initKeepAliveTimer;
+- (void)_forwardPing;
+
+@end
+
+#pragma mark -
+
+@implementation SPMySQLKeepAliveTimer
+
+/**
+ * Prevent SPMySQLKeepAliveTimer from being init'd normally.
+ */
+- (id)init
+{
+ [NSException raise:NSInternalInconsistencyException format:@"SPMySQLKeepAliveTimers should not be init'd directly; use initWithInterval:target:selector: instead."];
+ return nil;
+}
+
+/**
+ * Initialise the SPMySQLKeepAliveTimer. This also sets up the contained timer,
+ * which has to be wrapped in this class to prevent retain cycles preventing the
+ * parent connection from being released.
+ *
+ * After initialisation, the delegate should be set to ensure that the timer events
+ * are received.
+ */
+- (id)initWithInterval:(NSTimeInterval)anInterval target:(id)aTarget selector:(SEL)aSelector
+{
+ if ((self = [super init])) {
+ wrappedTimer = nil;
+
+ // Keep a weak reference to the target
+ timerTarget = aTarget;
+ timerSelector = aSelector;
+ timerRepeatInterval = anInterval;
+
+ // Ensure the timer is set up on the main thread
+ if ([NSThread isMainThread]) {
+ [self _initKeepAliveTimer];
+ } else {
+ [self performSelectorOnMainThread:@selector(_initKeepAliveTimer) withObject:nil waitUntilDone:YES];
+ }
+ }
+
+ return self;
+}
+
+/**
+ * Invalidate the wrapped timer, which also releases the reference to the timer
+ * target (this object), breaking retain loops.
+ */
+- (void)invalidate
+{
+ if ([NSThread isMainThread]) {
+ [wrappedTimer invalidate];
+ } else {
+ [wrappedTimer performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:YES];
+ }
+}
+
+- (void)dealloc
+{
+ [wrappedTimer dealloc];
+ [super dealloc];
+}
+
+@end
+
+@implementation SPMySQLKeepAliveTimer (Private_API)
+
+/**
+ * Set up the timer to tickle the target. This must be set up on the main thread
+ * to ensure the timer events keep firing.
+ */
+- (void)_initKeepAliveTimer
+{
+ wrappedTimer = [[NSTimer scheduledTimerWithTimeInterval:timerRepeatInterval target:self selector:@selector(_forwardPing) userInfo:nil repeats:YES] retain];
+}
+
+/**
+ * Forward the NSTimer-fired ping to the target object. Performing this forwarding
+ * breaks the retain cycle.
+ */
+- (void)_forwardPing
+{
+ [timerTarget performSelector:timerSelector];
+}
+
+@end