db_err.c

Go to the documentation of this file.
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 }

Generated on Sun Jun 8 10:56:36 2008 for GNUmifluz by  doxygen 1.5.5