Author: rfm
Date: Thu May 28 10:39:10 2015
New Revision: 38579

URL: http://svn.gna.org/viewcvs/gnustep?rev=38579&view=rev
Log:
Various pool management enhancements

Modified:
    libs/sqlclient/trunk/ChangeLog
    libs/sqlclient/trunk/SQLClient.h
    libs/sqlclient/trunk/SQLClient.m
    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=38579&r1=38578&r2=38579&view=diff
==============================================================================
--- libs/sqlclient/trunk/ChangeLog      (original)
+++ libs/sqlclient/trunk/ChangeLog      Thu May 28 10:39:10 2015
@@ -1,3 +1,10 @@
+2015-05-28 Richard Frith-Macdonald  <[email protected]>
+
+       * SQLClient.h: Add pool purge control method.
+       * SQLClient.m: Fix bug finding least recently used client.
+       * SQLClientPool.m: Refine purging of pool.  Fix autorelease bug.
+       Improve diagnostics.  Fix bug reporting time pool has blocked.
+
 2015-05-27 Richard Frith-Macdonald  <[email protected]>
 
        * Postgres.m: bugfixes

Modified: libs/sqlclient/trunk/SQLClient.h
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClient.h?rev=38579&r1=38578&r2=38579&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClient.h    (original)
+++ libs/sqlclient/trunk/SQLClient.h    Thu May 28 10:39:10 2015
@@ -1548,6 +1548,8 @@
   NSTimeInterval        _longest;       /** Count of longest delay */
   NSTimeInterval        _delayWaits;    /** Time waiting for provisions */
   NSTimeInterval        _failWaits;     /** Time waiting for timewouts */
+  NSTimeInterval        _purgeAll;      /** Age to purge all connections */
+  NSTimeInterval        _purgeMin;      /** Age to purge excess connections */
 }
 
 /** Returns the count of currently available connections in the pool.
@@ -1575,6 +1577,11 @@
                        name: (NSString*)reference
                          max: (int)maxConnections
                          min: (int)minConnections;
+
+/** Returns a long description of the pool including statistics and
+ * the description of a sample client.
+ */
+- (NSString*) longDescription;
 
 /** Return the maximum number of database connections in the pool.
  */
@@ -1637,6 +1644,13 @@
  * maxConnections and may not be less than 1.
  */
 - (void) setMax: (int)maxConnections min: (int)minConnections;
+
+/** Sets the ages (in seconds) after which idle connections are closed in
+ * the -purge method. Where there are excess connections (more than the
+ * minimum configured connection count) in the pool, minSeconds is used,
+ * otherwise allSeconds is used.
+ */
+- (void) setPurgeAll: (int)allSeconds min: (int)minSeconds;
 
 /** Returns a string describing the usage of the pool.
  */

Modified: libs/sqlclient/trunk/SQLClient.m
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClient.m?rev=38579&r1=38578&r2=38579&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClient.m    (original)
+++ libs/sqlclient/trunk/SQLClient.m    Thu May 28 10:39:10 2015
@@ -1444,11 +1444,11 @@
         }
     }
 
-  if (t1 > 0.0 && t1 <= t0)
+  if (t1 > 0.0 && (t1 <= t0 || 0.0 == t0))
     {
       return other;
     }
-  if (t0 > 0.0 && t0 <= t1)
+  if (t0 > 0.0 && (t0 <= t1 || 0.0 == t1))
     {
       return self;
     }

Modified: libs/sqlclient/trunk/SQLClientPool.m
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClientPool.m?rev=38579&r1=38578&r2=38579&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClientPool.m        (original)
+++ libs/sqlclient/trunk/SQLClientPool.m        Thu May 28 10:39:10 2015
@@ -37,16 +37,6 @@
 #import        <Performance/GSCache.h>
 #import        "SQLClient.h"
 
-/** Connections idle for more than this time are candidates for purging
- * as long as there are at leas min connections open.
- */
-static NSTimeInterval   purgeMinTime = 10.0;
-
-/** Connections idle for more than this time are candidates for purging
- * even if the number of open connections is less than or equal to min.
- */
-static NSTimeInterval   purgeAllTime = 300.0;
-
 @interface      SQLClient(Pool)
 - (void) _clearPool: (SQLClientPool*)p;
 @end
