2007-10-03 00:03:27 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 2004-2005 SKYRIX Software AG
|
|
|
|
|
|
|
|
This file is part of OpenGroupware.org.
|
|
|
|
|
|
|
|
OGo 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 2, or (at your option) any
|
|
|
|
later version.
|
|
|
|
|
|
|
|
OGo 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 OGo; see the file COPYING. If not, write to the
|
|
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2008-12-12 18:57:23 +01:00
|
|
|
#import <Foundation/NSArray.h>
|
|
|
|
#import <Foundation/NSCalendarDate.h>
|
|
|
|
#import <Foundation/NSDictionary.h>
|
|
|
|
#import <Foundation/NSEnumerator.h>
|
2008-12-12 19:55:12 +01:00
|
|
|
#import <Foundation/NSLock.h>
|
2008-12-12 18:57:23 +01:00
|
|
|
#import <Foundation/NSTimer.h>
|
|
|
|
#import <Foundation/NSUserDefaults.h>
|
2009-03-20 18:34:35 +01:00
|
|
|
#import <Foundation/NSValue.h>
|
2008-12-12 18:57:23 +01:00
|
|
|
|
|
|
|
#import <NGExtensions/NSNull+misc.h>
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
|
|
|
|
|
|
|
#import <GDLAccess/EOAdaptor.h>
|
|
|
|
#import <GDLAccess/EOAdaptorContext.h>
|
|
|
|
#import <GDLAccess/EOAdaptorChannel.h>
|
|
|
|
|
|
|
|
#import "GCSChannelManager.h"
|
|
|
|
#import "NSURL+GCS.h"
|
|
|
|
#import "EOAdaptorChannel+GCS.h"
|
2007-10-03 00:03:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
TODO:
|
|
|
|
- implemented pooling
|
2008-12-12 18:32:14 +01:00
|
|
|
- auto-close channels which are very old?!
|
|
|
|
(eg missing release due to an exception)
|
2007-10-03 00:03:27 +02:00
|
|
|
*/
|
|
|
|
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
static NSLock *channelLock;
|
|
|
|
static NSLock *adaptorLock;
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
@interface GCSChannelHandle : NSObject
|
|
|
|
{
|
|
|
|
@public
|
2008-12-12 18:32:14 +01:00
|
|
|
NSURL *url;
|
2007-10-03 00:03:27 +02:00
|
|
|
EOAdaptorChannel *channel;
|
2008-12-12 18:32:14 +01:00
|
|
|
NSDate *creationTime;
|
|
|
|
NSDate *lastReleaseTime;
|
|
|
|
NSDate *lastAcquireTime;
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (EOAdaptorChannel *) channel;
|
|
|
|
- (BOOL) canHandleURL: (NSURL *) _url;
|
|
|
|
- (NSTimeInterval) age;
|
2007-10-03 00:03:27 +02:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation GCSChannelManager
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
static BOOL debugOn = NO;
|
|
|
|
static BOOL debugPools = NO;
|
|
|
|
static int ChannelExpireAge = 180;
|
2007-10-03 00:03:27 +02:00
|
|
|
static NSTimeInterval ChannelCollectionTimer = 5 * 60;
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
debugOn = [ud boolForKey: @"GCSChannelManagerDebugEnabled"];
|
|
|
|
debugPools = [ud boolForKey: @"GCSChannelManagerPoolDebugEnabled"];
|
|
|
|
|
|
|
|
ChannelExpireAge = [[ud objectForKey: @"GCSChannelExpireAge"] intValue];
|
2007-10-03 00:03:27 +02:00
|
|
|
if (ChannelExpireAge < 1)
|
|
|
|
ChannelExpireAge = 180;
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
ChannelCollectionTimer =
|
|
|
|
[[ud objectForKey: @"GCSChannelCollectionTimer"] intValue];
|
2007-10-03 00:03:27 +02:00
|
|
|
if (ChannelCollectionTimer < 1)
|
|
|
|
ChannelCollectionTimer = 5*60;
|
2008-12-12 19:55:12 +01:00
|
|
|
|
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
channelLock = [NSLock new];
|
|
|
|
adaptorLock = [NSLock new];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
+ (NSString *) adaptorNameForURLScheme: (NSString *) _scheme
|
|
|
|
{
|
|
|
|
// TODO: map scheme to adaptors (eg 'postgresql: //' to PostgreSQL
|
2007-10-03 00:03:27 +02:00
|
|
|
return @"PostgreSQL";
|
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
+ (id) defaultChannelManager
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
static GCSChannelManager *cm = nil;
|
2008-12-12 18:32:14 +01:00
|
|
|
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock lock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
if (!cm)
|
|
|
|
cm = [self new];
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock unlock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
return cm;
|
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if ((self = [super init]))
|
|
|
|
{
|
|
|
|
urlToAdaptor = [[NSMutableDictionary alloc] initWithCapacity: 4];
|
|
|
|
availableChannels = [[NSMutableArray alloc] initWithCapacity: 16];
|
|
|
|
busyChannels = [[NSMutableArray alloc] initWithCapacity: 16];
|
|
|
|
|
|
|
|
gcTimer = [[NSTimer scheduledTimerWithTimeInterval:
|
|
|
|
ChannelCollectionTimer
|
2008-12-19 17:13:29 +01:00
|
|
|
target: self selector: @selector (_garbageCollect:)
|
2008-12-12 18:32:14 +01:00
|
|
|
userInfo: nil repeats: YES] retain];
|
|
|
|
}
|
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
if (gcTimer)
|
|
|
|
[gcTimer invalidate];
|
2007-10-03 00:03:27 +02:00
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
[busyChannels release];
|
|
|
|
[availableChannels release];
|
|
|
|
[urlToAdaptor release];
|
2007-10-03 00:03:27 +02:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DB key */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (NSString *) databaseKeyForURL: (NSURL *) _url
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
/*
|
|
|
|
We need to build a proper key that omits passwords and URL path components
|
|
|
|
which are not required.
|
|
|
|
*/
|
|
|
|
NSString *key;
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
key = [NSString stringWithFormat: @"%@\n%@\n%@\n%@",
|
2007-10-03 00:03:27 +02:00
|
|
|
[_url host], [_url port],
|
|
|
|
[_url user], [_url gcsDatabaseName]];
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adaptors */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (NSDictionary *) connectionDictionaryForURL: (NSURL *) _url
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
NSMutableDictionary *md;
|
|
|
|
id tmp;
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
md = [NSMutableDictionary dictionaryWithCapacity: 4];
|
|
|
|
|
|
|
|
if ((tmp = [_url host]))
|
|
|
|
[md setObject: tmp forKey: @"hostName"];
|
|
|
|
if ((tmp = [_url port]))
|
|
|
|
[md setObject: tmp forKey: @"port"];
|
|
|
|
if ((tmp = [_url user]))
|
|
|
|
[md setObject: tmp forKey: @"userName"];
|
|
|
|
if ((tmp = [_url password]))
|
|
|
|
[md setObject: tmp forKey: @"password"];
|
|
|
|
|
|
|
|
if ((tmp = [_url gcsDatabaseName]))
|
|
|
|
[md setObject: tmp forKey: @"databaseName"];
|
|
|
|
|
|
|
|
[self debugWithFormat: @"build connection dictionary for URL %@: %@",
|
2007-10-03 00:03:27 +02:00
|
|
|
[_url absoluteString], md];
|
2008-12-12 18:32:14 +01:00
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
return md;
|
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (EOAdaptor *) adaptorForURL: (NSURL *) _url
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
EOAdaptor *adaptor;
|
2008-12-12 18:32:14 +01:00
|
|
|
NSString *key;
|
|
|
|
NSString *adaptorName;
|
|
|
|
NSDictionary *condict;
|
|
|
|
|
|
|
|
adaptor = nil;
|
|
|
|
|
|
|
|
if (_url)
|
|
|
|
{
|
|
|
|
if ((key = [self databaseKeyForURL: _url]))
|
|
|
|
{
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[adaptorLock lock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
adaptor = [urlToAdaptor objectForKey: key];
|
|
|
|
if (adaptor)
|
|
|
|
[self debugWithFormat: @"using cached adaptor: %@", adaptor];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self debugWithFormat: @"creating new adaptor for URL: %@", _url];
|
|
|
|
|
2008-12-19 17:13:29 +01:00
|
|
|
if ([EOAdaptor respondsToSelector: @selector (adaptorForURL:)])
|
2008-12-12 18:32:14 +01:00
|
|
|
adaptor = [EOAdaptor adaptorForURL: _url];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
adaptorName = [[self class]
|
|
|
|
adaptorNameForURLScheme: [_url scheme]];
|
|
|
|
if ([adaptorName length])
|
|
|
|
{
|
|
|
|
condict = [self connectionDictionaryForURL: _url];
|
|
|
|
|
|
|
|
adaptor = [EOAdaptor adaptorWithName: adaptorName];
|
|
|
|
if (adaptor)
|
|
|
|
[adaptor setConnectionDictionary: condict];
|
|
|
|
else
|
|
|
|
[self errorWithFormat:
|
|
|
|
@"did not find adaptor '%@' for URL: %@",
|
|
|
|
adaptorName, _url];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self errorWithFormat: @"cannot handle URL: %@", _url];
|
|
|
|
}
|
|
|
|
|
|
|
|
[urlToAdaptor setObject: adaptor forKey: key];
|
|
|
|
}
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[adaptorLock unlock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
}
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
2008-12-12 18:32:14 +01:00
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
return adaptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* channels */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (GCSChannelHandle *)
|
|
|
|
findBusyChannelHandleForChannel: (EOAdaptorChannel *) _ch
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
NSEnumerator *e;
|
2008-12-12 18:32:14 +01:00
|
|
|
GCSChannelHandle *handle, *currentHandle;
|
|
|
|
|
|
|
|
handle = NULL;
|
|
|
|
|
|
|
|
e = [busyChannels objectEnumerator];
|
|
|
|
while (!handle && (currentHandle = [e nextObject]))
|
|
|
|
if ([currentHandle channel] == _ch)
|
|
|
|
handle = currentHandle;
|
|
|
|
|
|
|
|
return handle;
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
- (GCSChannelHandle *) findAvailChannelHandleForURL: (NSURL *) _url
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
NSEnumerator *e;
|
2008-12-12 18:32:14 +01:00
|
|
|
GCSChannelHandle *handle, *currentHandle;
|
|
|
|
|
|
|
|
handle = nil;
|
|
|
|
|
|
|
|
e = [availableChannels objectEnumerator];
|
|
|
|
while (!handle && (currentHandle = [e nextObject]))
|
|
|
|
if ([currentHandle canHandleURL: _url])
|
|
|
|
handle = currentHandle;
|
|
|
|
else if (debugPools)
|
|
|
|
[self logWithFormat: @"DBPOOL: cannot use handle (%@ vs %@) ",
|
|
|
|
[_url absoluteString], [handle->url absoluteString]];
|
|
|
|
|
|
|
|
return handle;
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (EOAdaptorChannel *) _createChannelForURL: (NSURL *) _url
|
|
|
|
{
|
|
|
|
EOAdaptor *adaptor;
|
2007-10-03 00:03:27 +02:00
|
|
|
EOAdaptorContext *adContext;
|
|
|
|
EOAdaptorChannel *adChannel;
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
adChannel = nil;
|
|
|
|
|
|
|
|
adaptor = [self adaptorForURL: _url];
|
|
|
|
if (adaptor)
|
|
|
|
{
|
|
|
|
adContext = [adaptor createAdaptorContext];
|
|
|
|
if (adContext)
|
|
|
|
{
|
|
|
|
adChannel = [adContext createAdaptorChannel];
|
|
|
|
if (!adChannel)
|
|
|
|
[self errorWithFormat: @"could not create adaptor channel!"];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self errorWithFormat: @"could not create adaptor context!"];
|
|
|
|
}
|
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
return adChannel;
|
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (EOAdaptorChannel *) acquireOpenChannelForURL: (NSURL *) _url
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
// TODO: naive implementation, add pooling!
|
|
|
|
EOAdaptorChannel *channel;
|
|
|
|
GCSChannelHandle *handle;
|
2008-12-12 18:32:14 +01:00
|
|
|
NSCalendarDate *now;
|
|
|
|
|
|
|
|
channel = nil;
|
2007-10-03 00:03:27 +02:00
|
|
|
|
|
|
|
now = [NSCalendarDate date];
|
2008-12-12 18:32:14 +01:00
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
/* look for cached handles */
|
2008-12-12 18:32:14 +01:00
|
|
|
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock lock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
handle = [self findAvailChannelHandleForURL: _url];
|
|
|
|
if (handle)
|
|
|
|
{
|
|
|
|
// TODO: check age?
|
|
|
|
[busyChannels addObject: handle];
|
|
|
|
[availableChannels removeObject: handle];
|
|
|
|
ASSIGN (handle->lastAcquireTime, now);
|
|
|
|
|
|
|
|
channel = [handle channel];
|
|
|
|
if (debugPools)
|
|
|
|
[self logWithFormat: @"DBPOOL: reused cached DB channel! (%p)",
|
|
|
|
channel];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (debugPools)
|
|
|
|
{
|
|
|
|
[self logWithFormat: @"DBPOOL: create new DB channel for URL: %@",
|
|
|
|
[_url absoluteString]];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create channel */
|
|
|
|
channel = [self _createChannelForURL: _url];
|
|
|
|
if (channel)
|
|
|
|
{
|
|
|
|
if ([channel isOpen]
|
|
|
|
|| [channel openChannel])
|
|
|
|
{
|
|
|
|
/* create handle for channel */
|
|
|
|
|
|
|
|
handle = [[GCSChannelHandle alloc] init];
|
|
|
|
handle->url = [_url retain];
|
|
|
|
handle->channel = [channel retain];
|
|
|
|
handle->creationTime = [now retain];
|
|
|
|
handle->lastAcquireTime = [now retain];
|
|
|
|
|
|
|
|
[busyChannels addObject: handle];
|
|
|
|
[handle release];
|
|
|
|
}
|
|
|
|
else
|
2009-03-20 18:34:35 +01:00
|
|
|
{
|
|
|
|
[self errorWithFormat: @"could not open channel %@ for URL: %@",
|
|
|
|
channel, [_url absoluteString]];
|
|
|
|
channel = nil;
|
|
|
|
}
|
2008-12-12 18:32:14 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock unlock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
return channel;
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
- (void) releaseChannel: (EOAdaptorChannel *) _channel
|
2009-11-19 17:43:29 +01:00
|
|
|
{
|
|
|
|
[self releaseChannel: _channel immediately: NO];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) releaseChannel: (EOAdaptorChannel *) _channel
|
|
|
|
immediately: (BOOL) _immediately
|
2008-12-12 18:32:14 +01:00
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
GCSChannelHandle *handle;
|
2009-03-20 21:35:39 +01:00
|
|
|
BOOL keepOpen;
|
2008-12-12 18:32:14 +01:00
|
|
|
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock lock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
handle = [self findBusyChannelHandleForChannel: _channel];
|
|
|
|
if (handle)
|
|
|
|
{
|
2009-11-19 17:43:29 +01:00
|
|
|
[handle retain];
|
2008-12-12 18:32:14 +01:00
|
|
|
|
|
|
|
ASSIGN (handle->lastReleaseTime, [NSCalendarDate date]);
|
|
|
|
[busyChannels removeObject: handle];
|
|
|
|
|
2009-03-20 21:35:39 +01:00
|
|
|
keepOpen = NO;
|
2009-11-19 17:43:29 +01:00
|
|
|
if (!_immediately && [_channel isOpen]
|
|
|
|
&& [handle age] < ChannelExpireAge)
|
2008-12-12 18:32:14 +01:00
|
|
|
{
|
2009-03-20 21:35:39 +01:00
|
|
|
keepOpen = YES;
|
2008-12-12 18:32:14 +01:00
|
|
|
// TODO: consider age
|
|
|
|
[availableChannels addObject: handle];
|
|
|
|
if (debugPools)
|
|
|
|
[self logWithFormat:
|
|
|
|
@"DBPOOL: keeping channel (age %ds, #%d, %p) : %@",
|
|
|
|
(int)
|
|
|
|
[handle age], [availableChannels count],
|
|
|
|
[handle->url absoluteString],
|
|
|
|
_channel];
|
|
|
|
}
|
|
|
|
else if (debugPools)
|
2009-03-20 21:35:39 +01:00
|
|
|
{
|
|
|
|
[self logWithFormat:
|
|
|
|
@"DBPOOL: freeing old channel (age %ds, %p) ", (int)
|
|
|
|
[handle age], _channel];
|
|
|
|
}
|
|
|
|
if (!keepOpen && [_channel isOpen])
|
|
|
|
[_channel closeChannel];
|
2007-10-03 00:03:27 +02:00
|
|
|
[handle release];
|
|
|
|
}
|
2008-12-12 18:32:14 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if ([_channel isOpen])
|
|
|
|
[_channel closeChannel];
|
2007-10-03 00:03:27 +02:00
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
[_channel release];
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock unlock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* checking for tables */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (BOOL) canConnect: (NSURL *) _url
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
this can check for DB connect as well as for table URLs (whether a table
|
|
|
|
exists)
|
2007-10-03 00:03:27 +02:00
|
|
|
*/
|
|
|
|
EOAdaptorChannel *channel;
|
|
|
|
NSString *table;
|
2008-12-12 18:32:14 +01:00
|
|
|
BOOL result;
|
|
|
|
|
|
|
|
channel = [self acquireOpenChannelForURL: _url];
|
|
|
|
if (channel)
|
|
|
|
{
|
|
|
|
if (debugOn)
|
|
|
|
[self debugWithFormat: @"acquired channel: %@", channel];
|
|
|
|
|
|
|
|
/* check whether table exists */
|
|
|
|
table = [_url gcsTableName];
|
|
|
|
if ([table length] > 0)
|
|
|
|
result = [channel tableExistsWithName: table];
|
|
|
|
else
|
|
|
|
result = YES; /* could open channel */
|
|
|
|
|
|
|
|
/* release channel */
|
|
|
|
[self releaseChannel: channel];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (debugOn)
|
|
|
|
[self debugWithFormat: @"could not acquire channel: %@", _url];
|
|
|
|
result = NO;
|
|
|
|
}
|
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* collect old channels */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (void) _garbageCollect: (NSTimer *) _timer
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
NSMutableArray *handlesToRemove;
|
|
|
|
unsigned i, count;
|
2008-12-12 18:32:14 +01:00
|
|
|
GCSChannelHandle *handle;
|
|
|
|
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock lock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2008-12-12 18:32:14 +01:00
|
|
|
count = [availableChannels count];
|
|
|
|
if (count)
|
|
|
|
{
|
|
|
|
/* collect channels to expire */
|
|
|
|
|
|
|
|
handlesToRemove = [[NSMutableArray alloc] initWithCapacity: count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
handle = [availableChannels objectAtIndex: i];
|
|
|
|
if ([[handle channel] isOpen])
|
|
|
|
{
|
|
|
|
if ([handle age] > ChannelExpireAge)
|
|
|
|
[handlesToRemove addObject: handle];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[handlesToRemove addObject: handle];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove channels */
|
|
|
|
count = [handlesToRemove count];
|
|
|
|
if (debugPools)
|
|
|
|
[self logWithFormat: @"DBPOOL: garbage collecting %d channels.", count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
handle = [handlesToRemove objectAtIndex: i];
|
|
|
|
[handle retain];
|
|
|
|
[availableChannels removeObject: handle];
|
|
|
|
if ([[handle channel] isOpen])
|
|
|
|
[[handle channel] closeChannel];
|
|
|
|
[handle release];
|
|
|
|
}
|
|
|
|
|
|
|
|
[handlesToRemove release];
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
2008-12-12 19:55:12 +01:00
|
|
|
#if defined(THREADSAFE)
|
2008-12-19 17:13:29 +01:00
|
|
|
[channelLock unlock];
|
2008-12-12 19:55:12 +01:00
|
|
|
#endif
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* debugging */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (BOOL) isDebuggingEnabled
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
return debugOn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* description */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (NSString *) description
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
NSMutableString *ms;
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
ms = [NSMutableString stringWithCapacity: 256];
|
|
|
|
[ms appendFormat: @"<0x%p[%@]: ", self, NSStringFromClass ([self class])];
|
|
|
|
|
|
|
|
[ms appendFormat: @" #adaptors=%d", [urlToAdaptor count]];
|
|
|
|
|
|
|
|
[ms appendString: @">"];
|
2007-10-03 00:03:27 +02:00
|
|
|
return ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end /* GCSChannelManager */
|
|
|
|
|
|
|
|
@implementation GCSChannelHandle
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[channel release];
|
|
|
|
[creationTime release];
|
|
|
|
[lastReleaseTime release];
|
|
|
|
[lastAcquireTime release];
|
2007-10-03 00:03:27 +02:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* accessors */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (EOAdaptorChannel *) channel
|
|
|
|
{
|
|
|
|
return channel;
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (BOOL) canHandleURL: (NSURL *) _url
|
|
|
|
{
|
|
|
|
BOOL result;
|
|
|
|
|
|
|
|
result = NO;
|
|
|
|
|
|
|
|
if (_url)
|
|
|
|
{
|
|
|
|
if (_url == url
|
|
|
|
|| [[_url scheme] isEqualToString: @"sqlite"])
|
|
|
|
result = YES;
|
|
|
|
else if ([[url host] isEqual: [_url host]])
|
|
|
|
{
|
|
|
|
if ([[url gcsDatabaseName]
|
|
|
|
isEqualToString: [_url gcsDatabaseName]])
|
|
|
|
{
|
|
|
|
if ([[url user] isEqual: [_url user]])
|
|
|
|
{
|
|
|
|
if ([[url port] intValue] == [[_url port] intValue])
|
|
|
|
result = YES;
|
|
|
|
else
|
|
|
|
[self logWithFormat:
|
|
|
|
@"MISMATCH: different port (%@ vs %@) ..",
|
|
|
|
[url port], [_url port]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self logWithFormat: @"MISMATCH: different user .."];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self logWithFormat: @"MISMATCH: different db .."];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[self logWithFormat: @"MISMATCH: different host (%@ vs %@) ",
|
|
|
|
[url host], [_url host]];
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
2008-12-12 18:32:14 +01:00
|
|
|
else
|
|
|
|
[self logWithFormat: @"MISMATCH: no url .."];
|
|
|
|
|
|
|
|
return result;
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (NSTimeInterval) age
|
|
|
|
{
|
|
|
|
return [[NSCalendarDate calendarDate]
|
|
|
|
timeIntervalSinceDate: creationTime];
|
2007-10-03 00:03:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* NSCopying */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (id) copyWithZone: (NSZone *) _zone
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
return [self retain];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* description */
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
- (NSString *) description
|
|
|
|
{
|
2007-10-03 00:03:27 +02:00
|
|
|
NSMutableString *ms;
|
|
|
|
|
2008-12-12 18:32:14 +01:00
|
|
|
ms = [NSMutableString stringWithCapacity: 256];
|
|
|
|
[ms appendFormat: @"<0x%p[%@]: ", self, NSStringFromClass ([self class])];
|
|
|
|
|
|
|
|
[ms appendFormat: @" channel=0x%p", channel];
|
|
|
|
if (creationTime)
|
|
|
|
[ms appendFormat: @" created=%@", creationTime];
|
|
|
|
if (lastReleaseTime)
|
|
|
|
[ms appendFormat: @" last-released=%@", lastReleaseTime];
|
|
|
|
if (lastAcquireTime)
|
|
|
|
[ms appendFormat: @" last-acquired=%@", lastAcquireTime];
|
|
|
|
|
|
|
|
[ms appendString: @">"];
|
|
|
|
|
2007-10-03 00:03:27 +02:00
|
|
|
return ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end /* GCSChannelHandle */
|