Code

Implemented a switch to disable journalling for a Class. CGI session
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Sun, 14 Jul 2002 04:03:15 +0000 (04:03 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Sun, 14 Jul 2002 04:03:15 +0000 (04:03 +0000)
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
roundup/backends/back_metakit.py
roundup/cgi_client.py
test/test_db.py

index 0acff4ac8fa5999b13dbbe8ecf878a5ae09fc68f..195c8d06f5a35d5322c4b59fc62af89468bae7d9 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.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 '<hypderdb.Class "%s">'%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
 #
index 6e51507fa7fe7f0b8496fce37d6f1bca9ed8976d..19a380f7f2f4b9eb225197bd1fa10ce38f2b298b 100755 (executable)
@@ -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'
index 416af3a5a993627c68e163ab0f89ac3ae0b1a337..ffef8ed3e40464993e8fff9e017c5ec5b0d1a2c7 100644 (file)
@@ -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
 #
index 1bfc15ed7a2004a5b5b422d0d8714071f4a4ab8b..94d657a768b77832c242abb491dde4b6d68e039a 100644 (file)
@@ -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
 #