[Checkins] SVN: zc.zodbdgc/branches/dev/s Added command-line interfaces and tests for them.

Jim Fulton jim at zope.com
Tue May 12 15:44:46 EDT 2009


Log message for revision 99883:
  Added command-line interfaces and tests for them.
  
  Added test unsing secondary databases for analysis.
  

Changed:
  U   zc.zodbdgc/branches/dev/setup.py
  U   zc.zodbdgc/branches/dev/src/zc/zodbdgc/README.test
  U   zc.zodbdgc/branches/dev/src/zc/zodbdgc/__init__.py

-=-
Modified: zc.zodbdgc/branches/dev/setup.py
===================================================================
--- zc.zodbdgc/branches/dev/setup.py	2009-05-12 18:35:37 UTC (rev 99882)
+++ zc.zodbdgc/branches/dev/setup.py	2009-05-12 19:44:45 UTC (rev 99883)
@@ -18,6 +18,9 @@
 from setuptools import setup, find_packages
 
 entry_points = """
+[console_scripts]
+multi-zodb-gc = zc.zodbdgc:gc_command
+multi-zodb-check-refs = zc.zodbdgc:check_command
 """
 
 def read(rname):

Modified: zc.zodbdgc/branches/dev/src/zc/zodbdgc/README.test
===================================================================
--- zc.zodbdgc/branches/dev/src/zc/zodbdgc/README.test	2009-05-12 18:35:37 UTC (rev 99882)
+++ zc.zodbdgc/branches/dev/src/zc/zodbdgc/README.test	2009-05-12 19:44:45 UTC (rev 99883)
@@ -24,18 +24,21 @@
     ... <zodb db1>
     ...     <filestorage>
     ...         pack-gc false
+    ...         pack-keep-old false
     ...         path 1.fs
     ...     </filestorage>
     ... </zodb>
     ... <zodb db2>
     ...     <filestorage>
     ...         pack-gc false
+    ...         pack-keep-old false
     ...         path 2.fs
     ...     </filestorage>
     ... </zodb>
     ... <zodb db3>
     ...     <filestorage>
     ...         pack-gc false
+    ...         pack-keep-old false
     ...         path 3.fs
     ...     </filestorage>
     ... </zodb>
@@ -146,6 +149,12 @@
 
     >>> _ = [d.close() for d in db.databases.values()]
 
+Save databases for later:
+
+    >>> import shutil
+    >>> for n in range(1, 4):
+    ...     shutil.copyfile('%s.fs' % n, '%s.fs-2' %n)
+
 Now let's perform gc.
 
     >>> import zc.zodbdgc
@@ -175,12 +184,6 @@
     >>> for d in db.databases.values():
     ...     d.pack()
 
-    >>> _ = [d.close() for d in db.databases.values()]
-    >>> db = ZODB.config.databaseFromFile(open('config'))
-    >>> conn1 = db.open()
-    >>> conn2 = conn1.get_connection('db2')
-    >>> conn3 = conn1.get_connection('db3')
-
     >>> len(conn1._storage), len(conn2._storage), len(conn3._storage)
     (2, 4, 2)
 
@@ -198,6 +201,94 @@
     >>> _ = [d.close() for d in db.databases.values()]
     >>> zc.zodbdgc.check('config')
 
