Code

yuck, a gdbm instance tests false :(
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 14 Dec 2001 23:42:57 +0000 (23:42 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 14 Dec 2001 23:42:57 +0000 (23:42 +0000)
I've left the debugging code in - it should be removed one day if we're ever
_really_ anal about performace :)

git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@464 57a73879-2fb5-44c3-a270-3262357dd7e2

roundup/backends/back_anydbm.py
roundup/hyperdb.py

index 8a4cca3b3e73de2edd5561aaf82efd90117be0eb..219eb7c3b08608f5ce59d1d8d5d205cdcbd59faa 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-#$Id: back_anydbm.py,v 1.16 2001-12-12 03:23:14 richard Exp $
+#$Id: back_anydbm.py,v 1.17 2001-12-14 23:42:57 richard Exp $
 '''
 This module defines a backend that saves the hyperdatabase in a database
 chosen by anydbm. It is guaranteed to always be available in python
@@ -26,6 +26,8 @@ serious bugs, and is not available)
 import whichdb, anydbm, os, marshal
 from roundup import hyperdb, date, password
 
+DEBUG=os.environ.get('HYPERDBDEBUG', '')
+
 #
 # Now the database
 #
@@ -58,14 +60,23 @@ class Database(hyperdb.Database):
         self.newnodes = {}      # keep track of the new nodes by class
         self.transactions = []
 
+    def __repr__(self):
+        return '<back_anydbm instance at %x>'%id(self) 
+
     #
     # Classes
     #
     def __getattr__(self, classname):
         """A convenient way of calling self.getclass(classname)."""
-        return self.classes[classname]
+        if self.classes.has_key(classname):
+            if DEBUG:
+                print '__getattr__', (self, classname)
+            return self.classes[classname]
+        raise AttributeError, classname
 
     def addclass(self, cl):
+        if DEBUG:
+            print 'addclass', (self, cl)
         cn = cl.classname
         if self.classes.has_key(cn):
             raise ValueError, cn
@@ -73,6 +84,8 @@ class Database(hyperdb.Database):
 
     def getclasses(self):
         """Return a list of the names of all existing classes."""
+        if DEBUG:
+            print 'getclasses', (self,)
         l = self.classes.keys()
         l.sort()
         return l
@@ -82,6 +95,8 @@ class Database(hyperdb.Database):
 
         If 'classname' is not a valid class name, a KeyError is raised.
         """
+        if DEBUG:
+            print 'getclass', (self, classname)
         return self.classes[classname]
 
     #
@@ -90,6 +105,8 @@ class Database(hyperdb.Database):
     def clear(self):
         '''Delete all database contents
         '''
+        if DEBUG:
+            print 'clear', (self,)
         for cn in self.classes.keys():
             for type in 'nodes', 'journals':
                 path = os.path.join(self.dir, 'journals.%s'%cn)
@@ -102,12 +119,16 @@ class Database(hyperdb.Database):
         ''' grab a connection to the class db that will be used for
             multiple actions
         '''
+        if DEBUG:
+            print 'getclassdb', (self, classname, mode)
         return self._opendb('nodes.%s'%classname, mode)
 
     def _opendb(self, name, mode):
         '''Low-level database opener that gets around anydbm/dbm
            eccentricities.
         '''
+        if DEBUG:
+            print '_opendb', (self, name, mode)
         # determine which DB wrote the class file
         db_type = ''
         path = os.path.join(os.getcwd(), self.dir, name)
@@ -122,6 +143,8 @@ class Database(hyperdb.Database):
 
         # new database? let anydbm pick the best dbm
         if not db_type:
+            if DEBUG:
+                print "_opendb anydbm.open(%r, 'n')"%path
             return anydbm.open(path, 'n')
 
         # open the database with the correct module
@@ -131,6 +154,8 @@ class Database(hyperdb.Database):
             raise hyperdb.DatabaseError, \
                 "Couldn't open database - the required module '%s'"\
                 "is not available"%db_type
+        if DEBUG:
+            print "_opendb %r.open(%r, %r)"%(db_type, path, mode)
         return dbm.open(path, mode)
 
     #
@@ -139,6 +164,8 @@ class Database(hyperdb.Database):
     def addnode(self, classname, nodeid, node):
         ''' add the specified node to its class's db
         '''
+        if DEBUG:
+            print 'addnode', (self, classname, nodeid, node)
         self.newnodes.setdefault(classname, {})[nodeid] = 1
         self.cache.setdefault(classname, {})[nodeid] = node
         self.savenode(classname, nodeid, node)
@@ -146,6 +173,8 @@ class Database(hyperdb.Database):
     def setnode(self, classname, nodeid, node):
         ''' change the specified node
         '''
+        if DEBUG:
+            print 'setnode', (self, classname, nodeid, node)
         self.dirtynodes.setdefault(classname, {})[nodeid] = 1
         # can't set without having already loaded the node
         self.cache[classname][nodeid] = node
@@ -154,51 +183,65 @@ class Database(hyperdb.Database):
     def savenode(self, classname, nodeid, node):
         ''' perform the saving of data specified by the set/addnode
         '''
+        if DEBUG:
+            print 'savenode', (self, classname, nodeid, node)
         self.transactions.append((self._doSaveNode, (classname, nodeid, node)))
 
-    def getnode(self, classname, nodeid, cldb=None):
+    def getnode(self, classname, nodeid, db=None):
         ''' add the specified node to its class's db
         '''
+        if DEBUG:
+            print 'getnode', (self, classname, nodeid, cldb)
         # try the cache
         cache = self.cache.setdefault(classname, {})
         if cache.has_key(nodeid):
             return cache[nodeid]
 
         # get from the database and save in the cache
-        db = cldb or self.getclassdb(classname)
+        if db is None:
+            db = self.getclassdb(classname)
         if not db.has_key(nodeid):
             raise IndexError, nodeid
         res = marshal.loads(db[nodeid])
         cache[nodeid] = res
         return res
 
-    def hasnode(self, classname, nodeid, cldb=None):
+    def hasnode(self, classname, nodeid, db=None):
         ''' add the specified node to its class's db
         '''
+        if DEBUG:
+            print 'hasnode', (self, classname, nodeid, cldb)
         # try the cache
         cache = self.cache.setdefault(classname, {})
         if cache.has_key(nodeid):
             return 1
 
         # not in the cache - check the database
-        db = cldb or self.getclassdb(classname)
+        if db is None:
+            db = self.getclassdb(classname)
         res = db.has_key(nodeid)
         return res
 
-    def countnodes(self, classname, cldb=None):
+    def countnodes(self, classname, db=None):
+        if DEBUG:
+            print 'countnodes', (self, classname, cldb)
         # include the new nodes not saved to the DB yet
         count = len(self.newnodes.get(classname, {}))
 
         # and count those in the DB
-        db = cldb or self.getclassdb(classname)
+        if db is None:
+            db = self.getclassdb(classname)
         count = count + len(db.keys())
         return count
 
-    def getnodeids(self, classname, cldb=None):
+    def getnodeids(self, classname, db=None):
+        if DEBUG:
+            print 'getnodeids', (self, classname, db)
         # start off with the new nodes
         res = self.newnodes.get(classname, {}).keys()
 
-        db = cldb or self.getclassdb(classname)
+        if db is None:
+            db = self.getclassdb(classname)
         res = res + db.keys()
         return res
 
@@ -213,12 +256,16 @@ class Database(hyperdb.Database):
             'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
             'retire' -- 'params' is None
         '''
+        if DEBUG:
+            print 'addjournal', (self, classname, nodeid, action, params)
         self.transactions.append((self._doSaveJournal, (classname, nodeid,
             action, params)))
 
     def getjournal(self, classname, nodeid):
         ''' get the journal for id
         '''
+        if DEBUG:
+            print 'getjournal', (self, classname, nodeid)
         # attempt to open the journal - in some rare cases, the journal may
         # not exist
         try:
@@ -242,6 +289,8 @@ class Database(hyperdb.Database):
     def commit(self):
         ''' Commit the current transactions.
         '''
+        if DEBUG:
+            print 'commit', (self,)
         # lock the DB
         for method, args in self.transactions:
             # TODO: optimise this, duh!
@@ -255,15 +304,19 @@ class Database(hyperdb.Database):
         self.transactions = []
 
     def _doSaveNode(self, classname, nodeid, node):
+        if DEBUG:
+            print '_doSaveNode', (self, classname, nodeid, node)
         db = self.getclassdb(classname, 'c')
         # now save the marshalled data
         db[nodeid] = marshal.dumps(node)
         db.close()
 
     def _doSaveJournal(self, classname, nodeid, action, params):
+        if DEBUG:
+            print '_doSaveJournal', (self, classname, nodeid, action, params)
         entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
             params)
