Vega strike Python Modules doc  0.5.1
Documentation of the " Modules " folder of Vega strike
 All Data Structures Namespaces Files Functions Variables
dumbdbm.py
Go to the documentation of this file.
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 import os as _os
25 import __builtin__
26 
27 _open = __builtin__.open
28 
29 _BLOCKSIZE = 512
30 
31 error = IOError # For anydbm
32 
33 class _Database:
34 
35  def __init__(self, file, mode):
36  self._mode = mode
37  self._dirfile = file + _os.extsep + 'dir'
38  self._datfile = file + _os.extsep + 'dat'
39  self._bakfile = file + _os.extsep + 'bak'
40  # Mod by Jack: create data file if needed
41  try:
42  f = _open(self._datfile, 'r')
43  except IOError:
44  f = _open(self._datfile, 'w', self._mode)
45  f.close()
46  self._update()
47 
48  def _update(self):
49  self._index = {}
50  try:
51  f = _open(self._dirfile)
52  except IOError:
53  pass
54  else:
55  while 1:
56  line = f.readline().rstrip()
57  if not line: break
58  key, (pos, siz) = eval(line)
59  self._index[key] = (pos, siz)
60  f.close()
61 
62  def _commit(self):
63  try: _os.unlink(self._bakfile)
64  except _os.error: pass
65  try: _os.rename(self._dirfile, self._bakfile)
66  except _os.error: pass
67  f = _open(self._dirfile, 'w', self._mode)
68  for key, (pos, siz) in self._index.items():
69  f.write("%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
70  f.close()
71 
72  def __getitem__(self, key):
73  pos, siz = self._index[key] # may raise KeyError
74  f = _open(self._datfile, 'rb')
75  f.seek(pos)
76  dat = f.read(siz)
77  f.close()
78  return dat
79 
80  def _addval(self, val):
81  f = _open(self._datfile, 'rb+')
82  f.seek(0, 2)
83  pos = int(f.tell())
84 ## Does not work under MW compiler
85 ## pos = ((pos + _BLOCKSIZE - 1) / _BLOCKSIZE) * _BLOCKSIZE
86 ## f.seek(pos)
87  npos = ((pos + _BLOCKSIZE - 1) // _BLOCKSIZE) * _BLOCKSIZE
88  f.write('\0'*(npos-pos))
89  pos = npos
90 
91  f.write(val)
92  f.close()
93  return (pos, len(val))
94 
95  def _setval(self, pos, val):
96  f = _open(self._datfile, 'rb+')
97  f.seek(pos)
98  f.write(val)
99  f.close()
100  return (pos, len(val))
101 
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`))
106  f.close()
107 
108  def __setitem__(self, key, val):
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))
114  else:
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
121  else:
122  pos, siz = self._addval(val)
123  self._index[key] = pos, siz
124 
125  def __delitem__(self, key):
126  del self._index[key]
127  self._commit()
128 
129  def keys(self):
130  return self._index.keys()
131 
132  def has_key(self, key):
133  return self._index.has_key(key)
134 
135  def __contains__(self, key):
136  return self._index.has_key(key)
137 
138  def iterkeys(self):
139  return self._index.iterkeys()
140  __iter__ = iterkeys
141 
142  def __len__(self):
143  return len(self._index)
144 
145  def close(self):
146  self._commit()
147  self._index = None
148  self._datfile = self._dirfile = self._bakfile = None
149 
150  def __del__(self):
151  if self._index is not None:
152  self._commit()
153 
154 
155 
156 def open(file, flag=None, mode=0666):
157  # flag, mode arguments are currently ignored
158  return _Database(file, mode)