1 """A dumb and slow but simple dbm clone.
3 For database spam, spam.dir contains the index (a text file),
4 spam.bak *may* contain a backup of the index (also a text file),
5 while spam.dat contains the data (a binary file).
9 - seems to contain a bug when updating...
11 - reclaim free space (currently, space once occupied by deleted or expanded
12 items is never reused)
14 - support concurrent access (currently, if two processes take turns making
15 updates, they can mess up the index)
17 - support efficient access to large databases (currently, the whole index
18 is read when the database is opened, and some updates rewrite the whole index)
20 - support opening for read-only (flag = 'm')
27 _open = __builtin__.open
37 self.
_dirfile = file + _os.extsep +
'dir'
38 self.
_datfile = file + _os.extsep +
'dat'
39 self.
_bakfile = file + _os.extsep +
'bak'
56 line = f.readline().
rstrip()
58 key, (pos, siz) = eval(line)
59 self.
_index[key] = (pos, siz)
64 except _os.error:
pass
66 except _os.error:
pass
68 for key, (pos, siz)
in self._index.items():
69 f.write(
"%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
73 pos, siz = self.
_index[key]
80 def _addval(self, val):
87 npos = ((pos + _BLOCKSIZE - 1) // _BLOCKSIZE) * _BLOCKSIZE
88 f.write(
'\0'*(npos-pos))
93 return (pos, len(val))
95 def _setval(self, pos, val):
96 f =
_open(self._datfile,
'rb+')
100 return (pos, len(val))
102 def _addkey(self, key, (pos, siz)):
103 self._index[key] = (pos, siz)
104 f =
_open(self._dirfile,
'a', self._mode)
105 f.write(
"%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
109 if not type(key) == type(
'') == type(val):
110 raise TypeError,
"keys and values must be strings"
111 if not self._index.has_key(key):
112 (pos, siz) = self._addval(val)
113 self._addkey(key, (pos, siz))
115 pos, siz = self._index[key]
116 oldblocks = (siz + _BLOCKSIZE - 1) / _BLOCKSIZE
117 newblocks = (len(val) + _BLOCKSIZE - 1) / _BLOCKSIZE
118 if newblocks <= oldblocks:
119 pos, siz = self._setval(pos, val)
120 self._index[key] = pos, siz
122 pos, siz = self._addval(val)
123 self._index[key] = pos, siz
130 return self._index.keys()
133 return self._index.has_key(key)
136 return self._index.has_key(key)
139 return self._index.iterkeys()
143 return len(self._index)
148 self._datfile = self._dirfile = self._bakfile =
None
151 if self._index
is not None:
156 def open(file, flag=None, mode=0666):