core (memory): Sessions fixes:
- avoid memory leak with forgotten _purgeSession in case of conflict: an exception is now raised instead
- _purgeSession now cancel the timer if it was not done before
- KeyError in profileGet is now explicitly raised throught a failure.Failure
- use iterator to iterate session in ProfileSessions
This commit is contained in:
parent
fd3e9ce044
commit
0a22619026
1 changed files with 25 additions and 12 deletions
|
|
@ -27,7 +27,8 @@ import copy
|
|||
from collections import namedtuple
|
||||
from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError
|
||||
from uuid import uuid4
|
||||
from twisted.internet import defer, reactor
|
||||
from twisted.python import failure
|
||||
from twisted.internet import defer, reactor, error
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from sat.core import exceptions
|
||||
from sat.core.constants import Const as C
|
||||
|
|
@ -40,6 +41,7 @@ from sat.tools import config as tools_config
|
|||
|
||||
|
||||
PresenceTuple = namedtuple("PresenceTuple", ('show', 'priority', 'statuses'))
|
||||
MSG_NO_SESSION = "Session id doesn't exist or is finished"
|
||||
|
||||
class Sessions(object):
|
||||
"""Sessions are data associated to key used for a temporary moment, with optional profile checking."""
|
||||
|
|
@ -55,7 +57,8 @@ class Sessions(object):
|
|||
self.resettable_timeout = resettable_timeout
|
||||
|
||||
def newSession(self, session_data=None, session_id=None, profile=None):
|
||||
""" Create a new session
|
||||
"""Create a new session
|
||||
|
||||
@param session_data: mutable data to use, default to a dict
|
||||
@param session_id (str): force the session_id to the given string
|
||||
@param profile: if set, the session is owned by the profile,
|
||||
|
|
@ -65,8 +68,7 @@ class Sessions(object):
|
|||
if session_id is None:
|
||||
session_id = str(uuid4())
|
||||
elif session_id in self._sessions:
|
||||
self._sessions[session_id][0].cancel()
|
||||
log.warning(u"Session [{id}] is going to be re-initialised".format(id=session_id))
|
||||
raise exceptions.ConflictError(u"Session id {} is already used".format(session_id))
|
||||
timer = reactor.callLater(self.timeout, self._purgeSession, session_id)
|
||||
if session_data is None:
|
||||
session_data = {}
|
||||
|
|
@ -74,8 +76,18 @@ class Sessions(object):
|
|||
return session_id, session_data
|
||||
|
||||
def _purgeSession(self, session_id):
|
||||
try:
|
||||
timer, session_data, profile = self._sessions[session_id]
|
||||
except ValueError:
|
||||
timer, session_data = self._sessions[session_id]
|
||||
profile = None
|
||||
try:
|
||||
timer.cancel()
|
||||
except error.AlreadyCalled:
|
||||
# if the session is time-outed, the timer has been called
|
||||
pass
|
||||
del self._sessions[session_id]
|
||||
log.debug(u"Session [%s] purged" % session_id)
|
||||
log.debug(u"Session {} purged{}".format(session_id, u' (profile {})'.format(profile) if profile is not None else u''))
|
||||
|
||||
def __len__(self):
|
||||
return len(self._sessions)
|
||||
|
|
@ -88,6 +100,8 @@ class Sessions(object):
|
|||
timer, session_data, profile_set = self._sessions[session_id]
|
||||
except ValueError:
|
||||
raise exceptions.InternalError("You need to use __getitem__ when profile is not set")
|
||||
except KeyError:
|
||||
raise failure.Failure(KeyError(MSG_NO_SESSION))
|
||||
if profile_set != profile:
|
||||
raise exceptions.InternalError("current profile differ from set profile !")
|
||||
if self.resettable_timeout:
|
||||
|
|
@ -99,6 +113,8 @@ class Sessions(object):
|
|||
timer, session_data = self._sessions[session_id]
|
||||
except ValueError:
|
||||
raise exceptions.InternalError("You need to use profileGet instead of __getitem__ when profile is set")
|
||||
except KeyError:
|
||||
raise failure.Failure(KeyError(MSG_NO_SESSION))
|
||||
if self.resettable_timeout:
|
||||
timer.reset(self.timeout)
|
||||
return session_data
|
||||
|
|
@ -108,12 +124,9 @@ class Sessions(object):
|
|||
|
||||
def __delitem__(self, session_id):
|
||||
""" Cancel the timer, then actually delete the session data """
|
||||
try:
|
||||
timer = self._sessions[session_id][0]
|
||||
timer.cancel()
|
||||
self._purgeSession(session_id)
|
||||
except KeyError:
|
||||
log.debug(u"Session [%s] doesn't exists, timeout expired?" % session_id)
|
||||
timer = self._sessions[session_id][0]
|
||||
timer.cancel()
|
||||
self._purgeSession(session_id)
|
||||
|
||||
def keys(self):
|
||||
return self._sessions.keys()
|
||||
|
|
@ -134,7 +147,7 @@ class ProfileSessions(Sessions):
|
|||
@return: a list containing the sessions ids
|
||||
"""
|
||||
ret = []
|
||||
for session_id in self._sessions:
|
||||
for session_id in self._sessions.iterkeys():
|
||||
try:
|
||||
timer, session_data, profile_set = self._sessions[session_id]
|
||||
except ValueError:
|
||||
|
|
|
|||
Loading…
Reference in a new issue