Skip to content

Commit 9f824a7

Browse files
committed
Initial revision
1 parent fda5c1a commit 9f824a7

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

Lib/dumbdbm.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
"""A dumb and slow but simple dbm clone.
2+
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).
6+
7+
XXX TO DO:
8+
9+
- seems to contain a bug when updating...
10+
11+
- reclaim free space (currently, space once occupied by deleted or expanded
12+
items is never reused)
13+
14+
- support concurrent access (currently, if two processes take turns making
15+
updates, they can mess up the index)
16+
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)
19+
20+
- support opening for read-only (flag = 'm')
21+
22+
"""
23+
24+
_os = __import__('os')
25+
import __builtin__
26+
27+
_open = __builtin__.open
28+
29+
_BLOCKSIZE = 512
30+
31+
class _Database:
32+
33+
def __init__(self, file):
34+
self._dirfile = file + '.dir'
35+
self._datfile = file + '.dat'
36+
self._bakfile = file + '.bak'
37+
# Mod by Jack: create data file if needed
38+
try:
39+
f = _open(self._datfile, 'r')
40+
except IOError:
41+
f = _open(self._datfile, 'w')
42+
f.close()
43+
self._update()
44+
45+
def _update(self):
46+
self._index = {}
47+
try:
48+
f = _open(self._dirfile)
49+
except IOError:
50+
pass
51+
else:
52+
while 1:
53+
line = f.readline()
54+
if not line: break
55+
key, (pos, siz) = eval(line)
56+
self._index[key] = (pos, siz)
57+
f.close()
58+
59+
def _commit(self):
60+
try: _os.unlink(self._bakfile)
61+
except _os.error: pass
62+
try: _os.rename(self._dirfile, self._bakfile)
63+
except _os.error: pass
64+
f = _open(self._dirfile, 'w')
65+
for key, (pos, siz) in self._index.items():
66+
f.write("%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
67+
f.close()
68+
69+
def __getitem__(self, key):
70+
pos, siz = self._index[key] # may raise KeyError
71+
f = _open(self._datfile, 'rb')
72+
f.seek(pos)
73+
dat = f.read(siz)
74+
f.close()
75+
return dat
76+
77+
def _addval(self, val):
78+
f = _open(self._datfile, 'rb+')
79+
f.seek(0, 2)
80+
pos = f.tell()
81+
## Does not work under MW compiler
82+
## pos = ((pos + _BLOCKSIZE - 1) / _BLOCKSIZE) * _BLOCKSIZE
83+
## f.seek(pos)
84+
npos = ((pos + _BLOCKSIZE - 1) / _BLOCKSIZE) * _BLOCKSIZE
85+
f.write('\0'*(npos-pos))
86+
pos = npos
87+
88+
f.write(val)
89+
f.close()
90+
return (pos, len(val))
91+
92+
def _setval(self, pos, val):
93+
f = _open(self._datfile, 'rb+')
94+
f.seek(pos)
95+
f.write(val)
96+
f.close()
97+
return pos, (val)
98+
99+
def _addkey(self, key, (pos, siz)):
100+
self._index[key] = (pos, siz)
101+
f = _open(self._dirfile, 'a')
102+
f.write("%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
103+
f.close()
104+
105+
def __setitem__(self, key, val):
106+
if not type(key) == type('') == type(val):
107+
raise TypeError, "keys and values must be strings"
108+
if not self._index.has_key(key):
109+
(pos, siz) = self._addval(val)
110+
self._addkey(key, (pos, siz))
111+
else:
112+
pos, siz = self._index[key]
113+
oldblocks = (siz + _BLOCKSIZE - 1) / _BLOCKSIZE
114+
newblocks = (len(val) + _BLOCKSIZE - 1) / _BLOCKSIZE
115+
if newblocks <= oldblocks:
116+
pos, siz = self._setval(pos, val)
117+
self._index[key] = pos, siz
118+
else:
119+
pos, siz = self._addval(val)
120+
self._index[key] = pos, siz
121+
self._addkey(key, (pos, siz))
122+
123+
def __delitem__(self, key):
124+
del self._index[key]
125+
self._commit()
126+
127+
def keys(self):
128+
return self._index.keys()
129+
130+
def has_key(self, key):
131+
return self._index.has_key(key)
132+
133+
def __len__(self):
134+
return len(self._index)
135+
136+
def close(self):
137+
self._index = None
138+
self._datfile = self._dirfile = self._bakfile = None
139+
140+
141+
def open(file, flag = None, mode = None):
142+
# flag, mode arguments are currently ignored
143+
return _Database(file)

0 commit comments

Comments
 (0)