diff --git a/ChangeLog b/ChangeLog index 6aafa78..89e4c2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-06-09 Richard Frith-Macdonald + + * SQLClient.m: Fix reace condition spotted by Wolfgang and change + purge operation to avoid disconnecting clients while the class lock + is locked. + 2015-05-28 Richard Frith-Macdonald * SQLClient.h: Add pool purge control method. diff --git a/SQLClient.m b/SQLClient.m index 6926b14..8872941 100644 --- a/SQLClient.m +++ b/SQLClient.m @@ -903,10 +903,15 @@ static int poolConnections = 0; + (void) purgeConnections: (NSDate*)since { NSHashEnumerator e; + NSMutableArray *a = nil; SQLClient *o; unsigned int connectionCount = 0; - NSTimeInterval t = [since timeIntervalSinceReferenceDate]; + NSTimeInterval t; + t = (nil == since) ? 0.0 : [since timeIntervalSinceReferenceDate]; + + /* Find clients we may want to disconnect. + */ [clientsLock lock]; e = NSEnumerateHashTable(clientsHash); while (nil != (o = (SQLClient*)NSNextHashEnumeratorItem(&e))) @@ -915,12 +920,20 @@ static int poolConnections = 0; { NSTimeInterval when = o->_lastOperation; + if (when < o->_lastStart) + { + when = o->_lastStart; + } if (when < t && YES == o->connected) { - [o disconnect]; + if (nil == a) + { + a = [NSMutableArray array]; + } + [a addObject: o]; } } - if ([o connected] == YES) + else if ([o connected] == YES) { connectionCount++; } @@ -928,6 +941,40 @@ static int poolConnections = 0; NSEndHashTableEnumeration(&e); [clientsLock unlock]; + /* Disconnect any clients idle too long + */ + while ([a count] > 0) + { + o = [a lastObject]; + if ([o->lock tryLock]) + { + NSTimeInterval when = o->_lastOperation; + + if (when < o->_lastStart) + { + when = o->_lastStart; + } + if (when < t && YES == o->connected) + { + NS_DURING + { + [o disconnect]; + if ([o connected] == YES) + { + connectionCount++; + } + } + NS_HANDLER + { + NSLog(@"Problem disconnecting: %@", localException); + } + NS_ENDHANDLER + } + [o->lock unlock]; + } + [a removeLastObject]; + } + while (connectionCount >= (maxConnections + poolConnections)) { SQLClient *other = nil; @@ -942,11 +989,15 @@ static int poolConnections = 0; { NSTimeInterval when = o->_lastOperation; + if (when < o->_lastStart) + { + when = o->_lastStart; + } connectionCount++; if (oldest == 0.0 || when < oldest) { oldest = when; - other = o; + ASSIGN(other, o); } } } @@ -959,7 +1010,7 @@ static int poolConnections = 0; @"Force disconnect of '%@' because max connections (%u) reached", other, maxConnections]; } - [other disconnect]; + [AUTORELEASE(other) disconnect]; } }