Apache Mod-Python - Different approach to req.get_session().

This is Interesting: Free IT Magazines  
Home > Archive > Apache Mod-Python > August 2005 > Different approach to req.get_session().





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author Different approach to req.get_session().
Graham Dumpleton

2005-08-08, 8:09 am

Some will know that I haven't been too keen on the way in which the
proposed new req.get_session() method was being implemented. My concerns
were that it was a magic box and didn't allow access to the underlying
variable holding the session object so as to allow checks such as
determining whether a session already existed before creating it. I also
had my concerns about how the session would be automatically unlocked
when req.internal_redirect() was used, something which may introduce
backward compatibility problems.

Anyway, have been thinking about this stuff on and off and have come
with an idea which might be worth pursuing.

Previously when discussing the issue of the "req" object not being
available to apache.import_module() unless explicitly provided, and the
implications of this as far as ensuring that settings for logging and
autoreload were consistent between code and Apache configuration files,
I proposed the idea of a request cache.

http://www.mail-archive.com/python-...g/msg00197.html

This was where the request object was put in a globally accessible
dictionary indexed by thread identifier. Having been done, the request
object could be accessed from anywhere. There were various issues
related to use of req.internal_request() that had to be catered for,
but in short it acted like a thread specific global variable.

Now consider something similar for the instance of a session object
that is created. Ie.,

def Session(...):

Determine session id if not supplied as argument.

Check session object cache to see if session instance already
stored for (threadId,sessionId).

If cached session object exists, use it and return it.

Otherwise create new session object, store it in the cache under
the key (threadId,sessionId) and return it.

A cleanup handler is already registered for a session object when a
session object is created. This same cleanup handler can remove the
session object from the cache.

In respect of req.internal_redirect(), with the above there doesn't need
to be any special code which unlocks the session. Instead, when any code
executed as a consequence of req.internal_redirect() calls
Session.Session()
to create the session object, it will be given the already constructed
session object instead of creating a new one. The session lock will
never
have been released and the code will simply use it. The code called by
req.internal_redirect() can save the session, or it could even be done
by the code which called req.internal_redirect() in the first place.

Because the session instance is stored in a global cache within the
session code and not in the request object itself, one can probably even
totally do away with the req.get_session() method. Code will simply
continue to use Session.Session() method and users can store it wherever
they like.

Well, thats the basic idea. It obviously needs a bit of work on the
caching
with respect to thread locks etc, but that shouldn't be too much work.

Comments? Have I explained it well enough?

Graham


Jim Gallacher

2005-08-08, 5:47 pm

Just so everyone is clear, implementation of req.get_session() or its
equivalent has been deferred to version 3.3.

Graham Dumpleton wrote:
> Some will know that I haven't been too keen on the way in which the
> proposed new req.get_session() method was being implemented. My concerns
> were that it was a magic box and didn't allow access to the underlying
> variable holding the session object so as to allow checks such as
> determining whether a session already existed before creating it. I also
> had my concerns about how the session would be automatically unlocked
> when req.internal_redirect() was used, something which may introduce
> backward compatibility problems.
>
> Anyway, have been thinking about this stuff on and off and have come
> with an idea which might be worth pursuing.
>
> Previously when discussing the issue of the "req" object not being
> available to apache.import_module() unless explicitly provided, and the
> implications of this as far as ensuring that settings for logging and
> autoreload were consistent between code and Apache configuration files,
> I proposed the idea of a request cache.
>
> http://www.mail-archive.com/python-...g/msg00197.html
>
> This was where the request object was put in a globally accessible
> dictionary indexed by thread identifier. Having been done, the request
> object could be accessed from anywhere. There were various issues
> related to use of req.internal_request() that had to be catered for,
> but in short it acted like a thread specific global variable.
>
> Now consider something similar for the instance of a session object
> that is created. Ie.,
>
> def Session(...):
>
> Determine session id if not supplied as argument.
>
> Check session object cache to see if session instance already
> stored for (threadId,sessionId).
>
> If cached session object exists, use it and return it.
>
> Otherwise create new session object, store it in the cache under
> the key (threadId,sessionId) and return it.
>
> A cleanup handler is already registered for a session object when a
> session object is created. This same cleanup handler can remove the
> session object from the cache.
>
> In respect of req.internal_redirect(), with the above there doesn't need
> to be any special code which unlocks the session. Instead, when any code
> executed as a consequence of req.internal_redirect() calls
> Session.Session()
> to create the session object, it will be given the already constructed
> session object instead of creating a new one. The session lock will never
> have been released and the code will simply use it. The code called by
> req.internal_redirect() can save the session, or it could even be done
> by the code which called req.internal_redirect() in the first place.
>
> Because the session instance is stored in a global cache within the
> session code and not in the request object itself, one can probably even
> totally do away with the req.get_session() method. Code will simply
> continue to use Session.Session() method and users can store it wherever
> they like.
>
> Well, thats the basic idea. It obviously needs a bit of work on the caching
> with respect to thread locks etc, but that shouldn't be too much work.
>
> Comments? Have I explained it well enough?
>
> Graham
>


