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.
#
# 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
'''
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
import whichdb, anydbm, os, marshal
from roundup import hyperdb, date, password
+DEBUG=os.environ.get('HYPERDBDEBUG', '')
+
#
# Now the database
#
#
# Now the database
#
self.newnodes = {} # keep track of the new nodes by class
self.transactions = []
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)."""
#
# 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):
def addclass(self, cl):
+ if DEBUG:
+ print 'addclass', (self, cl)
cn = cl.classname
if self.classes.has_key(cn):
raise ValueError, cn
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."""
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
l = self.classes.keys()
l.sort()
return l
If 'classname' is not a valid class name, a KeyError is raised.
"""
If 'classname' is not a valid class name, a KeyError is raised.
"""
+ if DEBUG:
+ print 'getclass', (self, classname)
return self.classes[classname]
#
return self.classes[classname]
#
def clear(self):
'''Delete all database contents
'''
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)
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
'''
''' 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.
'''
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)
# 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:
# 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
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
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)
#
return dbm.open(path, mode)
#
def addnode(self, classname, nodeid, node):
''' add the specified node to its class's db
'''
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)
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
'''
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
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
'''
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)))
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
'''
''' 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
# 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
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
'''
''' 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
# 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
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
# 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
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()
# 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
res = res + db.keys()
return res
'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
'retire' -- 'params' is None
'''
'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
'''
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:
# attempt to open the journal - in some rare cases, the journal may
# not exist
try:
def commit(self):
''' Commit the current transactions.
'''
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!
# lock the DB
for method, args in self.transactions:
# TODO: optimise this, duh!
self.transactions = []
def _doSaveNode(self, classname, nodeid, node):
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):
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)
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])
if db.has_key(nodeid):
s = db[nodeid]
l = marshal.loads(db[nodeid])
def rollback(self):
''' Reverse all actions from the current transaction.
'''
def rollback(self):
''' Reverse all actions from the current transaction.
'''
+ if DEBUG:
+ print 'rollback', (self, )
self.cache = {}
self.dirtynodes = {}
self.newnodes = {}
self.cache = {}
self.dirtynodes = {}
self.newnodes = {}
#
#$Log: not supported by cvs2svn $
#
#$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"
#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.
#
# 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.
__doc__ = """
Hyperdatabase implementation, especially field types.
# do the db-related init stuff
db.addclass(self)
# do the db-related init stuff
db.addclass(self)
+ def __repr__(self):
+ return '<hypderdb.Class "%s">'%self.classname
+
# Editing nodes:
def create(self, **propvalues):
# Editing nodes:
def create(self, **propvalues):
#
# $Log: not supported by cvs2svn $
#
# $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
# 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