diff --git a/SQLClient.h b/SQLClient.h
index c2608a3..d714adb 100644
--- a/SQLClient.h
+++ b/SQLClient.h
@@ -383,14 +383,15 @@ SQLCLIENT_PRIVATE
NSString *_user; /** The configured user */
NSMutableArray *_statements; /** Uncommitted statements */
/**
- * Timestamp of last operation.
+ * Timestamp of completion of last operation.
* Maintained by -simpleExecute: -simpleQuery:recordType:listType:
* and -cache:simpleQuery:recordType:listType:
* Also set for a failed connection attempt, but not reported by the
* -lastOperation method in that case.
*/
NSTimeInterval _lastOperation;
- NSTimeInterval _duration;
+ NSTimeInterval _lastStart; /** Last op start or connect */
+ NSTimeInterval _duration; /** Duration logging threshold */
unsigned int _debugging; /** The current debugging level */
GSCache *_cache; /** The cache for query results */
NSThread *_cacheThread; /** Thread for cache queries */
@@ -687,6 +688,14 @@ SQLCLIENT_PRIVATE
*/
- (NSDate*) lastOperation;
+/** Compares the receiver with the other client to see which one has been
+ * inactive but connected for longest (if they are connected) and returns
+ * that instance.
+ * If neither is idle but connected, the method returns nil.
+ * In a tie, the method returns the other instance.
+ */
+- (SQLClient*) longestIdle: (SQLClient*)other;
+
/**
* Return the database reference name for this instance (or nil).
*/
diff --git a/SQLClient.m b/SQLClient.m
index e6f011e..2080afb 100644
--- a/SQLClient.m
+++ b/SQLClient.m
@@ -76,10 +76,11 @@ NSString * const SQLClientDidDisconnectNotification
static NSNull *null = nil;
static NSArray *queryModes = nil;
static NSThread *mainThread = nil;
-static Class NSStringClass = 0;
-static Class NSArrayClass = 0;
-static Class NSDateClass = 0;
-static Class NSSetClass = 0;
+static Class NSStringClass = Nil;
+static Class NSArrayClass = Nil;
+static Class NSDateClass = Nil;
+static Class NSSetClass = Nil;
+static Class SQLClientClass = Nil;
@interface _ConcreteSQLRecord : SQLRecord
{
@@ -738,29 +739,34 @@ static unsigned int maxConnections = 8;
+ (void) initialize
{
- static id modes[1];
-
- modes[0] = NSDefaultRunLoopMode;
- queryModes = [[NSArray alloc] initWithObjects: modes count: 1];
- GSTickerTimeNow();
- [SQLRecord class]; // Force initialisation
- if (0 == clientsHash)
+ if (Nil == SQLClientClass && [SQLClient class] == self)
{
- clientsHash = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, 0);
- clientsMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
- NSNonRetainedObjectMapValueCallBacks, 0);
- clientsLock = [NSRecursiveLock new];
- beginStatement = [[NSArray arrayWithObject: beginString] retain];
- commitStatement = [[NSArray arrayWithObject: commitString] retain];
- rollbackStatement = [[NSArray arrayWithObject: rollbackString] retain];
- NSStringClass = [NSString class];
- NSArrayClass = [NSArray class];
- NSSetClass = [NSSet class];
- [NSTimer scheduledTimerWithTimeInterval: 1.0
- target: self
- selector: @selector(_tick:)
- userInfo: 0
- repeats: YES];
+ static id modes[1];
+
+ SQLClientClass = self;
+ modes[0] = NSDefaultRunLoopMode;
+ queryModes = [[NSArray alloc] initWithObjects: modes count: 1];
+ GSTickerTimeNow();
+ [SQLRecord class]; // Force initialisation
+ if (0 == clientsHash)
+ {
+ clientsHash = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, 0);
+ clientsMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
+ NSNonRetainedObjectMapValueCallBacks, 0);
+ clientsLock = [NSRecursiveLock new];
+ beginStatement = [[NSArray arrayWithObject: beginString] retain];
+ commitStatement = [[NSArray arrayWithObject: commitString] retain];
+ rollbackStatement
+ = [[NSArray arrayWithObject: rollbackString] retain];
+ NSStringClass = [NSString class];
+ NSArrayClass = [NSArray class];
+ NSSetClass = [NSSet class];
+ [NSTimer scheduledTimerWithTimeInterval: 1.0
+ target: self
+ selector: @selector(_tick:)
+ userInfo: 0
+ repeats: YES];
+ }
}
}
@@ -958,6 +964,7 @@ static unsigned int maxConnections = 8;
}
}
+ _lastStart = GSTickerTimeNow();
[self backendConnect];
/* On establishng a new connection, we must restore any
* listen instructions in the backend.
@@ -1274,6 +1281,51 @@ static unsigned int maxConnections = 8;
return nil;
}
+- (SQLClient*) longestIdle: (SQLClient*)other
+{
+ NSTimeInterval t0;
+ NSTimeInterval t1;
+
+ NSAssert([other isKindOfClass: SQLClientClass], NSInvalidArgumentException);
+
+ t0 = _lastOperation;
+ if (t0 < _lastStart)
+ {
+ t0 = _lastStart;
+ }
+ if (NO == connected || 0 != _connectFails)
+ {
+ t0 = 0.0;
+ }
+
+ if (YES == [other isProxy])
+ {
+ t1 = 0.0;
+ }
+ else
+ {
+ t1 = other->_lastOperation;
+ if (t1 < other->_lastStart)
+ {
+ t1 = other->_lastStart;
+ }
+ if (NO == connected || 0 != other->_connectFails)
+ {
+ t1 = 0.0;
+ }
+ }
+
+ if (t0 <= 0.0 && t1 <= 0.0)
+ {
+ return nil;
+ }
+ if (t1 <= t0)
+ {
+ return other;
+ }
+ return self;
+}
+
- (NSString*) name
{
return _name;
@@ -1706,7 +1758,6 @@ static unsigned int maxConnections = 8;
[lock lock];
NS_DURING
{
- NSTimeInterval start = 0.0;
NSString *statement;
BOOL isCommit = NO;
BOOL isRollback = NO;
@@ -1722,10 +1773,7 @@ static unsigned int maxConnections = 8;
isRollback = YES;
}
- if (_duration >= 0)
- {
- start = GSTickerTimeNow();
- }
+ _lastStart = GSTickerTimeNow();
result = [self backendExecute: info];
_lastOperation = GSTickerTimeNow();
[_statements addObject: statement];
@@ -1733,7 +1781,7 @@ static unsigned int maxConnections = 8;
{
NSTimeInterval d;
- d = _lastOperation - start;
+ d = _lastOperation - _lastStart;
if (d >= _duration)
{
if (isCommit || isRollback)
@@ -1814,19 +1862,14 @@ static unsigned int maxConnections = 8;
[lock lock];
NS_DURING
{
- NSTimeInterval start = 0.0;
-
- if (_duration >= 0)
- {
- start = GSTickerTimeNow();
- }
+ _lastStart = GSTickerTimeNow();
result = [self backendQuery: stmt recordType: rtype listType: ltype];
_lastOperation = GSTickerTimeNow();
if (_duration >= 0)
{
NSTimeInterval d;
- d = _lastOperation - start;
+ d = _lastOperation - _lastStart;
if (d >= _duration)
{
debug = [NSString stringWithFormat:
@@ -2678,7 +2721,6 @@ static unsigned int maxConnections = 8;
{
NSMutableArray *result;
NSMutableDictionary *md;
- NSTimeInterval start;
GSCache *c;
id toCache;
@@ -2688,7 +2730,7 @@ static unsigned int maxConnections = 8;
md = [[NSThread currentThread] threadDictionary];
[md setObject: rtype forKey: @"SQLClientRecordType"];
[md setObject: ltype forKey: @"SQLClientListType"];
- start = GSTickerTimeNow();
+ _lastStart = GSTickerTimeNow();
c = [self cache];
toCache = nil;
@@ -2733,7 +2775,7 @@ static unsigned int maxConnections = 8;
{
NSTimeInterval d;
- d = _lastOperation - start;
+ d = _lastOperation - _lastStart;
if (d >= _duration)
{
[self debug: @"Duration %g for query %@", d, stmt];
diff --git a/testPostgres.m b/testPostgres.m
index 0b221e2..88ceef0 100644
--- a/testPostgres.m
+++ b/testPostgres.m
@@ -69,11 +69,13 @@ main()
nil]
];
- sp = [[SQLClientPool alloc] initWithConfiguration: nil
- name: @"test"
- max: 2
- min: 1];
- db = [[sp autorelease] provideClient];
+ sp = [[[SQLClientPool alloc] initWithConfiguration: nil
+ name: @"test"
+ max: 2
+ min: 1] autorelease];
+ db = [sp provideClient];
+ [sp swallowClient: db];
+ db = [sp provideClient];
l = [Logger new];
[[NSNotificationCenter defaultCenter] addObserver: l