-        db = anydbm.open(os.path.join(self.dir, 'journals.%s'%classname), 'c')
+        db = self._opendb('journals.%s'%classname, 'c')
         if db.has_key(nodeid):
             s = db[nodeid]
             l = marshal.loads(db[nodeid])
@@ -276,6 +329,8 @@ class Database(hyperdb.Database):
     def rollback(self):
         ''' Reverse all actions from the current transaction.
         '''
+        if DEBUG:
+            print 'rollback', (self, )
         self.cache = {}
         self.dirtynodes = {}
         self.newnodes = {}
@@ -283,6 +338,12 @@ class Database(hyperdb.Database):
 
 #
 #$Log: not supported by cvs2svn $
+#Revision 1.16  2001/12/12 03:23:14  richard
+#Cor blimey this anydbm/whichdb stuff is yecchy. Turns out that whichdb
+#incorrectly identifies a dbm file as a dbhash file on my system. This has
+#been submitted to the python bug tracker as issue #491888:
+#https://sourceforge.net/tracker/index.php?func=detail&aid=491888&group_id=5470&atid=105470
+#
 #Revision 1.15  2001/12/12 02:30:51  richard
 #I fixed the problems with people whose anydbm was using the dbm module at the
 #backend. It turns out the dbm module modifies the file name to append ".db"
