From: richard Date: Fri, 14 Dec 2001 23:42:57 +0000 (+0000) Subject: yuck, a gdbm instance tests false :( X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=022e7193d0b05347176cd929bfb23e6d5bb99e0a;p=roundup.git yuck, a gdbm instance tests false :( 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 --- diff --git a/roundup/backends/back_anydbm.py b/roundup/backends/back_anydbm.py index 8a4cca3..219eb7c 100644 --- a/roundup/backends/back_anydbm.py +++ b/roundup/backends/back_anydbm.py @@ -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 ''%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" diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py index bfcd921..5310db7 100644 --- a/roundup/hyperdb.py +++ b/roundup/hyperdb.py @@ -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 ''%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