[Checkins] SVN: zc.FileStorage/trunk/src/zc/FileStorage/__init__.py Added file-based storage of object references.

Jim Fulton jim at zope.com
Sat Dec 6 20:02:23 EST 2008


Log message for revision 93740:
  Added file-based storage of object references.
  

Changed:
  U   zc.FileStorage/trunk/src/zc/FileStorage/__init__.py

-=-
Modified: zc.FileStorage/trunk/src/zc/FileStorage/__init__.py
===================================================================
--- zc.FileStorage/trunk/src/zc/FileStorage/__init__.py	2008-12-07 00:41:51 UTC (rev 93739)
+++ zc.FileStorage/trunk/src/zc/FileStorage/__init__.py	2008-12-07 01:02:22 UTC (rev 93740)
@@ -13,9 +13,12 @@
 ##############################################################################
 
 import cPickle
+import logging
 import os
+import shutil
 import subprocess
 import sys
+import tempfile
 
 from ZODB.FileStorage.format import FileStorageFormatter, CorruptedDataError
 from ZODB.serialize import referencesf
@@ -244,17 +247,24 @@
 
 pack_script_template = """
 
-import sys
+import sys, logging
 
 sys.path[:] = %(syspath)r
 
 import cPickle
 import zc.FileStorage
 
+logging.getLogger().setLevel(logging.INFO)
+handler = logging.FileHandler(%(path)r+'.packlog')
+handler.setFormatter(logging.Formatter(
+   '%%(asctime)s %%(name)s %%(levelname)s %%(message)s'))
+logging.getLogger().addHandler(handler)
+
 try:
     packer = zc.FileStorage.PackProcess(%(path)r, %(stop)r, %(size)r)
     packer.pack()
 except Exception, v:
+    logging.exception('packing')
     try:
         v = cPickle.dumps(v)
     except Exception:
@@ -293,18 +303,24 @@
         return FileStoragePacker._read_txn_header(self, pos, tid)
 
     def pack(self):
+        logging.info('started')
         do_gc = not os.path.exists(self._name+'.packnogc')
         packed, index, references, packpos = self.buildPackIndex(
             self._stop, self.file_end, do_gc)
         if packed:
             # nothing to do
+            logging.info('done, nothing to do')
             self._file.close()
             return
 
         if do_gc:
+            logging.info('read to end for gc')
             self.updateReferences(references, packpos, self.file_end)
+            logging.info('gc')
             index = self.gc(index, references)
 
+        
+        logging.info('copy to pack time')
         output = OptionalSeekFile(self._name + ".pack", "w+b")
         output._freecache = _freefunc(output)
         index, new_pos = self.copyToPacktime(packpos, index, output)
@@ -313,8 +329,10 @@
             self._file.close()
             output.close()
             os.remove(self._name + ".pack")
+            logging.info('done, no decrease')
             return
 
+        logging.info('copy from pack time')
         self.copyFromPacktime(packpos, self.file_end, output, index)
 
         # Save the index so the parent process can use it as a starting point.
@@ -330,6 +348,7 @@
     def buildPackIndex(self, stop, file_end, do_gc):
         index = ZODB.fsIndex.fsIndex()
         references = MemoryReferences()
+        references = FileReferences(self._name)
         pos = 4L
         packed = True
         if do_gc:
@@ -540,6 +559,7 @@
 
     return _free
 
+
 class MemoryReferences:
 
     def __init__(self):
@@ -590,7 +610,45 @@
             references_ioid1[1].pop(ioid2, None)
         
 
+class FileReferences:
 
+    def __init__(self, path):
+        self._tmp = tempfile.mkdtemp('.refs', dir=os.path.dirname(path))
+        self._path = self._data = None
 
-        
-    
+    def clear(self):
+        shutil.rmtree(self._tmp)
+
+    def _load(self, oid):
+        base, index = divmod(long(oid), 256)
+        path = os.path.join(self._tmp, hex(base))
+        if path != self._path:
+            try:
+                f = open(path, 'rb')
+            except IOError:
+                assert not os.path.exists(path)
+                data = {}
+            else:
+                data = cPickle.Unpickler(f).load()
+                f.close()
+            self._data = data
+            self._path = path
+        return self._data, index
+
+    def get(self, oid):
+        data, index = self._load(oid)
+        return data.get(index, ())
+
+    def __setitem__(self, oid, refs):
+        data, index = self._load(oid)
+        if set(refs) != set(data.get(index, ())):
+            data[index] = refs
+            cPickle.Pickler(open(self._path, 'wb'), 1).dump(data)
+
+
+    def rmf(self, oid):
+        data, index = self._load(oid)
+        if index in data:
+            del data[index]
+            cPickle.Pickler(open(self._path, 'wb'), 1).dump(data)
+            



More information about the Checkins mailing list