Skip to content

Commit f1b8d87

Browse files
author
Richard Jones
committed
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.
1 parent e0df0e6 commit f1b8d87

File tree

6 files changed

+77
-144
lines changed

6 files changed

+77
-144
lines changed

CHANGES.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ Feature:
1111
. Login now takes you to the page you back to the were denied access to.
1212
. Admin user now can has a user index link on their web interface.
1313
. We now have basic transaction support. Information is only written to
14-
the database when the commit() method is called. Only the anydbm backend
15-
is modified in this way - neither of the bsddb backends have been.
14+
the database when the commit() method is called. Only the anydbm and
15+
bsddb3 backends are modified in this way - the bsddb3 backend needs a
16+
lot more work anyway...
1617
- the CGI and mailgw automatically commit() at the end of processing a
1718
single transaction
1819
- the admin tool requires an explicit "commit" - it will prompt at exit
1920
if there are unsaved changes. A "rollback" removes all changes made
2021
during the session (up to the last commit).
2122
. Added the "display" command to the admin tool - displays a node's values
2223

23-
2424
Fixed:
2525
. Lots of bugs, thanks Roch� and others on the devel mailing list!
2626
. login_action and newuser_action return values were being ignored
@@ -34,6 +34,8 @@ Fixed:
3434
. #487476 ] INSTALL.txt
3535
. #489760 ] [issue] only subject
3636
. fixed doc/index.html to include the quoting in the mail alias.
37+
. fixed the backends __init__ so we can pydoc the backend modules
38+
. web i/f reports "note added" if there are no changes but a note is entered
3739

3840

3941
2001-11-23 - 0.3.0

roundup/backends/__init__.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: __init__.py,v 1.7 2001-12-10 00:57:38 richard Exp $
18+
# $Id: __init__.py,v 1.8 2001-12-10 22:20:01 richard Exp $
1919

2020
__all__ = []
2121

@@ -27,30 +27,38 @@
2727
del dumbdbm
2828
import back_anydbm
2929
anydbm = back_anydbm
30-
del back_anydbm
3130
__all__.append('anydbm')
31+
except AssertionError:
32+
del back_anydbm
3233
except:
3334
pass
3435

3536
try:
3637
import back_bsddb
3738
bsddb = back_bsddb
38-
del back_bsddb
3939
__all__.append('bsddb')
4040
except:
4141
pass
4242

4343
try:
4444
import back_bsddb3
4545
bsddb3 = back_bsddb3
46-
del back_bsddb3
4746
__all__.append('bsddb3')
4847
except:
4948
pass
5049

51-
5250
#
5351
# $Log: not supported by cvs2svn $
52+
# Revision 1.7 2001/12/10 00:57:38 richard
53+
# From CHANGES:
54+
# . Added the "display" command to the admin tool - displays a node's values
55+
# . #489760 ] [issue] only subject
56+
# . fixed the doc/index.html to include the quoting in the mail alias.
57+
#
58+
# Also:
59+
# . fixed roundup-admin so it works with transactions
60+
# . disabled the back_anydbm module if anydbm tries to use dumbdbm
61+
#
5462
# Revision 1.6 2001/08/07 00:24:42 richard
5563
# stupid typo
5664
#

roundup/backends/back_anydbm.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
#$Id: back_anydbm.py,v 1.13 2001-12-02 05:06:16 richard Exp $
18+
#$Id: back_anydbm.py,v 1.14 2001-12-10 22:20:01 richard Exp $
19+
'''
20+
This module defines a backend that saves the hyperdatabase in a database
21+
chosen by anydbm. It is guaranteed to always be available in python
22+
versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several
23+
serious bugs, and is not available)
24+
'''
1925

2026
import anydbm, os, marshal
2127
from roundup import hyperdb, date, password
@@ -32,7 +38,6 @@ class Database(hyperdb.Database):
3238
. perhaps detect write collisions (related to above)?
3339
3440
"""
35-
3641
def __init__(self, storagelocator, journaltag=None):
3742
"""Open a hyperdatabase given a specifier to some storage.
3843
@@ -52,6 +57,7 @@ def __init__(self, storagelocator, journaltag=None):
5257
self.dirtynodes = {} # keep track of the dirty nodes by class
5358
self.newnodes = {} # keep track of the new nodes by class
5459
self.transactions = []
60+
5561
#
5662
# Classes
5763
#
@@ -248,6 +254,20 @@ def rollback(self):
248254

