183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""A dumb and slow but simple dbm clone. 283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehFor database spam, spam.dir contains the index (a text file), 483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehspam.bak *may* contain a backup of the index (also a text file), 583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehwhile spam.dat contains the data (a binary file). 683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehXXX TO DO: 883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh- seems to contain a bug when updating... 1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh- reclaim free space (currently, space once occupied by deleted or expanded 1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehitems is never reused) 1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh- support concurrent access (currently, if two processes take turns making 1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehupdates, they can mess up the index) 1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh- support efficient access to large databases (currently, the whole index 1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehis read when the database is opened, and some updates rewrite the whole index) 1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh- support opening for read-only (flag = 'm') 2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh""" 2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport os as _os 2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport __builtin__ 2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport UserDict 2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh_open = __builtin__.open 2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh_BLOCKSIZE = 512 3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieherror = IOError # For anydbm 3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass _Database(UserDict.DictMixin): 3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # The on-disk directory and data files can remain in mutually 3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # inconsistent states for an arbitrarily long time (see comments 3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # at the end of __setitem__). This is only repaired when _commit() 3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # gets called. One place _commit() gets called is from __del__(), 4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # and if that occurs at program shutdown time, module globals may 4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # already have gotten rebound to None. Since it's crucial that 4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # _commit() finish successfully, we can't ignore shutdown races 4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # here, and _commit() must not reference any globals. 4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh _os = _os # for _commit() 4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh _open = _open # for _commit() 4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, filebasename, mode): 4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._mode = mode 4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # The directory file is a text file. Each line looks like 5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # "%r, (%d, %d)\n" % (key, pos, siz) 5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # where key is the string key, pos is the offset into the dat 5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # file of the associated value's first byte, and siz is the number 5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # of bytes in the associated value. 5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._dirfile = filebasename + _os.extsep + 'dir' 5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # The data file is a binary file pointed into by the directory 5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # file, and holds the values associated with keys. Each value 5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # begins at a _BLOCKSIZE-aligned byte offset, and is a raw 6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # binary 8-bit string value. 6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._datfile = filebasename + _os.extsep + 'dat' 6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._bakfile = filebasename + _os.extsep + 'bak' 6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # The index is an in-memory dict, mirroring the directory file. 6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._index = None # maps keys to (pos, siz) pairs 6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Mod by Jack: create data file if needed 6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = _open(self._datfile, 'r') 7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except IOError: 7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = _open(self._datfile, 'w') 7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._chmod(self._datfile) 7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._update() 7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Read directory file into the in-memory index dict. 7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _update(self): 7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._index = {} 7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = _open(self._dirfile) 8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except IOError: 8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pass 8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for line in f: 8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh line = line.rstrip() 8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh key, pos_and_siz_pair = eval(line) 8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._index[key] = pos_and_siz_pair 8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Write the index dict to the directory file. The original directory 9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # file (if any) is renamed with a .bak extension first. If a .bak 9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # file currently exists, it's deleted. 9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _commit(self): 9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # CAUTION: It's vital that _commit() succeed, and _commit() can 9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # be called from __del__(). Therefore we must never reference a 9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # global in this routine. 9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._index is None: 9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return # nothing to do 9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._os.unlink(self._bakfile) 10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except self._os.error: 10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pass 10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._os.rename(self._dirfile, self._bakfile) 10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except self._os.error: 10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pass 10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = self._open(self._dirfile, 'w') 11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._chmod(self._dirfile) 11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, pos_and_siz_pair in self._index.iteritems(): 11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.write("%r, %r\n" % (key, pos_and_siz_pair)) 11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh sync = _commit 11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getitem__(self, key): 11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pos, siz = self._index[key] # may raise KeyError 12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = _open(self._datfile, 'rb') 12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.seek(pos) 12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dat = f.read(siz) 12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return dat 12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Append val to the data file, starting at a _BLOCKSIZE-aligned 12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # offset. The data file is first padded with NUL bytes (if needed) 12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # to get to an aligned offset. Return pair 12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # (starting offset of val, len(val)) 13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _addval(self, val): 13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = _open(self._datfile, 'rb+') 13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.seek(0, 2) 13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pos = int(f.tell()) 13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh npos = ((pos + _BLOCKSIZE - 1) // _BLOCKSIZE) * _BLOCKSIZE 13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.write('\0'*(npos-pos)) 13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pos = npos 13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.write(val) 13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return (pos, len(val)) 14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Write val to the data file, starting at offset pos. The caller 14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # is responsible for ensuring that there's enough room starting at 14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # pos to hold val, without overwriting some other value. Return 14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # pair (pos, len(val)). 14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _setval(self, pos, val): 14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = _open(self._datfile, 'rb+') 14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.seek(pos) 14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.write(val) 14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return (pos, len(val)) 15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # key is a new key whose associated value starts in the data file 15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # at offset pos and with length siz. Add an index record to 15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # the in-memory index dict, and append one to the directory file. 15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _addkey(self, key, pos_and_siz_pair): 15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._index[key] = pos_and_siz_pair 15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = _open(self._dirfile, 'a') 15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._chmod(self._dirfile) 15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.write("%r, %r\n" % (key, pos_and_siz_pair)) 16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __setitem__(self, key, val): 16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not type(key) == type('') == type(val): 16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "keys and values must be strings" 16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if key not in self._index: 16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._addkey(key, self._addval(val)) 16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # See whether the new value is small enough to fit in the 16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # (padded) space currently occupied by the old value. 17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pos, siz = self._index[key] 17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh oldblocks = (siz + _BLOCKSIZE - 1) // _BLOCKSIZE 17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh newblocks = (len(val) + _BLOCKSIZE - 1) // _BLOCKSIZE 17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if newblocks <= oldblocks: 17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._index[key] = self._setval(pos, val) 17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # The new value doesn't fit in the (padded) space used 17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # by the old value. The blocks used by the old value are 17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # forever lost. 17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._index[key] = self._addval(val) 18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Note that _index may be out of synch with the directory 18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # file now: _setval() and _addval() don't update the directory 18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # file. This also means that the on-disk directory and data 18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # files are in a mutually inconsistent state, and they'll 18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # remain that way until _commit() is called. Note that this 18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # is a disaster (for the database) if the program crashes 18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # (so that _commit() never gets called). 18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __delitem__(self, key): 19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # The blocks used by the associated value are lost. 19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self._index[key] 19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # XXX It's unclear why we do a _commit() here (the code always 19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # XXX has, so I'm not changing it). _setitem__ doesn't try to 19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # XXX keep the directory file in synch. Why should we? Or 19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # XXX why shouldn't __setitem__? 19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._commit() 19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def keys(self): 19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._index.keys() 20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def has_key(self, key): 20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return key in self._index 20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __contains__(self, key): 20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return key in self._index 20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def iterkeys(self): 20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._index.iterkeys() 20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __iter__ = iterkeys 21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __len__(self): 21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return len(self._index) 21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def close(self): 21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._commit() 21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._index = self._datfile = self._dirfile = self._bakfile = None 21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __del__ = close 21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _chmod (self, file): 22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if hasattr(self._os, 'chmod'): 22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._os.chmod(file, self._mode) 22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef open(file, flag=None, mode=0666): 22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Open the database file, filename, and return corresponding object. 22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The flag argument, used to control how the database is opened in the 22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh other DBM implementations, is ignored in the dumbdbm module; the 23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh database is always opened for update, and will be created if it does 23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh not exist. 23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The optional mode argument is the UNIX mode of the file, used only when 23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh the database has to be created. It defaults to octal code 0666 (and 23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh will be modified by the prevailing umask). 23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # flag argument is currently ignored 23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Modify mode depending on the umask 24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh um = _os.umask(0) 24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh _os.umask(um) 24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except AttributeError: 24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pass 24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Turn off any bits that are set in the umask 24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mode = mode & (~um) 24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _Database(file, mode) 251