blob: 90bf92bc5e591e1593d093d07d807ae178bf7155 [file] [log] [blame]
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +00001#----------------------------------------------------------------------
2# Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
3# and Andrew Kuchling. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# o Redistributions of source code must retain the above copyright
10# notice, this list of conditions, and the disclaimer that follows.
11#
12# o Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions, and the following disclaimer in
14# the documentation and/or other materials provided with the
15# distribution.
16#
17# o Neither the name of Digital Creations nor the names of its
18# contributors may be used to endorse or promote products derived
19# from this software without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
22# IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
25# CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32# DAMAGE.
33#----------------------------------------------------------------------
34
35
Gregory P. Smith41631e82003-09-21 00:08:14 +000036"""Support for BerkeleyDB 3.2 through 4.2.
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000037"""
38
Martin v. Löwis65730a42002-11-24 08:26:01 +000039try:
Gregory P. Smith41631e82003-09-21 00:08:14 +000040 if __name__ == 'bsddb3':
41 # import _pybsddb binary as it should be the more recent version from
42 # a standalone pybsddb addon package than the version included with
43 # python as bsddb._bsddb.
44 import _pybsddb
45 _bsddb = _pybsddb
46 else:
47 import _bsddb
Martin v. Löwis65730a42002-11-24 08:26:01 +000048except ImportError:
49 # Remove ourselves from sys.modules
50 import sys
51 del sys.modules[__name__]
52 raise
Tim Peters0eadaac2003-04-24 16:02:54 +000053
Barry Warsawf71de3e2003-01-28 17:20:44 +000054# bsddb3 calls it db, but provide _db for backwards compatibility
55db = _db = _bsddb
56__version__ = db.__version__
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000057
Barry Warsawf71de3e2003-01-28 17:20:44 +000058error = db.DBError # So bsddb.error will mean something...
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000059
60#----------------------------------------------------------------------
61
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +000062import sys
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000063
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +000064# for backwards compatibility with python versions older than 2.3, the
65# iterator interface is dynamically defined and added using a mixin
66# class. old python can't tokenize it due to the yield keyword.
67if sys.version >= '2.3':
68 exec """
69import UserDict
Gregory P. Smitha703a212003-11-03 01:04:41 +000070from weakref import ref
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +000071class _iter_mixin(UserDict.DictMixin):
Gregory P. Smitha703a212003-11-03 01:04:41 +000072 def _make_iter_cursor(self):
73 cur = self.db.cursor()
74 key = id(cur)
75 self._cursor_refs[key] = ref(cur, self._gen_cref_cleaner(key))
76 return cur
77
78 def _gen_cref_cleaner(self, key):
79 # use generate the function for the weakref callback here
80 # to ensure that we do not hold a strict reference to cur
81 # in the callback.
82 return lambda ref: self._cursor_refs.pop(key, None)
83
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +000084 def __iter__(self):
85 try:
Gregory P. Smitha703a212003-11-03 01:04:41 +000086 cur = self._make_iter_cursor()
87
88 # FIXME-20031102-greg: race condition. cursor could
89 # be closed by another thread before this call.
Gregory P. Smithdc113a82003-11-02 09:10:16 +000090
91 # since we're only returning keys, we call the cursor
92 # methods with flags=0, dlen=0, dofs=0
Gregory P. Smitha703a212003-11-03 01:04:41 +000093 key = cur.first(0,0,0)[0]
94 yield key
Gregory P. Smithdc113a82003-11-02 09:10:16 +000095
96 next = cur.next
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +000097 while 1:
Gregory P. Smithdc113a82003-11-02 09:10:16 +000098 try:
Gregory P. Smitha703a212003-11-03 01:04:41 +000099 key = next(0,0,0)[0]
100 yield key
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000101 except _bsddb.DBCursorClosedError:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000102 cur = self._make_iter_cursor()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000103 # FIXME-20031101-greg: race condition. cursor could
Gregory P. Smitha703a212003-11-03 01:04:41 +0000104 # be closed by another thread before this call.
105 cur.set(key,0,0,0)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000106 next = cur.next
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +0000107 except _bsddb.DBNotFoundError:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000108 return
109 except _bsddb.DBCursorClosedError:
110 # the database was modified during iteration. abort.
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +0000111 return
112
113 def iteritems(self):
114 try:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000115 cur = self._make_iter_cursor()
116
117 # FIXME-20031102-greg: race condition. cursor could
118 # be closed by another thread before this call.
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000119
120 kv = cur.first()
Gregory P. Smitha703a212003-11-03 01:04:41 +0000121 key = kv[0]
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000122 yield kv
123
124 next = cur.next
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +0000125 while 1:
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000126 try:
127 kv = next()
Gregory P. Smitha703a212003-11-03 01:04:41 +0000128 key = kv[0]
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000129 yield kv
130 except _bsddb.DBCursorClosedError:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000131 cur = self._make_iter_cursor()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000132 # FIXME-20031101-greg: race condition. cursor could
Gregory P. Smitha703a212003-11-03 01:04:41 +0000133 # be closed by another thread before this call.
134 cur.set(key,0,0,0)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000135 next = cur.next
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +0000136 except _bsddb.DBNotFoundError:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000137 return
138 except _bsddb.DBCursorClosedError:
139 # the database was modified during iteration. abort.
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +0000140 return
141"""
142else:
143 class _iter_mixin: pass
144
145
146class _DBWithCursor(_iter_mixin):
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000147 """
148 A simple wrapper around DB that makes it look like the bsddbobject in
149 the old module. It uses a cursor as needed to provide DB traversal.
150 """
151 def __init__(self, db):
152 self.db = db
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000153 self.db.set_get_returns_none(0)
154
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000155 # FIXME-20031101-greg: I believe there is still the potential
156 # for deadlocks in a multithreaded environment if someone
157 # attempts to use the any of the cursor interfaces in one
158 # thread while doing a put or delete in another thread. The
159 # reason is that _checkCursor and _closeCursors are not atomic
160 # operations. Doing our own locking around self.dbc,
Gregory P. Smitha703a212003-11-03 01:04:41 +0000161 # self.saved_dbc_key and self._cursor_refs could prevent this.
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000162 # TODO: A test case demonstrating the problem needs to be written.
163
164 # self.dbc is a DBCursor object used to implement the
165 # first/next/previous/last/set_location methods.
166 self.dbc = None
167 self.saved_dbc_key = None
168
169 # a collection of all DBCursor objects currently allocated
170 # by the _iter_mixin interface.
Gregory P. Smitha703a212003-11-03 01:04:41 +0000171 self._cursor_refs = {}
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000172
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000173 def __del__(self):
174 self.close()
175
176 def _checkCursor(self):
177 if self.dbc is None:
178 self.dbc = self.db.cursor()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000179 if self.saved_dbc_key is not None:
180 self.dbc.set(self.saved_dbc_key)
181 self.saved_dbc_key = None
182
183 # This method is needed for all non-cursor DB calls to avoid
184 # BerkeleyDB deadlocks (due to being opened with DB_INIT_LOCK
185 # and DB_THREAD to be thread safe) when intermixing database
186 # operations that use the cursor internally with those that don't.
Gregory P. Smithe33aef72004-01-13 19:59:57 +0000187 def _closeCursors(self, save=1):
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000188 if self.dbc:
189 c = self.dbc
190 self.dbc = None
191 if save:
192 self.saved_dbc_key = c.current(0,0,0)[0]
193 c.close()
194 del c
Gregory P. Smitha703a212003-11-03 01:04:41 +0000195 for cref in self._cursor_refs.values():
196 c = cref()
197 if c is not None:
198 c.close()
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000199
200 def _checkOpen(self):
201 if self.db is None:
202 raise error, "BSDDB object has already been closed"
203
204 def isOpen(self):
205 return self.db is not None
206
207 def __len__(self):
208 self._checkOpen()
209 return len(self.db)
210
211 def __getitem__(self, key):
212 self._checkOpen()
213 return self.db[key]
214
215 def __setitem__(self, key, value):
216 self._checkOpen()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000217 self._closeCursors()
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000218 self.db[key] = value
219
220 def __delitem__(self, key):
221 self._checkOpen()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000222 self._closeCursors()
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000223 del self.db[key]
224
225 def close(self):
Gregory P. Smithe33aef72004-01-13 19:59:57 +0000226 self._closeCursors(save=0)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000227 if self.dbc is not None:
228 self.dbc.close()
229 v = 0
230 if self.db is not None:
231 v = self.db.close()
232 self.dbc = None
233 self.db = None
234 return v
235
236 def keys(self):
237 self._checkOpen()
238 return self.db.keys()
239
240 def has_key(self, key):
241 self._checkOpen()
242 return self.db.has_key(key)
243
244 def set_location(self, key):
245 self._checkOpen()
246 self._checkCursor()
Gregory P. Smitha7befda2004-02-26 10:07:14 +0000247 return self.dbc.set_range(key)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000248
249 def next(self):
250 self._checkOpen()
251 self._checkCursor()
252 rv = self.dbc.next()
253 return rv
254
255 def previous(self):
256 self._checkOpen()
257 self._checkCursor()
258 rv = self.dbc.prev()
259 return rv
260
261 def first(self):
262 self._checkOpen()
263 self._checkCursor()
264 rv = self.dbc.first()
265 return rv
266
267 def last(self):
268 self._checkOpen()
269 self._checkCursor()
270 rv = self.dbc.last()
271 return rv
272
273 def sync(self):
274 self._checkOpen()
275 return self.db.sync()
276
Raymond Hettinger2e9da602003-09-13 03:18:34 +0000277
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000278#----------------------------------------------------------------------
279# Compatibility object factory functions
280
281def hashopen(file, flag='c', mode=0666, pgsize=None, ffactor=None, nelem=None,
282 cachesize=None, lorder=None, hflags=0):
283
284 flags = _checkflag(flag)
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000285 e = _openDBEnv()
286 d = db.DB(e)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000287 d.set_flags(hflags)
288 if cachesize is not None: d.set_cachesize(0, cachesize)
289 if pgsize is not None: d.set_pagesize(pgsize)
290 if lorder is not None: d.set_lorder(lorder)
291 if ffactor is not None: d.set_h_ffactor(ffactor)
292 if nelem is not None: d.set_h_nelem(nelem)
Barry Warsawf71de3e2003-01-28 17:20:44 +0000293 d.open(file, db.DB_HASH, flags, mode)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000294 return _DBWithCursor(d)
295
296#----------------------------------------------------------------------
297
298def btopen(file, flag='c', mode=0666,
299 btflags=0, cachesize=None, maxkeypage=None, minkeypage=None,
300 pgsize=None, lorder=None):
301
302 flags = _checkflag(flag)
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000303 e = _openDBEnv()
304 d = db.DB(e)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000305 if cachesize is not None: d.set_cachesize(0, cachesize)
306 if pgsize is not None: d.set_pagesize(pgsize)
307 if lorder is not None: d.set_lorder(lorder)
308 d.set_flags(btflags)
309 if minkeypage is not None: d.set_bt_minkey(minkeypage)
310 if maxkeypage is not None: d.set_bt_maxkey(maxkeypage)
Barry Warsawf71de3e2003-01-28 17:20:44 +0000311 d.open(file, db.DB_BTREE, flags, mode)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000312 return _DBWithCursor(d)
313
314#----------------------------------------------------------------------
315
316
317def rnopen(file, flag='c', mode=0666,
318 rnflags=0, cachesize=None, pgsize=None, lorder=None,
319 rlen=None, delim=None, source=None, pad=None):
320
321 flags = _checkflag(flag)
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000322 e = _openDBEnv()
323 d = db.DB(e)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000324 if cachesize is not None: d.set_cachesize(0, cachesize)
325 if pgsize is not None: d.set_pagesize(pgsize)
326 if lorder is not None: d.set_lorder(lorder)
327 d.set_flags(rnflags)
328 if delim is not None: d.set_re_delim(delim)
329 if rlen is not None: d.set_re_len(rlen)
330 if source is not None: d.set_re_source(source)
331 if pad is not None: d.set_re_pad(pad)
Barry Warsawf71de3e2003-01-28 17:20:44 +0000332 d.open(file, db.DB_RECNO, flags, mode)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000333 return _DBWithCursor(d)
334
335#----------------------------------------------------------------------
336
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000337def _openDBEnv():
338 e = db.DBEnv()
339 e.open('.', db.DB_PRIVATE | db.DB_CREATE | db.DB_THREAD | db.DB_INIT_LOCK | db.DB_INIT_MPOOL)
340 return e
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000341
342def _checkflag(flag):
343 if flag == 'r':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000344 flags = db.DB_RDONLY
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000345 elif flag == 'rw':
346 flags = 0
347 elif flag == 'w':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000348 flags = db.DB_CREATE
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000349 elif flag == 'c':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000350 flags = db.DB_CREATE
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000351 elif flag == 'n':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000352 flags = db.DB_CREATE | db.DB_TRUNCATE
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000353 else:
354 raise error, "flags should be one of 'r', 'w', 'c' or 'n'"
Barry Warsawf71de3e2003-01-28 17:20:44 +0000355 return flags | db.DB_THREAD
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000356
357#----------------------------------------------------------------------
358
359
360# This is a silly little hack that allows apps to continue to use the
361# DB_THREAD flag even on systems without threads without freaking out
362# BerkeleyDB.
363#
364# This assumes that if Python was built with thread support then
365# BerkeleyDB was too.
366
367try:
368 import thread
369 del thread
370except ImportError:
Barry Warsawf71de3e2003-01-28 17:20:44 +0000371 db.DB_THREAD = 0
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000372
373
374#----------------------------------------------------------------------