[Zope-Checkins] CVS: Zope/lib/python/ZServer/PubCore - ZRendezvous.py:1.10.18.1 ZServerPublisher.py:1.9.18.1 __init__.py:1.8.18.1

Chris McDonough chrism at zope.com
Wed Oct 1 00:33:37 EDT 2003


Update of /cvs-repository/Zope/lib/python/ZServer/PubCore
In directory cvs.zope.org:/tmp/cvs-serv21030/PubCore

Modified Files:
      Tag: chrism-zserver-connection-policies-branch
	ZRendezvous.py ZServerPublisher.py __init__.py 
Log Message:
Experimental branch which allows ZServer servers to specify a different 
thread pool than the default thread pool, and a ZODB 'connection policy'.

The advantages of this include:

- Thread resource exhaustion will not effect servers which specify
  a different thread pool.

- The connection policy can be used for many purposes (including,
  for instance, specifying in the future, whether MVCC should be used for a i
  particular connection), but its main purpose in this context is
  to allow us to define a 'temporary' connection policy which obtains
  a connection outside of a (possibly exhausted) database connection
  pool.

HTTP, WebDAV, FTP, PCGI, and FCGI servers can make use of the new features
by using the 'thread-pool' and 'zodb-connection-policy' keys within
the zope.conf file within their respective server sections.  For instance:

<http-server>
  address 8080
  thread-pool emergency
  zodb-connection-policy temporary
</http-server>



=== Zope/lib/python/ZServer/PubCore/ZRendezvous.py 1.10 => 1.10.18.1 ===
--- Zope/lib/python/ZServer/PubCore/ZRendezvous.py:1.10	Tue Mar 18 16:15:16 2003
+++ Zope/lib/python/ZServer/PubCore/ZRendezvous.py	Wed Oct  1 00:33:36 2003
@@ -15,49 +15,50 @@
 from ZServerPublisher import ZServerPublisher
 
 class ZRendevous:
-
+    """ A class which can interface ZPublisher with Zope's thread model """
     def __init__(self, n=1):
-        sync=thread.allocate_lock()
-        self._a=sync.acquire
-        self._r=sync.release
-        pool=[]
-        self._lists=pool, [], []
-        self._a()
+        self.sync = thread.allocate_lock()
+        # self.sync is the lock that protects the local data (aka the
+        # data in self._lists)
+        pool = []
+        self._lists = (pool, [], [])
+        self.sync.acquire()
         try:
             while n > 0:
-                l=thread.allocate_lock()
-                l.acquire()
-                pool.append(l)
-                thread.start_new_thread(ZServerPublisher,
-                                        (self.accept,))
-                n=n-1
-        finally: self._r()
+                threadlock = thread.allocate_lock()
+                threadlock.acquire()
+                pool.append(threadlock)
+                thread.start_new_thread(ZServerPublisher, (self.accept,))
+                n = n - 1
+        finally:
+            self.sync.release()
 
     def accept(self):
-        self._a()
+        self.sync.acquire()
         try:
             pool, requests, ready = self._lists
             while not requests:
-                l=pool[-1]
-                del pool[-1]
-                ready.append(l)
-                self._r()
-                l.acquire()
-                self._a()
-                pool.append(l)
+                threadlock = pool.pop()
+                ready.append(threadlock)
+                self.sync.release()
+                threadlock.acquire()
+                self.sync.acquire()
+                pool.append(threadlock)
 
-            r=requests[0]
-            del requests[0]
+            r = requests.pop(0)
             return r
-        finally: self._r()
+        finally:
+            self.sync.release()
 
     def handle(self, name, request, response):
-        self._a()
+        self.sync.acquire()
         try:
             pool, requests, ready = self._lists
             requests.append((name, request, response))
             if ready:
-                l=ready[-1]
-                del ready[-1]
-                l.release()
-        finally: self._r()
+                threadlock = ready.pop()
+                threadlock.release()
+        finally:
+            self.sync.release()
+
+    


=== Zope/lib/python/ZServer/PubCore/ZServerPublisher.py 1.9 => 1.9.18.1 ===
--- Zope/lib/python/ZServer/PubCore/ZServerPublisher.py:1.9	Tue Mar 18 16:15:16 2003
+++ Zope/lib/python/ZServer/PubCore/ZServerPublisher.py	Wed Oct  1 00:33:36 2003
@@ -13,14 +13,12 @@
 from ZPublisher import publish_module
 
 class ZServerPublisher:
+    """ A class which publishes a module over and over """
     def __init__(self, accept):
         while 1:
             try:
-                name, request, response=accept()
-                publish_module(
-                    name,
-                    request=request,
-                    response=response)
+                name, request, response = accept()
+                publish_module(name, request=request, response=response)
             finally:
                 response._finish()
-                request=response=None
+                request = response = None


=== Zope/lib/python/ZServer/PubCore/__init__.py 1.8 => 1.8.18.1 ===
--- Zope/lib/python/ZServer/PubCore/__init__.py:1.8	Tue Mar 18 16:15:16 2003
+++ Zope/lib/python/ZServer/PubCore/__init__.py	Wed Oct  1 00:33:36 2003
@@ -13,18 +13,61 @@
 
 import ZRendezvous
 
+# DEFAULT_POOLNAME and DEFAULT_CONNPOLICY are importable from elsewhere
+DEFAULT_POOLNAME = DEFAULT_CONNPOLICY = 'default'
+
+# backwards compatibility module-level globals _handle and _n, these
+# are sadly imported from elsewhere
 _handle=None
 _n=1
 
+
+# backwards-compatibility functions handle and setNumberOfThreads
 def handle(*args, **kw):
+    """ backwards compatibility, pulls from 'default' pool """
     global _handle
+    if _handle is None:
+        _handle = pool_registry.get_handler(DEFAULT_POOLNAME)
+    return _handle(*args, **kw)
 
-    if _handle is None: _handle=ZRendezvous.ZRendevous(_n).handle
-
-    return apply(_handle, args, kw)
-
-def setNumberOfThreads(n):
-    global _n
-    _n=n
+def setNumberOfThreads(num_threads):
+    """ backwards compatibility method, initializes 'default' thread pool """
+    pool_registry.add_pool(DEFAULT_POOLNAME, num_threads)
     global setNumberOfThreads
     del setNumberOfThreads
+
+class ThreadPoolRegistry:
+    """
+    A registry for thread pools.  In Zopes prior to Zope 2.8, there
+    was only one thread pool.  Now, developers can create multiple thread
+    pools and ZServer servers can explicitly choose which pool to use.  This
+    is useful in case you want to 'reserve' a thread pool for some sort
+    of usage scenario, e.g. reserving a set of threads for 'management'
+    requests that can never be used for 'public' requests.
+    """
+    def __init__(self):
+        self.sizes = {}
+        self.handlers = {}
+
+    def add_pool(self, name, num_threads):
+        self.sizes[name] = num_threads
+        # set _n module level global for backwards compatibility
+        if name == 'default':
+            global _n
+            _n = num_threads
+
+    def get_handler(self, name):
+        handler = self.handlers.get(name)
+        if handler is None:
+            handler = ZRendezvous.ZRendevous(self.sizes[name]).handle
+            self.handlers[name] = handler
+        return handler
+
+# the singleton pool_registry
+pool_registry = ThreadPoolRegistry()
+
+# add the emergency pool
+pool_registry.add_pool('emergency', 1)
+
+# get_handler is used by servers to get a handler for a thread pool
+get_handler = pool_registry.get_handler




More information about the Zope-Checkins mailing list