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

Reply via email to