I think this may have merit although I need to mull it over.

Would the session cache be on disk or in memory? If in memory, what are
the implications in an mpm-prefork environment? If on disk, what are the
performance implications? Will it introduce new and exciting locking
issues for accessing the cache?

I'm not looking for answers to the above at this point, just recording
them for the record.

Jim

Graham Dumpleton

2005-08-08, 5:47 pm


On 09/08/2005, at 1:34 AM, Jim Gallacher wrote:
>
> I think this may have merit although I need to mull it over.
>
> Would the session cache be on disk or in memory?


The cache would just be a Python dictionary object. It would be
specific to just that process, ie., in memory.

> If in memory, what are the implications in an mpm-prefork environment?


No different to just MPM and single process (Win32). Only within
the one process so prefork shouldn't add any extra complications.

> If on disk, what are the performance implications?


N/A.

> Will it introduce new and exciting locking issues for accessing the
> cache?


I don't think so, the caching is effectively done on a thread specific
basis only and thus where the lock synchronisation point for different
threads wanting to create the same session object doesn't matter. The
whole point of the cache is only to deal with the one thread which does
an req.internal_redirect() and wants to access the session object with
that redirect as well.

Sorry, this probably isn't too clear. You might only understand if
I show some working code. :-)

Graham


Graham Dumpleton

2005-08-08, 5:47 pm


On 09/08/2005, at 7:51 AM, Graham Dumpleton wrote:
>
> I don't think so, the caching is effectively done on a thread specific
> basis only and thus where the lock synchronisation point for different
> threads wanting to create the same session object doesn't matter. The
> whole point of the cache is only to deal with the one thread which does
> an req.internal_redirect() and wants to access the session object with
> that redirect as well.


Whoops, it would introduce a single locking point around creation of all
session objects from Session() function, ie., from any thread. This may
have a performance impact. With some creative coding this might be
avoided though. I'll think about it some more. :-)

Graham


Graham Dumpleton

2005-08-08, 8:45 pm

Graham Dumpleton wrote ..
>
> On 09/08/2005, at 7:51 AM, Graham Dumpleton wrote:
>
> Whoops, it would introduce a single locking point around creation of all
> session objects from Session() function, ie., from any thread. This may
> have a performance impact. With some creative coding this might be
> avoided though. I'll think about it some more. :-)


Actually, no locking problems after all that I can see. I am going to be busy
giving training most of the day, but wacked together the following patches
on the train on the way to work. I tested it for simple case with no actual
internal redirect, but didn't have time to check it for internal redirect. :-(

Anyway, should give you a better idea of what I am talking about. The
changes are actually quite simple. Although, if someone doesn't use the
Session.Session() function and uses a specific class direct, then it bypasses
the code. That was the same for req.get_session() as well though.

Patch below for viewing online, but also added as attachment. Note, all
changes are in Session.py. There is no need to modify the request object
at all, ie., no req.get_session() and no changes to req.internal_redirect().

Index: lib/python/mod_python/Session.py
========================================
===========================
--- lib/python/mod_python/Session.py (revision 230781)
+++ lib/python/mod_python/Session.py (working copy)
@@ -37,6 +37,15 @@

tempdir = tempfile.gettempdir()

+try:
+ import threading
+ _current_thread = threading.currentThread
+except:
+ def _current_thread():
+ return None
+
+_per_request_cache = {}
+
def _init_rnd():
""" initialize random number generators
this is key in multithreaded env, see
@@ -220,9 +229,14 @@
_apache._global_lock(self._req.server, self._sid)
self._locked = 1
self._req. register_cleanup(unlock_session_cleanup,
self)
+ _per_request_cache[(_current_thread(),self._sid)] = self

def unlock(self):
if self._lock and self._locked:
+ try:
+ del _per_request_cache[(_current_thread(),self._sid)]
+ except:
+ pass
_apache._global_unlock(self._req.server, self._sid)
self._locked = 0

@@ -676,6 +690,27 @@
# For now, just raise an exception.
raise Exception, 'Unknown session type %s' % sess_type

+ # Following check for sid duplicates what BaseSession does
+ # and overrides it, but need it so we can look up cache.
+ session_cookie_name = req.get_options().get("session_cookie_name",COOKIE_NAME)
+ if not sid:
+ # check to see if cookie exists
+ if secret:
+ cookies = Cookie.get_cookies(req, Class=Cookie.SignedCookie,
+ secret=secret)
+ else:
+ cookies = Cookie.get_cookies(req)
+
+ if cookies.has_key(session_cookie_name):
+ sid = cookies[session_cookie_name].value
+
+ session = _per_request_cache.get((_current_thread(),sid),None)
+ if session:
+ # XXX Should possibly raise an exception here if type of
+ # cached session object is different to "sess". Would
+ # probably indicate an issue with users code if different.
+ return session
+
return sess(req, sid=sid, secret=secret,
timeout=timeout, lock=lock)


Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com