SVN: ZODB/trunk/src/ZEO/ Changed close to use the asyncore thread to try to avoid a race and

Jim Fulton <[email protected]>
Newsgroups gmane.comp.python.zope.zodb.cvs
Message-ID <20091222202807.89225941AE__13644.0444890924$1261513704$gmane$org@cvs.zope.org>
Log message for revision 106930:
  Changed close to use the asyncore thread to try to avoid a race and
  breaking the client loop.
  

Changed:
  U   ZODB/trunk/src/ZEO/ClientStorage.py
  U   ZODB/trunk/src/ZEO/tests/testZEO.py

-=-
Modified: ZODB/trunk/src/ZEO/ClientStorage.py
===================================================================
--- ZODB/trunk/src/ZEO/ClientStorage.py	2009-12-22 20:28:05 UTC (rev 106929)
+++ ZODB/trunk/src/ZEO/ClientStorage.py	2009-12-22 20:28:07 UTC (rev 106930)
@@ -442,11 +442,20 @@
             logger.info("%s Waiting for cache verification to finish",
                         self.__name__)
 
-    def close(self):
-        """Storage API: finalize the storage, releasing external resources."""
+    def close(self, kill=False):
+        "Storage API: finalize the storage, releasing external resources."
         if self._rpc_mgr is not None:
             self._rpc_mgr.close()
             self._rpc_mgr = None
+
+        if (self._connection is not None) and not kill:
+            event = threading.Event()
+            self._connection.trigger.pull_trigger(lambda: self._close(event))
+            event.wait(9)
+        else:
+            self._close()
+
+    def _close(self, event=None):
         if self._connection is not None:
             self._connection.register_object(None) # Don't call me!
             self._connection.close()
@@ -462,6 +471,9 @@
         if self._check_blob_size_thread is not None:
             self._check_blob_size_thread.join()
 
+        if event is not None:
+            event.set()
+
     _check_blob_size_thread = None
     def _check_blob_size(self, bytes=None):
         if self._blob_cache_size is None:

Modified: ZODB/trunk/src/ZEO/tests/testZEO.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/testZEO.py	2009-12-22 20:28:05 UTC (rev 106929)
+++ ZODB/trunk/src/ZEO/tests/testZEO.py	2009-12-22 20:28:07 UTC (rev 106930)
@@ -951,6 +951,8 @@
     ...         pass
     ...     def close(self):
     ...         print 'connection closed'
+    ...     trigger = property(lambda self: self)
+    ...     pull_trigger = lambda self, func: func()
 
     >>> class ConnectionManager:
     ...     def __init__(self, addr, client, tmin, tmax):
@@ -1228,6 +1230,35 @@
     testing exit immediately
     """
 
+def close_client_storage_w_invalidations():
+    r"""
+Invalidations could cause errors when closing client storages,
+
+    >>> addr, _ = start_server()
+    >>> writing = threading.Event()
+    >>> def mad_write_thread():
+    ...     global writing
+    ...     conn = ZEO.connection(addr)
+    ...     writing.set()
+    ...     while writing.isSet():
+    ...         conn.root.x = 1
+    ...         transaction.commit()
+    ...     conn.close()
+
+    >>> thread = threading.Thread(target=mad_write_thread)
+    >>> thread.setDaemon(True)
+    >>> thread.start()
+    >>> writing.wait()
+    >>> time.sleep(.01)
+    >>> for i in range(10):
+    ...     conn = ZEO.connection(addr)
+    ...     _ = conn._storage.load('\0'*8)
+    ...     conn.close()
+
+    >>> writing.clear()
+    >>> thread.join(1)
+    """
+
 slow_test_classes = [
     BlobAdaptedFileStorageTests, BlobWritableCacheTests,
     DemoStorageTests, FileStorageTests, MappingStorageTests,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.