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