Skip to content

Commit 91a6312

Browse files
author
Richard Jones
committed
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 :)
1 parent fc2cc86 commit 91a6312

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
lines changed

roundup/backends/back_anydbm.py

Lines changed: 72 additions & 11 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: back_anydbm.py,v 1.16 2001-12-12 03:23:14 richard Exp $
18+
#$Id: back_anydbm.py,v 1.17 2001-12-14 23:42:57 richard Exp $
1919
'''
2020
This module defines a backend that saves the hyperdatabase in a database
2121
chosen by anydbm. It is guaranteed to always be available in python
@@ -26,6 +26,8 @@
2626
import whichdb, anydbm, os, marshal
2727
from roundup import hyperdb, date, password
2828

29+
DEBUG=os.environ.get('HYPERDBDEBUG', '')
30+
2931
#
3032
# Now the database
3133
#
@@ -58,21 +60,32 @@ def __init__(self, storagelocator, journaltag=None):
5860
self.newnodes = {} # keep track of the new nodes by class
5961
self.transactions = []
6062

63+
def __repr__(self):
64+
return '<back_anydbm instance at %x>'%id(self)
65+
6166
#
6267
# Classes
6368
#
6469
def __getattr__(self, classname):
6570
"""A convenient way of calling self.getclass(classname)."""
66-
return self.classes[classname]
71+
if self.classes.has_key(classname):
72+
if DEBUG:
73+
print '__getattr__', (self, classname)
74+
return self.classes[classname]
75+
raise AttributeError, classname
6776

6877
def addclass(self, cl):
78+
if DEBUG:
79+
print 'addclass', (self, cl)
6980
cn = cl.classname
7081
if self.classes.has_key(cn):
7182
raise ValueError, cn
7283
self.classes[cn] = cl
7384

7485
def getclasses(self):
7586
"""Return a list of the names of all existing classes."""
87+
if DEBUG:
88+
print 'getclasses', (self,)
7689
l = self.classes.keys()
7790
l.sort()
7891
return l
@@ -82,6 +95,8 @@ def getclass(self, classname):
8295
8396
If 'classname' is not a valid class name, a KeyError is raised.
8497
"""
98+
if DEBUG:
99+
print 'getclass', (self, classname)
85100
return self.classes[classname]
86101

87102
#
@@ -90,6 +105,8 @@ def getclass(self, classname):
90105
def clear(self):
91106
'''Delete all database contents
92107
'''
108+
if DEBUG:
109+
print 'clear', (self,)
93110
for cn in self.classes.keys():
94111
for type in 'nodes', 'journals':
95112
path = os.path.join(self.dir, 'journals.%s'%cn)
@@ -102,12 +119,16 @@ def getclassdb(self, classname, mode='r'):
102119
''' grab a connection to the class db that will be used for
103120
multiple actions
104121
'''
122+
if DEBUG:
123+
print 'getclassdb', (self, classname, mode)
105124
return self._opendb('nodes.%s'%classname, mode)
106125

107126
def _opendb(self, name, mode):
108127
'''Low-level database opener that gets around anydbm/dbm
109128
eccentricities.
110129
'''
130+
if DEBUG:
131+
print '_opendb', (self, name, mode)
111132
# determine which DB wrote the class file
112133
db_type = ''
113134
path = os.path.join(os.getcwd(), self.dir, name)
@@ -122,6 +143,8 @@ def _opendb(self, name, mode):
122143

123144
# new database? let anydbm pick the best dbm
124145
if not db_type:
146+
if DEBUG:
147+
print "_opendb anydbm.open(%r, 'n')"%path
125148
return anydbm.open(path, 'n')
126149

127150
# open the database with the correct module
@@ -131,6 +154,8 @@ def _opendb(self, name, mode):
131154
raise hyperdb.DatabaseError, \
132155
"Couldn't open database - the required module '%s'"\
133156
"is not available"%db_type
157+
if DEBUG:
158+
print "_opendb %r.open(%r, %r)"%(db_type, path, mode)
134159
return dbm.open(path, mode)
135160

136161
#
@@ -139,13 +164,17 @@ def _opendb(self, name, mode):
139164
def addnode(self, classname, nodeid, node):
140165
''' add the specified node to its class's db
141166
'''
167+
if DEBUG:
168+
print 'addnode', (self, classname, nodeid, node)
142169
self.newnodes.setdefault(classname, {})[nodeid] = 1
143170
self.cache.setdefault(classname, {})[nodeid] = node
144171
self.savenode(classname, nodeid, node)
145172

146173
def setnode(self, classname, nodeid, node):
147174
''' change the specified node
148175
'''
176+
if DEBUG:
177+
print 'setnode', (self, classname, nodeid, node)
149178
self.dirtynodes.setdefault(classname, {})[nodeid] = 1
150179
# can't set without having already loaded the node
151180
self.cache[classname][nodeid] = node
@@ -154,51 +183,65 @@ def setnode(self, classname, nodeid, node):
154183
def savenode(self, classname, nodeid, node):
155184
''' perform the saving of data specified by the set/addnode
156185
'''
186+
if DEBUG:
187+
print 'savenode', (self, classname, nodeid, node)
157188
self.transactions.append((self._doSaveNode, (classname, nodeid, node)))
158189

159-
def getnode(self, classname, nodeid, cldb=None):
190+
def getnode(self, classname, nodeid, db=None):
160191
''' add the specified node to its class's db
161192
'''
193+
if DEBUG:
194+
print 'getnode', (self, classname, nodeid, cldb)
162195
# try the cache
163196
cache = self.cache.setdefault(classname, {})
164197
if cache.has_key(nodeid):
165198
return cache[nodeid]
166199

167200
# get from the database and save in the cache
168-
db = cldb or self.getclassdb(classname)
201+
if db is None:
202+
db = self.getclassdb(classname)
169203
if not db.has_key(nodeid):
170204
raise IndexError, nodeid
171205
res = marshal.loads(db[nodeid])
172206
cache[nodeid] = res
173207
return res
174208

175-
def hasnode(self, classname, nodeid, cldb=None):
209+
def hasnode(self, classname, nodeid, db=None):
176210
''' add the specified node to its class's db
177211
'''
212+
if DEBUG:
213+
print 'hasnode', (self, classname, nodeid, cldb)
178214
# try the cache
179215
cache = self.cache.setdefault(classname, {})
180216
if cache.has_key(nodeid):
181217
return 1
182218

183219
# not in the cache - check the database
184-
db = cldb or self.getclassdb(classname)
220+
if db is None:
221+
db = self.getclassdb(classname)
185222
res = db.has_key(nodeid)
186223
return res
187224

188-
def countnodes(self, classname, cldb=None):
225+
def countnodes(self, classname, db=None):
226+
if DEBUG:
227+
print 'countnodes', (self, classname, cldb)
189228
# include the new nodes not saved to the DB yet
190229
count = len(self.newnodes.get(classname, {}))
191230

192231
# and count those in the DB
193-
db = cldb or self.getclassdb(classname)
232+
if db is None:
233+
db = self.getclassdb(classname)
194234
count = count + len(db.keys())
195235
return count
196236

197-
def getnodeids(self, classname, cldb=None):
237+
def getnodeids(self, classname, db=None):
238+
if DEBUG:
239+
print 'getnodeids', (self, classname, db)
198240
# start off with the new nodes
199241
res = self.newnodes.get(classname, {}).keys()
200242

201-
db = cldb or self.getclassdb(classname)
243+
if db is None:
244+
db = self.getclassdb(classname)
202245
res = res + db.keys()
203246
return res
204247

@@ -213,12 +256,16 @@ def addjournal(self, classname, nodeid, action, params):
213256
'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
214257
'retire' -- 'params' is None
215258
'''
259+
if DEBUG:
260+
print 'addjournal', (self, classname, nodeid, action, params)
216261
self.transactions.append((self._doSaveJournal, (classname, nodeid,
217262
action, params)))
218263