249255
#
250256
#$Log: not supported by cvs2svn $
257+
#Revision 1.13 2001/12/02 05:06:16 richard
258+
#. We now use weakrefs in the Classes to keep the database reference, so
259+
# the close() method on the database is no longer needed.
260+
# I bumped the minimum python requirement up to 2.1 accordingly.
261+
#. #487480 ] roundup-server
262+
#. #487476 ] INSTALL.txt
263+
#
264+
#I also cleaned up the change message / post-edit stuff in the cgi client.
265+
#There's now a clearly marked "TODO: append the change note" where I believe
266+
#the change note should be added there. The "changes" list will obviously
267+
#have to be modified to be a dict of the changes, or somesuch.
268+
#
269+
#More testing needed.
270+
#
251271
#Revision 1.12 2001/12/01 07:17:50 richard
252272
#. We now have basic transaction support! Information is only written to
253273
# the database when the commit() method is called. Only the anydbm

roundup/backends/back_bsddb.py

Lines changed: 23 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -15,59 +15,22 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
#$Id: back_bsddb.py,v 1.12 2001-11-21 02:34:18 richard Exp $
18+
#$Id: back_bsddb.py,v 1.13 2001-12-10 22:20:01 richard Exp $
19+
'''
20+
This module defines a backend that saves the hyperdatabase in BSDDB.
21+
'''
1922

2023
import bsddb, os, marshal
2124
from roundup import hyperdb, date, password
2225

26+
# these classes are so similar, we just use the anydbm methods
27+
import back_anydbm
28+
2329
#
2430
# Now the database
2531
#
26-
class Database(hyperdb.Database):
32+
class Database(back_anydbm.Database):
2733
"""A database for storing records containing flexible data types."""
28-
29-
def __init__(self, storagelocator, journaltag=None):
30-
"""Open a hyperdatabase given a specifier to some storage.
31-
32-
The meaning of 'storagelocator' depends on the particular
33-
implementation of the hyperdatabase. It could be a file name,
34-
a directory path, a socket descriptor for a connection to a
35-
database over the network, etc.
36-
37-
The 'journaltag' is a token that will be attached to the journal
38-
entries for any edits done on the database. If 'journaltag' is
39-
None, the database is opened in read-only mode: the Class.create(),
40-
Class.set(), and Class.retire() methods are disabled.
41-
"""
42-
self.dir, self.journaltag = storagelocator, journaltag
43-
self.classes = {}
44-
45-
#
46-
# Classes
47-
#
48-
def __getattr__(self, classname):
49-
"""A convenient way of calling self.getclass(classname)."""
50-
return self.classes[classname]
51-
52-
def addclass(self, cl):
53-
cn = cl.classname
54-
if self.classes.has_key(cn):
55-
raise ValueError, cn
56-
self.classes[cn] = cl
57-
58-
def getclasses(self):
59-
"""Return a list of the names of all existing classes."""
60-
l = self.classes.keys()
61-
l.sort()
62-
return l
63-
64-
def getclass(self, classname):
65-
"""Get the Class object representing a particular class.
66-
67-
If 'classname' is not a valid class name, a KeyError is raised.
68-
"""
69-
return self.classes[classname]
70-
7134
#
7235
# Class DBs
7336
#
@@ -88,70 +51,9 @@ def getclassdb(self, classname, mode='r'):
8851
else:
8952
return bsddb.btopen(path, 'n')
9053

91-
#
92-
# Nodes
93-
#
94-
def addnode(self, classname, nodeid, node):
95-
''' add the specified node to its class's db
96-
'''
97-
db = self.getclassdb(classname, 'c')
98-
db[nodeid] = marshal.dumps(node)
99-
db.close()
100-
setnode = addnode
101-
102-
def getnode(self, classname, nodeid, cldb=None):
103-
''' add the specified node to its class's db
104-
'''
105-
db = cldb or self.getclassdb(classname)
106-
if not db.has_key(nodeid):
107-
raise IndexError, nodeid
108-
res = marshal.loads(db[nodeid])
109-
if not cldb: db.close()
110-
return res
111-
112-
def hasnode(self, classname, nodeid, cldb=None):
113-
''' add the specified node to its class's db
114-
'''
115-
db = cldb or self.getclassdb(classname)
116-
res = db.has_key(nodeid)
117-
if not cldb: db.close()
118-
return res
119-
120-
def countnodes(self, classname, cldb=None):
121-
db = cldb or self.getclassdb(classname)
122-
return len(db.keys())
123-
if not cldb: db.close()
124-
return res
125-
126-
def getnodeids(self, classname, cldb=None):
127-
db = cldb or self.getclassdb(classname)
128-
res = db.keys()
129-
if not cldb: db.close()
130-
return res
131-
13254
#
13355
# Journal
13456
#
135-
def addjournal(self, classname, nodeid, action, params):
136-
''' Journal the Action
137-
'action' may be:
138-
139-
'create' or 'set' -- 'params' is a dictionary of property values
140-
'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
141-
'retire' -- 'params' is None
142-
'''
143-
entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
144-
params)
145-
db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'c')
146-
if db.has_key(nodeid):
147-
s = db[nodeid]
148-
l = marshal.loads(db[nodeid])
149-
l.append(entry)
150-
else:
151-
l = [entry]
152-
db[nodeid] = marshal.dumps(l)
153-
db.close()
154-
15557
def getjournal(self, classname, nodeid):
15658
''' get the journal for id
15759
'''
@@ -174,32 +76,24 @@ def getjournal(self, classname, nodeid):
17476
db.close()
17577
return res
17678

