witten
/
luminotes
Archived
1
0
Fork 0

Rewrote Session_storage class, because it was periodically raising ProgrammingErrors due to simultaneous cursor access from different threads.

This commit is contained in:
Dan Helfman 2008-10-30 14:43:25 -07:00
parent 3a5ca1d462
commit 22c49a9590
1 changed files with 69 additions and 19 deletions

View File

@ -1,29 +1,79 @@
import cherrypy
from psycopg2 import ProgrammingError
from cherrypy.filters.sessionfilter import PostgreSQLStorage
import cPickle as pickle
from psycopg2 import ProgrammingError
class Session_storage( PostgreSQLStorage ):
"""
A wrapper for CherryPy's PostgreSQLStorage class that commits the current transaction to the
database so session changes actually take effect.
class Session_storage( object ):
"""
A CherryPy session storage class, originally based on CherryPy's PostgreSQLStorage. It assumes
a table like this:
create table session (
id text,
data text,
expiration_time timestamp
)
It differs from PostgreSQLStorage in the following ways:
* changes to the database are actually committed after they are made
* a new cursor is created for each database access to prevent problems with multiple threads
* a connection is requested from cherrypy.root.database instead of a session_filter.get_db method
* __del__ is not implemented because it should not be relied upon
* no locking is implemented
"""
def __init__( self ):
self.db = cherrypy.root.database.get_connection()
self.cursor = self.db.cursor()
self.conn = cherrypy.root.database.get_connection()
def load( self, id ):
cursor = self.conn.cursor()
def load( self, *args, **kwargs ):
try:
return PostgreSQLStorage.load( self, *args, **kwargs )
# catch "ProgrammingError: no results to fetch" from self.cursor.fetchall()
except ProgrammingError:
# Select session data from table
cursor.execute(
'select data, expiration_time from session where id=%s',
(id,))
rows = cursor.fetchall()
if not rows:
return None
pickled_data, expiration_time = rows[0]
# Unpickle data
data = pickle.loads(pickled_data)
return (data, expiration_time)
def save( self, id, data, expiration_time ):
cursor = self.conn.cursor()
def save( self, *args, **kwargs ):
PostgreSQLStorage.save( self, *args, **kwargs )
self.db.commit()
# Try to delete session if it was already there
cursor.execute(
'delete from session where id=%s',
(id,))
# Pickle data
pickled_data = pickle.dumps(data)
# Insert new session data
cursor.execute(
'insert into session (id, data, expiration_time) values (%s, %s, %s)',
(id, pickled_data, expiration_time))
def clean_up( self, *args, **kwargs ):
PostgreSQLStorage.clean_up( self, *args, **kwargs )
self.db.commit()
self.conn.commit()
def clean_up( self, sess ):
cursor = self.conn.cursor()
now = datetime.datetime.now()
cursor.execute(
'select data from session where expiration_time < %s',
(now,))
rows = cursor.fetchall()
for row in rows:
sess.on_delete_session(row[0])
cursor.execute(
'delete from session where expiration_time < %s',
(now,))
self.conn.commit()
def acquire_lock( self ):
raise NotImplemented()
def release_lock( self ):
raise NotImplemented()