[CalendarServer-changes] [4586] CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Fri Oct 16 13:58:57 PDT 2009
Revision: 4586
http://trac.macosforge.org/projects/calendarserver/changeset/4586
Author: cdaboo at apple.com
Date: 2009-10-16 13:58:56 -0700 (Fri, 16 Oct 2009)
Log Message:
-----------
Use reverse proxy for partition. This adds a generic http client pooling feature which can be used
in other areas too (e.g. scheduling with other partition nodes).
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/cache.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py
Added Paths:
-----------
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/pool.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/reverseproxy.py
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/cache.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/cache.py 2009-10-16 20:33:29 UTC (rev 4585)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/cache.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -28,7 +28,7 @@
from twisted.web2.stream import MemoryStream
from twistedcaldav.log import LoggingMixIn
-from twistedcaldav.memcachepool import CachePoolUserMixIn
+from twistedcaldav.memcachepool import CachePoolUserMixIn, defaultCachePool
from twistedcaldav.config import config
@@ -163,7 +163,7 @@
self._cachePool = cachePool
- def _tokenForURI(self, uri):
+ def _tokenForURI(self, uri, cachePoolHandle=None):
"""
Get a property store for the given C{uri}.
@@ -171,13 +171,16 @@
@return: A C{str} representing the token for the URI.
"""
- return self.getCachePool().get('cacheToken:%s' % (uri,))
+ if cachePoolHandle:
+ return defaultCachePool(cachePoolHandle).get('cacheToken:%s' % (uri,))
+ else:
+ return self.getCachePool().get('cacheToken:%s' % (uri,))
def _getTokens(self, request):
def _tokensForURIs((pURI, rURI)):
tokens = []
- d1 = self._tokenForURI(pURI)
+ d1 = self._tokenForURI(pURI, "PrincipalToken")
d1.addCallback(tokens.append)
d1.addCallback(lambda _ign: self._getRecordForURI(pURI, request))
d1.addCallback(lambda dToken: tokens.append(hash(dToken)))
Added: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/__init__.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/__init__.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -0,0 +1,16 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
Added: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/pool.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/pool.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/pool.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -0,0 +1,360 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+__all__ = [
+ "installPools",
+ "installPool",
+ "getReverseProxyPool",
+]
+
+from twext.internet.ssl import ChainingOpenSSLContextFactory
+from twisted.internet.address import IPv4Address
+from twisted.internet.defer import Deferred, inlineCallbacks, returnValue
+from twisted.internet.protocol import ReconnectingClientFactory
+from twisted.web2 import responsecode
+from twisted.web2.client.http import HTTPClientProtocol
+from twisted.web2.http import StatusResponse, HTTPError
+from twistedcaldav.config import config
+from twistedcaldav.log import LoggingMixIn
+import OpenSSL
+import urlparse
+
+class ReverseProxyClientFactory(ReconnectingClientFactory, LoggingMixIn):
+ """
+ A client factory for HTTPClient that reconnects and notifies a pool of it's
+ state.
+
+ @ivar connectionPool: A managing connection pool that we notify of events.
+ @ivar deferred: A L{Deferred} that represents the initial connection.
+ @ivar _protocolInstance: The current instance of our protocol that we pass
+ to our connectionPool.
+ """
+ protocol = HTTPClientProtocol
+ connectionPool = None
+ maxRetries = 2
+
+ def __init__(self, reactor, deferred):
+ self.reactor = reactor
+ self.instance = None
+ self.deferred = deferred
+
+ def clientConnectionLost(self, connector, reason):
+ """
+ Notify the connectionPool that we've lost our connection.
+ """
+
+ if self.connectionPool.shutdown_requested:
+ # The reactor is stopping; don't reconnect
+ return
+
+ self.log_error("ReverseProxy connection lost: %s" % (reason,))
+ if self.instance is not None:
+ self.connectionPool.clientGone(self.instance)
+# if self.instance is not None:
+# self.connectionPool.clientBusy(self.instance)
+#
+# ReconnectingClientFactory.clientConnectionLost(
+# self,
+# connector,
+# reason
+# )
+
+ def clientConnectionFailed(self, connector, reason):
+ """
+ Notify the connectionPool that we're unable to connect
+ """
+ self.log_error("ReverseProxy connection failed: %s" % (reason,))
+# if self.instance is not None:
+# self.connectionPool.clientBusy(self.instance)
+
+# ReconnectingClientFactory.clientConnectionFailed(
+# self,
+# connector,
+# reason
+# )
+ if hasattr(self, "deferred"):
+ self.reactor.callLater(0, self.deferred.errback, reason)
+ del self.deferred
+
+ def buildProtocol(self, addr):
+ if self.instance is not None:
+ self.connectionPool.clientGone(self.instance)
+
+ self.instance = self.protocol()
+ self.reactor.callLater(0, self.deferred.callback, self.instance)
+ del self.deferred
+ return self.instance
+
+class ReverseProxyPool(LoggingMixIn):
+ """
+ A connection pool for HTTPClientProtocol instances.
+
+ @ivar clientFactory: The L{ClientFactory} implementation that will be used
+ for each protocol.
+
+ @ivar _maxClients: A C{int} indicating the maximum number of clients.
+ @ivar _serverAddress: An L{IAddress} provider indicating the server to
+ connect to. (Only L{IPv4Address} currently supported.)
+ @ivar _reactor: The L{IReactorTCP} provider used to initiate new
+ connections.
+
+ @ivar _busyClients: A C{set} that contains all currently busy clients.
+ @ivar _freeClients: A C{set} that contains all currently free clients.
+ @ivar _pendingConnects: A C{int} indicating how many connections are in
+ progress.
+ """
+ clientFactory = ReverseProxyClientFactory
+
+ def __init__(self, scheme, serverAddress, maxClients=5, reactor=None):
+ """
+ @param serverAddress: An L{IPv4Address} indicating the server to
+ connect to.
+ @param maxClients: A C{int} indicating the maximum number of clients.
+ @param reactor: An L{IReactorTCP{ provider used to initiate new
+ connections.
+ """
+ self._scheme = scheme
+ self._serverAddress = serverAddress
+ self._maxClients = maxClients
+
+ if reactor is None:
+ from twisted.internet import reactor
+ self._reactor = reactor
+
+ self.shutdown_deferred = None
+ self.shutdown_requested = False
+ reactor.addSystemEventTrigger('before', 'shutdown', self._shutdownCallback)
+
+ self._busyClients = set([])
+ self._freeClients = set([])
+ self._pendingConnects = 0
+ self._commands = []
+
+ def _isIdle(self):
+ return (
+ len(self._busyClients) == 0 and
+ len(self._commands) == 0 and
+ self._pendingConnects == 0
+ )
+
+ def _shutdownCallback(self):
+ self.shutdown_requested = True
+ if self._isIdle():
+ return None
+ self.shutdown_deferred = Deferred()
+ return self.shutdown_deferred
+
+ @inlineCallbacks
+ def _newClientConnection(self):
+ """
+ Create a new client connection.
+
+ @return: A L{Deferred} that fires with the L{IProtocol} instance.
+ """
+ self.log_debug("Initiating new client connection to: %s" % (self._serverAddress,))
+ self._logClientStats()
+
+ self._pendingConnects += 1
+
+ def _connected(client):
+ self._pendingConnects -= 1
+
+ return client
+
+ d = Deferred()
+ factory = self.clientFactory(self._reactor, d)
+ factory.noisy = False
+
+ factory.connectionPool = self
+
+ try:
+ if self._scheme == "https":
+ context = ChainingOpenSSLContextFactory(config.SSLPrivateKey, config.SSLCertificate, certificateChainFile=config.SSLAuthorityChain, sslmethod=getattr(OpenSSL.SSL, config.SSLMethod))
+ self._reactor.connectSSL(self._serverAddress.host, self._serverAddress.port, factory, context)
+ elif self._scheme == "http":
+ self._reactor.connectTCP(self._serverAddress.host, self._serverAddress.port, factory)
+ else:
+ raise ValueError("URL scheme for client pool not supported")
+ client = (yield d)
+ except:
+ raise HTTPError(StatusResponse(responsecode.BAD_GATEWAY, "Could not connect to reverse proxy host."))
+ finally:
+ self._pendingConnects -= 1
+ returnValue(client)
+
+ @inlineCallbacks
+ def _performRequestOnClient(self, client, request, *args, **kwargs):
+ """
+ Perform the given request on the given client.
+
+ @param client: A L{PooledMemCacheProtocol} that will be used to perform
+ the given request.
+
+ @param command: A C{str} representing an attribute of
+ L{MemCacheProtocol}.
+ @parma args: Any positional arguments that should be passed to
+ C{command}.
+ @param kwargs: Any keyword arguments that should be passed to
+ C{command}.
+
+ @return: A L{Deferred} that fires with the result of the given command.
+ """
+
+ self.clientBusy(client)
+ try:
+ response = (yield client.submitRequest(request, closeAfter=False))
+ finally:
+ self.clientFree(client)
+
+ returnValue(response)
+
+ @inlineCallbacks
+ def submitRequest(self, request, *args, **kwargs):
+ """
+ Select an available client and perform the given request on it.
+
+ @param command: A C{str} representing an attribute of
+ L{MemCacheProtocol}.
+ @parma args: Any positional arguments that should be passed to
+ C{command}.
+ @param kwargs: Any keyword arguments that should be passed to
+ C{command}.
+
+ @return: A L{Deferred} that fires with the result of the given command.
+ """
+
+ client = None
+ if len(self._freeClients) > 0:
+ client = self._freeClients.pop()
+
+ elif len(self._busyClients) + self._pendingConnects >= self._maxClients:
+ d = Deferred()
+ self._commands.append((d, request, args, kwargs))
+ self.log_debug("Request queued: %s, %r, %r" % (request, args, kwargs))
+ self._logClientStats()
+ response = (yield d)
+ else:
+ client = (yield self._newClientConnection())
+
+ if client:
+ response = (yield self._performRequestOnClient(client, request, *args, **kwargs))
+
+ returnValue(response)
+
+ def _logClientStats(self):
+ self.log_debug("Clients #free: %d, #busy: %d, "
+ "#pending: %d, #queued: %d" % (
+ len(self._freeClients),
+ len(self._busyClients),
+ self._pendingConnects,
+ len(self._commands)))
+
+ def clientGone(self, client):
+ """
+ Notify that the given client is to be removed from the pool completely.
+
+ @param client: An instance of L{PooledMemCacheProtocol}.
+ """
+ if client in self._busyClients:
+ self._busyClients.remove(client)
+
+ elif client in self._freeClients:
+ self._freeClients.remove(client)
+
+ self.log_debug("Removed client: %r" % (client,))
+ self._logClientStats()
+
+ def clientBusy(self, client):
+ """
+ Notify that the given client is being used to complete a request.
+
+ @param client: An instance of C{self.clientFactory}
+ """
+
+ if client in self._freeClients:
+ self._freeClients.remove(client)
+
+ self._busyClients.add(client)
+
+ self.log_debug("Busied client: %r" % (client,))
+ self._logClientStats()
+
+ def clientFree(self, client):
+ """
+ Notify that the given client is free to handle more requests.
+
+ @param client: An instance of C{self.clientFactory}
+ """
+ if client in self._busyClients:
+ self._busyClients.remove(client)
+
+ self._freeClients.add(client)
+
+ if self.shutdown_deferred and self._isIdle():
+ self.shutdown_deferred.callback(None)
+
+ if len(self._commands) > 0:
+ d, command, args, kwargs = self._commands.pop(0)
+
+ self.log_debug("Performing Queued Command: %s, %r, %r" % (
+ command, args, kwargs))
+ self._logClientStats()
+
+ _ign_d = self.performRequest(command, *args, **kwargs)
+
+ _ign_d.addCallback(d.callback)
+
+ self.log_debug("Freed client: %r" % (client,))
+ self._logClientStats()
+
+ def suggestMaxClients(self, maxClients):
+ """
+ Suggest the maximum number of concurrently connected clients.
+
+ @param maxClients: A C{int} indicating how many client connections we
+ should keep open.
+ """
+ self._maxClients = maxClients
+
+_clientPools = {} # Maps a host:port to a pool object
+
+def installPools(hosts, maxClients=5, reactor=None):
+
+ for name, url in hosts:
+ installPool(
+ name,
+ url,
+ maxClients,
+ reactor,
+ )
+
+def installPool(name, url, maxClients=5, reactor=None):
+
+ parsedURL = urlparse.urlparse(url)
+ pool = ReverseProxyPool(
+ parsedURL.scheme,
+ IPv4Address(
+ "TCP",
+ parsedURL.hostname,
+ parsedURL.port,
+ ),
+ maxClients,
+ reactor,
+ )
+ _clientPools[name] = pool
+
+def getReverseProxyPool(name):
+ return _clientPools[name]
Added: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/reverseproxy.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/reverseproxy.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/client/reverseproxy.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -0,0 +1,70 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+__all__ = [
+ "ReverseProxyResource",
+]
+
+from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.web2 import iweb
+from twisted.web2.client.http import ClientRequest
+from twisted.web2.resource import LeafResource
+
+from twistedcaldav.client.pool import getReverseProxyPool
+from twistedcaldav.log import LoggingMixIn
+
+import urllib
+from zope.interface.declarations import implements
+
+class ReverseProxyResource(LeafResource, LoggingMixIn):
+ """
+ A L{LeafResource} which always performs a reverse proxy operation.
+ """
+ implements(iweb.IResource)
+
+ def __init__(self, poolID, *args, **kwargs):
+ """
+
+ @param poolID: idenitifier of the pool to use
+ @type poolID: C{str}
+ """
+
+ self.poolID = poolID
+ self._args = args
+ self._kwargs = kwargs
+
+ def isCollection(self):
+ return True
+
+ def exists(self):
+ return False
+
+ @inlineCallbacks
+ def renderHTTP(self, request):
+ """
+ Do the reverse proxy request and return the response.
+
+ @param request: the incoming request that needs to be proxied.
+ @type request: L{Request}
+
+ @return: Deferred L{Response}
+ """
+
+ self.logger.info("%s %s %s" % (request.method, urllib.unquote(request.uri), "HTTP/%s.%s" % request.clientproto))
+ clientPool = getReverseProxyPool(self.poolID)
+ proxyRequest = ClientRequest(request.method, request.uri, request.headers, request.stream)
+ response = (yield clientPool.submitRequest(proxyRequest))
+ returnValue(response)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py 2009-10-16 20:33:29 UTC (rev 4585)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -399,7 +399,7 @@
return None
def locallyHosted(self):
- return not self.hostedAt or not config.EnablePartitions or self.hostedAt == config.ServerPartitionID
+ return not self.hostedAt or not config.Partitioning.Enabled or self.hostedAt == config.Partitioning.ServerPartitionID
def hostedURL(self):
return partitions.getPartitionURL(self.hostedAt)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py 2009-10-16 20:33:29 UTC (rev 4585)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -883,8 +883,6 @@
url = home.url()
if name:
url = joinURL(url, name)
- if not self.locallyHosted():
- url = joinURL(self.hostedURL(), url)
return url
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py 2009-10-16 20:33:29 UTC (rev 4585)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -14,8 +14,9 @@
# limitations under the License.
##
+from twext.python.plistlib import readPlist
+from twistedcaldav.client.pool import installPool
from twistedcaldav.log import Logger
-from twext.python.plistlib import readPlist
"""
Collection of classes for managing partition information for a group of servers.
@@ -32,6 +33,7 @@
def clear(self):
self.partitions = {}
self.ownUID = ""
+ self.maxClients = 5
def readConfig(self, plistpath):
try:
@@ -49,8 +51,21 @@
def setSelfPartition(self, uid):
self.ownUID = uid
+ def setMaxClients(self, maxClients):
+ self.maxClients = maxClients
+
def getPartitionURL(self, uid):
# When the UID matches this server return an empty string
return self.partitions.get(uid, None) if uid != self.ownUID else ""
+ def installReverseProxies(self):
+
+ for partition, url in self.partitions.iteritems():
+ if partition != self.ownUID:
+ installPool(
+ partition,
+ url,
+ self.maxClients,
+ )
+
partitions = Partitions()
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py 2009-10-16 20:33:29 UTC (rev 4585)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -38,7 +38,6 @@
import os
import errno
from urlparse import urlsplit
-import urlparse
from twext.web2.dav.davxml import ErrorResponse
@@ -53,11 +52,11 @@
from twisted.web2.dav.resource import AccessDeniedError
from twisted.web2.dav.resource import davPrivilegeSet
from twisted.web2.dav.util import parentForURL, bindMethods, joinURL
-from twisted.web2.resource import RedirectResource
from twistedcaldav import caldavxml
from twistedcaldav import customxml
from twistedcaldav.caldavxml import caldav_namespace
+from twistedcaldav.client.reverseproxy import ReverseProxyResource
from twistedcaldav.config import config
from twistedcaldav.customxml import TwistedCalendarAccessProperty, TwistedScheduleMatchETags
from twistedcaldav.extensions import DAVFile, CachingPropertyStore
@@ -706,22 +705,21 @@
else:
childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
- child = CalendarHomeRedirectFile(childPath.path, self, record)
+ child = CalendarHomeReverseProxyFile(childPath.path, self, record)
return child
def createSimilarFile(self, path):
raise HTTPError(responsecode.NOT_FOUND)
-class CalendarHomeRedirectFile(RedirectResource):
+class CalendarHomeReverseProxyFile(ReverseProxyResource):
def __init__(self, path, parent, record):
self.path = path
self.parent = parent
self.record = record
- parsedURL = urlparse.urlparse(self.record.hostedURL())
- super(CalendarHomeRedirectFile, self).__init__(scheme=parsedURL.scheme, host=parsedURL.hostname, port=parsedURL.port)
+ super(CalendarHomeReverseProxyFile, self).__init__(self.record.hostedAt)
def url(self):
return joinURL(self.parent.url(), self.record.uid)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py 2009-10-16 20:33:29 UTC (rev 4585)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py 2009-10-16 20:58:56 UTC (rev 4586)
@@ -354,9 +354,12 @@
#
# Partitioning
#
- "EnablePartitions": False, # Partitioning enabled or not
- "ServerPartitionID": "", # Unique ID for this server's partition instance.
- "PartitionConfigFile": "/etc/caldavd/partitions.plist", # File path for partition information
+ "Partitioning" : {
+ "Enabled": False, # Partitioning enabled or not
+ "ServerPartitionID": "", # Unique ID for this server's partition instance.
+ "PartitionConfigFile": "/etc/caldavd/partitions.plist", # File path for partition information
+ "MaxClients": 5, # Pool size for connections to each partition
+ },
#
# Performance tuning
@@ -713,9 +716,11 @@
# Partitions
#
- if configDict.EnablePartitions:
- partitions.setSelfPartition(configDict.ServerPartitionID)
- partitions.readConfig(configDict.PartitionConfigFile)
+ if configDict.Partitioning.Enabled:
+ partitions.setSelfPartition(configDict.Partitioning.ServerPartitionID)
+ partitions.setMaxClients(configDict.Partitioning.MaxClients)
+ partitions.readConfig(configDict.Partitioning.PartitionConfigFile)
+ partitions.installReverseProxies()
else:
partitions.clear()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20091016/0276955e/attachment-0001.html>
More information about the calendarserver-changes
mailing list