[Zope-Checkins] CVS: Zope/lib/python/Products/TemporaryFolder - TemporaryStorage.py:1.5

Chris McDonough chrism@zope.com
Mon, 26 Nov 2001 10:35:26 -0500


Update of /cvs-repository/Zope/lib/python/Products/TemporaryFolder
In directory cvs.zope.org:/tmp/cvs-serv13394

Modified Files:
	TemporaryStorage.py 
Log Message:
Changed revision cache gc algorithm to be better on memory, addd revision cache gc tests.

=== Zope/lib/python/Products/TemporaryFolder/TemporaryStorage.py 1.4 => 1.5 ===
 
 from zLOG import LOG
-from struct import pack, unpack
 from ZODB.referencesf import referencesf
 from ZODB import POSException
 from ZODB.BaseStorage import BaseStorage
-from ZODB.ConflictResolution import ConflictResolvingStorage, ResolvedSerial,\
-     bad_classes, bad_class, _classFactory, PersistentReference, \
-     PersistentReferenceFactory, persistent_id, state
-from cStringIO import StringIO
-from cPickle import Unpickler, Pickler
+from ZODB.ConflictResolution import ConflictResolvingStorage, ResolvedSerial
+import time
 
-# number of transactions for which to keep prior object revisions
-CONFLICT_CACHE_SIZE = 100
+# keep old object revisions for CONFLICT_CACHE_MAXAGE seconds
+CONFLICT_CACHE_MAXAGE = 60
+# garbage collect conflict cache every CONFLICT_CACHE_GCEVERY seconds
+CONFLICT_CACHE_GCEVERY = 60
 
 class ReferenceCountError(POSException.POSError):
     """ An error occured while decrementing a reference to an object in
@@ -128,7 +126,7 @@
         opickle -- mapping of oid to pickle
         _tmp -- used by 'store' to collect changes before finalization
         _conflict_cache -- cache of recently-written object revisions
-        _transaction_counter -- rotating counter used in conflict resolution
+        _last_cache_gc -- last time that conflict cache was garbage collected
         """
         BaseStorage.__init__(self, name)
 
@@ -138,7 +136,7 @@
         self._opickle={}
         self._tmp = []
         self._conflict_cache = {}
-        self._transaction_counter = 0
+        self._last_cache_gc = 0
         self._oid = '\0\0\0\0\0\0\0\0'
 
     def __len__(self):
@@ -148,11 +146,14 @@
         return 0
 
     def _clear_temp(self):
+        now = time.time()
+        if now > (self._last_cache_gc + CONFLICT_CACHE_GCEVERY):
+            for k, v in self._conflict_cache.items():
+                data, t = v
+                if now > (t + CONFLICT_CACHE_MAXAGE):
+                    del self._conflict_cache[k]
+            self._last_cache_gc = now
         self._tmp = []
-        if self._transaction_counter % CONFLICT_CACHE_SIZE == 0:
-            # clear the revision cache before we run out of RAM.
-            self._transaction_counter = 0
-            self._conflict_cache = {}
         
     def close(self):
         """
@@ -174,7 +175,7 @@
         storage needs! """
         self._lock_acquire()
         try:
-            data = self._conflict_cache.get((oid, serial), marker)
+            data, t = self._conflict_cache.get((oid, serial), marker)
             if data is marker:
                 raise POSException.ConflictError, (oid, serial)
             return data
@@ -200,7 +201,8 @@
                 oserial = serial
             newserial=self._serial
             self._tmp.append((oid, data))
-            self._conflict_cache[(oid, newserial)] = data
+            now = time.time()
+            self._conflict_cache[(oid, newserial)] = data, now
             return serial == oserial and newserial or ResolvedSerial
         finally:
             self._lock_release()
@@ -279,9 +281,8 @@
                 if oid == '\0\0\0\0\0\0\0\0': continue
                 self._takeOutGarbage(oid)
 
-        self._transaction_counter = self._transaction_counter + 1
-        self._clear_temp()
-
+        self._tmp = []
+        
     def _takeOutGarbage(self, oid):
         # take out the garbage.
         referenceCount=self._referenceCount