[Checkins] SVN: lovely.session/trunk/ Made the DataManager savepoint aware.
Adam Groszer
agroszer at gmail.com
Thu Sep 25 17:35:16 EDT 2008
Log message for revision 91490:
Made the DataManager savepoint aware.
Changed:
U lovely.session/trunk/CHANGES.txt
U lovely.session/trunk/src/lovely/session/README.txt
U lovely.session/trunk/src/lovely/session/memcached.py
-=-
Modified: lovely.session/trunk/CHANGES.txt
===================================================================
--- lovely.session/trunk/CHANGES.txt 2008-09-25 21:16:36 UTC (rev 91489)
+++ lovely.session/trunk/CHANGES.txt 2008-09-25 21:35:16 UTC (rev 91490)
@@ -2,12 +2,18 @@
CHANGES
=======
-0.1.5 (unreleased)
+0.2.1 (unreleased)
------------------
- ...
+0.2.0 (2008-09-25)
+------------------
+
+- Made the DataManager savepoint aware.
+
+
0.1.4 (2008-07-31)
------------------
@@ -34,4 +40,3 @@
------------------
- Fixed dependency on `lovely.memcached`.
-
Modified: lovely.session/trunk/src/lovely/session/README.txt
===================================================================
--- lovely.session/trunk/src/lovely/session/README.txt 2008-09-25 21:16:36 UTC (rev 91489)
+++ lovely.session/trunk/src/lovely/session/README.txt 2008-09-25 21:35:16 UTC (rev 91490)
@@ -15,6 +15,9 @@
Start a memcache instance with : memcached <optional options>
+
+Once memcached is running, we can start testing:
+
>>> from zope import component
>>> from lovely.memcached.interfaces import IMemcachedClient
>>> from lovely.memcached.utility import MemcachedClient
@@ -51,13 +54,19 @@
>>> data
{'info': 'stored in memcache'}
+
+
+Transaction support
+~~~~~~~~~~~~~~~~~~~
+
Because the MemCacheSession is transaction aware we need to commit the
transaction to store data in the memcache.
>>> import transaction
+
>>> transaction.commit()
-If we now read session data is is read back from the memcache.
+If we now read session data it is read back from the memcache.
>>> session = sessionData['mySessionId']
>>> session['myData']
@@ -66,3 +75,77 @@
>>> sessionData.items()
[('mySessionId', <lovely.session.memcached.DataManager object at ...>)]
+
+MemCacheSession is now also savepoint aware, let's check how that works:
+
+We first set some data:
+
+ >>> session = sessionData['mySessionId']
+ >>> data = session['myData']
+ >>> data['info'] = 'we want to keep this'
+
+Set a savepoint:
+
+ >>> savepoint = transaction.savepoint()
+
+Change the data:
+
+ >>> data['info'] = 'this should be dumped'
+
+Rollback to the previous value:
+
+ >>> savepoint.rollback()
+
+And here it is, the before value:
+
+ >>> data['info']
+ 'we want to keep this'
+
+Newly added data must also go away:
+
+We add a new data:
+
+ >>> data['newinfo'] = 'go away'
+
+And a new container:
+
+ >>> newdata = session['myNewData']
+ >>> newdata['foo'] = 'bar'
+
+Roll it back to the previous savepoint:
+
+ >>> savepoint.rollback()
+
+The data is gone:
+
+ >>> data['newinfo']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'newinfo'
+
+The container is empty, because it gets always created on retrieval:
+
+ >>> session['myNewData']
+ {}
+
+Let's see what happens on commit:
+
+ >>> transaction.commit()
+
+If we now read session data it is read back from the memcache.
+
+ >>> session = sessionData['mySessionId']
+ >>> session['myData']
+ {'info': 'we want to keep this'}
+
+The data is not present:
+
+ >>> data['newinfo']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'newinfo'
+
+The container is empty, because it gets always created on retrieval:
+
+ >>> session['myNewData']
+ {}
Modified: lovely.session/trunk/src/lovely/session/memcached.py
===================================================================
--- lovely.session/trunk/src/lovely/session/memcached.py 2008-09-25 21:16:36 UTC (rev 91489)
+++ lovely.session/trunk/src/lovely/session/memcached.py 2008-09-25 21:35:16 UTC (rev 91490)
@@ -23,7 +23,8 @@
import persistent
import transaction
-from transaction.interfaces import IDataManager
+from transaction.interfaces import ISavepointDataManager
+from transaction.interfaces import IDataManagerSavepoint
from zope import interface
from zope import component
@@ -152,7 +153,7 @@
class DataManager(object):
"""A data manager for the transaction management of the session data"""
- interface.implements(IDataManager)
+ interface.implements(ISavepointDataManager)
def __init__(self, sessionData, key):
self.sessionData = sessionData
@@ -193,3 +194,43 @@
def sortKey(self):
return str(id(self))
+ def savepoint(self):
+ # When we create the savepoint, we save the existing database state.
+ return Savepoint(self, cPickle.dumps(self._data))
+
+ def _rollback_savepoint(self, data):
+ # When we rollback the savepoint, we restore the saved data.
+ # Caution: without the pickle, further changes to the database
+ # could reflect in savepoint.data, and then `savepoint` would no
+ # longer contain the originally saved data, and so `savepoint`
+ # couldn't restore the original state if a rollback to this
+ # savepoint was done again. IOW, pickle is necessary.
+
+ # there is also a small dance around with the container and
+ # and data not to break referenced variables
+ # the MemCachedSessionDataContainer / MemCacheSessionData / MemCachePkgData
+ # seems to be stable so this seems to be reasonable
+
+ state = cPickle.loads(data)
+ self._data.lastAccessTime = state.lastAccessTime
+ for k,v in state.items():
+ self._data[k].update(v)
+ todel = [x for x in self._data[k].keys() if x not in v.keys()]
+ for x in todel:
+ del self._data[k][x]
+
+ todel = [x for x in self._data.keys() if x not in state.keys()]
+ for x in todel:
+ del self._data[x]
+
+
+class Savepoint(object):
+
+ interface.implements(IDataManagerSavepoint)
+
+ def __init__(self, data_manager, data):
+ self.data_manager = data_manager
+ self.data = data
+
+ def rollback(self):
+ self.data_manager._rollback_savepoint(self.data)
More information about the Checkins
mailing list