1edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""A dumb and slow but simple dbm clone.
2edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFor database spam, spam.dir contains the index (a text file),
4edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepspam.bak *may* contain a backup of the index (also a text file),
5edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepwhile spam.dat contains the data (a binary file).
6edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
7edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepXXX TO DO:
8edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
9edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- seems to contain a bug when updating...
10edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
11edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- reclaim free space (currently, space once occupied by deleted or expanded
12edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepitems is never reused)
13edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
14edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- support concurrent access (currently, if two processes take turns making
15edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepupdates, they can mess up the index)
16edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
17edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- support efficient access to large databases (currently, the whole index
18edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepis read when the database is opened, and some updates rewrite the whole index)
19edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
20edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- support opening for read-only (flag = 'm')
21edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
22edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
23edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
24edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport os as _os
25edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport __builtin__
26edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport UserDict
27edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
28edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_open = __builtin__.open
29edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
30edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep_BLOCKSIZE = 512
31edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
32edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeperror = IOError                         # For anydbm
33edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
34edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass _Database(UserDict.DictMixin):
35edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
36edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # The on-disk directory and data files can remain in mutually
37edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # inconsistent states for an arbitrarily long time (see comments
38edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # at the end of __setitem__).  This is only repaired when _commit()
39edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # gets called.  One place _commit() gets called is from __del__(),
40edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # and if that occurs at program shutdown time, module globals may
41edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # already have gotten rebound to None.  Since it's crucial that
42edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # _commit() finish successfully, we can't ignore shutdown races
43edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # here, and _commit() must not reference any globals.
44edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    _os = _os       # for _commit()
45edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    _open = _open   # for _commit()
46edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
47edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def __init__(self, filebasename, mode):
48edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._mode = mode
49edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
50edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The directory file is a text file.  Each line looks like
51edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #    "%r, (%d, %d)\n" % (key, pos, siz)
52edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # where key is the string key, pos is the offset into the dat
53edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # file of the associated value's first byte, and siz is the number
54edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # of bytes in the associated value.
55edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._dirfile = filebasename + _os.extsep + 'dir'
56edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
57edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The data file is a binary file pointed into by the directory
58edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # file, and holds the values associated with keys.  Each value
59edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # begins at a _BLOCKSIZE-aligned byte offset, and is a raw
60edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # binary 8-bit string value.
61edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._datfile = filebasename + _os.extsep + 'dat'
62edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._bakfile = filebasename + _os.extsep + 'bak'
63edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
64edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The index is an in-memory dict, mirroring the directory file.
65edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._index = None  # maps keys to (pos, siz) pairs
66edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
67edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Mod by Jack: create data file if needed
68edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
69edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            f = _open(self._datfile, 'r')
70edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        except IOError:
71edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            f = _open(self._datfile, 'w')
72edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._chmod(self._datfile)
73edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.close()
74edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._update()
75edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
76edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # Read directory file into the in-memory index dict.
77edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _update(self):
78edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._index = {}
79edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
80edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            f = _open(self._dirfile)
81edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        except IOError:
82edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pass
83edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:
84edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            for line in f:
85edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                line = line.rstrip()
86edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                key, pos_and_siz_pair = eval(line)
87edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                self._index[key] = pos_and_siz_pair
88edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            f.close()
89edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
90edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # Write the index dict to the directory file.  The original directory
91edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # file (if any) is renamed with a .bak extension first.  If a .bak
92edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # file currently exists, it's deleted.
93edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _commit(self):
94edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # CAUTION:  It's vital that _commit() succeed, and _commit() can
95edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # be called from __del__().  Therefore we must never reference a
96edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # global in this routine.
97edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if self._index is None:
98edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            return  # nothing to do
99edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._os.unlink(self._bakfile)
102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        except self._os.error:
103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pass
104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._os.rename(self._dirfile, self._bakfile)
107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        except self._os.error:
108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pass
109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f = self._open(self._dirfile, 'w')
111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._chmod(self._dirfile)
112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for key, pos_and_siz_pair in self._index.iteritems():
113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            f.write("%r, %r\n" % (key, pos_and_siz_pair))
114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.close()
115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    sync = _commit
117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def __getitem__(self, key):
119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        pos, siz = self._index[key]     # may raise KeyError
120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f = _open(self._datfile, 'rb')
121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.seek(pos)
122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dat = f.read(siz)
123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.close()
124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return dat
125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # Append val to the data file, starting at a _BLOCKSIZE-aligned
127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # offset.  The data file is first padded with NUL bytes (if needed)
128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # to get to an aligned offset.  Return pair
129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    #     (starting offset of val, len(val))
130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _addval(self, val):
131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f = _open(self._datfile, 'rb+')
132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.seek(0, 2)
133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        pos = int(f.tell())
134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        npos = ((pos + _BLOCKSIZE - 1) // _BLOCKSIZE) * _BLOCKSIZE
135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.write('\0'*(npos-pos))
136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        pos = npos
137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.write(val)
138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.close()
139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return (pos, len(val))
140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # Write val to the data file, starting at offset pos.  The caller
142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # is responsible for ensuring that there's enough room starting at
143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # pos to hold val, without overwriting some other value.  Return
144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # pair (pos, len(val)).
145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _setval(self, pos, val):
146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f = _open(self._datfile, 'rb+')
147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.seek(pos)
148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.write(val)
149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.close()
150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return (pos, len(val))
151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # key is a new key whose associated value starts in the data file
153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # at offset pos and with length siz.  Add an index record to
154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # the in-memory index dict, and append one to the directory file.
155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _addkey(self, key, pos_and_siz_pair):
156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._index[key] = pos_and_siz_pair
157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f = _open(self._dirfile, 'a')
158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._chmod(self._dirfile)
159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.write("%r, %r\n" % (key, pos_and_siz_pair))
160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        f.close()
161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def __setitem__(self, key, val):
163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if not type(key) == type('') == type(val):
164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            raise TypeError, "keys and values must be strings"
165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if key not in self._index:
166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._addkey(key, self._addval(val))
167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:
168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # See whether the new value is small enough to fit in the
169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # (padded) space currently occupied by the old value.
170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pos, siz = self._index[key]
171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            oldblocks = (siz + _BLOCKSIZE - 1) // _BLOCKSIZE
172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            newblocks = (len(val) + _BLOCKSIZE - 1) // _BLOCKSIZE
173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if newblocks <= oldblocks:
174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                self._index[key] = self._setval(pos, val)
175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            else:
176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                # The new value doesn't fit in the (padded) space used
177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                # by the old value.  The blocks used by the old value are
178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                # forever lost.
179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                self._index[key] = self._addval(val)
180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # Note that _index may be out of synch with the directory
182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # file now:  _setval() and _addval() don't update the directory
183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # file.  This also means that the on-disk directory and data
184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # files are in a mutually inconsistent state, and they'll
185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # remain that way until _commit() is called.  Note that this
186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # is a disaster (for the database) if the program crashes
187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # (so that _commit() never gets called).
188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def __delitem__(self, key):
190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The blocks used by the associated value are lost.
191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del self._index[key]
192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # XXX It's unclear why we do a _commit() here (the code always
193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # XXX has, so I'm not changing it).  _setitem__ doesn't try to
194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # XXX keep the directory file in synch.  Why should we?  Or
195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # XXX why shouldn't __setitem__?
196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._commit()
197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def keys(self):
199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return self._index.keys()
200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def has_key(self, key):
202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return key in self._index
203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def __contains__(self, key):
205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return key in self._index
206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def iterkeys(self):
208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return self._index.iterkeys()
209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    __iter__ = iterkeys
210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def __len__(self):
212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return len(self._index)
213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def close(self):
215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._commit()
216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._index = self._datfile = self._dirfile = self._bakfile = None
217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    __del__ = close
219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _chmod (self, file):
221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if hasattr(self._os, 'chmod'):
222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._os.chmod(file, self._mode)
223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef open(file, flag=None, mode=0666):
226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """Open the database file, filename, and return corresponding object.
227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    The flag argument, used to control how the database is opened in the
229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    other DBM implementations, is ignored in the dumbdbm module; the
230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    database is always opened for update, and will be created if it does
231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    not exist.
232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    The optional mode argument is the UNIX mode of the file, used only when
234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    the database has to be created.  It defaults to octal code 0666 (and
235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    will be modified by the prevailing umask).
236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    """
238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # flag argument is currently ignored
239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # Modify mode depending on the umask
241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    try:
242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        um = _os.umask(0)
243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        _os.umask(um)
244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    except AttributeError:
245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        pass
246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    else:
247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Turn off any bits that are set in the umask
248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        mode = mode & (~um)
249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return _Database(file, mode)
251