From 42c912a767dd2124125b31dc9273a85a4374f60e Mon Sep 17 00:00:00 2001 From: richard Date: Sun, 14 Jul 2002 04:03:15 +0000 Subject: [PATCH] Implemented a switch to disable journalling for a Class. CGI session database now uses it. git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@872 57a73879-2fb5-44c3-a270-3262357dd7e2 --- roundup/backends/back_anydbm.py | 46 +++++++++++++++++++++++--------- roundup/backends/back_metakit.py | 36 +++++++++++++++++-------- roundup/cgi_client.py | 15 ++++++++--- test/test_db.py | 28 +++++++++++++++++-- 4 files changed, 96 insertions(+), 29 deletions(-) diff --git a/roundup/backends/back_anydbm.py b/roundup/backends/back_anydbm.py index 0acff4a..195c8d0 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.44 2002-07-14 02:05:53 richard Exp $ +#$Id: back_anydbm.py,v 1.45 2002-07-14 04:03:14 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 @@ -589,16 +589,24 @@ class Class(hyperdb.Class): self.db = weakref.proxy(db) # use a weak ref to avoid circularity self.key = '' + # should we journal changes (default yes) + self.do_journal = 1 + # do the db-related init stuff db.addclass(self) self.auditors = {'create': [], 'set': [], 'retire': []} self.reactors = {'create': [], 'set': [], 'retire': []} - def __repr__(self): - '''Slightly more useful representation + def enableJournalling(self): + '''Turn journalling on for this class ''' - return ''%self.classname + self.do_journal = 1 + + def disableJournalling(self): + '''Turn journalling off for this class + ''' + self.do_journal = 0 # Editing nodes: @@ -672,7 +680,7 @@ class Class(hyperdb.Class): propvalues[key] = value # register the link with the newly linked node - if self.properties[key].do_journal: + if self.do_journal and self.properties[key].do_journal: self.db.addjournal(link_class, value, 'link', (self.classname, newid, key)) @@ -703,7 +711,7 @@ class Class(hyperdb.Class): if not self.db.hasnode(link_class, id): raise IndexError, '%s has no node %s'%(link_class, id) # register the link with the newly linked node - if self.properties[key].do_journal: + if self.do_journal and self.properties[key].do_journal: self.db.addjournal(link_class, id, 'link', (self.classname, newid, key)) @@ -737,7 +745,8 @@ class Class(hyperdb.Class): # done self.db.addnode(self.classname, newid, propvalues) - self.db.addjournal(self.classname, newid, 'create', propvalues) + if self.do_journal: + self.db.addjournal(self.classname, newid, 'create', propvalues) self.fireReactors('create', newid, None) @@ -762,6 +771,8 @@ class Class(hyperdb.Class): return nodeid if propname == 'creation': + if not self.do_journal: + raise ValueError, 'Journalling is disabled for this class' journal = self.db.getjournal(self.classname, nodeid) if journal: return self.db.getjournal(self.classname, nodeid)[0][1] @@ -769,6 +780,8 @@ class Class(hyperdb.Class): # on the strange chance that there's no journal return date.Date() if propname == 'activity': + if not self.do_journal: + raise ValueError, 'Journalling is disabled for this class' journal = self.db.getjournal(self.classname, nodeid) if journal: return self.db.getjournal(self.classname, nodeid)[-1][1] @@ -776,6 +789,8 @@ class Class(hyperdb.Class): # on the strange chance that there's no journal return date.Date() if propname == 'creator': + if not self.do_journal: + raise ValueError, 'Journalling is disabled for this class' journal = self.db.getjournal(self.classname, nodeid) if journal: name = self.db.getjournal(self.classname, nodeid)[0][2] @@ -901,7 +916,7 @@ class Class(hyperdb.Class): if not self.db.hasnode(link_class, value): raise IndexError, '%s has no node %s'%(link_class, value) - if self.properties[key].do_journal: + if self.do_journal and self.properties[key].do_journal: # register the unlink with the old linked node if node[key] is not None: self.db.addjournal(link_class, node[key], 'unlink', @@ -941,7 +956,7 @@ class Class(hyperdb.Class): if id in value: continue # register the unlink with the old linked node - if self.properties[key].do_journal: + if self.do_journal and self.properties[key].do_journal: self.db.addjournal(link_class, id, 'unlink', (self.classname, nodeid, key)) l.remove(id) @@ -954,7 +969,7 @@ class Class(hyperdb.Class): if id in l: continue # register the link with the newly linked node - if self.properties[key].do_journal: + if self.do_journal and self.properties[key].do_journal: self.db.addjournal(link_class, id, 'link', (self.classname, nodeid, key)) l.append(id) @@ -986,7 +1001,8 @@ class Class(hyperdb.Class): # do the set, and journal it self.db.setnode(self.classname, nodeid, node) - self.db.addjournal(self.classname, nodeid, 'set', propvalues) + if self.do_journal: + self.db.addjournal(self.classname, nodeid, 'set', propvalues) self.fireReactors('set', nodeid, oldvalues) @@ -1010,7 +1026,8 @@ class Class(hyperdb.Class): node = self.db.getnode(self.classname, nodeid) node[self.db.RETIRED_FLAG] = 1 self.db.setnode(self.classname, nodeid, node) - self.db.addjournal(self.classname, nodeid, 'retired', None) + if self.do_journal: + self.db.addjournal(self.classname, nodeid, 'retired', None) self.fireReactors('retire', nodeid, None) @@ -1027,6 +1044,8 @@ class Class(hyperdb.Class): 'date' is a Timestamp object specifying the time of the change and 'tag' is the journaltag specified when the database was opened. """ + if not self.do_journal: + raise ValueError, 'Journalling is disabled for this class' return self.db.getjournal(self.classname, nodeid) # Locating nodes: @@ -1596,6 +1615,9 @@ class IssueClass(Class, roundupdb.IssueClass): # #$Log: not supported by cvs2svn $ +#Revision 1.44 2002/07/14 02:05:53 richard +#. all storage-specific code (ie. backend) is now implemented by the backends +# #Revision 1.43 2002/07/10 06:30:30 richard #...except of course it's nice to use valid Python syntax # diff --git a/roundup/backends/back_metakit.py b/roundup/backends/back_metakit.py index 6e51507..19a380f 100755 --- a/roundup/backends/back_metakit.py +++ b/roundup/backends/back_metakit.py @@ -216,6 +216,19 @@ class Class: # no, I'm not going to subclass the existing! self.properties = self.ruprops self.db.addclass(self) self.idcache = {} + + # default is to journal changes + self.do_journal = 1 + + def enableJournalling(self): + '''Turn journalling on for this class + ''' + self.do_journal = 1 + + def disableJournalling(self): + '''Turn journalling off for this class + ''' + self.do_journal = 0 # --- the roundup.Class methods def audit(self, event, detector): @@ -349,7 +362,7 @@ class Class: # no, I'm not going to subclass the existing! setattr(row, key, int(value)) changes[key] = oldvalue - if prop.do_journal: + if self.do_journal and prop.do_journal: # register the unlink with the old linked node if oldvalue: self.db.addjournal(link_class, value, _UNLINK, (self.classname, str(row.id), key)) @@ -385,7 +398,7 @@ class Class: # no, I'm not going to subclass the existing! if id not in value: rmvd.append(id) # register the unlink with the old linked node - if prop.do_journal: + if self.do_journal and prop.do_journal: self.db.addjournal(link_class, id, _UNLINK, (self.classname, str(row.id), key)) # handle additions @@ -397,7 +410,7 @@ class Class: # no, I'm not going to subclass the existing! link_class, id) adds.append(id) # register the link with the newly linked node - if prop.do_journal: + if self.do_journal and prop.do_journal: self.db.addjournal(link_class, id, _LINK, (self.classname, str(row.id), key)) sv = getattr(row, key) @@ -457,10 +470,11 @@ class Class: # no, I'm not going to subclass the existing! row.creator = self.db.curuserid self.db.dirty = 1 - if isnew: - self.db.addjournal(self.classname, nodeid, _CREATE, {}) - else: - self.db.addjournal(self.classname, nodeid, _SET, changes) + if self.do_journal: + if isnew: + self.db.addjournal(self.classname, nodeid, _CREATE, {}) + else: + self.db.addjournal(self.classname, nodeid, _SET, changes) def retire(self, nodeid): view = self.getview(1) @@ -471,13 +485,16 @@ class Class: # no, I'm not going to subclass the existing! oldvalues = self.uncommitted.setdefault(row.id, {}) oldval = oldvalues['_isdel'] = row._isdel row._isdel = 1 - self.db.addjournal(self.classname, nodeid, _RETIRE, {}) + if self.do_journal: + self.db.addjournal(self.classname, nodeid, _RETIRE, {}) iv = self.getindexview(1) ndx = iv.find(k=getattr(row, self.keyname),i=row.id) if ndx > -1: iv.delete(ndx) self.db.dirty = 1 def history(self, nodeid): + if not self.do_journal: + raise ValueError, 'Journalling is disabled for this class' return self.db.gethistory(self.classname, nodeid) def setkey(self, propname): if self.keyname: @@ -930,11 +947,8 @@ class FileClass(Class): self.db.indexer.add_text((self.classname, nodeid, 'content'), self.get(nodeid, 'content'), mimetype) -# Yuck - c&p to avoid getting hyperdb.Class class IssueClass(Class, roundupdb.IssueClass): - # Overridden methods: - def __init__(self, db, classname, **properties): """The newly-created class automatically includes the "messages", "files", "nosy", and "superseder" properties. If the 'properties' diff --git a/roundup/cgi_client.py b/roundup/cgi_client.py index 416af3a..ffef8ed 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.137 2002-07-10 07:00:30 richard Exp $ +# $Id: cgi_client.py,v 1.138 2002-07-14 04:03:13 richard Exp $ __doc__ = """ WWW request handler (also used in the stand-alone server). @@ -1214,11 +1214,14 @@ function help_window(helpurl, width, height) { try: sessions = self.db.getclass('__sessions') except: - # add the sessions Class - sessions = hyperdb.Class(self.db, '__sessions', + # add the sessions Class - use a non-journalling Class + # TODO: not happy with how we're getting the Class here :( + sessions = self.instance.dbinit.Class(self.db, '__sessions', sessid=hyperdb.String(), user=hyperdb.String(), last_use=hyperdb.Date()) sessions.setkey('sessid') + # make sure session db isn't journalled + sessions.disableJournalling() def main(self): '''Wrap the database accesses so we can close the database cleanly @@ -1253,6 +1256,7 @@ function help_window(helpurl, width, height) { except KeyError: user = 'anonymous' else: + # update the lifetime datestamp sessions.set(self.session, last_use=date.Date()) self.db.commit() user = sessions.get(sessid, 'user') @@ -1460,7 +1464,7 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')): # Quite likely to be a FormItem instance value = value.value if not isinstance(value, type([])): - value = [i.strip() for i in value.value.split(',')] + value = [i.strip() for i in value.split(',')] else: value = [i.strip() for i in value] link = cl.properties[key].classname @@ -1496,6 +1500,9 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')): # # $Log: not supported by cvs2svn $ +# Revision 1.137 2002/07/10 07:00:30 richard +# removed debugging +# # Revision 1.136 2002/07/10 06:51:08 richard # . #576241 ] MultiLink problems in parsePropsFromForm # diff --git a/test/test_db.py b/test/test_db.py index 1bfc15e..94d657a 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -15,9 +15,9 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: test_db.py,v 1.28 2002-07-14 02:16:29 richard Exp $ +# $Id: test_db.py,v 1.29 2002-07-14 04:03:15 richard Exp $ -import unittest, os, shutil +import unittest, os, shutil, time from roundup.hyperdb import String, Password, Link, Multilink, Date, \ Interval, DatabaseError @@ -284,6 +284,26 @@ class anydbmDBTestCase(MyTestCase): self.assertEqual('unlink', action) self.assertEqual(('issue', '1', 'fixer'), params) + # test disabling journalling + # ... get the last entry + time.sleep(1) + entry = self.db.getjournal('issue', '1')[-1] + (x, date_stamp, x, x, x) = entry + self.db.issue.disableJournalling() + self.db.issue.set('1', title='hello world') + self.db.commit() + entry = self.db.getjournal('issue', '1')[-1] + (x, date_stamp2, x, x, x) = entry + # see if the change was journalled when it shouldn't have been + self.assertEqual(date_stamp, date_stamp2) + self.db.issue.enableJournalling() + self.db.issue.set('1', title='hello world 2') + self.db.commit() + entry = self.db.getjournal('issue', '1')[-1] + (x, date_stamp2, x, x, x) = entry + # see if the change was journalled + self.assertNotEqual(date_stamp, date_stamp2) + def testPack(self): self.db.issue.create(title="spam", status='1') self.db.commit() @@ -504,6 +524,10 @@ def suite(): # # $Log: not supported by cvs2svn $ +# Revision 1.28 2002/07/14 02:16:29 richard +# Fixes for the metakit backend (removed the cut-n-paste IssueClass, removed +# a special case for it in testing) +# # Revision 1.27 2002/07/14 02:05:54 richard # . all storage-specific code (ie. backend) is now implemented by the backends # -- 2.30.2