RESULTS OF TESTS
TEST:
Trying to picle/unpickle the req object:
CODE:
from mod_python import Session, apache
def handler(req):
d = { "request" : req }
test1 = cPickle.loads(cPickle.dumps(d))
req.write(str(test1))
RESULT:
TypeError: can't pickle mp_request objects
COMMENT:
Expected, req is a transient object that shouldn't be pickled. Exception thrown
------------------------
TEST: Check to see if segfault is caused by storing req obj directly in req.sess
CODE:
from mod_python import Session, apache
def handler(req):
req.sess = Session.FileSession(req)
req.sess['req'] = req
req.sess.save()
req.content_type = 'text/html'
req.write('session_id: %s' % req.sess.id())
RESULT:
New session is created on each request. No segfault.
COMMENT:
I suppose mp catches the Exception and silently creates a new session. It's not
a good design idea to store the req object so the designer should be punished.
----------------------
TEST: Check to see if segfault is caused by custom classes ()
CODE:
from mod_python import Session, apache
from ozone.storage.db import dbobj
def handler(req):
req.sess = Session.FileSession(req)
try:
req.write('I have the db! (%s)' % req.sess['dbobj'])
except KeyError:
pass
req.sess['dbobj'] = dbobj
req.sess.save()
req.write('session_id: %s' % req.sess.id())
RESULT:
Nothing except session_id gets printed on the first time. Next time it correctly
loads the session and prints "I have the db" with the same session_id.
COMMENT:
Works as expected.
This are just sanity checks. I restarted apache after each test and I also
deleted the pysid cookie to get clear results. I will post the weird results I
got one minute later in my next email.
(I've also commented Nicholas email below)
Nicolas Lehuen wrote:
Hi dharana, I have a two parts answer :
1) One thing I'm really sure is that there is no way for the pickle
module to handle the request object correctly. Hence, if the session
code is trying to pickle an object which contains a reference to a
request object, I have no idea of how this can be done. This is
another possible explanation of the segfault. Maybe you could try to
pickle then reload an object with a reference to the request object,
like this :
import cPickle
def index(req):
d = { "request" : req }
test1 = cPickle.loads(cPickle.dumps(d))
return str(test1)
In any case, storing an object with a reference to the request in a
session is not a godd thing to do ; a request is a transient object,
which is not meant to live for more than the request's processing
time.
3) Another possible problem with loading pickled sessions is the case
where you are trying to load some user-defined class instances.
Due to the way pickling works, the class of an instance is saved by
name, and the unpickling code automagically reimports the module of
the class and rebuild the instance from there.
When the class is defined in a published module (and this is also true
for mod_python 3.1.4 and before), I can't see how the unpickling code
can possibly find the proper published module, since the standard
importing mechanism won't find the published module. This should raise
a nice Python exception, but maybe with cPickle or in certain
circumstances this causes a segmentation fault.
To rule out this problem I would try to define the object class in a
module that could be found on the PythonPath, rather than directly in
the published module.
Althought in the code above the import calls are in the handler in the full
version mp manages to find custom classes even if they are not imported in the
handler code.
3) Uh oh. If you're suspecting that this problem is related to
circular dependencies with the request object, then maybe this bug is
caused by the changes I've made to support the garbage collection of
the request object, since I had to implement some traversal code that
could fail for a reason or another.
Would it be possible for you to perform the same tests with the 3.1.4
version of mod_python.so ? We would make clear whether this is due to
something like that.
Nicholas I can't test this in 3.1.4 because of the _pspparsestring bug (fixed in
daily snapshots) which I use extensively in my framework. However, if it's
becomes necessary to test with it I will do it no matter how much hackery it needs.
The circular dependencies I refered to were related to the fact that the
req.sess['website'] instance pointed to a Website object and that the Website
object received a call to the same req instance in one of its methods. But don't
worry, I believe this has no effect, read my next email, please.
--
dharana