Fix retain/release issue and add more diagnostics

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@38580 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2015-05-28 12:57:08 +00:00
parent 35ee61bad9
commit 6eee4f014a
4 changed files with 74 additions and 43 deletions

View file

@ -1534,7 +1534,6 @@ SQLCLIENT_PRIVATE
{ {
NSConditionLock *lock; /** Controls access to the pool contents */ NSConditionLock *lock; /** Controls access to the pool contents */
SQLClient **c; /** The clients of the pool. */ SQLClient **c; /** The clients of the pool. */
SQLClient *q; /** The clients used for quoting. */
BOOL *u; /** Whether the client is in use. */ BOOL *u; /** Whether the client is in use. */
int max; /** Maximum connection count */ int max; /** Maximum connection count */
int min; /** Minimum connection count */ int min; /** Minimum connection count */

View file

@ -85,6 +85,10 @@ static Class NSDateClass = Nil;
static Class NSSetClass = Nil; static Class NSSetClass = Nil;
static Class SQLClientClass = Nil; static Class SQLClientClass = Nil;
@interface SQLClientPool (Swallow)
- (BOOL) _swallowClient: (SQLClient*)client withRetain: (BOOL)shouldRetain;
@end
@implementation SQLRecordKeys @implementation SQLRecordKeys
- (NSUInteger) count - (NSUInteger) count
@ -1765,7 +1769,7 @@ static int poolConnections = 0;
{ {
if (nil != _pool) if (nil != _pool)
{ {
[_pool swallowClient: self]; [_pool _swallowClient: self withRetain: NO];
} }
else else
{ {

View file

@ -56,6 +56,7 @@
@interface SQLClientPool (Private) @interface SQLClientPool (Private)
- (void) _lock; - (void) _lock;
- (NSString*) _rc: (SQLClient*)o;
- (void) _unlock; - (void) _unlock;
@end @end
@ -81,7 +82,7 @@
- (GSCache*) cache - (GSCache*) cache
{ {
return [q cache]; return [c[0] cache];
} }
- (void) dealloc - (void) dealloc
@ -132,18 +133,10 @@
{ {
if (nil != (self = [super init])) if (nil != (self = [super init]))
{ {
CREATE_AUTORELEASE_POOL(arp);
ASSIGN(_config, config); ASSIGN(_config, config);
ASSIGNCOPY(_name, reference); ASSIGNCOPY(_name, reference);
lock = [[NSConditionLock alloc] initWithCondition: 0]; lock = [[NSConditionLock alloc] initWithCondition: 0];
[self setMax: maxConnections min: minConnections]; [self setMax: maxConnections min: minConnections];
/* Get a client to be used for quoting ... we can then make it
* available for general use since quoting does not actually
* require any database operation.
*/
q = RETAIN([self provideClient]);
[self swallowClient: q];
RELEASE(arp);
} }
return self; return self;
} }
@ -155,7 +148,7 @@
[s appendString: [self description]]; [s appendString: [self description]];
[s appendFormat: @", max:%d, min:%d\n", max, min]; [s appendFormat: @", max:%d, min:%d\n", max, min];
[s appendString: [self statistics]]; [s appendString: [self statistics]];
[s appendString: [q description]]; [s appendString: [c[0] description]];
return s; return s;
} }
@ -176,10 +169,11 @@
- (SQLClient*) provideClientBeforeDate: (NSDate*)when - (SQLClient*) provideClientBeforeDate: (NSDate*)when
{ {
int connected = -1; SQLClient *client;
int found = -1; int connected = -1;
int index; int found = -1;
int cond = 0; int index;
int cond = 0;
/* If we haven't been given a timeout, we should wait for a client /* If we haven't been given a timeout, we should wait for a client
* indefinitely ... so we set the timeout to be in the distant future. * indefinitely ... so we set the timeout to be in the distant future.
@ -215,7 +209,7 @@
if (_debugging > 1) if (_debugging > 1)
{ {
NSLog(@"%@ has no clients available", [self description]); NSLog(@"%@ has no clients available", self);
} }
now = [NSDate timeIntervalSinceReferenceDate]; now = [NSDate timeIntervalSinceReferenceDate];
until = [[NSDate alloc] until = [[NSDate alloc]
@ -244,7 +238,7 @@
if (_debugging > 0 || (_duration >= 0.0 && dif > _duration)) if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
{ {
NSLog(@"%@ still waiting after %g seconds", NSLog(@"%@ still waiting after %g seconds",
[self description], dif); self, dif);
} }
[until release]; [until release];
until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0]; until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0];
@ -260,7 +254,7 @@
if (_debugging > 0 || (_duration >= 0.0 && dif > _duration)) if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
{ {
NSLog(@"%@ abandoned wait after %g seconds", NSLog(@"%@ abandoned wait after %g seconds",
[self description], dif); self, dif);
} }
_failed++; _failed++;
_failWaits += dif; _failWaits += dif;
@ -269,7 +263,7 @@
if (_debugging > 0 || (_duration >= 0.0 && dif > _duration)) if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
{ {
NSLog(@"%@ provided client after %g seconds", NSLog(@"%@ provided client after %g seconds",
[self description], dif); self, dif);
} }
_delayed++; _delayed++;
_delayWaits += dif; _delayWaits += dif;
@ -306,11 +300,12 @@
} }
u[found] = YES; u[found] = YES;
[lock unlockWithCondition: cond]; [lock unlockWithCondition: cond];
client = [c[found] autorelease];
if (_debugging > 2) if (_debugging > 2)
{ {
NSLog(@"%@ provides %p", [self description], c[found]); NSLog(@"%@ provides %p%@", self, c[found], [self _rc: client]);
} }
return [c[found] autorelease]; return client;
} }
- (void) purge - (void) purge
@ -349,7 +344,7 @@
if (_debugging > 2) if (_debugging > 2)
{ {
NSLog(@"%@ purge found %p age %g", NSLog(@"%@ purge found %p age %g",
[self description], found, age); self, found, age);
} }
if (age > _purgeAll if (age > _purgeAll
|| (connected > min && age > _purgeMin)) || (connected > min && age > _purgeMin))
@ -531,7 +526,7 @@
return s; return s;
} }
- (BOOL) swallowClient: (SQLClient*)client - (BOOL) _swallowClient: (SQLClient*)client withRetain: (BOOL)shouldRetain
{ {
BOOL found = NO; BOOL found = NO;
int index; int index;
@ -564,6 +559,10 @@
{ {
u[index] = NO; u[index] = NO;
found = YES; found = YES;
if (YES == shouldRetain)
{
NSIncrementExtraRefCount(client);
}
} }
} }
[self _unlock]; [self _unlock];
@ -572,17 +571,21 @@
{ {
if (YES == found) if (YES == found)
{ {
NSLog(@"%@ swallows %p", [self description], client); NSLog(@"%@ swallows %p%@", self, client, [self _rc: client]);
} }
else else
{ {
NSLog(@"%@ rejects %p", [self description], client); NSLog(@"%@ rejects %p%@", self, client, [self _rc: client]);
} }
} }
return found; return found;
} }
- (BOOL) swallowClient: (SQLClient*)client
{
return [self _swallowClient: client withRetain: YES];
}
@end @end
@implementation SQLClientPool (Private) @implementation SQLClientPool (Private)
@ -592,6 +595,28 @@
[lock lock]; [lock lock];
} }
- (NSString*) _rc: (SQLClient*)o
{
#if defined(GNUSTEP)
if (_debugging > 3)
{
static Class cls = Nil;
unsigned long rc;
unsigned long ac;
if (Nil == cls)
{
cls = [NSAutoreleasePool class];
}
rc = (unsigned long)[o retainCount];
ac = (unsigned long)[cls autoreleaseCountForObject: o];
return [NSString stringWithFormat: @" refs %ld (%lu-%lu)",
rc - ac, rc, ac];
}
#endif
return @"";
}
- (void) _unlock - (void) _unlock
{ {
int idle = 0; int idle = 0;
@ -660,7 +685,7 @@
* First check validity and concatenate parts of the query. * First check validity and concatenate parts of the query.
*/ */
va_start (ap, stmt); va_start (ap, stmt);
sql = [[q prepare: stmt args: ap] objectAtIndex: 0]; sql = [[c[0] prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap); va_end (ap);
return sql; return sql;
@ -668,7 +693,7 @@
- (NSString*) buildQuery: (NSString*)stmt with: (NSDictionary*)values - (NSString*) buildQuery: (NSString*)stmt with: (NSDictionary*)values
{ {
NSString *result = [q buildQuery: stmt with: values]; NSString *result = [c[0] buildQuery: stmt with: values];
return result; return result;
} }
@ -681,7 +706,7 @@
va_list ap; va_list ap;
va_start (ap, stmt); va_start (ap, stmt);
stmt = [[q prepare: stmt args: ap] objectAtIndex: 0]; stmt = [[c[0] prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap); va_end (ap);
db = [self provideClient]; db = [self provideClient];
@ -764,7 +789,7 @@
va_list ap; va_list ap;
va_start (ap, stmt); va_start (ap, stmt);
info = [q prepare: stmt args: ap]; info = [c[0] prepare: stmt args: ap];
va_end (ap); va_end (ap);
db = [self provideClient]; db = [self provideClient];
NS_DURING NS_DURING
@ -803,7 +828,7 @@
* First check validity and concatenate parts of the query. * First check validity and concatenate parts of the query.
*/ */
va_start (ap, stmt); va_start (ap, stmt);
stmt = [[q prepare: stmt args: ap] objectAtIndex: 0]; stmt = [[c[0] prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap); va_end (ap);
db = [self provideClient]; db = [self provideClient];
@ -842,7 +867,7 @@
va_list ap; va_list ap;
va_start (ap, stmt); va_start (ap, stmt);
stmt = [[q prepare: stmt args: ap] objectAtIndex: 0]; stmt = [[c[0] prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap); va_end (ap);
db = [self provideClient]; db = [self provideClient];
@ -876,7 +901,7 @@
va_list ap; va_list ap;
va_start (ap, stmt); va_start (ap, stmt);
stmt = [[q prepare: stmt args: ap] objectAtIndex: 0]; stmt = [[c[0] prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap); va_end (ap);
db = [self provideClient]; db = [self provideClient];
@ -909,7 +934,7 @@
- (NSString*) quote: (id)obj - (NSString*) quote: (id)obj
{ {
NSString *result = [q quote: obj]; NSString *result = [c[0] quote: obj];
return result; return result;
} }
@ -920,7 +945,7 @@
{ {
NSMutableString *result; NSMutableString *result;
result = [q quoteArray: a toString:s quotingStrings: _q]; result = [c[0] quoteArray: a toString:s quotingStrings: _q];
return result; return result;
} }
@ -935,49 +960,49 @@
str = [[NSString allocWithZone: NSDefaultMallocZone()] str = [[NSString allocWithZone: NSDefaultMallocZone()]
initWithFormat: fmt arguments: ap]; initWithFormat: fmt arguments: ap];
va_end(ap); va_end(ap);
quoted = [q quoteString: str]; quoted = [c[0] quoteString: str];
[str release]; [str release];
return quoted; return quoted;
} }
- (NSString*) quoteBigInteger: (int64_t)i - (NSString*) quoteBigInteger: (int64_t)i
{ {
NSString *result = [q quoteBigInteger: i]; NSString *result = [c[0] quoteBigInteger: i];
return result; return result;
} }
- (NSString*) quoteCString: (const char *)s - (NSString*) quoteCString: (const char *)s
{ {
NSString *result = [q quoteCString: s]; NSString *result = [c[0] quoteCString: s];
return result; return result;
} }
- (NSString*) quoteChar: (char)chr - (NSString*) quoteChar: (char)chr
{ {
NSString *result = [q quoteChar: chr]; NSString *result = [c[0] quoteChar: chr];
return result; return result;
} }
- (NSString*) quoteFloat: (float)f - (NSString*) quoteFloat: (float)f
{ {
NSString *result = [q quoteFloat: f]; NSString *result = [c[0] quoteFloat: f];
return result; return result;
} }
- (NSString*) quoteInteger: (int)i - (NSString*) quoteInteger: (int)i
{ {
NSString *result = [q quoteInteger: i]; NSString *result = [c[0] quoteInteger: i];
return result; return result;
} }
- (NSString*) quoteString: (NSString *)s - (NSString*) quoteString: (NSString *)s
{ {
NSString *result = [q quoteString: s]; NSString *result = [c[0] quoteString: s];
return result; return result;
} }

View file

@ -79,7 +79,7 @@ main()
SQLClient *c0; SQLClient *c0;
SQLClient *c1; SQLClient *c1;
[sp setDebugging: 2]; [sp setDebugging: 4];
p = [NSAutoreleasePool new]; p = [NSAutoreleasePool new];
c0 = [sp provideClient]; c0 = [sp provideClient];
c1 = [sp provideClient]; c1 = [sp provideClient];
@ -89,6 +89,9 @@ main()
NSLog(@"Now putting clients back in pool again"); NSLog(@"Now putting clients back in pool again");
[sp swallowClient: c0]; [sp swallowClient: c0];
[sp swallowClient: c1]; [sp swallowClient: c1];
NSLog(@"And emptying autorelease pool");
[p release];
p = [NSAutoreleasePool new];
[sp setPurgeAll: 60 min: 1]; [sp setPurgeAll: 60 min: 1];
[NSThread sleepForTimeInterval: 1.0]; [NSThread sleepForTimeInterval: 1.0];
NSLog(@"Expecting purge to disconnect one client"); NSLog(@"Expecting purge to disconnect one client");