+We can use separate databases for the analysis and update.
+First restore the databases.
+
+    >>> for n in range(1, 4):
+    ...     shutil.copyfile('%s.fs-2' % n, '%s.fs' %n)
+
+Make a secondary config:
+
+    >>> open('config2', 'w').write("""
+    ... <zodb db1>
+    ...     <filestorage>
+    ...         pack-gc false
+    ...         pack-keep-old false
+    ...         path 1.fs-2
+    ...     </filestorage>
+    ... </zodb>
+    ... <zodb db2>
+    ...     <filestorage>
+    ...         pack-gc false
+    ...         pack-keep-old false
+    ...         path 2.fs-2
+    ...     </filestorage>
+    ... </zodb>
+    ... <zodb db3>
+    ...     <filestorage>
+    ...         pack-gc false
+    ...         pack-keep-old false
+    ...         path 3.fs-2
+    ...     </filestorage>
+    ... </zodb>
+    ... """)
+
+
+This time we'll use the command-line interface:
+
+    >>> import logging, sys
+    >>> handler = logging.StreamHandler(sys.stdout)
+    >>> old_level = logging.getLogger().getEffectiveLevel()
+    >>> logging.getLogger().setLevel(logging.INFO)
+    >>> logging.getLogger().addHandler(handler)
+
+    >>> old_prog = sys.argv[0]
+    >>> sys.argv[0] = 'test'
+    >>> try: zc.zodbdgc.gc_command([])
+    ... except SystemExit: pass
+    usage: test [options] config1 [config2]
+    <BLANKLINE>
+    options:
+      -h, --help            show this help message and exit
+      -d DAYS, --days=DAYS  Number of trailing days to treat as non-garbage
+
+    >>> bad2 = zc.zodbdgc.gc_command(['-d2', 'config', 'config2'])
+    Ignoring index for 1.fs
+    Ignoring index for 2.fs
+    Ignoring index for 3.fs
+    Using secondary configuration, config2, for analysis
+    Removed 2 objects from db1
+    Removed 2 objects from db3
+    Removed 1 objects from db2
+
+    >>> sorted(bad2.iterator()) == sorted(bad2.iterator())
+    True
+
+    >>> db = ZODB.config.databaseFromFile(open('config'))
+    >>> conn1 = db.open()
+    >>> conn2 = conn1.get_connection('db2')
+    >>> conn3 = conn1.get_connection('db3')
+
+    >>> for d in db.databases.values():
+    ...     d.pack()
+
+    >>> len(conn1._storage), len(conn2._storage), len(conn3._storage)
+    (2, 4, 2)
+
+    >>> _ = [d.close() for d in db.databases.values()]
+
+    >>> try: zc.zodbdgc.check_command([])
+    ... except SystemExit: pass
+    usage: test [options] config
+    <BLANKLINE>
+    options:
+      -h, --help  show this help message and exit
+
+    >>> zc.zodbdgc.check_command(['config'])
+
 .. cleanup
 
+    >>> logging.getLogger().setLevel(old_level)
+    >>> logging.getLogger().removeHandler(handler)
     >>> time.time = time_time
+    >>> sys.argv[0] = old_prog

Modified: zc.zodbdgc/branches/dev/src/zc/zodbdgc/__init__.py
===================================================================
--- zc.zodbdgc/branches/dev/src/zc/zodbdgc/__init__.py	2009-05-12 18:35:37 UTC (rev 99882)
+++ zc.zodbdgc/branches/dev/src/zc/zodbdgc/__init__.py	2009-05-12 19:44:45 UTC (rev 99883)
@@ -18,8 +18,10 @@
 import cStringIO
 import logging
 import marshal
+import optparse
 import os
 import shutil
+import sys
 import tempfile
 import time
 import transaction
@@ -33,6 +35,7 @@
     if conf2 is None:
         db2 = db
     else:
+        logger.info("Using secondary configuration, %s, for analysis", conf2)
         db2 = ZODB.config.databaseFromFile(open(conf2))
         if set(db.databases) != set(db2.databases):
             raise ValueError("primary and secondary databases don't match.")
@@ -192,6 +195,21 @@
                 for ioid2 in data:
                     yield p64(ioid1+ioid2)
 
+def gc_command(args=None):
+    if args is None:
+        args = sys.argv[1:]
+    parser = optparse.OptionParser("usage: %prog [options] config1 [config2]")
+    parser.add_option(
+        '-d', '--days', dest='days', type='int',
+        help='Number of trailing days to treat as non-garbage')
+
+    options, args = parser.parse_args(args)
+
+    if not args or len(args) > 2:
+        parser.parse_args(['-h'])
+
+    return gc(args[0], options.days, *args[1:])
+
 def check(config):
     db = ZODB.config.databaseFromFile(open(config))
     databases = db.databases
@@ -225,3 +243,16 @@
                 continue
             roots.add(ref)
             referers[ref] = name, oid
+
+    [d.close() for d in db.databases.values()]
+
+def check_command(args=None):
+    if args is None:
+        args = sys.argv[1:]
+    parser = optparse.OptionParser("usage: %prog [options] config")
+    options, args = parser.parse_args(args)
+
+    if not args or len(args) > 1:
+        parser.parse_args(['-h'])
+
+    check(args[0])



More information about the Checkins mailing list