summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d1b4856)
raw | patch | inline | side by side (parent: d1b4856)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 14 Dec 2001 23:42:57 +0000 (23:42 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Fri, 14 Dec 2001 23:42:57 +0000 (23:42 +0000) |
I've left the debugging code in - it should be removed one day if we're ever
_really_ anal about performace :)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@464 57a73879-2fb5-44c3-a270-3262357dd7e2
_really_ anal about performace :)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@464 57a73879-2fb5-44c3-a270-3262357dd7e2
roundup/backends/back_anydbm.py | patch | blob | history | |
roundup/hyperdb.py | patch | blob | history |
index 8a4cca3b3e73de2edd5561aaf82efd90117be0eb..219eb7c3b08608f5ce59d1d8d5d205cdcbd59faa 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_anydbm.py,v 1.16 2001-12-12 03:23:14 richard Exp $
+#$Id: back_anydbm.py,v 1.17 2001-12-14 23:42:57 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
import whichdb, anydbm, os, marshal
from roundup import hyperdb, date, password
+DEBUG=os.environ.get('HYPERDBDEBUG', '')
+
#
# Now the database
#
self.newnodes = {} # keep track of the new nodes by class
self.transactions = []
+ def __repr__(self):
+ return '<back_anydbm instance at %x>'%id(self)
+
#
# Classes
#
def __getattr__(self, classname):
"""A convenient way of calling self.getclass(classname)."""
- return self.classes[classname]
+ if self.classes.has_key(classname):
+ if DEBUG:
+ print '__getattr__', (self, classname)
+ return self.classes[classname]
+ raise AttributeError, classname
def addclass(self, cl):
+ if DEBUG:
+ print 'addclass', (self, cl)
cn = cl.classname
if self.classes.has_key(cn):
raise ValueError, cn
def getclasses(self):
"""Return a list of the names of all existing classes."""
+ if DEBUG:
+ print 'getclasses', (self,)
l = self.classes.keys()
l.sort()
return l
If 'classname' is not a valid class name, a KeyError is raised.
"""
+ if DEBUG:
+ print 'getclass', (self, classname)
return self.classes[classname]
#
def clear(self):
'''Delete all database contents
'''
+ if DEBUG:
+ print 'clear', (self,)
for cn in self.classes.keys():
for type in 'nodes', 'journals':
path = os.path.join(self.dir, 'journals.%s'%cn)
''' grab a connection to the class db that will be used for
multiple actions
'''
+ if DEBUG:
+ print 'getclassdb', (self, classname, mode)
return self._opendb('nodes.%s'%classname, mode)
def _opendb(self, name, mode):
'''Low-level database opener that gets around anydbm/dbm
eccentricities.
'''
+ if DEBUG:
+ print '_opendb', (self, name, mode)
# determine which DB wrote the class file
db_type = ''
path = os.path.join(os.getcwd(), self.dir, name)
# new database? let anydbm pick the best dbm
if not db_type:
+ if DEBUG:
+ print "_opendb anydbm.open(%r, 'n')"%path
return anydbm.open(path, 'n')
# open the database with the correct module
raise hyperdb.DatabaseError, \
"Couldn't open database - the required module '%s'"\
"is not available"%db_type
+ if DEBUG:
+ print "_opendb %r.open(%r, %r)"%(db_type, path, mode)
return dbm.open(path, mode)
#
def addnode(self, classname, nodeid, node):
''' add the specified node to its class's db
'''
+ if DEBUG:
+ print 'addnode', (self, classname, nodeid, node)
self.newnodes.setdefault(classname, {})[nodeid] = 1
self.cache.setdefault(classname, {})[nodeid] = node
self.savenode(classname, nodeid, node)
def setnode(self, classname, nodeid, node):
''' change the specified node
'''
+ if DEBUG:
+ print 'setnode', (self, classname, nodeid, node)
self.dirtynodes.setdefault(classname, {})[nodeid] = 1
# can't set without having already loaded the node
self.cache[classname][nodeid] = node
def savenode(self, classname, nodeid, node):
''' perform the saving of data specified by the set/addnode
'''
+ if DEBUG:
+ print 'savenode', (self, classname, nodeid, node)
self.transactions.append((self._doSaveNode, (classname, nodeid, node)))
- def getnode(self, classname, nodeid, cldb=None):
+ def getnode(self, classname, nodeid, db=None):
''' add the specified node to its class's db
'''
+ if DEBUG:
+ print 'getnode', (self, classname, nodeid, cldb)
# try the cache
cache = self.cache.setdefault(classname, {})
if cache.has_key(nodeid):
return cache[nodeid]
# get from the database and save in the cache
- db = cldb or self.getclassdb(classname)
+ if db is None:
+ db = self.getclassdb(classname)
if not db.has_key(nodeid):
raise IndexError, nodeid
res = marshal.loads(db[nodeid])
cache[nodeid] = res
return res
- def hasnode(self, classname, nodeid, cldb=None):
+ def hasnode(self, classname, nodeid, db=None):
''' add the specified node to its class's db
'''
+ if DEBUG:
+ print 'hasnode', (self, classname, nodeid, cldb)
# try the cache
cache = self.cache.setdefault(classname, {})
if cache.has_key(nodeid):
return 1
# not in the cache - check the database
- db = cldb or self.getclassdb(classname)
+ if db is None:
+ db = self.getclassdb(classname)
res = db.has_key(nodeid)
return res
- def countnodes(self, classname, cldb=None):
+ def countnodes(self, classname, db=None):
+ if DEBUG:
+ print 'countnodes', (self, classname, cldb)
# include the new nodes not saved to the DB yet
count = len(self.newnodes.get(classname, {}))
# and count those in the DB
- db = cldb or self.getclassdb(classname)
+ if db is None:
+ db = self.getclassdb(classname)
count = count + len(db.keys())
return count
- def getnodeids(self, classname, cldb=None):
+ def getnodeids(self, classname, db=None):
+ if DEBUG:
+ print 'getnodeids', (self, classname, db)
# start off with the new nodes
res = self.newnodes.get(classname, {}).keys()
- db = cldb or self.getclassdb(classname)
+ if db is None:
+ db = self.getclassdb(classname)
res = res + db.keys()
return res
'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
'retire' -- 'params' is None
'''
+ if DEBUG:
+ print 'addjournal', (self, classname, nodeid, action, params)
self.transactions.append((self._doSaveJournal, (classname, nodeid,
action, params)))
def getjournal(self, classname, nodeid):
''' get the journal for id
'''
+ if DEBUG:
+ print 'getjournal', (self, classname, nodeid)
# attempt to open the journal - in some rare cases, the journal may
# not exist
try:
def commit(self):
''' Commit the current transactions.
'''
+ if DEBUG:
+ print 'commit', (self,)
# lock the DB
for method, args in self.transactions:
# TODO: optimise this, duh!
self.transactions = []
def _doSaveNode(self, classname, nodeid, node):
+ if DEBUG:
+ print '_doSaveNode', (self, classname, nodeid, node)
db = self.getclassdb(classname, 'c')
# now save the marshalled data
db[nodeid] = marshal.dumps(node)
db.close()
def _doSaveJournal(self, classname, nodeid, action, params):
+ if DEBUG:
+ print '_doSaveJournal', (self, classname, nodeid, action, params)
entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
params)
- db = anydbm.open(os.path.join(self.dir, 'journals.%s'%classname), 'c')
+ db = self._opendb('journals.%s'%classname, 'c')
if db.has_key(nodeid):
s = db[nodeid]
l = marshal.loads(db[nodeid])
def rollback(self):
''' Reverse all actions from the current transaction.
'''
+ if DEBUG:
+ print 'rollback', (self, )
self.cache = {}
self.dirtynodes = {}
self.newnodes = {}
#
#$Log: not supported by cvs2svn $
+#Revision 1.16 2001/12/12 03:23:14 richard
+#Cor blimey this anydbm/whichdb stuff is yecchy. Turns out that whichdb
+#incorrectly identifies a dbm file as a dbhash file on my system. This has
+#been submitted to the python bug tracker as issue #491888:
+#https://sourceforge.net/tracker/index.php?func=detail&aid=491888&group_id=5470&atid=105470
+#
#Revision 1.15 2001/12/12 02:30:51 richard
#I fixed the problems with people whose anydbm was using the dbm module at the
#backend. It turns out the dbm module modifies the file name to append ".db"
diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py
index bfcd921b2b89c4b9cd2d4f1efd49a4f13a603deb..5310db79895149e8c3f4c8c4ecaeef5da429b29f 100644 (file)
--- a/roundup/hyperdb.py
+++ b/roundup/hyperdb.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: hyperdb.py,v 1.39 2001-12-02 05:06:16 richard Exp $
+# $Id: hyperdb.py,v 1.40 2001-12-14 23:42:57 richard Exp $
__doc__ = """
Hyperdatabase implementation, especially field types.
# do the db-related init stuff
db.addclass(self)
+ def __repr__(self):
+ return '<hypderdb.Class "%s">'%self.classname
+
# Editing nodes:
def create(self, **propvalues):
#
# $Log: not supported by cvs2svn $
+# Revision 1.39 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.38 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