mirror of
https://github.com/gnustep/libs-sqlclient.git
synced 2025-02-19 01:50:49 +00:00
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:
parent
35ee61bad9
commit
6eee4f014a
4 changed files with 74 additions and 43 deletions
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
105
SQLClientPool.m
105
SQLClientPool.m
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in a new issue