Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_vrfyutil.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2000-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_vrfyutil.c,v 12.5 2005/06/16 20:21:15 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/db_verify.h"
00021 #include "dbinc/db_am.h"
00022 
00023 static int __db_vrfy_childinc __P((DBC *, VRFY_CHILDINFO *));
00024 static int __db_vrfy_pageinfo_create __P((DB_ENV *, VRFY_PAGEINFO **));
00025 
00026 /*
00027  * __db_vrfy_dbinfo_create --
00028  *      Allocate and initialize a VRFY_DBINFO structure.
00029  *
00030  * PUBLIC: int __db_vrfy_dbinfo_create
00031  * PUBLIC:     __P((DB_ENV *, u_int32_t, VRFY_DBINFO **));
00032  */
00033 int
00034 __db_vrfy_dbinfo_create(dbenv, pgsize, vdpp)
00035         DB_ENV *dbenv;
00036         u_int32_t pgsize;
00037         VRFY_DBINFO **vdpp;
00038 {
00039         DB *cdbp, *pgdbp, *pgset;
00040         VRFY_DBINFO *vdp;
00041         int ret;
00042 
00043         vdp = NULL;
00044         cdbp = pgdbp = pgset = NULL;
00045 
00046         if ((ret = __os_calloc(NULL, 1, sizeof(VRFY_DBINFO), &vdp)) != 0)
00047                 goto err;
00048 
00049         if ((ret = db_create(&cdbp, dbenv, 0)) != 0)
00050                 goto err;
00051 
00052         if ((ret = __db_set_flags(cdbp, DB_DUP)) != 0)
00053                 goto err;
00054 
00055         if ((ret = __db_set_pagesize(cdbp, pgsize)) != 0)
00056                 goto err;
00057 
00058         if ((ret = __db_open(cdbp,
00059             NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600, PGNO_BASE_MD)) != 0)
00060                 goto err;
00061 
00062         if ((ret = db_create(&pgdbp, dbenv, 0)) != 0)
00063                 goto err;
00064 
00065         if ((ret = __db_set_pagesize(pgdbp, pgsize)) != 0)
00066                 goto err;
00067 
00068         if ((ret = __db_open(pgdbp,
00069             NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600, PGNO_BASE_MD)) != 0)
00070                 goto err;
00071 
00072         if ((ret = __db_vrfy_pgset(dbenv, pgsize, &pgset)) != 0)
00073                 goto err;
00074 
00075         LIST_INIT(&vdp->subdbs);
00076         LIST_INIT(&vdp->activepips);
00077 
00078         vdp->cdbp = cdbp;
00079         vdp->pgdbp = pgdbp;
00080         vdp->pgset = pgset;
00081         *vdpp = vdp;
00082         return (0);
00083 
00084 err:    if (cdbp != NULL)
00085                 (void)__db_close(cdbp, NULL, 0);
00086         if (pgdbp != NULL)
00087                 (void)__db_close(pgdbp, NULL, 0);
00088         if (vdp != NULL)
00089                 __os_free(dbenv, vdp);
00090         return (ret);
00091 }
00092 
00093 /*
00094  * __db_vrfy_dbinfo_destroy --
00095  *      Destructor for VRFY_DBINFO.  Destroys VRFY_PAGEINFOs and deallocates
00096  *      structure.
00097  *
00098  * PUBLIC: int __db_vrfy_dbinfo_destroy __P((DB_ENV *, VRFY_DBINFO *));
00099  */
00100 int
00101 __db_vrfy_dbinfo_destroy(dbenv, vdp)
00102         DB_ENV *dbenv;
00103         VRFY_DBINFO *vdp;
00104 {
00105         VRFY_CHILDINFO *c;
00106         int t_ret, ret;
00107 
00108         ret = 0;
00109 
00110         /*
00111          * Discard active page structures.  Ideally there wouldn't be any,
00112          * but in some error cases we may not have cleared them all out.
00113          */
00114         while (LIST_FIRST(&vdp->activepips) != NULL)
00115                 if ((t_ret = __db_vrfy_putpageinfo(
00116                     dbenv, vdp, LIST_FIRST(&vdp->activepips))) != 0) {
00117                         if (ret == 0)
00118                                 ret = t_ret;
00119                         break;
00120                 }
00121 
00122         /* Discard subdatabase list structures. */
00123         while ((c = LIST_FIRST(&vdp->subdbs)) != NULL) {
00124                 LIST_REMOVE(c, links);
00125                 __os_free(NULL, c);
00126         }
00127 
00128         if ((t_ret = __db_close(vdp->pgdbp, NULL, 0)) != 0)
00129                 ret = t_ret;
00130 
00131         if ((t_ret = __db_close(vdp->cdbp, NULL, 0)) != 0 && ret == 0)
00132                 ret = t_ret;
00133 
00134         if ((t_ret = __db_close(vdp->pgset, NULL, 0)) != 0 && ret == 0)
00135                 ret = t_ret;
00136 
00137         if (vdp->extents != NULL)
00138                 __os_free(dbenv, vdp->extents);
00139         __os_free(dbenv, vdp);
00140         return (ret);
00141 }
00142 
00143 /*
00144  * __db_vrfy_getpageinfo --
00145  *      Get a PAGEINFO structure for a given page, creating it if necessary.
00146  *
00147  * PUBLIC: int __db_vrfy_getpageinfo
00148  * PUBLIC:     __P((VRFY_DBINFO *, db_pgno_t, VRFY_PAGEINFO **));
00149  */
00150 int
00151 __db_vrfy_getpageinfo(vdp, pgno, pipp)
00152         VRFY_DBINFO *vdp;
00153         db_pgno_t pgno;
00154         VRFY_PAGEINFO **pipp;
00155 {
00156         DBT key, data;
00157         DB *pgdbp;
00158         VRFY_PAGEINFO *pip;
00159         int ret;
00160 
00161         /*
00162          * We want a page info struct.  There are three places to get it from,
00163          * in decreasing order of preference:
00164          *
00165          * 1. vdp->activepips.  If it's already "checked out", we're
00166          *      already using it, we return the same exact structure with a
00167          *      bumped refcount.  This is necessary because this code is
00168          *      replacing array accesses, and it's common for f() to make some
00169          *      changes to a pip, and then call g() and h() which each make
00170          *      changes to the same pip.  vdps are never shared between threads
00171          *      (they're never returned to the application), so this is safe.
00172          * 2. The pgdbp.  It's not in memory, but it's in the database, so
00173          *      get it, give it a refcount of 1, and stick it on activepips.
00174          * 3. malloc.  It doesn't exist yet;  create it, then stick it on
00175          *      activepips.  We'll put it in the database when we putpageinfo
00176          *      later.
00177          */
00178 
00179         /* Case 1. */
00180         for (pip = LIST_FIRST(&vdp->activepips); pip != NULL;
00181             pip = LIST_NEXT(pip, links))
00182                 if (pip->pgno == pgno)
00183                         /* Found it. */
00184                         goto found;
00185 
00186         /* Case 2. */
00187         pgdbp = vdp->pgdbp;
00188         memset(&key, 0, sizeof(DBT));
00189         memset(&data, 0, sizeof(DBT));
00190         F_SET(&data, DB_DBT_MALLOC);
00191         key.data = &pgno;
00192         key.size = sizeof(db_pgno_t);
00193 
00194         if ((ret = __db_get(pgdbp, NULL, &key, &data, 0)) == 0) {
00195                 /* Found it. */
00196                 DB_ASSERT(data.size == sizeof(VRFY_PAGEINFO));
00197                 pip = data.data;
00198                 LIST_INSERT_HEAD(&vdp->activepips, pip, links);
00199                 goto found;
00200         } else if (ret != DB_NOTFOUND)  /* Something nasty happened. */
00201                 return (ret);
00202 
00203         /* Case 3 */
00204         if ((ret = __db_vrfy_pageinfo_create(pgdbp->dbenv, &pip)) != 0)
00205                 return (ret);
00206 
00207         LIST_INSERT_HEAD(&vdp->activepips, pip, links);
00208 found:  pip->pi_refcount++;
00209 
00210         *pipp = pip;
00211         return (0);
00212 }
00213 
00214 /*
00215  * __db_vrfy_putpageinfo --
00216  *      Put back a VRFY_PAGEINFO that we're done with.
00217  *
00218  * PUBLIC: int __db_vrfy_putpageinfo __P((DB_ENV *,
00219  * PUBLIC:     VRFY_DBINFO *, VRFY_PAGEINFO *));
00220  */
00221 int
00222 __db_vrfy_putpageinfo(dbenv, vdp, pip)
00223         DB_ENV *dbenv;
00224         VRFY_DBINFO *vdp;
00225         VRFY_PAGEINFO *pip;
00226 {
00227         DBT key, data;
00228         DB *pgdbp;
00229         VRFY_PAGEINFO *p;
00230         int ret;
00231 
00232         if (--pip->pi_refcount > 0)
00233                 return (0);
00234 
00235         pgdbp = vdp->pgdbp;
00236         memset(&key, 0, sizeof(DBT));
00237         memset(&data, 0, sizeof(DBT));
00238 
00239         key.data = &pip->pgno;
00240         key.size = sizeof(db_pgno_t);
00241         data.data = pip;
00242         data.size = sizeof(VRFY_PAGEINFO);
00243 
00244         if ((ret = __db_put(pgdbp, NULL, &key, &data, 0)) != 0)
00245                 return (ret);
00246 
00247         for (p =
00248             LIST_FIRST(&vdp->activepips); p != NULL; p = LIST_NEXT(p, links))
00249                 if (p == pip)
00250                         break;
00251         if (p != NULL)
00252                 LIST_REMOVE(p, links);
00253 
00254         __os_ufree(dbenv, p);
00255         return (0);
00256 }
00257 
00258 /*
00259  * __db_vrfy_pgset --
00260  *      Create a temporary database for the storing of sets of page numbers.
00261  *      (A mapping from page number to int, used by the *_meta2pgset functions,
00262  *      as well as for keeping track of which pages the verifier has seen.)
00263  *
00264  * PUBLIC: int __db_vrfy_pgset __P((DB_ENV *, u_int32_t, DB **));
00265  */
00266 int
00267 __db_vrfy_pgset(dbenv, pgsize, dbpp)
00268         DB_ENV *dbenv;
00269         u_int32_t pgsize;
00270         DB **dbpp;
00271 {
00272         DB *dbp;
00273         int ret;
00274 
00275         if ((ret = db_create(&dbp, dbenv, 0)) != 0)
00276                 return (ret);
00277         if ((ret = __db_set_pagesize(dbp, pgsize)) != 0)
00278                 goto err;
00279         if ((ret = __db_open(dbp,
00280             NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600, PGNO_BASE_MD)) == 0)
00281                 *dbpp = dbp;
00282         else
00283 err:            (void)__db_close(dbp, NULL, 0);
00284 
00285         return (ret);
00286 }
00287 
00288 /*
00289  * __db_vrfy_pgset_get --
00290  *      Get the value associated in a page set with a given pgno.  Return
00291  *      a 0 value (and succeed) if we've never heard of this page.
00292  *
00293  * PUBLIC: int __db_vrfy_pgset_get __P((DB *, db_pgno_t, int *));
00294  */
00295 int
00296 __db_vrfy_pgset_get(dbp, pgno, valp)
00297         DB *dbp;
00298         db_pgno_t pgno;
00299         int *valp;
00300 {
00301         DBT key, data;
00302         int ret, val;
00303 
00304         memset(&key, 0, sizeof(DBT));
00305         memset(&data, 0, sizeof(DBT));
00306 
00307         key.data = &pgno;
00308         key.size = sizeof(db_pgno_t);
00309         data.data = &val;
00310         data.ulen = sizeof(int);
00311         F_SET(&data, DB_DBT_USERMEM);
00312 
00313         if ((ret = __db_get(dbp, NULL, &key, &data, 0)) == 0) {
00314                 DB_ASSERT(data.size == sizeof(int));
00315         } else if (ret == DB_NOTFOUND)
00316                 val = 0;
00317         else
00318                 return (ret);
00319 
00320         *valp = val;
00321         return (0);
00322 }
00323 
00324 /*
00325  * __db_vrfy_pgset_inc --
00326  *      Increment the value associated with a pgno by 1.
00327  *
00328  * PUBLIC: int __db_vrfy_pgset_inc __P((DB *, db_pgno_t));
00329  */
00330 int
00331 __db_vrfy_pgset_inc(dbp, pgno)
00332         DB *dbp;
00333         db_pgno_t pgno;
00334 {
00335         DBT key, data;
00336         int ret;
00337         int val;
00338 
00339         memset(&key, 0, sizeof(DBT));
00340         memset(&data, 0, sizeof(DBT));
00341 
00342         val = 0;
00343 
00344         key.data = &pgno;
00345         key.size = sizeof(db_pgno_t);
00346         data.data = &val;
00347         data.ulen = sizeof(int);
00348         F_SET(&data, DB_DBT_USERMEM);
00349 
00350         if ((ret = __db_get(dbp, NULL, &key, &data, 0)) == 0) {
00351                 DB_ASSERT(data.size == sizeof(int));
00352         } else if (ret != DB_NOTFOUND)
00353                 return (ret);
00354 
00355         data.size = sizeof(int);
00356         ++val;
00357 
00358         return (__db_put(dbp, NULL, &key, &data, 0));
00359 }
00360 
00361 /*
00362  * __db_vrfy_pgset_next --
00363  *      Given a cursor open in a pgset database, get the next page in the
00364  *      set.
00365  *
00366  * PUBLIC: int __db_vrfy_pgset_next __P((DBC *, db_pgno_t *));
00367  */
00368 int
00369 __db_vrfy_pgset_next(dbc, pgnop)
00370         DBC *dbc;
00371         db_pgno_t *pgnop;
00372 {
00373         DBT key, data;
00374         db_pgno_t pgno;
00375         int ret;
00376 
00377         memset(&key, 0, sizeof(DBT));
00378         memset(&data, 0, sizeof(DBT));
00379         /* We don't care about the data, just the keys. */
00380         F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL);
00381         F_SET(&key, DB_DBT_USERMEM);
00382         key.data = &pgno;
00383         key.ulen = sizeof(db_pgno_t);
00384 
00385         if ((ret = __db_c_get(dbc, &key, &data, DB_NEXT)) != 0)
00386                 return (ret);
00387 
00388         DB_ASSERT(key.size == sizeof(db_pgno_t));
00389         *pgnop = pgno;
00390 
00391         return (0);
00392 }
00393 
00394 /*
00395  * __db_vrfy_childcursor --
00396  *      Create a cursor to walk the child list with.  Returns with a nonzero
00397  *      final argument if the specified page has no children.
00398  *
00399  * PUBLIC: int __db_vrfy_childcursor __P((VRFY_DBINFO *, DBC **));
00400  */
00401 int
00402 __db_vrfy_childcursor(vdp, dbcp)
00403         VRFY_DBINFO *vdp;
00404         DBC **dbcp;
00405 {
00406         DB *cdbp;
00407         DBC *dbc;
00408         int ret;
00409 
00410         cdbp = vdp->cdbp;
00411 
00412         if ((ret = __db_cursor(cdbp, NULL, &dbc, 0)) == 0)
00413                 *dbcp = dbc;
00414 
00415         return (ret);
00416 }
00417 
00418 /*
00419  * __db_vrfy_childput --
00420  *      Add a child structure to the set for a given page.
00421  *
00422  * PUBLIC: int __db_vrfy_childput
00423  * PUBLIC:     __P((VRFY_DBINFO *, db_pgno_t, VRFY_CHILDINFO *));
00424  */
00425 int
00426 __db_vrfy_childput(vdp, pgno, cip)
00427         VRFY_DBINFO *vdp;
00428         db_pgno_t pgno;
00429         VRFY_CHILDINFO *cip;
00430 {
00431         DB *cdbp;
00432         DBC *cc;
00433         DBT key, data;
00434         VRFY_CHILDINFO *oldcip;
00435         int ret;
00436 
00437         cdbp = vdp->cdbp;
00438         memset(&key, 0, sizeof(DBT));
00439         memset(&data, 0, sizeof(DBT));
00440 
00441         key.data = &pgno;
00442         key.size = sizeof(db_pgno_t);
00443 
00444         /*
00445          * We want to avoid adding multiple entries for a single child page;
00446          * we only need to verify each child once, even if a child (such
00447          * as an overflow key) is multiply referenced.
00448          *
00449          * However, we also need to make sure that when walking the list
00450          * of children, we encounter them in the order they're referenced
00451          * on a page.  (This permits us, for example, to verify the
00452          * prev_pgno/next_pgno chain of Btree leaf pages.)
00453          *
00454          * Check the child database to make sure that this page isn't
00455          * already a child of the specified page number.  If it's not,
00456          * put it at the end of the duplicate set.
00457          */
00458         if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0)
00459                 return (ret);
00460         for (ret = __db_vrfy_ccset(cc, pgno, &oldcip); ret == 0;
00461             ret = __db_vrfy_ccnext(cc, &oldcip))
00462                 if (oldcip->pgno == cip->pgno) {
00463                         /*
00464                          * Found a matching child.  Increment its reference
00465                          * count--we've run into it again--but don't put it
00466                          * again.
00467                          */
00468                         if ((ret = __db_vrfy_childinc(cc, oldcip)) != 0 ||
00469                             (ret = __db_vrfy_ccclose(cc)) != 0)
00470                                 return (ret);
00471                         return (0);
00472                 }
00473         if (ret != DB_NOTFOUND) {
00474                 (void)__db_vrfy_ccclose(cc);
00475                 return (ret);
00476         }
00477         if ((ret = __db_vrfy_ccclose(cc)) != 0)
00478                 return (ret);
00479 
00480         cip->refcnt = 1;
00481         data.data = cip;
00482         data.size = sizeof(VRFY_CHILDINFO);
00483 
00484         return (__db_put(cdbp, NULL, &key, &data, 0));
00485 }
00486 
00487 /*
00488  * __db_vrfy_childinc --
00489  *      Increment the refcount of the VRFY_CHILDINFO struct that the child
00490  * cursor is pointing to.  (The caller has just retrieved this struct, and
00491  * passes it in as cip to save us a get.)
00492  */
00493 static int
00494 __db_vrfy_childinc(dbc, cip)
00495         DBC *dbc;
00496         VRFY_CHILDINFO *cip;
00497 {
00498         DBT key, data;
00499 
00500         memset(&key, 0, sizeof(DBT));
00501         memset(&data, 0, sizeof(DBT));
00502 
00503         cip->refcnt++;
00504         data.data = cip;
00505         data.size = sizeof(VRFY_CHILDINFO);
00506 
00507         return (__db_c_put(dbc, &key, &data, DB_CURRENT));
00508 }
00509 
00510 /*
00511  * __db_vrfy_ccset --
00512  *      Sets a cursor created with __db_vrfy_childcursor to the first
00513  *      child of the given pgno, and returns it in the third arg.
00514  *
00515  * PUBLIC: int __db_vrfy_ccset __P((DBC *, db_pgno_t, VRFY_CHILDINFO **));
00516  */
00517 int
00518 __db_vrfy_ccset(dbc, pgno, cipp)
00519         DBC *dbc;
00520         db_pgno_t pgno;
00521         VRFY_CHILDINFO **cipp;
00522 {
00523         DBT key, data;
00524         int ret;
00525 
00526         memset(&key, 0, sizeof(DBT));
00527         memset(&data, 0, sizeof(DBT));
00528 
00529         key.data = &pgno;
00530         key.size = sizeof(db_pgno_t);
00531 
00532         if ((ret = __db_c_get(dbc, &key, &data, DB_SET)) != 0)
00533                 return (ret);
00534 
00535         DB_ASSERT(data.size == sizeof(VRFY_CHILDINFO));
00536         *cipp = (VRFY_CHILDINFO *)data.data;
00537 
00538         return (0);
00539 }
00540 
00541 /*
00542  * __db_vrfy_ccnext --
00543  *      Gets the next child of the given cursor created with
00544  *      __db_vrfy_childcursor, and returns it in the memory provided in the
00545  *      second arg.
00546  *
00547  * PUBLIC: int __db_vrfy_ccnext __P((DBC *, VRFY_CHILDINFO **));
00548  */
00549 int
00550 __db_vrfy_ccnext(dbc, cipp)
00551         DBC *dbc;
00552         VRFY_CHILDINFO **cipp;
00553 {
00554         DBT key, data;
00555         int ret;
00556 
00557         memset(&key, 0, sizeof(DBT));
00558         memset(&data, 0, sizeof(DBT));
00559 
00560         if ((ret = __db_c_get(dbc, &key, &data, DB_NEXT_DUP)) != 0)
00561                 return (ret);
00562 
00563         DB_ASSERT(data.size == sizeof(VRFY_CHILDINFO));
00564         *cipp = (VRFY_CHILDINFO *)data.data;
00565 
00566         return (0);
00567 }
00568 
00569 /*
00570  * __db_vrfy_ccclose --
00571  *      Closes the cursor created with __db_vrfy_childcursor.
00572  *
00573  *      This doesn't actually do anything interesting now, but it's
00574  *      not inconceivable that we might change the internal database usage
00575  *      and keep the interfaces the same, and a function call here or there
00576  *      seldom hurts anyone.
00577  *
00578  * PUBLIC: int __db_vrfy_ccclose __P((DBC *));
00579  */
00580 int
00581 __db_vrfy_ccclose(dbc)
00582         DBC *dbc;
00583 {
00584 
00585         return (__db_c_close(dbc));
00586 }
00587 
00588 /*
00589  * __db_vrfy_pageinfo_create --
00590  *      Constructor for VRFY_PAGEINFO;  allocates and initializes.
00591  */
00592 static int
00593 __db_vrfy_pageinfo_create(dbenv, pipp)
00594         DB_ENV *dbenv;
00595         VRFY_PAGEINFO **pipp;
00596 {
00597         VRFY_PAGEINFO *pip;
00598         int ret;
00599 
00600         /*
00601          * pageinfo structs are sometimes allocated here and sometimes
00602          * allocated by fetching them from a database with DB_DBT_MALLOC.
00603          * There's no easy way for the destructor to tell which was
00604          * used, and so we always allocate with __os_umalloc so we can free
00605          * with __os_ufree.
00606          */
00607         if ((ret = __os_umalloc(dbenv, sizeof(VRFY_PAGEINFO), &pip)) != 0)
00608                 return (ret);
00609         memset(pip, 0, sizeof(VRFY_PAGEINFO));
00610 
00611         *pipp = pip;
00612         return (0);
00613 }
00614 
00615 /*
00616  * __db_salvage_init --
00617  *      Set up salvager database.
00618  *
00619  * PUBLIC: int  __db_salvage_init __P((VRFY_DBINFO *));
00620  */
00621 int
00622 __db_salvage_init(vdp)
00623         VRFY_DBINFO *vdp;
00624 {
00625         DB *dbp;
00626         int ret;
00627 
00628         if ((ret = db_create(&dbp, NULL, 0)) != 0)
00629                 return (ret);
00630 
00631         if ((ret = __db_set_pagesize(dbp, 1024)) != 0)
00632                 goto err;
00633 
00634         if ((ret = __db_open(dbp,
00635             NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0, PGNO_BASE_MD)) != 0)
00636                 goto err;
00637 
00638         vdp->salvage_pages = dbp;
00639         return (0);
00640 
00641 err:    (void)__db_close(dbp, NULL, 0);
00642         return (ret);
00643 }
00644 
00645 /*
00646  * __db_salvage_destroy --
00647  *      Close salvager database.
00648  * PUBLIC: void  __db_salvage_destroy __P((VRFY_DBINFO *));
00649  */
00650 void
00651 __db_salvage_destroy(vdp)
00652         VRFY_DBINFO *vdp;
00653 {
00654         (void)__db_close(vdp->salvage_pages, NULL, 0);
00655 }
00656 
00657 /*
00658  * __db_salvage_getnext --
00659  *      Get the next (first) unprinted page in the database of pages we need to
00660  *      print still.  Delete entries for any already-printed pages we encounter
00661  *      in this search, as well as the page we're returning.
00662  *
00663  * PUBLIC: int __db_salvage_getnext
00664  * PUBLIC:     __P((VRFY_DBINFO *, DBC **, db_pgno_t *, u_int32_t *, int));
00665  */
00666 int
00667 __db_salvage_getnext(vdp, dbcp, pgnop, pgtypep, skip_overflow)
00668         VRFY_DBINFO *vdp;
00669         DBC **dbcp;
00670         db_pgno_t *pgnop;
00671         u_int32_t *pgtypep;
00672         int skip_overflow;
00673 {
00674         DB *dbp;
00675         DBT key, data;
00676         int ret;
00677         u_int32_t pgtype;
00678 
00679         dbp = vdp->salvage_pages;
00680 
00681         memset(&key, 0, sizeof(DBT));
00682         memset(&data, 0, sizeof(DBT));
00683 
00684         if (*dbcp == NULL &&
00685             (ret = __db_cursor(dbp, NULL, dbcp, 0)) != 0)
00686                 return (ret);
00687 
00688         while ((ret = __db_c_get(*dbcp, &key, &data, DB_NEXT)) == 0) {
00689                 DB_ASSERT(data.size == sizeof(u_int32_t));
00690                 memcpy(&pgtype, data.data, sizeof(pgtype));
00691 
00692                 if (skip_overflow && pgtype == SALVAGE_OVERFLOW)
00693                         continue;
00694 
00695                 if ((ret = __db_c_del(*dbcp, 0)) != 0)
00696                         return (ret);
00697                 if (pgtype != SALVAGE_IGNORE) {
00698                         DB_ASSERT(key.size == sizeof(db_pgno_t));
00699                         DB_ASSERT(data.size == sizeof(u_int32_t));
00700 
00701                         *pgnop = *(db_pgno_t *)key.data;
00702                         *pgtypep = *(u_int32_t *)data.data;
00703                         break;
00704                 }
00705         }
00706 
00707         return (ret);
00708 }
00709 
00710 /*
00711  * __db_salvage_isdone --
00712  *      Return whether or not the given pgno is already marked
00713  *      SALVAGE_IGNORE (meaning that we don't need to print it again).
00714  *
00715  *      Returns DB_KEYEXIST if it is marked, 0 if not, or another error on
00716  *      error.
00717  *
00718  * PUBLIC: int __db_salvage_isdone __P((VRFY_DBINFO *, db_pgno_t));
00719  */
00720 int
00721 __db_salvage_isdone(vdp, pgno)
00722         VRFY_DBINFO *vdp;
00723         db_pgno_t pgno;
00724 {
00725         DBT key, data;
00726         DB *dbp;
00727         int ret;
00728         u_int32_t currtype;
00729 
00730         dbp = vdp->salvage_pages;
00731 
00732         memset(&key, 0, sizeof(DBT));
00733         memset(&data, 0, sizeof(DBT));
00734 
00735         currtype = SALVAGE_INVALID;
00736         data.data = &currtype;
00737         data.ulen = sizeof(u_int32_t);
00738         data.flags = DB_DBT_USERMEM;
00739 
00740         key.data = &pgno;
00741         key.size = sizeof(db_pgno_t);
00742 
00743         /*
00744          * Put an entry for this page, with pgno as key and type as data,
00745          * unless it's already there and is marked done.
00746          * If it's there and is marked anything else, that's fine--we
00747          * want to mark it done.
00748          */
00749         if ((ret = __db_get(dbp, NULL, &key, &data, 0)) == 0) {
00750                 /*
00751                  * The key's already here.  Check and see if it's already
00752                  * marked done.  If it is, return DB_KEYEXIST.  If it's not,
00753                  * return 0.
00754                  */
00755                 if (currtype == SALVAGE_IGNORE)
00756                         return (DB_KEYEXIST);
00757                 else
00758                         return (0);
00759         } else if (ret != DB_NOTFOUND)
00760                 return (ret);
00761 
00762         /* The pgno is not yet marked anything; return 0. */
00763         return (0);
00764 }
00765 
00766 /*
00767  * __db_salvage_markdone --
00768  *      Mark as done a given page.
00769  *
00770  * PUBLIC: int __db_salvage_markdone __P((VRFY_DBINFO *, db_pgno_t));
00771  */
00772 int
00773 __db_salvage_markdone(vdp, pgno)
00774         VRFY_DBINFO *vdp;
00775         db_pgno_t pgno;
00776 {
00777         DBT key, data;
00778         DB *dbp;
00779         int pgtype, ret;
00780         u_int32_t currtype;
00781 
00782         pgtype = SALVAGE_IGNORE;
00783         dbp = vdp->salvage_pages;
00784 
00785         memset(&key, 0, sizeof(DBT));
00786         memset(&data, 0, sizeof(DBT));
00787 
00788         currtype = SALVAGE_INVALID;
00789         data.data = &currtype;
00790         data.ulen = sizeof(u_int32_t);
00791         data.flags = DB_DBT_USERMEM;
00792 
00793         key.data = &pgno;
00794         key.size = sizeof(db_pgno_t);
00795 
00796         /*
00797          * Put an entry for this page, with pgno as key and type as data,
00798          * unless it's already there and is marked done.
00799          * If it's there and is marked anything else, that's fine--we
00800          * want to mark it done, but db_salvage_isdone only lets
00801          * us know if it's marked IGNORE.
00802          *
00803          * We don't want to return DB_KEYEXIST, though;  this will
00804          * likely get passed up all the way and make no sense to the
00805          * application.  Instead, use DB_VERIFY_BAD to indicate that
00806          * we've seen this page already--it probably indicates a
00807          * multiply-linked page.
00808          */
00809         if ((ret = __db_salvage_isdone(vdp, pgno)) != 0)
00810                 return (ret == DB_KEYEXIST ? DB_VERIFY_BAD : ret);
00811 
00812         data.size = sizeof(u_int32_t);
00813         data.data = &pgtype;
00814 
00815         return (__db_put(dbp, NULL, &key, &data, 0));
00816 }
00817 
00818 /*
00819  * __db_salvage_markneeded --
00820  *      If it has not yet been printed, make note of the fact that a page
00821  *      must be dealt with later.
00822  *
00823  * PUBLIC: int __db_salvage_markneeded
00824  * PUBLIC:     __P((VRFY_DBINFO *, db_pgno_t, u_int32_t));
00825  */
00826 int
00827 __db_salvage_markneeded(vdp, pgno, pgtype)
00828         VRFY_DBINFO *vdp;
00829         db_pgno_t pgno;
00830         u_int32_t pgtype;
00831 {
00832         DB *dbp;
00833         DBT key, data;
00834         int ret;
00835 
00836         dbp = vdp->salvage_pages;
00837 
00838         memset(&key, 0, sizeof(DBT));
00839         memset(&data, 0, sizeof(DBT));
00840 
00841         key.data = &pgno;
00842         key.size = sizeof(db_pgno_t);
00843 
00844         data.data = &pgtype;
00845         data.size = sizeof(u_int32_t);
00846 
00847         /*
00848          * Put an entry for this page, with pgno as key and type as data,
00849          * unless it's already there, in which case it's presumably
00850          * already been marked done.
00851          */
00852         ret = __db_put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
00853         return (ret == DB_KEYEXIST ? 0 : ret);
00854 }
00855 
00856 /*
00857  * __db_vrfy_prdbt --
00858  *      Print out a DBT data element from a verification routine.
00859  *
00860  * PUBLIC: int __db_vrfy_prdbt __P((DBT *, int, const char *, void *,
00861  * PUBLIC:     int (*)(void *, const void *), int, VRFY_DBINFO *));
00862  */
00863 int
00864 __db_vrfy_prdbt(dbtp, checkprint, prefix, handle, callback, is_recno, vdp)
00865         DBT *dbtp;
00866         int checkprint;
00867         const char *prefix;
00868         void *handle;
00869         int (*callback) __P((void *, const void *));
00870         int is_recno;
00871         VRFY_DBINFO *vdp;
00872 {
00873         if (vdp != NULL) {
00874                 /*
00875                  * If vdp is non-NULL, we might be the first key in the
00876                  * "fake" subdatabase used for key/data pairs we can't
00877                  * associate with a known subdb.
00878                  *
00879                  * Check and clear the SALVAGE_PRINTHEADER flag;  if
00880                  * it was set, print a subdatabase header.
00881                  */
00882                 if (F_ISSET(vdp, SALVAGE_PRINTHEADER)) {
00883                         (void)__db_prheader(
00884                             NULL, "__OTHER__", 0, 0, handle, callback, vdp, 0);
00885                         F_CLR(vdp, SALVAGE_PRINTHEADER);
00886                         F_SET(vdp, SALVAGE_PRINTFOOTER);
00887                 }
00888 
00889                 /*
00890                  * Even if the printable flag wasn't set by our immediate
00891                  * caller, it may be set on a salvage-wide basis.
00892                  */
00893                 if (F_ISSET(vdp, SALVAGE_PRINTABLE))
00894                         checkprint = 1;
00895         }
00896         return (
00897             __db_prdbt(dbtp, checkprint, prefix, handle, callback, is_recno));
00898 }

Generated on Sun Dec 25 12:14:22 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2