Commits

Robert Brewer committed 424a066

Moved default threadlocal objects into the serving class instead of the proxy. Benchmark is now 6% faster.

Comments (0)

Files changed (2)

cherrypy/__init__.py

 
 from cherrypy import _cpdispatch as dispatch
 from cherrypy import _cprequest
+from cherrypy.lib import http as _http
 from cherrypy import _cpengine
 engine = _cpengine.Engine()
 
 # a new HTTP conversation, yet still refer to them as module-level globals
 # in a thread-safe way.
 class _Serving(_local):
-    """An interface for registering request and response objects."""
+    """An interface for registering request and response objects.
+    
+    Rather than have a separate "thread local" object for the request and
+    the response, this class works as a single threadlocal container for
+    both objects.
+    """
+    
+    __metaclass__ = _AttributeDocstrings
+    
+    request = _cprequest.Request(_http.Host("localhost", 80),
+                                 _http.Host("localhost", 1111))
+    request__doc = """
+    The request object for the current thread. In the main thread,
+    and any threads which are not receiving HTTP requests, this is None."""
+    
+    response = _cprequest.Response()
+    response__doc = """
+    The response object for the current thread. In the main thread,
+    and any threads which are not receiving HTTP requests, this is None."""
     
     def load(self, request, response):
         self.request = request
 
 class _ThreadLocalProxy(object):
     
-    __slots__ = ['__attrname__', '_default_child', '__dict__']
+    __slots__ = ['__attrname__', '__dict__']
     
-    def __init__(self, attrname, default):
+    def __init__(self, attrname):
         self.__attrname__ = attrname
-        self._default_child = default
-    
-    def _get_child(self):
-        try:
-            return getattr(_serving, self.__attrname__)
-        except AttributeError:
-            # Bind dummy instances of default objects to help introspection.
-            return self._default_child
     
     def __getattr__(self, name):
-        return getattr(self._get_child(), name)
+        child = getattr(serving, self.__attrname__)
+        return getattr(child, name)
     
     def __setattr__(self, name, value):
-        if name in ("__attrname__", "_default_child"):
+        if name in ("__attrname__", ):
             object.__setattr__(self, name, value)
         else:
-            setattr(self._get_child(), name, value)
+            child = getattr(serving, self.__attrname__)
+            setattr(child, name, value)
     
     def __delattr__(self, name):
-        delattr(self._get_child(), name)
+        child = getattr(serving, self.__attrname__)
+        delattr(child, name)
     
     def _get_dict(self):
-        childobject = self._get_child()
-        d = childobject.__class__.__dict__.copy()
-        d.update(childobject.__dict__)
+        child = getattr(serving, self.__attrname__)
+        d = child.__class__.__dict__.copy()
+        d.update(child.__dict__)
         return d
     __dict__ = property(_get_dict)
     
     def __getitem__(self, key):
-        return self._get_child()[key]
+        child = getattr(serving, self.__attrname__)
+        return child[key]
     
     def __setitem__(self, key, value):
-        self._get_child()[key] = value
+        child = getattr(serving, self.__attrname__)
+        child[key] = value
     
     def __delitem__(self, key):
-        del self._get_child()[key]
+        child = getattr(serving, self.__attrname__)
+        del child[key]
     
     def __contains__(self, key):
-        return key in self._get_child()
+        child = getattr(serving, self.__attrname__)
+        return key in child
 
 
 # Create request and response object (the same objects will be used
 #   throughout the entire life of the webserver, but will redirect
-#   to the "_serving" object)
-from cherrypy.lib import http as _http
-request = _ThreadLocalProxy('request',
-                            _cprequest.Request(_http.Host("localhost", 80),
-                                               _http.Host("localhost", 1111)))
-response = _ThreadLocalProxy('response', _cprequest.Response())
+#   to the "serving" object)
+request = _ThreadLocalProxy('request')
+response = _ThreadLocalProxy('response')
 
 # Create thread_data object as a thread-specific all-purpose storage
 thread_data = _local()
 def _cherrypy_pydoc_resolve(thing, forceload=0):
     """Given an object or a path to an object, get the object and its name."""
     if isinstance(thing, _ThreadLocalProxy):
-        thing = thing._get_child()
+        thing = getattr(serving, thing.__attrname__)
     return pydoc._builtin_resolve(thing, forceload)
 
 try:

cherrypy/lib/sessions.py

 missing = object()
 
 class Session(object):
-    """A CherryPy dict-like Session object (one per request).
+    """A CherryPy dict-like Session object (one per request)."""
     
-    id: current session ID.
-    expiration_time (datetime): when the current session will expire.
-    timeout (minutes): used to calculate expiration_time from now.
-    clean_freq (minutes): the poll rate for expired session cleanup.
-    locked: If True, this session instance has exclusive read/write access
-        to session data.
-    loaded: If True, data has been retrieved from storage. This should
-        happen automatically on the first attempt to access session data.
-    """
+    __metaclass__ = cherrypy._AttributeDocstrings
+    
+    id = None
+    id__doc = "The current session ID."
+    
+    timeout = 60
+    timeout__doc = "Number of minutes after which to delete session data."
+    
+    locked = False
+    locked__doc = """
+    If True, this session instance has exclusive read/write access
+    to session data."""
+    
+    loaded = False
+    loaded__doc = """
+    If True, data has been retrieved from storage. This should happen
+    automatically on the first attempt to access session data."""
     
     clean_thread = None
+    clean_thread__doc = "Class-level PerpetualTimer which calls self.clean_up."
+    
+    clean_freq = 5
+    clean_freq__doc = "The poll rate for expired session cleanup in minutes."
     
     def __init__(self, id=None, **kwargs):
-        self.locked = False
-        self.loaded = False
         self._data = {}
         
         for k, v in kwargs.iteritems():
 close.priority = 90
 
 
-_def_session = RamSession()
-
 def init(storage_type='ram', path=None, path_header=None, name='session_id',
          timeout=60, domain=None, secure=False, clean_freq=5, **kwargs):
     """Initialize session object (using cookies).
     request = cherrypy.request
     
     # Guard against running twice
-    if hasattr(cherrypy._serving, "session"):
+    if hasattr(request, "_session_init_flag"):
         return
+    request._session_init_flag = True
     
     # Check if request came with a session ID
     id = None
     cherrypy._serving.session = sess = globals()[storage_class](id, **kwargs)
     
     if not hasattr(cherrypy, "session"):
-        cherrypy.session = cherrypy._ThreadLocalProxy('session', _def_session)
+        cherrypy.session = cherrypy._ThreadLocalProxy('session')
         if hasattr(sess, "setup"):
             sess.setup()
     
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.