Author: rfm
Date: Wed Jul 22 14:45:21 2015
New Revision: 38827
URL: http://svn.gna.org/viewcvs/gnustep?rev=38827&view=rev
Log:
first attempt at allowing re-use of a client by different code layers as
long as they are in the same thread.
Modified:
libs/sqlclient/trunk/ChangeLog
libs/sqlclient/trunk/SQLClient.h
libs/sqlclient/trunk/SQLClientPool.m
libs/sqlclient/trunk/testPostgres.m
Modified: libs/sqlclient/trunk/ChangeLog
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/ChangeLog?rev=38827&r1=38826&r2=38827&view=diff
==============================================================================
--- libs/sqlclient/trunk/ChangeLog (original)
+++ libs/sqlclient/trunk/ChangeLog Wed Jul 22 14:45:21 2015
@@ -3,7 +3,15 @@
* SQLClient.h:
* SQLClientPool.m:
Change internal pool data to allow for storing reference counts and
- the threads which own each client conenction.
+ the threads which own each client connection.
+ Support exclusive and non-exclusive clients in the pool, where an
+ exclusive client is one which is only usable by the code which
+ fetched it from the pool, but a non-exclusive client may be provided
+ to other code in the same thread.
+ Change behavior of -provideClient and -provideClientBeforeDate: to
+ provide non-exclusive clients.
+ Add -provideClientExclusive and -provideClientBeforeDate:exclusive:
+ to support the old behavior.
2015-07-17 Niels Grewe <[email protected]>
Modified: libs/sqlclient/trunk/SQLClient.h
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClient.h?rev=38827&r1=38826&r2=38827&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClient.h (original)
+++ libs/sqlclient/trunk/SQLClient.h Wed Jul 22 14:45:21 2015
@@ -1635,17 +1635,36 @@
/** Fetches an (autoreleased) client from the pool.<br />
* This method blocks indefinitely waiting for a client to become
- * available in the pool.
+ * available in the pool.<br />
+ * Calls -provideClientBeforeDate:exclusive: for a date in the distant
+ * future and for a non-exclusive client.
*/
- (SQLClient*) provideClient;
+
+/** Fetches an (autoreleased) client from the pool.<br />
+ * Calls -provideClientBeforeDate:exclusive: for a non-exclusive client.
+ */
+- (SQLClient*) provideClientBeforeDate: (NSDate*)when;
/** Fetches an (autoreleased) client from the pool.<br />
* If no client is or becomes available before the specified date then
* the method returns nil.<br />
* If when is nil then a date in the distant future is used so that
- * the method will effectively wait forever to get a client.
- */
-- (SQLClient*) provideClientBeforeDate: (NSDate*)when;
+ * the method will effectively wait forever to get a client.<br />
+ * If isLocal is YES, this method provides a client which will not be
+ * used elsewhere in the same thread until/unless the calling code
+ * returns it to the pool. Otherwise (isLocal is NO), the client may
+ * be used by other code in the same thread.
+ */
+- (SQLClient*) provideClientBeforeDate: (NSDate*)when exclusive: (BOOL)isLocal;
+
+/** Fetches an (autoreleased) client from the pool.<br />
+ * This method blocks indefinitely waiting for a client to become
+ * available in the pool.<br />
+ * Calls -provideClientBeforeDate:exclusive: for a date in the distant
+ * future and for an exclusive client.
+ */
+- (SQLClient*) provideClientExclusive;
/**
* Disconnects the least recently active unused database clients in the
Modified: libs/sqlclient/trunk/SQLClientPool.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClientPool.m?rev=38827&r1=38826&r2=38827&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClientPool.m (original)
+++ libs/sqlclient/trunk/SQLClientPool.m Wed Jul 22 14:45:21 2015
@@ -112,23 +112,23 @@
_max = 0;
_min = 0;
_items = 0;
+ if (0 != old)
+ {
+ for (i = 0; i < count; i++)
+ {
+ [old[i].c _clearPool: self];
+ [old[i].o release];
+ if (0 == old[i].u)
+ {
+ [old[i].c release];
+ }
+ }
+ free(old);
+ }
[_lock unlock];
DESTROY(_lock);
DESTROY(_config);
DESTROY(_name);
- if (0 != old)
- {
- for (i = 0; i < count; i++)
- {
- [old[i].c _clearPool: self];
- [old[i].o release];
- if (0 == old[i].u)
- {
- [old[i].c release];
- }
- }
- free(old);
- }
[SQLClientPool _adjustPoolConnections: -count];
[super dealloc];
}
@@ -194,18 +194,83 @@
- (SQLClient*) provideClient
{
- return [self provideClientBeforeDate: nil];
+ return [self provideClientBeforeDate: nil exclusive: NO];
}
- (SQLClient*) provideClientBeforeDate: (NSDate*)when
{
+ return [self provideClientBeforeDate: when exclusive: NO];
+}
+
+- (SQLClient*) provideClientBeforeDate: (NSDate*)when exclusive: (BOOL)isLocal
+{
+ NSThread *thread = [NSThread currentThread];
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval now = start;
- SQLClient *client;
+ SQLClient *client = nil;
int connected = -1;
int found = -1;
int cond = 0;
int index;
+
+ /* If this is a request for a non-exclusive connection, we can simply
+ * check to see if there's already such a connection available.
+ */
+ if (NO == isLocal)
+ {
+ [_lock lock];
+ for (index = 0; index < _max; index++)
+ {
+ if (_items[index].o == thread && _items[index].u < NSNotFound)
+ {
+ connected = -1; // Ignore any other connected client
+ found = index;
+ break;
+ }
+ if (nil == _items[index].o && 0 == _items[index].u)
+ {
+ if (connected < 0 && YES == [_items[index].c connected])
+ {
+ connected = index;
+ }
+ else
+ {
+ found = index;
+ }
+ }
+ }
+ if (connected >= 0)
+ {
+ found = connected; // Prefer a connected client.
+ }
+ if (found >= 0)
+ {
+ _items[found].t = now;
+ if (0 == _items[found].u++)
+ {
+ ASSIGN(_items[found].o, thread);
+ client = [_items[found].c autorelease];
+ }
+ else
+ {
+ /* We have already provided this client, so we must retain it
+ * before we autorelease it, to keep retain counts in sync.
+ */
+ client = [[_items[found].c retain] autorelease];
+ }
+ _immediate++;
+ }
+ [self _unlock];
+ if (nil != client)
+ {
+ if (_debugging > 2)
+ {
+ NSLog(@"%@ provides %p%@",
+ self, _items[found].c, [self _rc: client]);
+ }
+ return 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.
@@ -329,8 +394,16 @@
{
found = connected;
}
- _items[found].u++;
+ if (YES == isLocal)
+ {
+ _items[found].u = NSNotFound;
+ }
+ else
+ {
+ _items[found].u++;
+ }
_items[found].t = now;
+ ASSIGN(_items[found].o, thread);
[self _unlock];
client = [_items[found].c autorelease];
if (_debugging > 2)
@@ -338,6 +411,11 @@
NSLog(@"%@ provides %p%@", self, _items[found].c, [self _rc: client]);
}
return client;
+}
+
+- (SQLClient*) provideClientExclusive
+{
+ return [self provideClientBeforeDate: nil exclusive: YES];
}
- (void) purge
@@ -700,11 +778,32 @@
{
if (_items[index].u > 0 && client == _items[index].c)
{
- _items[index].u--;
found = YES;
if (YES == shouldRetain)
{
NSIncrementExtraRefCount(client);
+ if (NSNotFound == _items[index].u)
+ {
+ /* This was exclusively owned, so now it must not be
+ * owned by any thread.
+ */
+ _items[index].u = 0;
+ }
+ else
+ {
+ _items[index].u--;
+ }
+ }
+ else
+ {
+ /* Nothing is using this client connection any more (it had
+ * -dealloc called), so we know the count must be zero.
+ */
+ _items[index].u = 0;
+ }
+ if (0 == _items[index].u)
+ {
+ DESTROY(_items[index].o);
}
}
}
Modified: libs/sqlclient/trunk/testPostgres.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/testPostgres.m?rev=38827&r1=38826&r2=38827&view=diff
==============================================================================
--- libs/sqlclient/trunk/testPostgres.m (original)
+++ libs/sqlclient/trunk/testPostgres.m Wed Jul 22 14:45:21 2015
@@ -76,13 +76,14 @@
#if 1
{
NSAutoreleasePool *p;
+ NSAutoreleasePool *q;
SQLClient *c0;
SQLClient *c1;
[sp setDebugging: 4];
p = [NSAutoreleasePool new];
- c0 = [sp provideClient];
- c1 = [sp provideClient];
+ c0 = [sp provideClientExclusive];
+ c1 = [sp provideClientExclusive];
NSLog(@"Got two clients from pool");
[c0 connect];
[c1 connect];
@@ -96,31 +97,46 @@
[NSThread sleepForTimeInterval: 1.0];
NSLog(@"Expecting purge to disconnect one client");
[sp purge];
- c0 = [sp provideClient];
- c1 = [sp provideClient];
+ c0 = [sp provideClientExclusive];
+ c1 = [sp provideClientExclusive];
NSLog(@"Expecting connected: %@", [c0 connected] ? @"YES" : @"NO");
NSLog(@"Expecting not connected: %@", [c1 connected] ? @"NO" : @"YES");
NSLog(@"Pool has provided both it's clients ... now try for another with a
15 second timeout");
- [sp provideClientBeforeDate: [NSDate dateWithTimeIntervalSinceNow: 15.0]];
+ [sp provideClientBeforeDate: [NSDate dateWithTimeIntervalSinceNow: 15.0]
+ exclusive: YES];
NSLog(@"Emptying autorelease pool ... clients should be put back in pool");
[p release];
p = [NSAutoreleasePool new];
NSLog(@"Getting two clients again");
- c0 = [sp provideClient];
- c1 = [sp provideClient];
+ c0 = [sp provideClientExclusive];
+ c1 = [sp provideClientExclusive];
NSLog(@"Pool has provided both it's clients ... now try for another with a
15 second timeout");
- [sp provideClientBeforeDate: [NSDate dateWithTimeIntervalSinceNow: 15.0]];
+ [sp provideClientBeforeDate: [NSDate dateWithTimeIntervalSinceNow: 15.0]
+ exclusive: YES];
NSLog(@"Emptying autorelease pool again");
[p release];
+ p = [NSAutoreleasePool new];
+ c0 = [sp provideClient];
+ q = [NSAutoreleasePool new];
+ c1 = [sp provideClient];
+ if (c0 != c1)
+ {
+ NSLog(@"ERROR was expecting provideClient to give the same object");
+ exit(1);
+ }
+ [q release];
+ [c0 connect];
+ [p release];
+
NSLog(@"Expect to get client immediately");
}
#endif
- db = [sp provideClient];
+ db = [sp provideClientExclusive];
[sp swallowClient: db];
[sp queryString: @"SELECT CURRENT_TIMESTAMP", nil];
- db = [sp provideClient];
+ db = [sp provideClientExclusive];
l = [Logger new];
[[NSNotificationCenter defaultCenter] addObserver: l
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs