Mercurial > cpython-lru_cache-weakref
annotate Modules/dbhashmodule.c @ 4566:6403c94de50d legacy-trunk
Added safeguard against failure in __del__.
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Wed, 27 Nov 1996 19:39:58 +0000 |
| parents | 65d2d8e67da3 |
| children |
| rev | line source |
|---|---|
| 2847 | 1 /*********************************************************** |
| 2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, | |
| 3 The Netherlands. | |
| 4 | |
| 5 All Rights Reserved | |
| 6 | |
|
4503
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
7 Permission to use, copy, modify, and distribute this software and its |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
8 documentation for any purpose and without fee is hereby granted, |
| 2847 | 9 provided that the above copyright notice appear in all copies and that |
|
4503
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
10 both that copyright notice and this permission notice appear in |
| 2847 | 11 supporting documentation, and that the names of Stichting Mathematisch |
|
4503
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
12 Centrum or CWI or Corporation for National Research Initiatives or |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
13 CNRI not be used in advertising or publicity pertaining to |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
14 distribution of the software without specific, written prior |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
15 permission. |
| 2847 | 16 |
|
4503
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
17 While CWI is the initial source for this software, a modified version |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
18 is made available by the Corporation for National Research Initiatives |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
19 (CNRI) at the Internet address ftp://ftp.python.org. |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
20 |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
65d2d8e67da3
New permission notice, includes CNRI.
Guido van Rossum <guido@python.org>
parents:
2861
diff
changeset
|
28 PERFORMANCE OF THIS SOFTWARE. |
| 2847 | 29 |
| 30 ******************************************************************/ | |
| 31 | |
| 32 /* Berkeley DB hash interface. | |
| 33 Author: Michael McLay | |
| 34 Hacked: Guido van Rossum | |
| 35 | |
| 36 XXX To do: | |
| 37 - provide interface to the B-tree and record libraries too | |
| 38 - provide a way to access the various hash functions | |
| 39 - support more open flags | |
| 40 */ | |
| 41 | |
| 42 #include "allobjects.h" | |
| 43 #include "modsupport.h" | |
| 44 | |
| 45 #include <sys/types.h> | |
| 46 #include <sys/stat.h> | |
| 47 #include <fcntl.h> | |
| 48 #include <db.h> | |
| 49 /* Please don't include internal header files of the Berkeley db package | |
| 50 (it messes up the info required in the Setup file) */ | |
| 51 | |
| 52 typedef struct { | |
| 53 OB_HEAD | |
| 54 DB *di_dbhash; | |
| 55 int di_size; /* -1 means recompute */ | |
| 56 } dbhashobject; | |
| 57 | |
| 58 staticforward typeobject Dbhashtype; | |
| 59 | |
| 60 #define is_dbhashobject(v) ((v)->ob_type == &Dbhashtype) | |
| 61 | |
| 62 static object *DbhashError; | |
| 63 | |
| 64 static object * | |
| 65 newdbhashobject(file, flags, mode, | |
| 66 bsize, ffactor, nelem, cachesize, hash, lorder) | |
| 67 char *file; | |
| 68 int flags; | |
| 69 int mode; | |
| 70 int bsize; | |
| 71 int ffactor; | |
| 72 int nelem; | |
| 73 int cachesize; | |
| 74 int hash; /* XXX ignored */ | |
| 75 int lorder; | |
| 76 { | |
| 77 dbhashobject *dp; | |
| 78 HASHINFO info; | |
| 79 | |
| 80 if ((dp = NEWOBJ(dbhashobject, &Dbhashtype)) == NULL) | |
| 81 return NULL; | |
| 82 | |
| 83 info.bsize = bsize; | |
| 84 info.ffactor = ffactor; | |
| 85 info.nelem = nelem; | |
| 86 info.cachesize = cachesize; | |
| 87 info.hash = NULL; /* XXX should derive from hash argument */ | |
| 88 info.lorder = lorder; | |
| 89 | |
| 90 if ((dp->di_dbhash = dbopen(file, flags, mode, DB_HASH, &info)) == NULL) { | |
| 91 err_errno(DbhashError); | |
| 92 DECREF(dp); | |
| 93 return NULL; | |
| 94 } | |
| 95 | |
| 96 dp->di_size = -1; | |
| 97 | |
| 98 return (object *)dp; | |
| 99 } | |
| 100 | |
| 101 static void | |
| 102 dbhash_dealloc(dp) | |
| 103 dbhashobject *dp; | |
| 104 { | |
| 105 if (dp->di_dbhash != NULL) { | |
| 106 if ((dp->di_dbhash->close)(dp->di_dbhash) != 0) | |
| 107 fprintf(stderr, | |
| 108 "Python dbhash: close errno %s in dealloc\n", errno); | |
| 109 } | |
| 110 DEL(dp); | |
| 111 } | |
| 112 | |
| 113 static int | |
| 114 dbhash_length(dp) | |
| 115 dbhashobject *dp; | |
| 116 { | |
| 117 if (dp->di_size < 0) { | |
| 118 DBT krec, drec; | |
| 119 int status; | |
| 120 int size = 0; | |
| 121 for (status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec,R_FIRST); | |
| 122 status == 0; | |
| 123 status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec, R_NEXT)) | |
| 124 size++; | |
| 125 if (status < 0) { | |
| 126 err_errno(DbhashError); | |
| 127 return -1; | |
| 128 } | |
| 129 dp->di_size = size; | |
| 130 } | |
| 131 return dp->di_size; | |
| 132 } | |
| 133 | |
| 134 static object * | |
| 135 dbhash_subscript(dp, key) | |
| 136 dbhashobject *dp; | |
| 137 object *key; | |
| 138 { | |
| 139 int status; | |
| 140 object *v; | |
| 141 DBT krec, drec; | |
| 142 char *data; | |
| 143 int size; | |
| 144 | |
| 145 if (!getargs(key, "s#", &data, &size)) | |
| 146 return NULL; | |
| 147 krec.data = data; | |
| 148 krec.size = size; | |
| 149 | |
| 150 status = (dp->di_dbhash->get)(dp->di_dbhash, &krec, &drec, 0); | |
| 151 if (status != 0) { | |
| 152 if (status < 0) | |
| 153 err_errno(DbhashError); | |
| 154 else | |
| 155 err_setval(KeyError, key); | |
| 156 return NULL; | |
| 157 } | |
| 158 | |
| 159 return newsizedstringobject((char *)drec.data, (int)drec.size); | |
| 160 } | |
| 161 | |
| 162 static int | |
| 163 dbhash_ass_sub(dp, key, value) | |
| 164 dbhashobject *dp; | |
| 165 object *key, *value; | |
| 166 { | |
| 167 int status; | |
| 168 DBT krec, drec; | |
| 169 char *data; | |
| 170 int size; | |
| 171 | |
| 172 if (!getargs(key, "s#", &data, &size)) { | |
| 173 err_setstr(TypeError, "dbhash key type must be string"); | |
| 174 return -1; | |
| 175 } | |
| 176 krec.data = data; | |
| 177 krec.size = size; | |
| 178 dp->di_size = -1; | |
| 179 if (value == NULL) { | |
| 180 status = (dp->di_dbhash->del)(dp->di_dbhash, &krec, 0); | |
| 181 } | |
| 182 else { | |
| 183 if (!getargs(value, "s#", &data, &size)) { | |
| 184 err_setstr(TypeError, "dbhash value type must be string"); | |
| 185 return -1; | |
| 186 } | |
| 187 drec.data = data; | |
| 188 drec.size = size; | |
| 189 status = (dp->di_dbhash->put)(dp->di_dbhash, &krec, &drec, 0); | |
| 190 } | |
| 191 if (status != 0) { | |
| 192 if (status < 0) | |
| 193 err_errno(DbhashError); | |
| 194 else | |
| 195 err_setval(KeyError, key); | |
| 196 return -1; | |
| 197 } | |
| 198 return 0; | |
| 199 } | |
| 200 | |
| 201 static mapping_methods dbhash_as_mapping = { | |
| 202 (inquiry)dbhash_length, /*mp_length*/ | |
| 203 (binaryfunc)dbhash_subscript, /*mp_subscript*/ | |
| 204 (objobjargproc)dbhash_ass_sub, /*mp_ass_subscript*/ | |
| 205 }; | |
| 206 | |
| 207 static object * | |
|
2848
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
208 dbhash_close(dp, args) |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
209 dbhashobject *dp; |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
210 object *args; |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
211 { |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
212 if (!getnoarg(args)) |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
213 return NULL; |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
214 if (dp->di_dbhash != NULL) { |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
215 if ((dp->di_dbhash->close)(dp->di_dbhash) != 0) { |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
216 dp->di_dbhash = NULL; |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
217 err_errno(DbhashError); |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
218 return NULL; |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
219 } |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
220 } |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
221 dp->di_dbhash = NULL; |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
222 INCREF(None); |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
223 return None; |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
224 } |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
225 |
|
4f6d5fe19812
fixed arg checking for keys() and close()
Guido van Rossum <guido@python.org>
parents:
2847
diff
changeset
|
226 static object * |
| 2847 | 227 dbhash_keys(dp, args) |
| 228 dbhashobject *dp; | |
| 229 object *args; | |
| 230 { | |
| 231 object *list, *item; | |
| 232 DBT krec, drec; | |
| 233 int status; | |
| 234 int err; | |
| 235 | |
| 236 if (!getnoarg(args)) | |
| 237 return NULL; | |
| 238 list = newlistobject(0); | |
| 239 if (list == NULL) | |
| 240 return NULL; | |
| 241 for (status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec, R_FIRST); | |
| 242 status == 0; | |
| 243 status = (dp->di_dbhash->seq)(dp->di_dbhash, &krec, &drec, R_NEXT)) { | |
| 244 item = newsizedstringobject((char *)krec.data, (int)krec.size); | |
| 245 if (item == NULL) { | |
| 246 DECREF(list); | |
| 247 return NULL; | |
| 248 } | |
| 249 err = addlistitem(list, item); | |
| 250 DECREF(item); | |
| 251 if (err != 0) { | |
| 252 DECREF(list); | |
| 253 return NULL; | |
| 254 } | |
| 255 } | |
| 256 if (status < 0) { | |
| 257 err_errno(DbhashError); | |
| 258 DECREF(list); | |
| 259 return NULL; | |
| 260 } | |
| 261 if (dp->di_size < 0) | |
| 262 dp->di_size = getlistsize(list); /* We just did the work for this... */ | |
| 263 return list; | |
| 264 } | |
| 265 | |
| 266 static object * | |
| 267 dbhash_has_key(dp, args) | |
| 268 dbhashobject *dp; | |
| 269 object *args; | |
| 270 { | |
| 271 DBT krec, drec; | |
| 272 int status; | |
| 273 char *data; | |
| 274 int size; | |
| 275 | |
| 276 if (!getargs(args, "s#", &data, &size)) | |
| 277 return NULL; | |
| 278 krec.data = data; | |
| 279 krec.size = size; | |
| 280 | |
| 281 status = (dp->di_dbhash->get)(dp->di_dbhash, &krec, &drec, 0); | |
| 282 if (status < 0) { | |
| 283 err_errno(DbhashError); | |
| 284 return NULL; | |
| 285 } | |
| 286 | |
| 287 return newintobject(status == 0); | |
| 288 } | |
| 289 | |
| 290 static struct methodlist dbhash_methods[] = { | |
| 291 {"close", (method)dbhash_close}, | |
| 292 {"keys", (method)dbhash_keys}, | |
| 293 {"has_key", (method)dbhash_has_key}, | |
| 294 {NULL, NULL} /* sentinel */ | |
| 295 }; | |
| 296 | |
| 297 static object * | |
| 298 dbhash_getattr(dp, name) | |
| 299 object *dp; | |
| 300 char *name; | |
| 301 { | |
| 302 return findmethod(dbhash_methods, dp, name); | |
| 303 } | |
| 304 | |
| 305 static typeobject Dbhashtype = { | |
| 306 OB_HEAD_INIT(&Typetype) | |
| 307 0, | |
| 308 "dbhash", | |
| 309 sizeof(dbhashobject), | |
| 310 0, | |
| 311 (destructor)dbhash_dealloc, /*tp_dealloc*/ | |
| 312 0, /*tp_print*/ | |
| 313 (getattrfunc)dbhash_getattr, /*tp_getattr*/ | |
| 314 0, /*tp_setattr*/ | |
| 315 0, /*tp_compare*/ | |
| 316 0, /*tp_repr*/ | |
| 317 0, /*tp_as_number*/ | |
| 318 0, /*tp_as_sequence*/ | |
| 319 &dbhash_as_mapping, /*tp_as_mapping*/ | |
| 320 }; | |
| 321 | |
| 322 static object * | |
| 323 dbhashopen(self, args) | |
| 324 object *self; | |
| 325 object *args; | |
| 326 { | |
| 327 char *file; | |
| 328 char *flag = NULL; | |
| 329 int flags = O_RDONLY; | |
| 330 int mode = 0666; | |
| 331 int bsize = 0; | |
| 332 int ffactor = 0; | |
| 333 int nelem = 0; | |
| 334 int cachesize = 0; | |
| 335 int hash = 0; /* XXX currently ignored */ | |
| 336 int lorder = 0; | |
| 337 | |
| 338 if (!newgetargs(args, "s|siiiiiii", | |
| 339 &file, &flag, &mode, | |
| 340 &bsize, &ffactor, &nelem, &cachesize, &hash, &lorder)) | |
| 341 return NULL; | |
| 342 if (flag != NULL) { | |
| 343 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */ | |
|
2861
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
344 if (flag[0] == 'r') |
| 2847 | 345 flags = O_RDONLY; |
|
2861
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
346 else if (flag[0] == 'w') |
| 2847 | 347 flags = O_RDWR; |
|
2861
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
348 else if (flag[0] == 'c') |
| 2847 | 349 flags = O_RDWR|O_CREAT; |
|
2861
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
350 else if (flag[0] == 'n') |
| 2847 | 351 flags = O_RDWR|O_CREAT|O_TRUNC; |
| 352 else { | |
| 353 err_setstr(DbhashError, | |
|
2861
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
354 "Flag should begin with 'r', 'w', 'c' or 'n'"); |
| 2847 | 355 return NULL; |
| 356 } | |
|
2861
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
357 if (flag[1] == 'l') { |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
358 #if defined(O_EXLOCK) && defined(O_SHLOCK) |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
359 if (flag[0] == 'r') |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
360 flags |= O_SHLOCK; |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
361 else |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
362 flags |= O_EXLOCK; |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
363 #else |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
364 err_setstr(DbhashError, "locking not supported on this platform"); |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
365 return NULL; |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
366 #endif |
|
dc6b3e76cce6
add locking where it exists
Guido van Rossum <guido@python.org>
parents:
2848
diff
changeset
|
367 } |
| 2847 | 368 } |
| 369 return newdbhashobject(file, flags, mode, | |
| 370 bsize, ffactor, nelem, cachesize, hash, lorder); | |
| 371 } | |
| 372 | |
| 373 static struct methodlist dbhashmodule_methods[] = { | |
| 374 {"open", (method)dbhashopen, 1}, | |
| 375 {0, 0}, | |
| 376 }; | |
| 377 | |
| 378 void | |
| 379 initdbhash() { | |
| 380 object *m, *d; | |
| 381 | |
| 382 m = initmodule("dbhash", dbhashmodule_methods); | |
| 383 d = getmoduledict(m); | |
| 384 DbhashError = newstringobject("dbhash.error"); | |
| 385 if (DbhashError == NULL || dictinsert(d, "error", DbhashError)) | |
| 386 fatal("can't define dbhash.error"); | |
| 387 } |
