You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mod_python-commits@quetz.apache.org by nl...@apache.org on 2005/04/30 09:15:43 UTC

svn commit: r165387 - in /httpd/mod_python/trunk/lib/python/mod_python: FileSession.py Session.py

Author: nlehuen
Date: Sat Apr 30 00:15:41 2005
New Revision: 165387

URL: http://svn.apache.org/viewcvs?rev=165387&view=rev
Log:
FileSession integrated into Session.py.

Removed:
    httpd/mod_python/trunk/lib/python/mod_python/FileSession.py
Modified:
    httpd/mod_python/trunk/lib/python/mod_python/Session.py

Modified: httpd/mod_python/trunk/lib/python/mod_python/Session.py
URL: http://svn.apache.org/viewcvs/httpd/mod_python/trunk/lib/python/mod_python/Session.py?rev=165387&r1=165386&r2=165387&view=diff
==============================================================================
--- httpd/mod_python/trunk/lib/python/mod_python/Session.py (original)
+++ httpd/mod_python/trunk/lib/python/mod_python/Session.py Sat Apr 30 00:15:41 2005
@@ -20,13 +20,14 @@
 import apache, Cookie
 import _apache
 
-import os
+import os, os.path
 import time
 import anydbm, whichdb
 import random
 import md5
-import cPickle
+import cPickle, cStringIO
 import tempfile
+import traceback
 
 COOKIE_NAME="pysid"
 DFT_TIMEOUT=30*60 # 30 min
@@ -242,6 +243,9 @@
 def unlock_session_cleanup(sess):
     sess.unlock()
 
+###########################################################################
+## DbmSession
+
 def dbm_cleanup(data):
     dbm, server = data
     _apache._global_lock(server, None, 0)
@@ -336,6 +340,189 @@
             dbm.close()
             _apache._global_unlock(self._req.server, None, 0)
 
