Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 575

Show
Ignore:
Timestamp:
08/29/05 12:26:47
Author:
mikerobi
Message:

sessionFilter: fixed some threading issuses, updated the mrow module so that a thread can acquire a lock multiple times.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/lib/filter/sessionfilter/baseadaptor.py

    r568 r575  
    3131import cherrypy 
    3232 
     33import mrow 
     34 
    3335class BaseAdaptor(object): 
    3436    """ 
     
    6062    def newSession(self): 
    6163        """ Return a new sessiondict instance """ 
    62         attributes = {  
    63                'timestamp'  : int(time.time()), 
    64                'timeout'    : cherrypy.config.get('sessionFilter.timeout'), 
    65                'lastAccess' : int(time.time()), 
    66                'key'        : self.generateSessionKey() 
    67                } 
     64        attributes = self.getDefaultAttributes() 
    6865        return SessionDict(sessionAttributes = attributes) 
    6966     
    7067    # there should never be a reason to modify the remaining functions, they are used  
    7168    # internally by the sessionFilter 
    72          
     69     
     70    def getDefaultAttributes(self): 
     71        """ return the default attributes as a dict""" 
     72        return {  
     73                 'timestamp'  : int(time.time()), 
     74                 'timeout'    : cherrypy.config.get('sessionFilter.timeout'), 
     75                 'lastAccess' : int(time.time()), 
     76                 'key'        : self.generateSessionKey() 
     77               } 
     78  
    7379    def __init__(self): 
    7480        """ 
     
    7985         
    8086        self.__sessionCache = {} 
     87        self.__sessionLocks = {} 
    8188         
    8289        #set the path 
     
    100107            # look for the session in the cache 
    101108            session = self.__sessionCache[sessionKey] 
    102             session.threadCount += 1 
     109            session.lock_write() 
     110            try: 
     111                session.threadCount += 1 
     112            finally: 
     113                session.unlock_write() 
    103114        except KeyError: 
    104             # look in the primary storage 
    105             session = self._getSessionDict(sessionKey) 
    106             session.threadCount += 1 
    107             self.__sessionCache[sessionKey] = session 
    108  
     115            lock = self.__sessionLocks.setdefault(sessionKey, mrow.MROWLock()) 
     116            lock.lock_write() 
     117            try: 
     118                # look in the primary storage 
     119                session = self._getSessionDict(sessionKey) 
     120             
     121                # make the session use same lock the internally 
     122                session.setLock(self.__sessionLocks[sessionKey]) 
     123             
     124                session.threadCount += 1 
     125                self.__sessionCache[sessionKey] = session 
     126            finally: 
     127                lock.unlock_write() 
    109128        return session 
    110129 
     
    114133        session.lastAccess = time.time() 
    115134 
    116         #setattr(cherrypy.session, 'default', session) 
    117135        cherrypy.session._setDict(session) 
    118136     
     
    129147        try: 
    130148            session = self.__sessionCache[sessionKey] 
    131             session.threadCount = 0 
    132             self.saveSessionDict(session) 
     149            session.threadCount -= 1 
     150            try: 
     151                session.lock_write() 
     152                 
     153                self.saveSessionDict(session) 
    133154         
    134             cacheTimeout = cherrypy.config.get('sessionFilter.cacheTimeout') 
     155                cacheTimeout = cherrypy.config.get('sessionFilter.cacheTimeout') 
    135156             
    136             if session.threadCount == 0 and (self.noCache or not cacheTimeout): 
    137                 del self.__sessionCache[sessionKey] 
     157                if session.threadCount == 0 and (self.noCache or not cacheTimeout): 
     158                    del self.__sessionCache[sessionKey] 
     159                    del self.__sessionLocks[sessionKey] 
     160            finally: 
     161                session.unlock_write() 
    138162        except KeyError: 
    139             # i don't think this should happen but it does 
    140             # this is probably the result of two thread calling commitCache 
    141             # but nothing bad should happen 
     163            # another thread beat us to the delete 
    142164            pass 
    143165     
     
    155177                if session.threadCount == 0 and expired: 
    156178                    deleteList.append(session) 
     179             
    157180            for session in deleteList: 
    158181                self.commitCache(session.key) 
    159                 del self.__sessionCache[session.key] 
    160182 
    161183    def _cacheSize(self): 
  • trunk/cherrypy/lib/filter/sessionfilter/fileadaptor.py

    r568 r575  
    7575        filePath = os.path.join(storagePath, fileName) 
    7676 
    77         self.__fileLock.lock_write() 
     77        #self.__fileLock.lock_write() 
    7878        try: 
    7979            f = open(filePath,"wb") 
     
    8181            f.close() 
    8282        finally: 
    83             self.__fileLock.unlock_write() 
     83            pass 
     84            #self.__fileLock.unlock_write() 
    8485 
    8586    def _cleanUpOldSessions(self): 
  • trunk/cherrypy/lib/filter/sessionfilter/mrow.py

    r566 r575  
    1313        self.readers = [] # list of all reader Events. when clear, they are reading. must wait() for all of these to be sure no one is reading 
    1414        self.readerslock = threading.RLock() # lock for readers list so it is not changed while looping 
     15     
    1516    def lock_read(self): 
    1617        if not hasattr(self.local, "reader"): 
     
    2021            self.readers.append(self.local.reader) 
    2122            self.readerslock.release() 
    22         self.writing.wait() # wait for any writes to finish 
     23         
     24        # only wait if the writing thread is not the thread same which is requesting a read lock 
     25        if not hasattr(self.local, 'writing'): 
     26            self.writing.wait() # wait for any writes to finish 
     27 
    2328        # tell everyone we are reading 
    2429        self.local.reader.clear() 
     30     
    2531    def lock_write(self): 
    26         self.writing.wait() # wait for any writes to finish (this is a bit redundant with the next line) 
     32        # we set the writing attribute so we know if  
     33        # lock_write is being called by the same thread 
     34        if not hasattr(self.local, 'writing'): 
     35            self.local.writing = True 
     36            self.writing.wait() # wait for any writes to finish (this is a bit redundant with the next line) 
     37             
    2738        self.writelock.acquire() 
    2839        self.writing.clear() # lock out everyone reading from this dict 
     
    3243        self.readerslock.release() 
    3344        # at this point, all systems go 
     45     
    3446    def unlock_read(self): 
    3547        if hasattr(self.local, "reader"): 
    3648            self.local.reader.set() 
     49     
    3750    def unlock_write(self): 
    3851        self.writing.set() # wake everyone else up. TODO: what if one thread has the lock, and another calls this method? 
    3952        self.writelock.release() 
     53 
    4054 
    4155class MROWDict(dict): 
     
    4660        self._auto_lock = auto_lock # automatically acquire locks for getitem setitem (BAD IDEA) 
    4761        self._auto_lock_safe = auto_lock_safe # when autolocking, lock the whole dict (GOOD IDEA) 
     62     
    4863    def _init_lock(self, key): 
    4964        self._lockslock.acquire() 
     
    5166            self._locks[key] = MROWLock() 
    5267        self._lockslock.release() 
     68     
    5369    def lock_read(self, key = "__me__"): 
    5470        self._init_lock(key) 
    5571        return self._locks[key].lock_read() 
     72     
    5673    def lock_write(self, key = "__me__"): 
    5774        self._init_lock(key) 
    5875        return self._locks[key].lock_write() 
     76     
    5977    def unlock_read(self, key = "__me__"): 
    6078        return self._locks[key].unlock_read() 
     79     
    6180    def unlock_write(self, key = "__me__"): 
    6281        return self._locks[key].unlock_write() 
     82     
    6383    def __delitem__(self, key): 
    6484        if key in self._locks: 
     
    6787            del self._locks[key] 
    6888            dict.__delitem__(self, key) 
     89     
    6990    def __getitem__(self, key): 
    7091        if self._auto_lock: 
     
    7495                self.lock_read(key) 
    7596        return dict.__getitem__(self, key) 
     97     
    7698    def __setitem__(self, key, value): 
    7799        if self._auto_lock: 
     
    81103                self.lock_write(key) 
    82104        dict.__setitem__(self, key, value) 
     105     
     106    def get(self, key): 
     107        if self._auto_lock: 
     108            if self._auto_lock_safe: 
     109                self.lock_read() 
     110            else: 
     111                self.lock_read(key) 
     112        return dict.get(self, key) 
     113     
     114    def setdefault(self, key, value): 
     115        if self._auto_lock: 
     116            if self._auto_lock_safe: 
     117                self.lock_write() 
     118            else: 
     119                self.lock_write(key) 
     120        dict.setdefault(self, key, value) 
    83121 
     122    def update(self, values): 
     123        if self._auto_lock: 
     124            if self._auto_lock_safe: 
     125                self.lock_write() 
     126            else: 
     127                self.lock_write(key) 
     128        dict.update(self, values) 
     129 
     130''' 
    84131# test code 
    85 ''' 
    86132import time, thread 
    87133 
  • trunk/cherrypy/lib/filter/sessionfilter/sessiondict.py

    r548 r575  
    3131from sessionerrors import SessionImmutableError 
    3232 
    33 def locker(function): 
     33def readLocker(function): 
    3434    def _inner(self, *args, **kwds): 
    35         self._lock.acquire() 
     35        self._lock.lock_read() 
    3636        try: 
    3737            return function(self, *args, **kwds) 
    3838        finally: 
    39             self._lock.release() 
     39            self._lock.unlock_read() 
     40    return _inner 
     41 
     42def writeLocker(function): 
     43    def _inner(self, *args, **kwds): 
     44        self._lock.lock_write() 
     45        try: 
     46            return function(self, *args, **kwds) 
     47        finally: 
     48            self._lock.unlock_write() 
    4049    return _inner 
    4150 
    4251import threading  
    4352 
     53import mrow 
     54 
    4455class SessionDict(dict): 
    4556 
    4657    def __init__(self, sessionData = {}, sessionAttributes = {}): 
    47         self._lock = threading.RLock() 
     58        self._lock = mrow.MROWLock() 
    4859        self.threadCount = 0 
    4960         
     
    5162        self.__sessionAttributes = sessionAttributes 
    5263         
    53     get=locker(dict.get) 
    54     setdefault=locker(dict.setdefault) 
     64    get=readLocker(dict.get) 
     65    setdefault=writeLocker(dict.setdefault) 
     66     
     67    def setLock(self, lockObject): 
     68        """ set the lock object """ 
     69        self._lock = lockObject 
     70     
     71    def lock_write(self): 
     72        self._lock.lock_write() 
    5573 
     74    def unlock_write(self): 
     75        self._lock.unlock_write() 
     76 
     77    def lock_read(self): 
     78        self._lock.lock_read() 
     79 
     80    def unlock_read(self): 
     81        self._lock.unlock_read() 
     82     
    5683    def __getattr__(self, attr): 
    5784        try: 
     
    5986        except KeyError: 
    6087            return object.__getattribute__(self, attr) 
    61     __getattr__=locker(__getattr__) 
     88    __getattr__=readLocker(__getattr__) 
    6289     
    6390    # this function we lock the hard way 
     
    6895            return 
    6996 
    70         self._lock.acquire() 
     97        self._lock.lock_read() 
     98        try: 
    7199         
    72         if attr in ['timeout', 'lastAccess' ]: 
    73             self.__sessionAttributes[attr] = value 
    74         elif attr in ['timestamp', 'key']: 
    75             raise AttributeError('%s is immutable' % attr) 
    76         else: 
    77             object.__setattr__(self, attr, value) 
    78  
    79         self._lock.release() 
     100            if attr in ['timeout', 'lastAccess' ]: 
     101                self.__sessionAttributes[attr] = value 
     102            elif attr in ['timestamp', 'key']: 
     103                raise AttributeError('%s is immutable' % attr) 
     104            else: 
     105                object.__setattr__(self, attr, value) 
     106        finally: 
     107            self._lock.unlock_read() 
    80108     
    81109    def expired(self): 
    82110        now = time.time() 
    83111        return (now - self.lastAccess) > self.timeout 
    84     expired = locker(expired) 
     112    expired = readLocker(expired) 
    85113         
    86114    def __getstate__(self): 
     
    90118        stateDict.pop('_lock') 
    91119        return stateDict 
    92     __getstate__ = locker(__getstate__) 
     120    __getstate__ = readLocker(__getstate__) 
    93121 
    94122    def __setstate__(self, stateDict): 
    95123        """ create a new lock object """ 
    96         self.__dict__['_lock'] = threading.RLock() 
     124        self.__dict__['_lock'] = mrow.MROWLock() 
    97125        self.__dict__.update(stateDict) 
    98126 

Hosted by WebFaction

Log in as guest/cpguest to create tickets