00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: db__err_8c-source.html,v 1.1 2008年06月08日 10:17:27 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 00017 #include <errno.h> 00018 #include <stdio.h> 00019 #include <stdlib.h> 00020 #include <string.h> 00021 #endif 00022 00023 #include "db_int.h" 00024 #include "db_shash.h" 00025 #include "lock.h" 00026 #include "lock_ext.h" 00027 #include "log.h" 00028 #include "log_ext.h" 00029 #include "mp.h" 00030 #include "mp_ext.h" 00031 #include "txn.h" 00032 #include "txn_ext.h" 00033 #include "common_ext.h" 00034 #include "db_auto.h" 00035 00036 static void __db_errcall __P((const DB_ENV *, int, int, const char *, va_list)); 00037 static void __db_errfile __P((const DB_ENV *, int, int, const char *, va_list)); 00038 00039 /* 00040 * CDB___db_fchk -- 00041 * General flags checking routine. 00042 * 00043 * PUBLIC: int CDB___db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t)); 00044 */ 00045 int 00046 CDB___db_fchk(dbenv, name, flags, ok_flags) 00047 DB_ENV *dbenv; 00048 const char *name; 00049 u_int32_t flags, ok_flags; 00050 { 00051 return (LF_ISSET(~ok_flags) ? CDB___db_ferr(dbenv, name, 0) : 0); 00052 } 00053 00054 /* 00055 * CDB___db_fcchk -- 00056 * General combination flags checking routine. 00057 * 00058 * PUBLIC: int CDB___db_fcchk 00059 * PUBLIC: __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t)); 00060 */ 00061 int 00062 CDB___db_fcchk(dbenv, name, flags, flag1, flag2) 00063 DB_ENV *dbenv; 00064 const char *name; 00065 u_int32_t flags, flag1, flag2; 00066 { 00067 return (LF_ISSET(flag1) && 00068 LF_ISSET(flag2) ? CDB___db_ferr(dbenv, name, 1) : 0); 00069 } 00070 00071 /* 00072 * CDB___db_ferr -- 00073 * Common flag errors. 00074 * 00075 * PUBLIC: int CDB___db_ferr __P((const DB_ENV *, const char *, int)); 00076 */ 00077 int 00078 CDB___db_ferr(dbenv, name, iscombo) 00079 const DB_ENV *dbenv; 00080 const char *name; 00081 int iscombo; 00082 { 00083 CDB___db_err(dbenv, "illegal flag %sspecified to %s", 00084 iscombo ? "combination " : "", name); 00085 return (EINVAL); 00086 } 00087 00088 /* 00089 * CDB___db_pgerr -- 00090 * Error when unable to retrieve a specified page. 00091 * 00092 * PUBLIC: int CDB___db_pgerr __P((DB *, db_pgno_t)); 00093 */ 00094 int 00095 CDB___db_pgerr(dbp, pgno) 00096 DB *dbp; 00097 db_pgno_t pgno; 00098 { 00099 /* 00100 * Three things are certain: 00101 * Death, taxes, and lost data. 00102 * Guess which has occurred. 00103 */ 00104 CDB___db_err(dbp->dbenv, 00105 "unable to create/retrieve page %lu", (u_long)pgno); 00106 return (CDB___db_panic(dbp->dbenv, EIO)); 00107 } 00108 00109 /* 00110 * CDB___db_pgfmt -- 00111 * Error when a page has the wrong format. 00112 * 00113 * PUBLIC: int CDB___db_pgfmt __P((DB *, db_pgno_t)); 00114 */ 00115 int 00116 CDB___db_pgfmt(dbp, pgno) 00117 DB *dbp; 00118 db_pgno_t pgno; 00119 { 00120 CDB___db_err(dbp->dbenv, 00121 "page %lu: illegal page type or format", (u_long)pgno); 00122 return (CDB___db_panic(dbp->dbenv, EINVAL)); 00123 } 00124 00125 /* 00126 * CDB___db_eopnotsup -- 00127 * Common operation not supported message. 00128 * 00129 * PUBLIC: int CDB___db_eopnotsup __P((const DB_ENV *)); 00130 */ 00131 int 00132 CDB___db_eopnotsup(dbenv) 00133 const DB_ENV *dbenv; 00134 { 00135 CDB___db_err(dbenv, "operation not supported"); 00136 #ifdef EOPNOTSUPP 00137 return (EOPNOTSUPP); 00138 #else 00139 return (EINVAL); 00140 #endif 00141 } 00142 00143 #ifdef DIAGNOSTIC 00144 /* 00145 * __db_assert -- 00146 * Error when an assertion fails. Only checked if #DIAGNOSTIC defined. 00147 * 00148 * PUBLIC: #ifdef DIAGNOSTIC 00149 * PUBLIC: void __db_assert __P((const char *, const char *, int)); 00150 * PUBLIC: #endif 00151 */ 00152 void 00153 __db_assert(failedexpr, file, line) 00154 const char *failedexpr, *file; 00155 int line; 00156 { 00157 (void)fprintf(stderr, 00158 "__db_assert: \"%s\" failed: file \"%s\", line %d\n", 00159 failedexpr, file, line); 00160 fflush(stderr); 00161 00162 /* We want a stack trace of how this could possibly happen. */ 00163 abort(); 00164 00165 /* NOTREACHED */ 00166 } 00167 #endif 00168 00169 /* 00170 * CDB___db_panic_msg -- 00171 * Just report that someone else paniced. 00172 * 00173 * PUBLIC: int CDB___db_panic_msg __P((DB_ENV *)); 00174 */ 00175 int 00176 CDB___db_panic_msg(dbenv) 00177 DB_ENV *dbenv; 00178 { 00179 CDB___db_err(dbenv, "region error detected; run recovery."); 00180 return (DB_RUNRECOVERY); 00181 } 00182 00183 /* 00184 * CDB___db_panic -- 00185 * Lock out the tree due to unrecoverable error. 00186 * 00187 * PUBLIC: int CDB___db_panic __P((DB_ENV *, int)); 00188 */ 00189 int 00190 CDB___db_panic(dbenv, errval) 00191 DB_ENV *dbenv; 00192 int errval; 00193 { 00194 /* 00195 * Drop core if we're running with DIAGNOSTIC defined. Do so before 00196 * we set the panic bits, it's easier to run diagnostic tools on the 00197 * tree then. 00198 */ 00199 DB_ASSERT(0); 00200 00201 if (dbenv != NULL) { 00202 ((REGENV *)((REGINFO *)dbenv->reginfo)->addr)->panic = 1; 00203 00204 dbenv->db_panic = errval; 00205 00206 CDB___db_err(dbenv, "PANIC: %s", CDB_db_strerror(errval)); 00207 00208 if (dbenv->db_paniccall != NULL) 00209 dbenv->db_paniccall(dbenv, errval); 00210 } 00211 00212 /* 00213 * Chaos reigns within. 00214 * Reflect, repent, and reboot. 00215 * Order shall return. 00216 */ 00217 return (DB_RUNRECOVERY); 00218 } 00219 00220 /* 00221 * CDB_db_strerror -- 00222 * ANSI C strerror(3) for DB. 00223 */ 00224 char * 00225 CDB_db_strerror(error) 00226 int error; 00227 { 00228 if (error == 0) 00229 return ("Successful return: 0"); 00230 if (error > 0) 00231 return (strerror(error)); 00232 00233 /* 00234 * !!! 00235 * The Tcl API requires that some of these return strings be compared 00236 * against strings stored in application scripts. So, any of these 00237 * errors that do not invariably result in a Tcl exception may not be 00238 * altered. 00239 */ 00240 switch (error) { 00241 case DB_INCOMPLETE: 00242 return ("DB_INCOMPLETE: Cache flush was unable to complete"); 00243 case DB_KEYEMPTY: 00244 return ("DB_KEYEMPTY: Non-existent key/data pair"); 00245 case DB_KEYEXIST: 00246 return ("DB_KEYEXIST: Key/data pair already exists"); 00247 case DB_LOCK_DEADLOCK: 00248 return 00249 ("DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock"); 00250 case DB_LOCK_NOTGRANTED: 00251 return ("DB_LOCK_NOTGRANTED: Lock not granted"); 00252 case DB_NOSERVER: 00253 return ("DB_NOSERVER: Fatal error, no server"); 00254 case DB_NOSERVER_HOME: 00255 return ("DB_NOSERVER_HOME: Home unrecognized at server"); 00256 case DB_NOSERVER_ID: 00257 return ("DB_NOSERVER_ID: Identifier unrecognized at server"); 00258 case DB_NOTFOUND: 00259 return ("DB_NOTFOUND: No matching key/data pair found"); 00260 case DB_OLD_VERSION: 00261 return ("DB_OLDVERSION: Database requires a version upgrade"); 00262 case DB_RUNRECOVERY: 00263 return ("DB_RUNRECOVERY: Fatal error, run database recovery"); 00264 case DB_VERIFY_BAD: 00265 return ("DB_VERIFY_BAD: Database verification failed"); 00266 default: { 00267 /* 00268 * !!! 00269 * Room for a 64-bit number + slop. This buffer is only used 00270 * if we're given an unknown error, which should never happen. 00271 * Note, however, we're no longer thread-safe if it does. 00272 */ 00273 static char ebuf[40]; 00274 00275 (void)snprintf(ebuf, sizeof(ebuf), "Unknown error: %d", error); 00276 return(ebuf); 00277 } 00278 } 00279 } 00280 00281 /* 00282 * CDB___db_err -- 00283 * Standard DB error routine. The same as db_errx, except that we 00284 * don't write to stderr if no output mechanism was specified. 00285 * 00286 * PUBLIC: #ifdef __STDC__ 00287 * PUBLIC: void CDB___db_err __P((const DB_ENV *, const char *, ...)); 00288 * PUBLIC: #else 00289 * PUBLIC: void CDB___db_err(); 00290 * PUBLIC: #endif 00291 */ 00292 void 00293 #ifdef __STDC__ 00294 CDB___db_err(const DB_ENV *dbenv, const char *fmt, ...) 00295 #else 00296 CDB___db_err(dbenv, fmt, va_alist) 00297 const DB_ENV *dbenv; 00298 const char *fmt; 00299 va_dcl 00300 #endif 00301 { 00302 va_list ap; 00303 00304 /* 00305 XXX 00306 Log the message. 00307 00308 It would be nice to automatically log the error into the log files 00309 if the application is configured for logging. The problem is that 00310 if we currently hold the log region mutex, we will self-deadlock. 00311 Leave all the structure in place, but turned off. I'd like to fix 00312 this in the future by detecting if we have the log region already 00313 locked (e.g., a flag in the environment handle), or perhaps even 00314 have a finer granularity so that the only calls to CDB___db_err we 00315 can't log are those made while we have the current log buffer 00316 locked, or perhaps have a separate buffer into which we log error 00317 messages. 00318 00319 #ifdef __STDC__ 00320 va_start(ap, fmt); 00321 #else 00322 va_start(ap); 00323 #endif 00324 CDB___db_real_log(dbenv, NULL, "db_err", 0, fmt, ap); 00325 00326 va_end(ap); 00327 #endif 00328 */ 00329 00330 /* Tell the application. */ 00331 #ifdef __STDC__ 00332 va_start(ap, fmt); 00333 #else 00334 va_start(ap); 00335 #endif 00336 CDB___db_real_err(dbenv, 0, 0, 0, fmt, ap); 00337 00338 va_end(ap); 00339 } 00340 00341 /* 00342 * CDB___db_real_err -- 00343 * All the DB error routines end up here. 00344 * 00345 * PUBLIC: void CDB___db_real_err 00346 * PUBLIC: __P((const DB_ENV *, int, int, int, const char *, va_list)); 00347 */ 00348 void 00349 CDB___db_real_err(dbenv, error, error_set, stderr_default, fmt, ap) 00350 const DB_ENV *dbenv; 00351 int error, error_set, stderr_default; 00352 const char *fmt; 00353 va_list ap; 00354 { 00355 if (dbenv != NULL && dbenv->db_errcall != NULL) 00356 __db_errcall(dbenv, error, error_set, fmt, ap); 00357 00358 if (dbenv != NULL && dbenv->db_errfile != NULL) 00359 __db_errfile(dbenv, error, error_set, fmt, ap); 00360 00361 if (stderr_default && (dbenv == NULL || 00362 (dbenv->db_errcall == NULL && dbenv->db_errfile == NULL))) 00363 __db_errfile(NULL, error, error_set, fmt, ap); 00364 } 00365 00366 /* 00367 * __db_errcall -- 00368 * Do the error message work for callback functions. 00369 */ 00370 static void 00371 __db_errcall(dbenv, error, error_set, fmt, ap) 00372 const DB_ENV *dbenv; 00373 int error, error_set; 00374 const char *fmt; 00375 va_list ap; 00376 { 00377 char *p; 00378 char __errbuf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */ 00379 00380 p = __errbuf; 00381 if (fmt != NULL) { 00382 p += vsnprintf(__errbuf, sizeof(__errbuf), fmt, ap); 00383 if (error_set) { 00384 *p++ = ':'; 00385 *p++ = ' '; 00386 } 00387 } 00388 if (error_set) 00389 (void)strcpy(p, CDB_db_strerror(error)); 00390 00391 dbenv->db_errcall(dbenv->db_errpfx, __errbuf); 00392 } 00393 00394 /* 00395 * __db_errfile -- 00396 * Do the error message work for FILE *s. 00397 */ 00398 static void 00399 __db_errfile(dbenv, error, error_set, fmt, ap) 00400 const DB_ENV *dbenv; 00401 int error, error_set; 00402 const char *fmt; 00403 va_list ap; 00404 { 00405 FILE *fp; 00406 00407 fp = dbenv == NULL || 00408 dbenv->db_errfile == NULL ? stderr : dbenv->db_errfile; 00409 00410 if (dbenv != NULL && dbenv->db_errpfx != NULL) 00411 (void)fprintf(fp, "%s: ", dbenv->db_errpfx); 00412 if (fmt != NULL) { 00413 (void)vfprintf(fp, fmt, ap); 00414 if (error_set) 00415 (void)fprintf(fp, ": "); 00416 } 00417 if (error_set) 00418 (void)fprintf(fp, "%s", CDB_db_strerror(error)); 00419 (void)fprintf(fp, "\n"); 00420 (void)fflush(fp); 00421 } 00422 00423 /* 00424 * CDB___db_logmsg -- 00425 * Write information into the DB log. 00426 * 00427 * PUBLIC: #ifdef __STDC__ 00428 * PUBLIC: void CDB___db_logmsg __P((const DB_ENV *, 00429 * PUBLIC: DB_TXN *, const char *, u_int32_t, const char *, ...)); 00430 * PUBLIC: #else 00431 * PUBLIC: void CDB___db_logmsg(); 00432 * PUBLIC: #endif 00433 */ 00434 void 00435 #ifdef __STDC__ 00436 CDB___db_logmsg(const DB_ENV *dbenv, 00437 DB_TXN *txnid, const char *opname, u_int32_t flags, const char *fmt, ...) 00438 #else 00439 CDB___db_logmsg(dbenv, txnid, opname, flags, fmt, va_alist) 00440 const DB_ENV *dbenv; 00441 DB_TXN *txnid; 00442 const char *opname, *fmt; 00443 u_int32_t flags; 00444 va_dcl 00445 #endif 00446 { 00447 va_list ap; 00448 00449 #ifdef __STDC__ 00450 va_start(ap, fmt); 00451 #else 00452 va_start(ap); 00453 #endif 00454 CDB___db_real_log(dbenv, txnid, opname, flags, fmt, ap); 00455 00456 va_end(ap); 00457 } 00458 00459 /* 00460 * CDB___db_real_log -- 00461 * Write information into the DB log. 00462 * 00463 * PUBLIC: #ifdef __STDC__ 00464 * PUBLIC: void CDB___db_real_log __P((const DB_ENV *, 00465 * PUBLIC: DB_TXN *, const char *, u_int32_t, const char *, va_list ap)); 00466 * PUBLIC: #else 00467 * PUBLIC: void CDB___db_real_log(); 00468 * PUBLIC: #endif 00469 */ 00470 void 00471 #ifdef __STDC__ 00472 CDB___db_real_log(const DB_ENV *dbenv, DB_TXN *txnid, 00473 const char *opname, u_int32_t flags, const char *fmt, va_list ap) 00474 #else 00475 CDB___db_real_log(dbenv, txnid, opname, flags, fmt, ap) 00476 const DB_ENV *dbenv; 00477 DB_TXN *txnid; 00478 const char *opname, *fmt; 00479 u_int32_t flags; 00480 va_list ap; 00481 #endif 00482 { 00483 DBT opdbt, msgdbt; 00484 DB_LSN lsn; 00485 char __logbuf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */ 00486 00487 if (!LOGGING_ON(dbenv)) 00488 return; 00489 00490 memset(&opdbt, 0, sizeof(opdbt)); 00491 opdbt.data = (void *)opname; 00492 opdbt.size = strlen(opname) + 1; 00493 00494 memset(&msgdbt, 0, sizeof(msgdbt)); 00495 msgdbt.data = __logbuf; 00496 msgdbt.size = vsnprintf(__logbuf, sizeof(__logbuf), fmt, ap); 00497 00498 /* 00499 * XXX 00500 * Explicitly discard the const. Otherwise, we have to const DB_ENV 00501 * references throughout the logging subsystem. 00502 */ 00503 CDB___db_debug_log( 00504 (DB_ENV *)dbenv, txnid, &lsn, flags, &opdbt, -1, &msgdbt, NULL, 0); 00505 } 00506 00507 /* 00508 * CDB___db_unknown_flag -- report internal error 00509 * 00510 * PUBLIC: int CDB___db_unknown_flag __P((DB_ENV *, char *, u_int32_t)); 00511 */ 00512 int 00513 CDB___db_unknown_flag(dbenv, routine, flag) 00514 DB_ENV *dbenv; 00515 char *routine; 00516 u_int32_t flag; 00517 { 00518 CDB___db_err(dbenv, "%s: Unknown flag: 0x%x", routine, flag); 00519 DB_ASSERT(0); 00520 return (EINVAL); 00521 } 00522 00523 /* 00524 * CDB___db_unknown_type -- report internal error 00525 * 00526 * PUBLIC: int CDB___db_unknown_type __P((DB_ENV *, char *, u_int32_t)); 00527 */ 00528 int 00529 CDB___db_unknown_type(dbenv, routine, type) 00530 DB_ENV *dbenv; 00531 char *routine; 00532 u_int32_t type; 00533 { 00534 CDB___db_err(dbenv, "%s: Unknown db type: 0x%x", routine, type); 00535 DB_ASSERT(0); 00536 return (EINVAL); 00537 } 00538 00539 /* 00540 * CDB___db_child_active_err -- cannot do an update with active child 00541 * 00542 * PUBLIC: int CDB___db_child_active_err __P((DB_ENV *)); 00543 */ 00544 int 00545 CDB___db_child_active_err(dbenv) 00546 DB_ENV *dbenv; 00547 { 00548 CDB___db_err(dbenv, "Child transaction is active"); 00549 return (EPERM); 00550 }