From 514e7a08ff789dc6958b137690533c8951efab31 Mon Sep 17 00:00:00 2001 From: richard Date: Mon, 10 Dec 2001 22:20:01 +0000 Subject: [PATCH] Enabled transaction support in the bsddb backend. It uses the anydbm code where possible, only replacing methods where the db is opened (it uses the btree opener specifically.) Also cleaned up some change note generation. Made the backends package work with pydoc too. git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@452 57a73879-2fb5-44c3-a270-3262357dd7e2 --- CHANGES.txt | 8 +- roundup/backends/__init__.py | 18 ++-- roundup/backends/back_anydbm.py | 24 ++++- roundup/backends/back_bsddb.py | 152 +++++--------------------------- roundup/cgi_client.py | 13 ++- roundup/roundupdb.py | 6 +- 6 files changed, 77 insertions(+), 144 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 50ea6fa..3114b45 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -11,8 +11,9 @@ Feature: . Login now takes you to the page you back to the were denied access to. . Admin user now can has a user index link on their web interface. . We now have basic transaction support. Information is only written to - the database when the commit() method is called. Only the anydbm backend - is modified in this way - neither of the bsddb backends have been. + the database when the commit() method is called. Only the anydbm and + bsddb3 backends are modified in this way - the bsddb3 backend needs a + lot more work anyway... - the CGI and mailgw automatically commit() at the end of processing a single transaction - the admin tool requires an explicit "commit" - it will prompt at exit @@ -20,7 +21,6 @@ Feature: during the session (up to the last commit). . Added the "display" command to the admin tool - displays a node's values - Fixed: . Lots of bugs, thanks Roché and others on the devel mailing list! . login_action and newuser_action return values were being ignored @@ -34,6 +34,8 @@ Fixed: . #487476 ] INSTALL.txt . #489760 ] [issue] only subject . fixed doc/index.html to include the quoting in the mail alias. + . fixed the backends __init__ so we can pydoc the backend modules + . web i/f reports "note added" if there are no changes but a note is entered 2001-11-23 - 0.3.0 diff --git a/roundup/backends/__init__.py b/roundup/backends/__init__.py index cb01a56..2c181a2 100644 --- a/roundup/backends/__init__.py +++ b/roundup/backends/__init__.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: __init__.py,v 1.7 2001-12-10 00:57:38 richard Exp $ +# $Id: __init__.py,v 1.8 2001-12-10 22:20:01 richard Exp $ __all__ = [] @@ -27,15 +27,15 @@ try: del dumbdbm import back_anydbm anydbm = back_anydbm - del back_anydbm __all__.append('anydbm') +except AssertionError: + del back_anydbm except: pass try: import back_bsddb bsddb = back_bsddb - del back_bsddb __all__.append('bsddb') except: pass @@ -43,14 +43,22 @@ except: try: import back_bsddb3 bsddb3 = back_bsddb3 - del back_bsddb3 __all__.append('bsddb3') except: pass - # # $Log: not supported by cvs2svn $ +# Revision 1.7 2001/12/10 00:57:38 richard +# From CHANGES: +# . Added the "display" command to the admin tool - displays a node's values +# . #489760 ] [issue] only subject +# . fixed the doc/index.html to include the quoting in the mail alias. +# +# Also: +# . fixed roundup-admin so it works with transactions +# . disabled the back_anydbm module if anydbm tries to use dumbdbm +# # Revision 1.6 2001/08/07 00:24:42 richard # stupid typo # diff --git a/roundup/backends/back_anydbm.py b/roundup/backends/back_anydbm.py index 156857e..6a90a1d 100644 --- a/roundup/backends/back_anydbm.py +++ b/roundup/backends/back_anydbm.py @@ -15,7 +15,13 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_anydbm.py,v 1.13 2001-12-02 05:06:16 richard Exp $ +#$Id: back_anydbm.py,v 1.14 2001-12-10 22:20:01 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 +versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several +serious bugs, and is not available) +''' import anydbm, os, marshal from roundup import hyperdb, date, password @@ -32,7 +38,6 @@ class Database(hyperdb.Database): . perhaps detect write collisions (related to above)? """ - def __init__(self, storagelocator, journaltag=None): """Open a hyperdatabase given a specifier to some storage. @@ -52,6 +57,7 @@ class Database(hyperdb.Database): self.dirtynodes = {} # keep track of the dirty nodes by class self.newnodes = {} # keep track of the new nodes by class self.transactions = [] + # # Classes # @@ -248,6 +254,20 @@ class Database(hyperdb.Database): # #$Log: not supported by cvs2svn $ +#Revision 1.13 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.12 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 diff --git a/roundup/backends/back_bsddb.py b/roundup/backends/back_bsddb.py index baa8070..9f62f57 100644 --- a/roundup/backends/back_bsddb.py +++ b/roundup/backends/back_bsddb.py @@ -15,59 +15,22 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_bsddb.py,v 1.12 2001-11-21 02:34:18 richard Exp $ +#$Id: back_bsddb.py,v 1.13 2001-12-10 22:20:01 richard Exp $ +''' +This module defines a backend that saves the hyperdatabase in BSDDB. +''' import bsddb, os, marshal from roundup import hyperdb, date, password +# these classes are so similar, we just use the anydbm methods +import back_anydbm + # # Now the database # -class Database(hyperdb.Database): +class Database(back_anydbm.Database): """A database for storing records containing flexible data types.""" - - def __init__(self, storagelocator, journaltag=None): - """Open a hyperdatabase given a specifier to some storage. - - The meaning of 'storagelocator' depends on the particular - implementation of the hyperdatabase. It could be a file name, - a directory path, a socket descriptor for a connection to a - database over the network, etc. - - The 'journaltag' is a token that will be attached to the journal - entries for any edits done on the database. If 'journaltag' is - None, the database is opened in read-only mode: the Class.create(), - Class.set(), and Class.retire() methods are disabled. - """ - self.dir, self.journaltag = storagelocator, journaltag - self.classes = {} - - # - # Classes - # - def __getattr__(self, classname): - """A convenient way of calling self.getclass(classname).""" - return self.classes[classname] - - def addclass(self, cl): - cn = cl.classname - if self.classes.has_key(cn): - raise ValueError, cn - self.classes[cn] = cl - - def getclasses(self): - """Return a list of the names of all existing classes.""" - l = self.classes.keys() - l.sort() - return l - - def getclass(self, classname): - """Get the Class object representing a particular class. - - If 'classname' is not a valid class name, a KeyError is raised. - """ - return self.classes[classname] - # # Class DBs # @@ -88,70 +51,9 @@ class Database(hyperdb.Database): else: return bsddb.btopen(path, 'n') - # - # Nodes - # - def addnode(self, classname, nodeid, node): - ''' add the specified node to its class's db - ''' - db = self.getclassdb(classname, 'c') - db[nodeid] = marshal.dumps(node) - db.close() - setnode = addnode - - def getnode(self, classname, nodeid, cldb=None): - ''' add the specified node to its class's db - ''' - db = cldb or self.getclassdb(classname) - if not db.has_key(nodeid): - raise IndexError, nodeid - res = marshal.loads(db[nodeid]) - if not cldb: db.close() - return res - - def hasnode(self, classname, nodeid, cldb=None): - ''' add the specified node to its class's db - ''' - db = cldb or self.getclassdb(classname) - res = db.has_key(nodeid) - if not cldb: db.close() - return res - - def countnodes(self, classname, cldb=None): - db = cldb or self.getclassdb(classname) - return len(db.keys()) - if not cldb: db.close() - return res - - def getnodeids(self, classname, cldb=None): - db = cldb or self.getclassdb(classname) - res = db.keys() - if not cldb: db.close() - return res - # # Journal # - def addjournal(self, classname, nodeid, action, params): - ''' Journal the Action - 'action' may be: - - 'create' or 'set' -- 'params' is a dictionary of property values - 'link' or 'unlink' -- 'params' is (classname, nodeid, propname) - 'retire' -- 'params' is None - ''' - entry = (nodeid, date.Date().get_tuple(), self.journaltag, action, - params) - db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'c') - if db.has_key(nodeid): - s = db[nodeid] - l = marshal.loads(db[nodeid]) - l.append(entry) - else: - l = [entry] - db[nodeid] = marshal.dumps(l) - db.close() - def getjournal(self, classname, nodeid): ''' get the journal for id ''' @@ -174,32 +76,24 @@ class Database(hyperdb.Database): db.close() return res - def close(self): - ''' Close the Database - we must release the circular refs so that - we can be del'ed and the underlying bsddb connections closed - cleanly. - ''' - self.classes = {} - - - # - # Basic transaction support - # - # TODO: well, write these methods (and then use them in other code) - def register_action(self): - ''' Register an action to the transaction undo log - ''' - - def commit(self): - ''' Commit the current transaction, start a new one - ''' - - def rollback(self): - ''' Reverse all actions from the current transaction - ''' + def _doSaveJournal(self, classname, nodeid, action, params): + entry = (nodeid, date.Date().get_tuple(), self.journaltag, action, + params) + db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'c') + if db.has_key(nodeid): + s = db[nodeid] + l = marshal.loads(db[nodeid]) + l.append(entry) + else: + l = [entry] + db[nodeid] = marshal.dumps(l) + db.close() # #$Log: not supported by cvs2svn $ +#Revision 1.12 2001/11/21 02:34:18 richard +#Added a target version field to the extended issue schema +# #Revision 1.11 2001/10/09 23:58:10 richard #Moved the data stringification up into the hyperdb.Class class' get, set #and create methods. This means that the data is also stringified for the diff --git a/roundup/cgi_client.py b/roundup/cgi_client.py index b98039f..6fe8b28 100644 --- a/roundup/cgi_client.py +++ b/roundup/cgi_client.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: cgi_client.py,v 1.78 2001-12-07 05:59:27 rochecompaan Exp $ +# $Id: cgi_client.py,v 1.79 2001-12-10 22:20:01 richard Exp $ __doc__ = """ WWW request handler (also used in the stand-alone server). @@ -341,6 +341,8 @@ class Client: if changed: message = _('%(changes)s edited ok')%{'changes': ', '.join(changed.keys())} + elif self.form.has_key('__note') and self.form['__note'].value: + message = _('note added') else: message = _('nothing changed') except: @@ -452,7 +454,7 @@ class Client: props['status'] = unread_id return cl.create(**props) - def _post_editnode(self, nid, change_note=None): + def _post_editnode(self, nid, change_note=''): ''' do the linking and message sending part of the node creation ''' cn = self.classname @@ -501,8 +503,7 @@ class Client: props = cl.getprops() note = None if self.form.has_key('__note'): - note = self.form['__note'] - note = note.value + note = self.form['__note'].value if not props.has_key('messages'): return if not isinstance(props['messages'], hyperdb.Multilink): @@ -616,6 +617,7 @@ class Client: # and some nice feedback for the user message = _('%(classname)s created ok')%{'classname': cn} except: + self.db.rollback() s = StringIO.StringIO() traceback.print_exc(None, s) message = '
%s
'%cgi.escape(s.getvalue()) @@ -1085,6 +1087,9 @@ def parsePropsFromForm(db, cl, form, nodeid=0): # # $Log: not supported by cvs2svn $ +# Revision 1.78 2001/12/07 05:59:27 rochecompaan +# Fixed small bug that prevented adding issues through the web. +# # Revision 1.77 2001/12/06 22:48:29 richard # files multilink was being nuked in post_edit_node # diff --git a/roundup/roundupdb.py b/roundup/roundupdb.py index 1d15ab4..966f77d 100644 --- a/roundup/roundupdb.py +++ b/roundup/roundupdb.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundupdb.py,v 1.27 2001-12-10 21:02:53 richard Exp $ +# $Id: roundupdb.py,v 1.28 2001-12-10 22:20:01 richard Exp $ __doc__ = """ Extending hyperdb with types specific to issue-tracking. @@ -439,6 +439,7 @@ class IssueClass(Class): changed[key] = new_value # list the changes + m = [] for propname, value in changed.items(): prop = cl.properties[propname] oldvalue = cl.get(nodeid, propname, None) @@ -490,6 +491,9 @@ class IssueClass(Class): # # $Log: not supported by cvs2svn $ +# Revision 1.27 2001/12/10 21:02:53 richard +# only insert the -------- change note marker if there is a change note +# # Revision 1.26 2001/12/05 14:26:44 rochecompaan # Removed generation of change note from "sendmessage" in roundupdb.py. # The change note is now generated when the message is created. -- 2.30.2