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.16 2002-09-10 00:11:50 richard Exp $
20 import bsddb3, os, marshal
21 from roundup import hyperdb, date
23 # these classes are so similar, we just use the anydbm methods
24 from back_anydbm import Database, Class, FileClass, IssueClass
26 #
27 # Now the database
28 #
29 class Database(Database):
30 """A database for storing records containing flexible data types."""
31 #
32 # Class DBs
33 #
34 def clear(self):
35 for cn in self.classes.keys():
36 db = os.path.join(self.dir, 'nodes.%s'%cn)
37 bsddb3.btopen(db, 'n')
38 db = os.path.join(self.dir, 'journals.%s'%cn)
39 bsddb3.btopen(db, 'n')
41 def getclassdb(self, classname, mode='r'):
42 ''' grab a connection to the class db that will be used for
43 multiple actions
44 '''
45 path = os.path.join(os.getcwd(), self.dir, 'nodes.%s'%classname)
46 if os.path.exists(path):
47 return bsddb3.btopen(path, mode)
48 else:
49 return bsddb3.btopen(path, 'c')
51 def opendb(self, name, mode):
52 '''Low-level database opener that gets around anydbm/dbm
53 eccentricities.
54 '''
55 if __debug__:
56 print >>hyperdb.DEBUG, self, 'opendb', (self, name, mode)
57 # determine which DB wrote the class file
58 path = os.path.join(os.getcwd(), self.dir, name)
59 if not os.path.exists(path):
60 if __debug__:
61 print >>hyperdb.DEBUG, "opendb bsddb3.open(%r, 'c')"%path
62 return bsddb3.btopen(path, 'c')
64 # open the database with the correct module
65 if __debug__:
66 print >>hyperdb.DEBUG, "opendb bsddb3.open(%r, %r)"%(path, mode)
67 return bsddb3.btopen(path, mode)
69 #
70 # Journal
71 #
72 def getjournal(self, classname, nodeid):
73 ''' get the journal for id
74 '''
75 # attempt to open the journal - in some rare cases, the journal may
76 # not exist
77 try:
78 db = bsddb3.btopen(os.path.join(self.dir, 'journals.%s'%classname),
79 'r')
80 except bsddb3._db.DBNoSuchFileError:
81 raise IndexError, 'no such %s %s'%(classname, nodeid)
82 # more handling of bad journals
83 if not db.has_key(nodeid):
84 raise IndexError, 'no such %s %s'%(classname, nodeid)
85 journal = marshal.loads(db[nodeid])
86 res = []
87 for entry in journal:
88 (nodeid, date_stamp, user, action, params) = entry
89 date_obj = date.Date(date_stamp)
90 res.append((nodeid, date_obj, user, action, params))
91 db.close()
92 return res
94 def getCachedJournalDB(self, classname):
95 ''' get the journal db, looking in our cache of databases for commit
96 '''
97 # get the database handle
98 db_name = 'journals.%s'%classname
99 if self.databases.has_key(db_name):
100 return self.databases[db_name]
101 else:
102 db = bsddb3.btopen(os.path.join(self.dir, db_name), 'c')
103 self.databases[db_name] = db
104 return db
106 def doSaveJournal(self, classname, nodeid, action, params):
107 # serialise first
108 if action in ('set', 'create'):
109 params = self.serialise(classname, params)
111 entry = (nodeid, date.Date().get_tuple(), self.journaltag, action,
112 params)
114 if __debug__:
115 print >>hyperdb.DEBUG, 'doSaveJournal', entry
117 db = self.getCachedJournalDB(classname)
119 if db.has_key(nodeid):
120 s = db[nodeid]
121 l = marshal.loads(s)
122 l.append(entry)
123 else:
124 l = [entry]
126 db[nodeid] = marshal.dumps(l)