[mod_python] Session Hanging Problems

Martijn Moeling martijn at xs4us.nu
Wed Nov 28 03:04:23 EST 2007


See below what I did to use MySQL as a session store.
This is done since I use multiple mod_python frond ends to connect to one DB server.
 
Martijn
 
(these are changes made to the original Session.py from the mod_python package)
 
 
###########################################################################
## MySQLSession
## M. Moeling, martijn at xs4us.nu <mailto:martijn at xs4us.nu> 
##
## In order to use MySQLSession:
## in your handler.py:        
## import MySQLdb
##
##  Use:
##        req.db = MySQLdb.connect(host=Chost,user=Cuser,passwd=Cpasswd,db=Cdb)
##        req.cursor = req.db.cursor()
## 
##  When req.cursor is existing, Session.py will default to MySQLSession
##  Can be overruled with pythonoptions in apacheconfig
##
## To create table in MySQL use the following:
## CREATE TABLE `Session` (
##  `sid` varchar(50) NOT NULL,
##  `store` text NOT NULL,
##  PRIMARY KEY  (`sid`)
## ) TYPE=MyISAM;
        
def MySQL_cleanup(req):
    req.cursor.execute("Select * from Session")
    AllSessions = req.cursor.fetchall()
    stale=0
    total=0
    for record in AllSessions:
        total+=1
        session = cPickle.loads(record[1])
        if (time.time() - session["_accessed"]) > session["_timeout"]:
            stale+=1
            req.cursor.execute("DELETE FROM Session where sid='"+record[0]+"'")        
    req.log_error("MySQLSession: Removed: "+str(stale)+" stale records from "+str(total)+" in total",apache.APLOG_NOTICE)
        
class MySQLSession(BaseSession):

    def __init__(self, req, sid=0, secret=None, timeout=0, lock=1):
        BaseSession.__init__(self, req, sid=sid, secret=secret,
                             timeout=timeout, lock=lock)
    def do_cleanup(self):
        self._req.register_cleanup(MySQL_cleanup, self._req)
        self._req.log_error("MySQLSession: registered session cleanup.",apache.APLOG_NOTICE)
    def do_load(self):
        self._req.cursor.execute("Select store from Session where sid='"+self._sid+"'")
        store=self._req.cursor.fetchone()
        if self._req.cursor.rowcount==1:
            return cPickle.loads(store[0].encode('utf-8'))
        return None
    def do_save(self, dict):
        self._req.cursor.execute("Select store from Session where sid='"+self._sid+"'")
        store=self._req.cursor.fetchone()
        if self._req.cursor.rowcount==1:
            Query="Update Session set store=\""+cPickle.dumps(dict)+"\" where sid='"+self._sid+"'"
        else:
            Query="Insert into Session (sid,store) values (\""+self._sid+"\",\""+cPickle.dumps(dict)+"\")"           
        self._req.cursor.execute(Query)
            
        
    def do_delete(self):
        try:
            self._req.cursor.execute("DELETE FROM Session where sid='"+self._sid+"'")
        except:
            pass

###########################################################################
## Session
## Changes made for MySQLSession
## the application should set req.cursor as an MySQLdb cursor object

def Session(req, sid=0, secret=None, timeout=0, lock=1):
    opts = req.get_options()
    if opts.has_key('session'):
        # Check the apache config for the type of session
        sess_type = opts['session']
    else:
        ## MySQLSession is default when req.cursor exists
        if req.cursor:
            sess_type = 'MySQLSession'
        else:
        ## END of MySQLSession modification
            # no session class in config so get the default for the platform
            threaded = _apache.mpm_query(apache.AP_MPMQ_IS_THREADED)
            forked = _apache.mpm_query(apache.AP_MPMQ_IS_FORKED)
            daemons =  _apache.mpm_query(apache.AP_MPMQ_MAX_DAEMONS)
            if (threaded and ((not forked) or (daemons == 1))):
                sess_type = 'MemorySession'
            else:
                sess_type = 'DbmSession'
    if sess_type == 'FileSession':
        sess =  FileSession
    elif sess_type == 'DbmSession':
        sess = DbmSession
    elif sess_type == 'MemorySession':
        sess = MemorySession
    ## Added for MySQLSession
    elif sess_type == 'MySQLSession':
        sess = MySQLSession
    else:
        # TODO Add capability to load a user defined class
        # For now, just raise an exception.
        raise Exception, 'Unknown session type %s' % sess_type
    return sess(req, sid=sid, secret=secret,
                         timeout=timeout, lock=lock)

 

________________________________

Van: mod_python-bounces at modpython.org namens David Janes
Verzonden: di 27.11.2007 20:06
Aan: Harish Agarwal
CC: mod_python at modpython.org; Graham Dumpleton
Onderwerp: Re: [mod_python] Session Hanging Problems



Here's what I'm experimenting with right now -- I'm subclassing
FileSession and overriding all the lock methods. Obviously this will
have to be adapted for people not working in the FileSession world.

Regards, etc...

    class BMFileSession(Session.FileSession):
        def __init__(self, req, sid = None):
            self.bm_lockf = None
            ... more init stuff ...


        def lock(self):
            if self._lock:
                self.bm_lock(self._req.server, self._sid)
                self._locked = 1
                self._req.register_cleanup(Session.unlock_session_cleanup, self)

        def unlock(self):
            if self._lock and self._locked:
                self.bm_unlock(self._req.server, self._sid)
                self._locked = 0

        def lock_file(self):
            if not self._locked:
                self.bm_lock(self._req.server, self._sid)
                self._locked = 1

        def unlock_file(self):
            if self._locked and not self._lock:
                self.bm_unlock(self._req.server, self._sid)
                self._locked = 0

        def bm_lockfile(self, sid):
            lockdir = os.path.join(self._sessdir, sid[:2])
            if not os.path.exists(lockdir):
                os.makedirs(lockdir)

            return  os.path.join(lockdir, sid)

        def bm_lock(self, server, sid):
            if self.bm_lockf:
                try: self.bm_lockf.close()
                except: pass

            self.bm_lockf = open(self.bm_lockfile(sid), 'a+')
            fcntl.lockf(self.bm_lockf, fcntl.LOCK_EX)

        def bm_unlock(self, server, sid):
            if self.bm_lockf:
                fcntl.lockf(self.bm_lockf, fcntl.LOCK_UN)

                try: self.bm_lockf.close()
                except: pass

                self.bm_lockf = None
_______________________________________________
Mod_python mailing list
Mod_python at modpython.org
http://mailman.modpython.org/mailman/listinfo/mod_python


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mm_cfg_has_not_been_edited_to_set_host_domains/pipermail/mod_python/attachments/20071128/0aaa4735/attachment.html


More information about the Mod_python mailing list