[Zope-CVS] CVS: Products/FileCacheManager - CHANGES.txt:1.2 FileCache.py:1.10

Chris McDonough chrism at plope.com
Fri Nov 19 01:31:53 EST 2004


Update of /cvs-repository/Products/FileCacheManager
In directory cvs.zope.org:/tmp/cvs-serv14131

Modified Files:
	CHANGES.txt FileCache.py 
Log Message:
Add "entries_being_written" cache to prevent returning of stale data from ZCache_get after a ZCache_set of an already-cached object has been performed.


=== Products/FileCacheManager/CHANGES.txt 1.1 => 1.2 ===
--- Products/FileCacheManager/CHANGES.txt:1.1	Mon Aug 30 13:40:43 2004
+++ Products/FileCacheManager/CHANGES.txt	Fri Nov 19 01:31:52 2004
@@ -1,6 +1,16 @@
 CHANGES.txt for the FileCacheManager product
 
+    post-1.0
+
+      After a ZCache_set has been performed, during the transaction lifetime,
+      return the file data fed to ZCache_set via ZCache_get even though it
+      hasn't yet been written to the ultimate filepath.  If this is not done,
+      ZCache_get could return "stale" data from the perspective of the
+      application using FCM.
+
+      HTTP caching added.
+
     1.0
 
       First public release
-
+      


=== Products/FileCacheManager/FileCache.py 1.9 => 1.10 ===
--- Products/FileCacheManager/FileCache.py:1.9	Sun Oct 31 12:59:29 2004
+++ Products/FileCacheManager/FileCache.py	Fri Nov 19 01:31:52 2004
@@ -20,7 +20,7 @@
 
 import zLOG
 
-from thread import allocate_lock
+from ThreadLock import allocate_lock
 
 from AccessControl.SecurityManagement import getSecurityManager
 from App.Common import rfc1123_date
@@ -33,6 +33,9 @@
 
 _debug = 0
 
+entries_being_written = {}
+entries_being_written_lock = allocate_lock()
+
 class FileCache(RAMCache):
     """ A cache that caches rendered content to the filesystem """
     _tempfile_path = ''
@@ -51,6 +54,10 @@
         self._http_caching_anonymous_only = True
         self.entries = {}
 
+    def get_entries_being_written(self):
+        # for unit testing
+        return entries_being_written
+
     def _fileName(self, ob):
         """ Compute a filename based on an MD5 hash: doesn't preserve
         human-readable path, but otherwise makes life much easier """
@@ -126,6 +133,15 @@
         pp = '/'.join(ob.getPhysicalPath())
         fname = self._fileName(ob)
 
+        entries_being_written_lock.acquire()
+        try:
+            entry = entries_being_written.get(fname)
+        finally:
+            entries_being_written_lock.release()
+
+        if entry is not None:
+            fname = entry.get_temppath()
+            
         try:
             fiter = filestream_iterator(fname, 'rb')
         except IOError:
@@ -249,7 +265,20 @@
 
         # Register as Transaction Manager so my transaction hooks get called.
         get_transaction().register(self)
+ 
+    def get_temppath(self):
+        if not self.temppath:
+            raise AssertionError, 'temppath is None'
+        return self.temppath
 
+    def del_from_entry_registry(self):
+        entries_being_written_lock.acquire()
+        try:
+            entry = entries_being_written.get(self.path)
+            if entry and entry.temppath == self.temppath:
+                del entries_being_written[self.path]
+        finally:
+            entries_being_written_lock.release()
 
     def remove(self):
         """ Delete the cache file from disk """
@@ -285,6 +314,12 @@
 
             self.op_write = 1
 
+            entries_being_written_lock.acquire()
+            try:
+                entries_being_written[self.path] = self
+            finally:
+                entries_being_written_lock.release()
+
         except IOError, msg:
             zLOG.LOG( 'FileCacheManager'
                     , zLOG.ERROR
@@ -322,11 +357,11 @@
             except (OSError, IOError):
                 pass
 
+        self.del_from_entry_registry()
         self.temppath = None
         self.op_write = 0
         self.op_remove = 0
 
-
     def tpc_vote(self, transaction):
         """ Only called for real transactions, not subtransactions """
         self._transaction_done = 1
@@ -395,6 +430,7 @@
                              , error=sys.exc_info()
                              )
             finally:
+                self.del_from_entry_registry()
                 self.writelock.release()
                 self.temppath = None
                 self.op_write = 0



More information about the Zope-CVS mailing list