[Checkins] SVN: z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/ - changed the caching of the connection and session object for Zope wrapper

Andreas Jung andreas at andreas-jung.com
Tue May 1 05:54:46 EDT 2007


Log message for revision 74956:
     - changed the caching of the connection and session object for Zope wrapper
       since the id of a transaction is not reliable (different transaction
       object can re-use the same memory address leading to cache errors)
  
  

Changed:
  U   z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/CHANGES.txt
  U   z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/base.py

-=-
Modified: z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/CHANGES.txt
===================================================================
--- z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/CHANGES.txt	2007-05-01 09:01:30 UTC (rev 74955)
+++ z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/CHANGES.txt	2007-05-01 09:54:45 UTC (rev 74956)
@@ -3,6 +3,16 @@
    - added check for the 'mapper_class' attribute (classes from now
      on must be a subclass of MapperClassBase)
 
+   - a Zope-aware SAWrapper now has a 'connection' property that can
+     be used to execute SQL statements directly. 'connection' is an 
+     instance of sqlalchemy.Connection and directly tied to the current
+     Zope transaction.
+
+   - changed the caching of the connection and session object for Zope wrapper
+     since the id of a transaction is not reliable (different transaction
+     object can re-use the same memory address leading to cache errors)
+
+
 0.1.10 (30.04.2007)
 
    - fixed a bug in mapper (unfortunately I forgot to commit a

Modified: z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/base.py
===================================================================
--- z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/base.py	2007-05-01 09:01:30 UTC (rev 74955)
+++ z3c.sqlalchemy/trunk/src/z3c/sqlalchemy/base.py	2007-05-01 09:54:45 UTC (rev 74956)
@@ -23,6 +23,30 @@
 from transaction.interfaces import IDataManager
 
 
+class SynchronizedThreadCache(object):
+
+    def __init__(self):
+        self.lock = threading.Lock()
+        self.cache = threading.local()
+
+
+    def set(self, **kw):
+
+        self.lock.acquire()
+        for k,v in kw.items():
+            setattr(self.cache, k, v)
+        self.lock.release()
+
+
+    def get(self, *names):
+        self.lock.acquire()
+        lst = []
+        for name in names:
+            lst.append(getattr(self.cache, name, None))
+        self.lock.release()
+        return lst
+
+
 class BaseWrapper(object):
 
     implements(ISQLAlchemyWrapper)
@@ -113,8 +137,8 @@
     def _createEngine(self):
         return sqlalchemy.create_engine(self.dsn, **self.kw)
 
-_session_cache = threading.local() # module-level cache 
-_connection_cache = threading.local() # module-level cache 
+session_cache = SynchronizedThreadCache()
+connection_cache = SynchronizedThreadCache()
 
 
 class SessionDataManager(object):
@@ -131,10 +155,12 @@
 
     def abort(self, trans):
         self.transaction.rollback()
+        session_cache.set(last_session=None, last_transaction=None)
 
     def commit(self, trans):
         self.session.flush()
         self.transaction.commit()
+        session_cache.set(last_session=None, last_transaction=None)
 
     def tpc_vote(self, trans):
         pass
@@ -165,11 +191,13 @@
         self.transaction.rollback()
         self.connection.close()
         self.connection = None
+        connection_cache.set(last_connection=None, last_transaction=None)
 
     def commit(self, trans):
         self.transaction.commit()
         self.connection.close()
         self.connection = None
+        connection_cache.set(last_connection=None, last_transaction=None)
 
     def tpc_vote(self, trans):
         pass
@@ -192,28 +220,21 @@
     @property
     def session(self):
 
-        if not hasattr(_session_cache, 'last_transaction'):
-            _session_cache.last_transaction = None
-            _session_cache.last_session = None
+        last_session, = connection_cache.get('last_session')
 
-        # get current transaction
-        txn = transaction.get()
-        txn_str = str(txn)
-
         # return cached session if we are within the same transaction
         # and same thread
-        if txn_str == _session_cache.last_transaction:
-            return _session_cache.last_session
+        if last_session is not None:
+            return last_session
 
         # no cached session, let's create a new one
         session = sqlalchemy.create_session(self._engine)
                                           
         # register a DataManager with the current transaction
-        txn.join(SessionDataManager(session))
+        transaction.get().join(SessionDataManager(session))
 
         # update thread-local cache
-        _session_cache.last_transaction = txn_str
-        _session_cache.last_session = session
+        session_cache.set(last_session=session)
 
         # return the session
         return session 
@@ -221,28 +242,21 @@
     @property
     def connection(self):
 
-        if not hasattr(_connection_cache, 'last_connection'):
-            _connection_cache.last_transaction = None
-            _connection_cache.last_connection = None
+        last_connection, = connection_cache.get('last_connection')
 
-        # get current transaction
-        txn = transaction.get()
-        txn_str = str(txn)
-
         # return cached connection if we are within the same transaction
         # and same thread
-        if txn_str == _connection_cache.last_transaction:
-            return _connection_cache.last_connection
+        if last_connection is not None:
+            return last_connection
 
         # no cached connection, let's create a new one
         connection = self.engine.connect()
                                           
         # register a DataManager with the current transaction
-        txn.join(ConnectionDataManager(connection))
+        transaction.get().join(ConnectionDataManager(connection))
 
         # update thread-local cache
-        _connection_cache.last_transaction = txn_str
-        _connection_cache.last_connection = connection
+        connection_cache.set(last_connection=connection)
 
         # return the connection
         return connection



More information about the Checkins mailing list