219264
def getjournal(self, classname, nodeid):
220265
''' get the journal for id
221266
'''
267+
if DEBUG:
268+
print 'getjournal', (self, classname, nodeid)
222269
# attempt to open the journal - in some rare cases, the journal may
223270
# not exist
224271
try:
@@ -242,6 +289,8 @@ def getjournal(self, classname, nodeid):
242289
def commit(self):
243290
''' Commit the current transactions.
244291
'''
292+
if DEBUG:
293+
print 'commit', (self,)
245294
# lock the DB
246295
for method, args in self.transactions:
247296
# TODO: optimise this, duh!
@@ -255,15 +304,19 @@ def commit(self):
255304
self.transactions = []
256305

257306
def _doSaveNode(self, classname, nodeid, node):
307+
if DEBUG:
308+
print '_doSaveNode', (self, classname, nodeid, node)
258309
db = self.getclassdb(classname, 'c')
259310
# now save the marshalled data
260311
db[nodeid] = marshal.dumps(node)
261312
db.close()
262313

263314
def _doSaveJournal(self, classname, nodeid, action, params):
315+
if DEBUG:
316+
print '_doSaveJournal', (self, classname, nodeid, action, params)
264317
entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
265318
params)
266-
db = anydbm.open(os.path.join(self.dir, 'journals.%s'%classname), 'c')
319+
db = self._opendb('journals.%s'%classname, 'c')
267320
if db.has_key(nodeid):
268321
s = db[nodeid]
269322
l = marshal.loads(db[nodeid])
@@ -276,13 +329,21 @@ def _doSaveJournal(self, classname, nodeid, action, params):
276329
def rollback(self):
277330
''' Reverse all actions from the current transaction.
278331
'''
332+
if DEBUG:
333+
print 'rollback', (self, )
279334
self.cache = {}
280335
self.dirtynodes = {}
281336
self.newnodes = {}
282337
self.transactions = []
283338

