Author: rfm
Date: Tue Jun 24 12:30:00 2014
New Revision: 37963

URL: http://svn.gna.org/viewcvs/gnustep?rev=37963&view=rev
Log:
add missing file

Added:
    libs/sqlclient/trunk/SQLClientPool.m

Added: libs/sqlclient/trunk/SQLClientPool.m
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClientPool.m?rev=37963&view=auto
==============================================================================
--- libs/sqlclient/trunk/SQLClientPool.m        (added)
+++ libs/sqlclient/trunk/SQLClientPool.m        Tue Jun 24 12:30:00 2014
@@ -0,0 +1,412 @@
+/* -*-objc-*- */
+
+/** Implementation of SQLClientPool for GNUStep
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   
+   Written by:  Richard Frith-Macdonald <[email protected]>
+   Date:       June 2014
+   
+   This file is part of the SQLClient Library.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+   
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+
+   $Date: 2014-05-19 10:31:02 +0100 (Mon, 19 May 2014) $ $Revision: 37893 $
+   */ 
+
+#import        <Foundation/NSArray.h>
+#import        <Foundation/NSAutoreleasePool.h>
+#import        <Foundation/NSDebug.h>
+#import        <Foundation/NSException.h>
+#import        <Foundation/NSLock.h>
+#import        <Foundation/NSString.h>
+
+#import        <Performance/GSCache.h>
+#import        "SQLClient.h"
+
+
+@interface      SQLClient(Pool)
+- (void) _clearPool: (SQLClientPool*)p;
+@end
+
+@implementation SQLClient(Pool)
+- (void) _clearPool: (SQLClientPool*)p
+{
+  NSAssert(_pool == p, NSInternalInconsistencyException);
+
+  _pool = nil;
+}
+@end
+
+
+@implementation        SQLClientPool
+
+- (void) dealloc
+{
+  SQLClient     **clients;
+  BOOL          *used;
+  int           count;
+  int           i;
+
+  [lock lock];
+  count = max;
+  max = 0;
+  min = 0;
+  clients = c;
+  used = u;
+  c = 0;
+  u = 0;
+  [lock unlock];
+  DESTROY(lock);
+
+  if (0 != clients)
+    {
+      for (i = 0; i < count; i++)
+        {
+          if (YES == used[i])
+            {
+              [clients[i] _clearPool: self];
+            }
+          else
+            {
+              [clients[i] release];
+            }
+        }
+      free(clients);
+      free(used);
+    }
+  [super dealloc];
+}
+
+- (id) initWithConfiguration: (NSDictionary*)config
+                       name: (NSString*)reference
+                         max: (int)maxConnections
+                         min: (int)minConnections
+{
+  NSAssert(minConnections > 0, NSInvalidArgumentException);
+  NSAssert(maxConnections >= minConnections, NSInvalidArgumentException);
+  NSAssert(maxConnections <= 100, NSInvalidArgumentException);
+
+  if (nil != (self = [super init]))
+    {
+      GSCache   *cache = nil;
+      int       i;
+
+      max = maxConnections;
+      min = minConnections;
+      c = calloc(max, sizeof(SQLClient*));
+      u = calloc(max, sizeof(BOOL));
+      
+      for (i = 0; i < max; i++)
+        {
+          c[i] = [[SQLClient alloc] initWithConfiguration: config
+                                                     name: reference
+                                                     pool: self];
+
+          /* All the clients in the pool should share the same cache.
+           */
+          if (0 == i)
+            {
+              cache = [c[i] cache];
+            }
+          else
+            {
+              [c[i] setCache: cache];
+            }
+        }
+      /* We start the condition lock with condition '1' to indicate
+       * that there are clients ion the pool that we can provide.
+       */
+      lock = [[NSConditionLock alloc] initWithCondition: 1];
+    }
+  return self;
+}
+
+- (SQLClient*) provideClient
+{
+  return [self provideClientBeforeDate: nil];
+}
+
+- (SQLClient*) provideClientBeforeDate: (NSDate*)when
+{
+  int   connected = -1;
+  int   found = -1;
+  int   index;
+  int   cond = 0;
+
+  if (nil == when)
+    {
+      static NSDate     *future = nil;
+
+      if (nil == future)
+        {
+          future = [[NSDate distantFuture] retain];
+        }
+      when = future;
+    }
+
+  /* We want to log stuff if we don't get a client quickly.
+   * Ideally we get the lock straight away,
+   * but if not we want to log every ten seconds (and possibly
+   * when we begin waiting.
+   */
+  if (YES == [lock tryLockWhenCondition: 1])
+    {
+      _immediate++;
+    }
+  else
+    {
+      NSTimeInterval    start = [NSDate timeIntervalSinceReferenceDate];
+      NSTimeInterval    end = [when timeIntervalSinceReferenceDate];
+      NSTimeInterval    now = 0.0;
+      NSTimeInterval    dif = 0.0;
+      NSDate            *until;
+      BOOL              locked;
+
+      if (_debugging > 1)
+        {
+          NSLog(@"%@ has no clients available", self);
+        }
+      until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0];
+      locked = NO;
+      while (NO == locked && now < end)
+        {
+          if ([when earlierDate: until] == until)
+            { 
+              locked = [lock lockWhenCondition: 1 beforeDate: until];
+            }
+          else
+            { 
+              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);
+                }
+              [until release];
+              until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0];
+            }
+        }
+      [until release];
+      if (dif > _longest)
+        {
+          _longest = dif;
+        }
+      if (NO == locked)
+        {
+          if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
+            {
+              NSLog(@"%@ abandoned wait after %g seconds", self, dif);
+            }
+          _failed++;
+          _failWaits += dif;
+          return nil;
+        }
+      if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
+        {
+          NSLog(@"%@ provided client after %g seconds", self, dif);
+        }
+      _delayed++;
+      _delayWaits += dif;
+    }
+
+  for (index = 0; index < max && 0 == cond; index++)
+    {
+      if (NO == u[index])
+        {
+          if (connected >= 0 || found >= 0)
+            {
+              /* There's at least one more client available to be
+               * provided, so we want to re-lock with condition 1.
+               */
+              cond = 1;
+            }
+          if (connected < 0 && YES == [c[index] connected])
+            {
+              connected = index;
+            }
+          else
+            {
+              found = index;
+            }
+        }
+    }
+
+  /* We prefer to use a client which is already connected, so we
+   * avoid opening unnecessary connections.
+   */
+  if (connected >= 0)
+    {
+      found = connected;
+    }
+  u[found] = YES;
+  [lock unlockWithCondition: cond];
+  return [c[found] autorelease];
+}
+
+- (void) setCache: (GSCache*)aCache
+{
+  int   index;
+
+  /* We don't allow a nil cache for the pool (each client would creae its
+   * own cache on demand). So we treat a nil cache as a request to create
+   * a new cache with the default config.
+   */
+  if (nil == aCache)
+    {
+      [c[0] setCache: nil];
+      aCache = [c[0] cache];
+    }
+
+  for (index = 0; index < max; index++)
+    {
+      [c[index] setCache: aCache];
+    }
+}
+
+- (void) setCacheThread: (NSThread*)aThread
+{
+  int   index;
+
+  for (index = 0; index < max; index++)
+    {
+      [c[index] setCacheThread: aThread];
+    }
+}
+
+- (void) setDebugging: (unsigned int)level
+{
+  int   index;
+
+  _debugging = level;
+  for (index = 0; index < max; index++)
+    {
+      [c[index] setDebugging: _debugging];
+    }
+}
+
+- (void) setDurationLogging: (NSTimeInterval)threshold
+{
+  int   index;
+
+  _duration = threshold;
+  for (index = 0; index < max; index++)
+    {
+      [c[index] setDurationLogging: _duration];
+    }
+}
+
+- (NSString*) statistics
+{
+  NSString      *s;
+
+  s = [NSString stringWithFormat:
+    @"  Immediate provisions: %llu\n"
+    @"  Delayed provisions:   %llu\n"
+    @"  Timed out provisions: %llu\n"
+    @"  Slowest provision:    %g\n"
+    @"  Average delay:        %g\n"
+    @"  Average timeout:      %g\n"
+    @"  Average over all:     %g\n",
+    (unsigned long long)_immediate,
+    (unsigned long long)_delayed,
+    (unsigned long long)_failed,
+    _longest,
+    (_delayed > 0) ? _delayWaits / _delayed : 0.0,
+    (_failed > 0) ? _failWaits / _failed : 0.0,
+    (_immediate + _delayed + _failed) > 0
+      ? (_failWaits + _delayWaits) / (_immediate + _delayed + _failed)
+      : 0.0];
+  return s;
+}
+
+- (BOOL) swallowClient: (SQLClient*)client
+{
+  BOOL  found = NO;
+  int   idle = 0;
+  int   used = 0;
+  int   cond = 0;
+  int   index;
+
+  [lock lock];
+  for (index = 0; index < max; index++)
+    {
+      if (YES == u[index] && client == c[index])
+        {
+          u[index] = NO;
+          [c[index] retain];
+          found = YES;
+        }
+
+      /* Check to see if this client is free to be taken from the pool.
+       * Also, if a client is connected but not in use, we call it idle.
+       */
+      if (YES == u[index])
+        {
+          /* This is a client which has been provided by the pool,
+           * so it is in use by some code.
+           */
+          used++;
+        }
+      else
+        {
+          /* The client is not in use and can be provided by the pool,
+           * so we must therefore re-lock with condition 1.
+           */
+          cond = 1;
+
+          if (YES == [c[index] connected])
+            {
+              /* This unused client is still connected, so we count
+               * it as an idle connection.
+               */
+              idle++;
+            }
+        }
+    }
+
+  /* If we have more idle client connections than we want,
+   * disconnect the longest idle first.
+   */
+  while (idle > 0 && (used + idle) > min)
+    {
+      SQLClient *oldest = nil;
+
+      for (index = 0; index < max; index++)
+        {
+          if (NO == u[index] && YES == [c[index] connected])
+            {
+              if (nil == oldest)
+                {
+                  oldest = c[index];
+                }
+              else
+                {
+                  oldest = [oldest longestIdle: c[index]];
+                }
+            }
+        }
+      [oldest disconnect];
+      idle--;
+    }
+  [lock unlockWithCondition: cond];
+  return found;
+}
+
+@end
+


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

Reply via email to