+###########################################################################
+## FileSession
+
+# Credits : this was initially contributed by dharana <dh...@dharana.net>
+class FileSession(BaseSession):
+
+    def __init__(self, req, sid=0, secret=None, timeout=0, lock=1,
+                fast_cleanup=True, verify_cleanup=False, grace_period=240):
+        
+        opts = req.get_options()
+        self._sessdir = opts.get('FileSessionDir',tempdir)
+        
+        self._fast_cleanup = fast_cleanup
+        self._verify_cleanup = verify_cleanup
+        self._grace_period = grace_period
+        if timeout:
+            self._cleanup_timeout = timeout
+        else:
+            self._cleanup_timeout = Session.DFT_TIMEOUT
+        
+        BaseSession.__init__(self, req, sid=sid, secret=secret,
+            timeout=timeout, lock=lock)
+
+    def do_cleanup(self):
+        data = {'req':self._req,
+                'sessdir':self._sessdir,
+                'fast_cleanup':self._fast_cleanup, 
+                'verify_cleanup':self._verify_cleanup, 
+                'timeout':self._cleanup_timeout,
+                'grace_period':self._grace_period}
+
+        self._req.register_cleanup(filesession_cleanup, data)
+        self._req.log_error("FileSession: registered filesession cleanup.",
+                            apache.APLOG_NOTICE)
+
+    def do_load(self):
+        self.lock_file()
+        try:
+            try:
+                filename = os.path.join(self._sessdir, 'mp_sess_%s' % self._sid)
+                fp = file(filename,'rb')
+                try:
+                    data = cPickle.load(fp)
+                    if (time.time() - data["_accessed"]) <= data["_timeout"]:
+                        # Change the file access time to the current time so the 
+                        # cleanup does not delete this file before the request
+                        # can save it's session data
+                        os.utime(filename,None)
+                    return data
+                finally:
+                    fp.close()
+            except:
+                s = cStringIO.StringIO()
+                traceback.print_exc(file=s)
+                s = s.getvalue()
+                self._req.log_error('Error while loading a session : %s'%s)
+                return None
+        finally:
+            self.unlock_file()
+
+    def do_save(self, dict):
+        self.lock_file()
+        try:
+            try:
+                filename = os.path.join(self._sessdir, 'mp_sess_%s' % self._sid)
+                fp = file(filename, 'wb')
+                try:
+                    cPickle.dump(dict, fp, 2)
+                finally:
+                    fp.close()
+            except:
+                s = cStringIO.StringIO()
+                traceback.print_exc(file=s)
+                s = s.getvalue()
+                self._req.log_error('Error while saving a session : %s'%s)
+        finally:
+            self.unlock_file()
+
+    def do_delete(self):
+        self.lock_file()
+        try:
+            try:
+                os.unlink(os.path.join(self._sessdir, 'mp_sess_%s' % self._sid))
+            except Exception:
+                pass
+        finally:
+            self.unlock_file()
+
+    def lock_file(self):
+        # self._lock = 1 indicates that session locking is turned on,
+        # so let BaseSession handle it.
+        # Otherwise, explicitly acquire a lock for the file manipulation.
+        if not self._locked:
+            _apache._global_lock(self._req.server, self._sid)
+            self._locked = 1
+
+    def unlock_file(self):
+        if self._locked and not self._lock:
+            _apache._global_unlock(self._req.server, self._sid)
+            self._locked = 0
+
+
+def filesession_cleanup(data):
+    # There is a small chance that a the cleanup for a given session file
+    # may occur at the exact time that the session is being accessed by
+    # another request. It is possible under certain circumstances for that
+    # session file to be saved in another request only to immediately deleted
+    # by the cleanup. To avoid this race condition, a session is allowed a 
+    # grace_period before it is considered for deletion by the cleanup. 
+    # As long as the grace_period is longer that the time it takes to complete
+    # the request (which should normally be less than 1 second), the session will
+    # not be mistakenly deleted by the cleanup. By doing this we also avoid the
+    # need to lock individual sessions and bypass any potential deadlock
+    # situations.
+   
+    req = data['req']
+    sessdir = data['sessdir']
+    fast_cleanup = data['fast_cleanup']
+    verify_cleanup = data['verify_cleanup']
+    timeout = data['timeout']
+    grace_period = data['grace_period']
+
+    req.log_error('Sessions cleanup (fast=%s, verify=%s) ...'
+        % (fast_cleanup,verify_cleanup),
+        apache.APLOG_NOTICE)
+
+    lockfile = os.path.join(sessdir,'.mp_sess.lck')
+    try:
+        lockfp = os.open(lockfile, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0660) 
+    except:
+        req.log_error('filesession_cleanup: another process is already running.') 
+        return
+
+    try:
+        start_time = time.time()
+        filelist =  os.listdir(sessdir)
+        count = 0
+        i = 0
+        for f in filelist:
+            if not f.startswith('mp_sess_'):
+                continue
+            try:
+                filename = os.path.join(sessdir, f)
+                if fast_cleanup:
+                    accessed = os.stat(filename).st_mtime
+                    if time.time() - accessed < (timeout + grace_period):
+                        continue
+
+                if fast_cleanup and not verify_cleanup:        
+                    delete_session = True
+                else:
+                    try:
+                        fp = file(filename)
+                        dict = cPickle.load(fp)
+                        if (time.time() - dict['_accessed']) > (dict['_timeout'] + grace_period):
+                            delete_session = True
+                        else:
+                            delete_session = False
+                    finally:
+                        fp.close()
+                if delete_session:
+                    os.unlink(filename)
+                    count += 1
+            except:
+                s = cStringIO.StringIO()
+                traceback.print_exc(file=s)
+                s = s.getvalue()
+                req.log_error('Error while cleaning up the sessions : %s' % s)
+
+        elapsed_time = time.time() - start_time
+        req.log_error('filesession cleanup: %d of %d in %.4f seconds' % (count,len(filelist), elapsed_time))
+   
+        try:
+            os.unlink(lockfile)
+        except:
+            pass
+
+    finally:
+        os.close(lockfp)
+
+###########################################################################
+## MemorySession
+
 def mem_cleanup(sdict):
     for sid in sdict:
         dict = sdict[sid]
@@ -368,6 +555,9 @@
         try:
             del MemorySession.sdict[self._sid]
         except KeyError: pass
+
+###########################################################################
+## Session
 
 def Session(req, sid=0, secret=None, timeout=0, lock=1):