1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
from _gdbm_cffi import ffi, lib # generated by _gdbm_build.py
import os, thread
_lock = thread.allocate_lock()
class error(Exception):
pass
def _checkstr(key):
if isinstance(key, unicode):
key = key.encode("ascii")
if not isinstance(key, str):
raise TypeError("gdbm mappings have string indices only")
return key
def _fromstr(key):
if isinstance(key, unicode):
key = key.encode("ascii")
if not isinstance(key, str):
raise TypeError("gdbm mappings have string indices only")
return {'dptr': ffi.new("char[]", key), 'dsize': len(key)}
class gdbm(object):
__ll_dbm = None
# All public methods need to acquire the lock; all private methods
# assume the lock is already held. Thus public methods cannot call
# other public methods.
def __init__(self, filename, iflags, mode):
with _lock:
res = lib.gdbm_open(filename, 0, iflags, mode, ffi.NULL)
self.__size = -1
if not res:
self.__raise_from_errno()
self.__ll_dbm = res
def close(self):
with _lock:
if self.__ll_dbm:
lib.gdbm_close(self.__ll_dbm)
self.__ll_dbm = None
def __raise_from_errno(self):
if ffi.errno:
raise error(ffi.errno, os.strerror(ffi.errno))
raise error(lib.gdbm_errno, lib.gdbm_strerror(lib.gdbm_errno))
def __len__(self):
with _lock:
if self.__size < 0:
self.__size = len(self.__keys())
return self.__size
def __setitem__(self, key, value):
with _lock:
self.__check_closed()
self.__size = -1
r = lib.gdbm_store(self.__ll_dbm, _fromstr(key), _fromstr(value),
lib.GDBM_REPLACE)
if r < 0:
self.__raise_from_errno()
def __delitem__(self, key):
with _lock:
self.__check_closed()
self.__size = -1
res = lib.gdbm_delete(self.__ll_dbm, _fromstr(key))
if res < 0:
raise KeyError(key)
def __contains__(self, key):
with _lock:
self.__check_closed()
key = _checkstr(key)
return lib.pygdbm_exists(self.__ll_dbm, key, len(key))
has_key = __contains__
def __getitem__(self, key):
with _lock:
self.__check_closed()
key = _checkstr(key)
drec = lib.pygdbm_fetch(self.__ll_dbm, key, len(key))
if not drec.dptr:
raise KeyError(key)
res = str(ffi.buffer(drec.dptr, drec.dsize))
lib.free(drec.dptr)
return res
def __keys(self):
self.__check_closed()
l = []
key = lib.gdbm_firstkey(self.__ll_dbm)
while key.dptr:
l.append(str(ffi.buffer(key.dptr, key.dsize)))
nextkey = lib.gdbm_nextkey(self.__ll_dbm, key)
lib.free(key.dptr)
key = nextkey
return l
def keys(self):
with _lock:
return self.__keys()
def firstkey(self):
with _lock:
self.__check_closed()
key = lib.gdbm_firstkey(self.__ll_dbm)
if key.dptr:
res = str(ffi.buffer(key.dptr, key.dsize))
lib.free(key.dptr)
return res
def nextkey(self, key):
with _lock:
self.__check_closed()
key = lib.gdbm_nextkey(self.__ll_dbm, _fromstr(key))
if key.dptr:
res = str(ffi.buffer(key.dptr, key.dsize))
lib.free(key.dptr)
return res
def reorganize(self):
with _lock:
self.__check_closed()
if lib.gdbm_reorganize(self.__ll_dbm) < 0:
self.__raise_from_errno()
def __check_closed(self):
if not self.__ll_dbm:
raise error(0, "GDBM object has already been closed")
__del__ = close
def sync(self):
with _lock:
self.__check_closed()
lib.gdbm_sync(self.__ll_dbm)
def open(filename, flags='r', mode=0666):
if isinstance(filename, unicode):
filename = filename.encode()
if flags[0] == 'r':
iflags = lib.GDBM_READER
elif flags[0] == 'w':
iflags = lib.GDBM_WRITER
elif flags[0] == 'c':
iflags = lib.GDBM_WRCREAT
elif flags[0] == 'n':
iflags = lib.GDBM_NEWDB
else:
raise error(0, "First flag must be one of 'r', 'w', 'c' or 'n'")
for flag in flags[1:]:
if flag == 'f':
iflags |= lib.GDBM_FAST
elif flag == 's':
iflags |= lib.GDBM_SYNC
elif flag == 'u':
iflags |= lib.GDBM_NOLOCK
else:
raise error(0, "Flag '%s' not supported" % flag)
return gdbm(filename, iflags, mode)
open_flags = "rwcnfsu"
|