1 #
2 # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
6 #
7 # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
8 # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
9 # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
10 # POSSIBILITY OF SUCH DAMAGE.
11 #
12 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17 #
18 #$Id: back_bsddb3.py,v 1.18 2002-10-03 06:56:29 richard Exp $
19 '''
20 This module defines a backend that saves the hyperdatabase in BSDDB3.
21 '''
23 import bsddb3, os, marshal
24 from roundup import hyperdb, date
26 # these classes are so similar, we just use the anydbm methods
27 from back_anydbm import Database, Class, FileClass, IssueClass
29 #
30 # Now the database
31 #
32 class Database(Database):
33 """A database for storing records containing flexible data types."""
34 #
35 # Class DBs
36 #
37 def clear(self):
38 for cn in self.classes.keys():
39 db = os.path.join(self.dir, 'nodes.%s'%cn)
40 bsddb3.btopen(db, 'n')
41 db = os.path.join(self.dir, 'journals.%s'%cn)
42 bsddb3.btopen(db, 'n')
44 def getclassdb(self, classname, mode='r'):
45 ''' grab a connection to the class db that will be used for
46 multiple actions
47 '''
48 path = os.path.join(os.getcwd(), self.dir, 'nodes.%s'%classname)
49 if os.path.exists(path):
50 return bsddb3.btopen(path, mode)
51 else:
52 return bsddb3.btopen(path, 'c')
54 def opendb(self, name, mode):
55 '''Low-level database opener that gets around anydbm/dbm
56 eccentricities.
57 '''
58 if __debug__:
59 print >>hyperdb.DEBUG, self, 'opendb', (self, name, mode)
60 # determine which DB wrote the class file
61 path = os.path.join(os.getcwd(), self.dir, name)
62 if not os.path.exists(path):
63 if __debug__:
64 print >>hyperdb.DEBUG, "opendb bsddb3.open(%r, 'c')"%path
65 return bsddb3.btopen(path, 'c')
67 # open the database with the correct module
68 if __debug__:
69 print >>hyperdb.DEBUG, "opendb bsddb3.open(%r, %r)"%(path, mode)
70 return bsddb3.btopen(path, mode)
72 #
73 # Journal
74 #
75 def getjournal(self, classname, nodeid):
76 ''' get the journal for id
77 '''
78 # attempt to open the journal - in some rare cases, the journal may
79 # not exist
80 try:
81 db = bsddb3.btopen(os.path.join(self.dir, 'journals.%s'%classname),
82 'r')
83 except bsddb3._db.DBNoSuchFileError:
84 raise IndexError, 'no such %s %s'%(classname, nodeid)
85 # more handling of bad journals
86 if not db.has_key(nodeid):
87 raise IndexError, 'no such %s %s'%(classname, nodeid)
88 journal = marshal.loads(db[nodeid])
89 res = []
90 for entry in journal:
91 (nodeid, date_stamp, user, action, params) = entry
92 date_obj = date.Date(date_stamp)
93 res.append((nodeid, date_obj, user, action, params))
94 db.close()
95 return res
97 def getCachedJournalDB(self, classname):
98 ''' get the journal db, looking in our cache of databases for commit
99 '''
100 # get the database handle
101 db_name = 'journals.%s'%classname
102 if self.databases.has_key(db_name):
103 return self.databases[db_name]
104 else:
105 db = bsddb3.btopen(os.path.join(self.dir, db_name), 'c')
106 self.databases[db_name] = db
107 return db