index bfcd921b2b89c4b9cd2d4f1efd49a4f13a603deb..5310db79895149e8c3f4c8c4ecaeef5da429b29f 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: hyperdb.py,v 1.39 2001-12-02 05:06:16 richard Exp $
+# $Id: hyperdb.py,v 1.40 2001-12-14 23:42:57 richard Exp $
 
 __doc__ = """
 Hyperdatabase implementation, especially field types.
@@ -102,6 +102,9 @@ class Class:
         # do the db-related init stuff
         db.addclass(self)
 
+    def __repr__(self):
+        return '<hypderdb.Class "%s">'%self.classname
+
     # Editing nodes:
 
     def create(self, **propvalues):
@@ -868,6 +871,20 @@ def Choice(name, *options):
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.39  2001/12/02 05:06:16  richard
+# . We now use weakrefs in the Classes to keep the database reference, so
+#   the close() method on the database is no longer needed.
+#   I bumped the minimum python requirement up to 2.1 accordingly.
+# . #487480 ] roundup-server
+# . #487476 ] INSTALL.txt
+#
+# I also cleaned up the change message / post-edit stuff in the cgi client.
+# There's now a clearly marked "TODO: append the change note" where I believe
+# the change note should be added there. The "changes" list will obviously
+# have to be modified to be a dict of the changes, or somesuch.
+#
+# More testing needed.
+#
 # Revision 1.38  2001/12/01 07:17:50  richard
 # . We now have basic transaction support! Information is only written to
 #   the database when the commit() method is called. Only the anydbm