177-
def close(self):
178-
''' Close the Database - we must release the circular refs so that
179-
we can be del'ed and the underlying bsddb connections closed
180-
cleanly.
181-
'''
182-
self.classes = {}
183-
184-
185-
#
186-
# Basic transaction support
187-
#
188-
# TODO: well, write these methods (and then use them in other code)
189-
def register_action(self):
190-
''' Register an action to the transaction undo log
191-
'''
192-
193-
def commit(self):
194-
''' Commit the current transaction, start a new one
195-
'''
196-
197-
def rollback(self):
198-
''' Reverse all actions from the current transaction
199-
'''
79+
def _doSaveJournal(self, classname, nodeid, action, params):
80+
entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
81+
params)
82+
db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'c')
83+
if db.has_key(nodeid):
84+
s = db[nodeid]
85+
l = marshal.loads(db[nodeid])
86+
l.append(entry)
87+
else:
88+
l = [entry]
89+
db[nodeid] = marshal.dumps(l)
90+
db.close()
20091

20192
#
20293
#$Log: not supported by cvs2svn $
94+
#Revision 1.12 2001/11/21 02:34:18 richard
95+
#Added a target version field to the extended issue schema
96+
#
20397
#Revision 1.11 2001/10/09 23:58:10 richard
20498
#Moved the data stringification up into the hyperdb.Class class' get, set
20599
#and create methods. This means that the data is also stringified for the

roundup/cgi_client.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: cgi_client.py,v 1.78 2001-12-07 05:59:27 rochecompaan Exp $
18+
# $Id: cgi_client.py,v 1.79 2001-12-10 22:20:01 richard Exp $
1919

2020
__doc__ = """
2121
WWW request handler (also used in the stand-alone server).
@@ -341,6 +341,8 @@ def shownode(self, message=None):
341341
if changed:
342342
message = _('%(changes)s edited ok')%{'changes':
343343
', '.join(changed.keys())}
344+
elif self.form.has_key('__note') and self.form['__note'].value:
345+
message = _('note added')
344346
else:
345347
message = _('nothing changed')
346348
except:
@@ -452,7 +454,7 @@ def _createnode(self):
452454
props['status'] = unread_id
453455
return cl.create(**props)
454456

455-
def _post_editnode(self, nid, change_note=None):
457+
def _post_editnode(self, nid, change_note=''):
456458
''' do the linking and message sending part of the node creation
457459
'''
458460
cn = self.classname
@@ -501,8 +503,7 @@ def _post_editnode(self, nid, change_note=None):
501503
props = cl.getprops()
502504
note = None
503505
if self.form.has_key('__note'):
504-
note = self.form['__note']
505-
note = note.value
506+
note = self.form['__note'].value
506507
if not props.has_key('messages'):
507508
return
508509
if not isinstance(props['messages'], hyperdb.Multilink):
@@ -616,6 +617,7 @@ def newfile(self, message=None):
616617
# and some nice feedback for the user
617618
message = _('%(classname)s created ok')%{'classname': cn}
618619
except:
620+
self.db.rollback()
619621
s = StringIO.StringIO()
620622
traceback.print_exc(None, s)
621623
message = '<pre>%s</pre>'%cgi.escape(s.getvalue())
@@ -1085,6 +1087,9 @@ def parsePropsFromForm(db, cl, form, nodeid=0):
10851087

10861088
#
10871089
# $Log: not supported by cvs2svn $
1090+
# Revision 1.78 2001/12/07 05:59:27 rochecompaan
1091+
# Fixed small bug that prevented adding issues through the web.
1092+
#
10881093
# Revision 1.77 2001/12/06 22:48:29 richard
10891094
# files multilink was being nuked in post_edit_node
10901095
#

0 commit comments

Comments
 (0)