@@ -132,13 +122,7 @@
 
 - (NSString*) description
 {
-  NSMutableString      *s = [[NSMutableString new] autorelease];
-
-  [s appendString: [super description]];
-  [s appendFormat: @"name:'%@', max:%d, min:%d\n", _name, max, min];
-  [s appendString: [self statistics]];
-  [s appendString: [q description]];
-  return s;
+  return [NSString stringWithFormat: @"%@ '%@'", [super description], _name];
 }
 
 - (id) initWithConfiguration: (NSDictionary*)config
@@ -148,6 +132,7 @@
 {
   if (nil != (self = [super init]))
     {
+      CREATE_AUTORELEASE_POOL(arp);
       ASSIGN(_config, config);
       ASSIGNCOPY(_name, reference);
       lock = [[NSConditionLock alloc] initWithCondition: 0];
@@ -156,10 +141,22 @@
        * available for general use since quoting does not actually
        * require any database operation.
        */
-      q = [[self provideClient] retain];
+      q = RETAIN([self provideClient]);
       [self swallowClient: q];
+      RELEASE(arp);
     }
   return self;
+}
+
+- (NSString*) longDescription
+{
+  NSMutableString      *s = [[NSMutableString new] autorelease];
+
+  [s appendString: [self description]];
+  [s appendFormat: @", max:%d, min:%d\n", max, min];
+  [s appendString: [self statistics]];
+  [s appendString: [q description]];
+  return s;
 }
 
 - (int) maxConnections
@@ -193,7 +190,7 @@
 
       if (nil == future)
         {
-          future = [[NSDate distantFuture] retain];
+          future = RETAIN([NSDate distantFuture]);
         }
       when = future;
     }
@@ -218,13 +215,14 @@
 
       if (_debugging > 1)
         {
-          NSLog(@"%@ has no clients available", self);
-        }
-      until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0];
+          NSLog(@"%@ has no clients available", [self description]);
+        }
+      now = [NSDate timeIntervalSinceReferenceDate];
+      until = [[NSDate alloc]
+        initWithTimeIntervalSinceReferenceDate: now + 10.0];
       locked = NO;
       while (NO == locked && now < end)
         {
-          now = [NSDate timeIntervalSinceReferenceDate];
           if (now >= end)
             {
               /* End date is passed ... try to get the lock immediately.
@@ -239,12 +237,14 @@
             { 
               locked = [lock lockWhenCondition: 1 beforeDate: when];
             }
+          now = [NSDate timeIntervalSinceReferenceDate];
           dif = now - start;
           if (NO == locked && now < end)
             {
               if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
                 {
-                  NSLog(@"%@ still waiting after %g seconds", self, dif);
+                  NSLog(@"%@ still waiting after %g seconds",
+                    [self description], dif);
                 }
               [until release];
               until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0];
@@ -259,7 +259,8 @@
         {
           if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
             {
-              NSLog(@"%@ abandoned wait after %g seconds", self, dif);
+              NSLog(@"%@ abandoned wait after %g seconds",
+                [self description], dif);
             }
           _failed++;
           _failWaits += dif;
@@ -267,7 +268,8 @@
         }
       if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
         {
-          NSLog(@"%@ provided client after %g seconds", self, dif);
+          NSLog(@"%@ provided client after %g seconds",
+            [self description], dif);
         }
       _delayed++;
       _delayWaits += dif;
@@ -306,7 +308,7 @@
   [lock unlockWithCondition: cond];
   if (_debugging > 2)
     {
-      NSLog(@"%@ provides %p", self, c[found]);
+      NSLog(@"%@ provides %p", [self description], c[found]);
     }
   return [c[found] autorelease];
 }
@@ -344,8 +346,13 @@
           NSTimeInterval        age;
 
           age = -[[found lastOperation] timeIntervalSinceNow];
-          if (age > purgeAllTime
-            || (connected > min && age > purgeMinTime))
+          if (_debugging > 2)
+            {
+              NSLog(@"%@ purge found %p age %g",
+                [self description], found, age);
+            }
+          if (age > _purgeAll
+            || (connected > min && age > _purgeMin))
             {
               NS_DURING
                 {
@@ -480,6 +487,24 @@
     }
   min = minConnections;
   [self _unlock];
+}
+
+- (void) setPurgeAll: (int)allSeconds min: (int)minSeconds
+{
+  if (allSeconds < 1)
+    {
+      allSeconds = 300;
+    }
+  if (minSeconds < 1)
+    {
+      minSeconds = 10;
+    }
+  if (allSeconds < minSeconds)
+    {
+      allSeconds = minSeconds;
+    }
+  _purgeMin = minSeconds;
+  _purgeAll = allSeconds;
 }
 
 - (NSString*) statistics
@@ -508,11 +533,30 @@
 
 - (BOOL) swallowClient: (SQLClient*)client
 {
-  BOOL  disconnected = NO;
-  BOOL  replaced = NO;
   BOOL  found = NO;
   int   index;
 
+  if (YES == [client isInTransaction])
+    {
+      /* The client has a transaction in progress ... if it's in the
+       * current thread we should be able to disconnect (implicit rollback)
+       * and return the client to the pool, otherwise we raise an exception.
+       */
+      if (YES == [client lockBeforeDate: nil])
+        {
+          [client disconnect];
+          [client unlock];
+          NSLog(@"ERROR: Disconnected client which was returned to pool"
+            @" while a transaction was in progress: %@", client);
+        }
+      else
+        {
+          [NSException raise: SQLConnectionException
+            format: @"failed to return to pool because a transaction"
+            @" was in progress: %@", client];
+        }
+    }
+
   [self _lock];
   for (index = 0; index < max && NO == found; index++)
     {
@@ -522,46 +566,18 @@
           found = YES;
         }
     }
