1515# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717#
18- #$Id: back_bsddb3.py,v 1.11 2002-01-14 02:20:15 richard Exp $
18+ #$Id: back_bsddb3.py,v 1.12 2002-05-21 05:52:11 richard Exp $
1919
2020import bsddb3 , os , marshal
21- from roundup import hyperdb , date , password
21+ from roundup import hyperdb , date
22+
23+ # these classes are so similar, we just use the anydbm methods
24+ import back_anydbm
2225
2326#
2427# Now the database
2528#
26- class Database (hyperdb .Database ):
29+ class Database (back_anydbm .Database ):
2730 """A database for storing records containing flexible data types."""
28-
29- def __init__ (self , config , journaltag = None ):
30- """Open a hyperdatabase given a specifier to some storage.
31-
32- The 'storagelocator' is obtained from config.DATABASE.
33- The meaning of 'storagelocator' depends on the particular
34- implementation of the hyperdatabase. It could be a file name,
35- a directory path, a socket descriptor for a connection to a
36- database over the network, etc.
37-
38- The 'journaltag' is a token that will be attached to the journal
39- entries for any edits done on the database. If 'journaltag' is
40- None, the database is opened in read-only mode: the Class.create(),
41- Class.set(), and Class.retire() methods are disabled.
42- """
43- self .config , self .journaltag = config , journaltag
44- self .dir = config .DATABASE
45- self .classes = {}
46-
47- #
48- # Classes
49- #
50- def __getattr__ (self , classname ):
51- """A convenient way of calling self.getclass(classname)."""
52- return self .classes [classname ]
53-
54- def addclass (self , cl ):
55- cn = cl .classname
56- if self .classes .has_key (cn ):
57- raise ValueError , cn
58- self .classes [cn ] = cl
59-
60- def getclasses (self ):
61- """Return a list of the names of all existing classes."""
62- l = self .classes .keys ()
63- l .sort ()
64- return l
65-
66- def getclass (self , classname ):
67- """Get the Class object representing a particular class.
68-
69- If 'classname' is not a valid class name, a KeyError is raised.
70- """
71- return self .classes [classname ]
72-
7331 #
7432 # Class DBs
7533 #
7634 def clear (self ):
7735 for cn in self .classes .keys ():
7836 db = os .path .join (self .dir , 'nodes.%s' % cn )
79- bsddb3 .btopen (db , 'c ' )
37+ bsddb3 .btopen (db , 'n ' )
8038 db = os .path .join (self .dir , 'journals.%s' % cn )
81- bsddb3 .btopen (db , 'c ' )
39+ bsddb3 .btopen (db , 'n ' )
8240
8341 def getclassdb (self , classname , mode = 'r' ):
8442 ''' grab a connection to the class db that will be used for
@@ -88,73 +46,29 @@ def getclassdb(self, classname, mode='r'):
8846 if os .path .exists (path ):
8947 return bsddb3 .btopen (path , mode )
9048 else :
91- return bsddb3 .btopen (path , 'c ' )
49+ return bsddb3 .btopen (path , 'n ' )
9250
93- #
94- # Nodes
95- #
96- def addnode (self , classname , nodeid , node ):
97- ''' add the specified node to its class's db
51+ def _opendb (self , name , mode ):
52+ '''Low-level database opener that gets around anydbm/dbm
53+ eccentricities.
9854 '''
99- db = self .getclassdb (classname , 'c' )
100- # now save the marshalled data
101- db [nodeid ] = marshal .dumps (node )
102- db .close ()
103- setnode = addnode
104-
105- def getnode (self , classname , nodeid , cldb = None ):
106- ''' add the specified node to its class's db
107- '''
108- db = cldb or self .getclassdb (classname )
109- if not db .has_key (nodeid ):
110- raise IndexError , nodeid
111- res = marshal .loads (db [nodeid ])
112- if not cldb : db .close ()
113- return res
114-
115- def hasnode (self , classname , nodeid , cldb = None ):
116- ''' add the specified node to its class's db
117- '''
118- db = cldb or self .getclassdb (classname )
119- res = db .has_key (nodeid )
120- if not cldb : db .close ()
121- return res
122-
123- def countnodes (self , classname , cldb = None ):
124- db = cldb or self .getclassdb (classname )
125- return len (db .keys ())
126- if not cldb : db .close ()
127- return res
128-
129- def getnodeids (self , classname , cldb = None ):
130- db = cldb or self .getclassdb (classname )
131- res = db .keys ()
132- if not cldb : db .close ()
133- return res
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, 'n')" % path
62+ return bsddb3 .btopen (path , 'n' )
63+
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 )
13468
13569 #
13670 # Journal
13771 #
138- def addjournal (self , classname , nodeid , action , params ):
139- ''' Journal the Action
140- 'action' may be:
141-
142- 'create' or 'set' -- 'params' is a dictionary of property values
143- 'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
144- 'retire' -- 'params' is None
145- '''
146- entry = (nodeid , date .Date ().get_tuple (), self .journaltag , action ,
147- params )
148- db = bsddb3 .btopen (os .path .join (self .dir , 'journals.%s' % classname ), 'c' )
149- if db .has_key (nodeid ):
150- s = db [nodeid ]
151- l = marshal .loads (db [nodeid ])
152- l .append (entry )
153- else :
154- l = [entry ]
155- db [nodeid ] = marshal .dumps (l )
156- db .close ()
157-
15872 def getjournal (self , classname , nodeid ):
15973 ''' get the journal for id
16074 '''
@@ -163,46 +77,53 @@ def getjournal(self, classname, nodeid):
16377 try :
16478 db = bsddb3 .btopen (os .path .join (self .dir , 'journals.%s' % classname ),
16579 'r' )
166- except bsddb3 .error , error :
167- if error .args [0 ] != 2 : raise
80+ except bsddb3 .NoSuchFileError :
16881 return []
16982 # mor handling of bad journals
17083 if not db .has_key (nodeid ): return []
17184 journal = marshal .loads (db [nodeid ])
17285 res = []
17386 for entry in journal :
174- (nodeid , date_stamp , self . journaltag , action , params ) = entry
87+ (nodeid , date_stamp , user , action , params ) = entry
17588 date_obj = date .Date (date_stamp )
176- res .append ((nodeid , date_obj , self . journaltag , action , params ))
89+ res .append ((nodeid , date_obj , user , action , params ))
17790 db .close ()
17891 return res
17992
180- def close (self ):
181- ''' Close the Database - we must release the circular refs so that
182- we can be del'ed and the underlying bsddb connections closed
183- cleanly.
184- '''
185- self .classes = {}
93+ def _doSaveJournal (self , classname , nodeid , action , params ):
94+ # serialise first
95+ if action in ('set' , 'create' ):
96+ params = self .serialise (classname , params )
18697
98+ entry = (nodeid , date .Date ().get_tuple (), self .journaltag , action ,
99+ params )
187100
188- #
189- # Basic transaction support
190- #
191- # TODO: well, write these methods (and then use them in other code)
192- def register_action (self ):
193- ''' Register an action to the transaction undo log
194- '''
101+ if __debug__ :
102+ print >> hyperdb .DEBUG , '_doSaveJournal' , entry
195103
196- def commit (self ):
197- ''' Commit the current transaction, start a new one
198- '''
104+ db = bsddb3 .btopen (os .path .join (self .dir , 'journals.%s' % classname ), 'c' )
199105
200- def rollback (self ):
201- ''' Reverse all actions from the current transaction
202- '''
106+ if db .has_key (nodeid ):
107+ s = db [nodeid ]
108+ l = marshal .loads (s )
109+ l .append (entry )
110+ else :
111+ l = [entry ]
112+
113+ db [nodeid ] = marshal .dumps (l )
114+ db .close ()
203115
204116#
205117#$Log: not supported by cvs2svn $
118+ #Revision 1.11 2002/01/14 02:20:15 richard
119+ # . changed all config accesses so they access either the instance or the
120+ # config attriubute on the db. This means that all config is obtained from
121+ # instance_config instead of the mish-mash of classes. This will make
122+ # switching to a ConfigParser setup easier too, I hope.
123+ #
124+ #At a minimum, this makes migration a _little_ easier (a lot easier in the
125+ #0.5.0 switch, I hope!)
126+ #
206127#Revision 1.10 2001/11/21 02:34:18 richard
207128#Added a target version field to the extended issue schema
208129#
0 commit comments