[Checkins] SVN: z3c.extfile/trunk/src/z3c/extfile/ the readfile does not use thread local anymore, we handle the closing of readfiles in extbytesproperty, because this is the only place where the file is implicitly opened, and should be impl. closed too

Bernd Dorn bernd.dorn at fhv.at
Thu Sep 14 03:39:36 EDT 2006


Log message for revision 70164:
  the readfile does not use thread local anymore, we handle the closing of readfiles in extbytesproperty, because this is the  only place where the file is implicitly opened, and should be impl. closed too

Changed:
  U   z3c.extfile/trunk/src/z3c/extfile/hashdir.py
  U   z3c.extfile/trunk/src/z3c/extfile/property.py

-=-
Modified: z3c.extfile/trunk/src/z3c/extfile/hashdir.py
===================================================================
--- z3c.extfile/trunk/src/z3c/extfile/hashdir.py	2006-09-13 22:28:56 UTC (rev 70163)
+++ z3c.extfile/trunk/src/z3c/extfile/hashdir.py	2006-09-14 07:39:34 UTC (rev 70164)
@@ -7,8 +7,8 @@
 import interfaces
 from zope import interface
 from persistent import Persistent
-from zope import thread
 
+
 class HashDir(Persistent):
 
     """a directory holding files named after their sha1 hash"""
@@ -72,8 +72,8 @@
     def open(self, digest):
         return ReadFile(self.getPath(digest))
         
-openFiles = thread.local()
 
+
 class ReadFile(object):
 
     interface.implements(interfaces.IReadFile)
@@ -83,18 +83,15 @@
         self.digest = os.path.split(self.name)[1]
         self.bufsize=bufsize
         self._v_len = None
+        self._v_file = None
 
     @property
     def _file(self):
-        if hasattr(openFiles, self.digest):
-            f = getattr(openFiles, self.digest)
-            if f.closed:
-                delattr(openFiles, self.digest)
-            else:
-                return f
-        f = file(self.name, 'rb', self.bufsize)
-        setattr(openFiles, self.digest, f)
-        return f
+        if self._v_file is not None:
+            if not self._v_file.closed:
+                return self._v_file
+        self._v_file = file(self.name, 'rb', self.bufsize)
+        return self._v_file
     
     def __len__(self):
         if self._v_len is None:
@@ -121,11 +118,10 @@
 
     def close(self):
         """see file.close"""
-        if hasattr(openFiles, self.digest):
-            f = getattr(openFiles, self.digest)
-            if not f.closed:
-                f.close()
-            delattr(openFiles, self.digest)
+        if self._v_file is not None:
+            if not self._v_file.closed:
+                return self._v_file.close()
+        self._v_file = None
         
     def fileno(self):
         return self._file.fileno()

Modified: z3c.extfile/trunk/src/z3c/extfile/property.py
===================================================================
--- z3c.extfile/trunk/src/z3c/extfile/property.py	2006-09-13 22:28:56 UTC (rev 70163)
+++ z3c.extfile/trunk/src/z3c/extfile/property.py	2006-09-14 07:39:34 UTC (rev 70164)
@@ -1,29 +1,43 @@
 from zope import component, interface
 import interfaces
 from cStringIO import StringIO
+from transaction.interfaces import IDataManager
+from zope import thread
+import transaction
 
 _marker = object()
 BLOCK_SIZE = 1024*128
 
+_storage = thread.local()
+
 class ExtBytesProperty(object):
 
     """a property which's values are stored as external files"""
 
     def __init__(self, name):
         self.__name = name
+        
 
     @property
     def hd(self):
         return component.getUtility(interfaces.IHashDir)
     
     def __get__(self, inst, klass):
+
         if inst is None:
             return self
         digest = inst.__dict__.get(self.__name, _marker)
         if digest is _marker:
             return None
-        return self.hd.open(digest)
 
+        
+        if not hasattr(_storage, 'dataManager'):
+            _storage.dataManager = ReadFileDataManager()
+            txn = transaction.manager.get()
+            if txn is not None:
+                txn.join(_storage.dataManager)
+        return _storage.dataManager.getFile(digest)
+
     def __set__(self, inst, value):
         # ignore if value is None
         if value is None:
@@ -44,3 +58,48 @@
             f.write(chunk)
 
 
+class ReadFileDataManager(object):
+
+    """Takes care of closing open files"""
+    
+    interface.implements(IDataManager)
+
+    def __init__(self):
+        self.files = {}
+        
+    @property
+    def hd(self):
+        return component.getUtility(interfaces.IHashDir)
+
+    def getFile(self, digest):
+        if digest in self.files:
+            return self.files[digest]
+        self.files[digest] = self.hd.open(digest)
+        return self.files[digest]
+
+    def _close(self):
+        import logging
+        logging.info('RFD.colse %r' % self.files.keys())
+        for f in self.files.values():
+            f.close()
+        
+    def abort(self, trans):
+        self._close()
+
+    def tpc_begin(self, trans):
+        pass
+
+    def commit(self, trans):
+        self._close()
+
+    def tpc_vote(self, trans):
+        pass
+
+    def tpc_finish(self, trans):
+        self._close()
+
+    def tpc_abort(self, trans):
+        self._close()
+
+    def sortKey(self):
+        return str(id(self))



More information about the Checkins mailing list