-  if (YES == found && YES == [client isInTransaction])
-    {
-      if (YES == [client lockBeforeDate: nil])
-        {
-          disconnected = YES;
-          [client disconnect];
-          [client unlock];
+  [self _unlock];
+
+  if (_debugging > 2)
+    {
+      if (YES == found)
+        {
+          NSLog(@"%@ swallows %p", [self description], client);
         }
       else
         {
-          replaced = YES;
-          c[index] = [[SQLClient alloc] initWithConfiguration: _config
-                                                         name: _name
-                                                         pool: self];
-        }
-    }
-  [self _unlock];
-
-  if (_debugging > 2)
-    {
-      if (YES == found)
-        {
-          NSLog(@"%@ swallows %p", self, client);
-        }
-      else
-        {
-          NSLog(@"%@ rejects %p", self, client);
-        }
-    }
-
-  if (YES == disconnected)
-    {
-      NSLog(@"ERROR: Disconnected client which was returned to pool"
-        @" while a transaction was in progress: %@", client);
-    }
-  else if (YES == replaced)
-    {
-      NSLog(@"ERROR: Replaced client which was returned to pool"
-        @" while a transaction was in progress: %@", client);
-      [client release];
+          NSLog(@"%@ rejects %p", [self description], client);
+        }
     }
 
   return found;

Modified: libs/sqlclient/trunk/testPostgres.m
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/testPostgres.m?rev=38579&r1=38578&r2=38579&view=diff
==============================================================================
--- libs/sqlclient/trunk/testPostgres.m (original)
+++ libs/sqlclient/trunk/testPostgres.m Thu May 28 10:39:10 2015
@@ -73,7 +73,7 @@
                                                 name: @"test"
                                                  max: 2
                                                  min: 1] autorelease];
-#if 0
+#if 1
 {
   NSAutoreleasePool     *p;
   SQLClient             *c0;
@@ -83,18 +83,39 @@
   p = [NSAutoreleasePool new];
   c0 = [sp provideClient];
   c1 = [sp provideClient];
+  NSLog(@"Got two clients from pool");
+  [c0 connect];
+  [c1 connect];
+  NSLog(@"Now putting clients back in pool again");
+  [sp swallowClient: c0];
+  [sp swallowClient: c1];
+  [sp setPurgeAll: 60 min: 1];
+  [NSThread sleepForTimeInterval: 1.0];
+  NSLog(@"Expecting purge to disconnect one client");
+  [sp purge];
+  c0 = [sp provideClient];
+  c1 = [sp provideClient];
+  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]];
+  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];
+  NSLog(@"Pool has provided both it's clients ... now try for another with a 
15 second timeout");
   [sp provideClientBeforeDate: [NSDate dateWithTimeIntervalSinceNow: 15.0]];
+  NSLog(@"Emptying autorelease pool again");
   [p release];
-  [sp provideClientBeforeDate: [NSDate dateWithTimeIntervalSinceNow: 25.0]];
+  NSLog(@"Expect to get client immediately");
 }
 #endif
   db = [sp provideClient];
   [sp swallowClient: db];
+
   [sp queryString: @"SELECT CURRENT_TIMESTAMP", nil];
   db = [sp provideClient];
 


_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs

Reply via email to