Attempted deadlock fix

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@38606 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2015-06-09 16:47:36 +00:00
parent 9282a5134d
commit c47c323a7f
2 changed files with 62 additions and 5 deletions

View file

@ -1,3 +1,9 @@
2015-06-09 Richard Frith-Macdonald <rfm@gnu.org>
* 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 <rfm@gnu.org> 2015-05-28 Richard Frith-Macdonald <rfm@gnu.org>
* SQLClient.h: Add pool purge control method. * SQLClient.h: Add pool purge control method.

View file

@ -903,10 +903,15 @@ static int poolConnections = 0;
+ (void) purgeConnections: (NSDate*)since + (void) purgeConnections: (NSDate*)since
{ {
NSHashEnumerator e; NSHashEnumerator e;
NSMutableArray *a = nil;
SQLClient *o; SQLClient *o;
unsigned int connectionCount = 0; 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]; [clientsLock lock];
e = NSEnumerateHashTable(clientsHash); e = NSEnumerateHashTable(clientsHash);
while (nil != (o = (SQLClient*)NSNextHashEnumeratorItem(&e))) while (nil != (o = (SQLClient*)NSNextHashEnumeratorItem(&e)))
@ -915,12 +920,20 @@ static int poolConnections = 0;
{ {
NSTimeInterval when = o->_lastOperation; NSTimeInterval when = o->_lastOperation;
if (when < o->_lastStart)
{
when = o->_lastStart;
}
if (when < t && YES == o->connected) 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++; connectionCount++;
} }
@ -928,6 +941,40 @@ static int poolConnections = 0;
NSEndHashTableEnumeration(&e); NSEndHashTableEnumeration(&e);
[clientsLock unlock]; [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)) while (connectionCount >= (maxConnections + poolConnections))
{ {
SQLClient *other = nil; SQLClient *other = nil;
@ -942,11 +989,15 @@ static int poolConnections = 0;
{ {
NSTimeInterval when = o->_lastOperation; NSTimeInterval when = o->_lastOperation;
if (when < o->_lastStart)
{
when = o->_lastStart;
}
connectionCount++; connectionCount++;
if (oldest == 0.0 || when < oldest) if (oldest == 0.0 || when < oldest)
{ {
oldest = when; oldest = when;
other = o; ASSIGN(other, o);
} }
} }
} }
@ -959,7 +1010,7 @@ static int poolConnections = 0;
@"Force disconnect of '%@' because max connections (%u) reached", @"Force disconnect of '%@' because max connections (%u) reached",
other, maxConnections]; other, maxConnections];
} }
[other disconnect]; [AUTORELEASE(other) disconnect];
} }
} }