284339
#
285340
#$Log: not supported by cvs2svn $
341+
#Revision 1.16 2001/12/12 03:23:14 richard
342+
#Cor blimey this anydbm/whichdb stuff is yecchy. Turns out that whichdb
343+
#incorrectly identifies a dbm file as a dbhash file on my system. This has
344+
#been submitted to the python bug tracker as issue #491888:
345+
#https://sourceforge.net/tracker/index.php?func=detail&aid=491888&group_id=5470&atid=105470
346+
#
286347
#Revision 1.15 2001/12/12 02:30:51 richard
287348
#I fixed the problems with people whose anydbm was using the dbm module at the
288349
#backend. It turns out the dbm module modifies the file name to append ".db"

roundup/hyperdb.py

Lines changed: 18 additions & 1 deletion
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: hyperdb.py,v 1.39 2001-12-02 05:06:16 richard Exp $
18+
# $Id: hyperdb.py,v 1.40 2001-12-14 23:42:57 richard Exp $
1919

2020
__doc__ = """
2121
Hyperdatabase implementation, especially field types.
@@ -102,6 +102,9 @@ def __init__(self, db, classname, **properties):
102102
# do the db-related init stuff
103103
db.addclass(self)
104104

105+
def __repr__(self):
106+
return '<hypderdb.Class "%s">'%self.classname
107+
105108
# Editing nodes:
106109

107110
def create(self, **propvalues):
@@ -868,6 +871,20 @@ def Choice(name, *options):
868871

869872
#
870873
# $Log: not supported by cvs2svn $
874+
# Revision 1.39 2001/12/02 05:06:16 richard
875+
# . We now use weakrefs in the Classes to keep the database reference, so
876+
# the close() method on the database is no longer needed.
877+
# I bumped the minimum python requirement up to 2.1 accordingly.
878+
# . #487480 ] roundup-server
879+
# . #487476 ] INSTALL.txt
880+
#
881+
# I also cleaned up the change message / post-edit stuff in the cgi client.
882+
# There's now a clearly marked "TODO: append the change note" where I believe
883+
# the change note should be added there. The "changes" list will obviously
884+
# have to be modified to be a dict of the changes, or somesuch.
885+
#
886+
# More testing needed.
887+
#
871888
# Revision 1.38 2001/12/01 07:17:50 richard
872889
# . We now have basic transaction support! Information is only written to
873890
# the database when the commit() method is called. Only the anydbm

0 commit comments

Comments
 (0)