db_overflow.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  * Copyright (c) 1990, 1993, 1994, 1995, 1996
00009  *      Keith Bostic.  All rights reserved.
00010  */
00011 /*
00012  * Copyright (c) 1990, 1993, 1994, 1995
00013  *      The Regents of the University of California.  All rights reserved.
00014  *
00015  * This code is derived from software contributed to Berkeley by
00016  * Mike Olson.
00017  *
00018  * Redistribution and use in source and binary forms, with or without
00019  * modification, are permitted provided that the following conditions
00020  * are met:
00021  * 1. Redistributions of source code must retain the above copyright
00022  *    notice, this list of conditions and the following disclaimer.
00023  * 2. Redistributions in binary form must reproduce the above copyright
00024  *    notice, this list of conditions and the following disclaimer in the
00025  *    documentation and/or other materials provided with the distribution.
00026  * 3. Neither the name of the University nor the names of its contributors
00027  *    may be used to endorse or promote products derived from this software
00028  *    without specific prior written permission.
00029  *
00030  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00031  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00032  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00033  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00034  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00035  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00036  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00037  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00038  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00039  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00040  * SUCH DAMAGE.
00041  */
00042 
00043 #include "config.h"
00044 
00045 #ifndef lint
00046 static const char revid[] = "$Id: db__overflow_8c-source.html,v 1.1 2008/06/08 10:17:55 sebdiaz Exp $";
00047 #endif /* not lint */
00048 
00049 #ifndef NO_SYSTEM_INCLUDES
00050 #include <sys/types.h>
00051 
00052 #include <errno.h>
00053 #include <string.h>
00054 #endif
00055 
00056 #include "db_int.h"
00057 #include "db_page.h"
00058 #include "db_am.h"
00059 #include "db_verify.h"
00060 
00061 /*
00062  * Big key/data code.
00063  *
00064  * Big key and data entries are stored on linked lists of pages.  The initial
00065  * reference is a structure with the total length of the item and the page
00066  * number where it begins.  Each entry in the linked list contains a pointer
00067  * to the next page of data, and so on.
00068  */
00069 
00070 /*
00071  * CDB___db_goff --
00072  *      Get an offpage item.
00073  *
00074  * PUBLIC: int CDB___db_goff __P((DB *, DBT *,
00075  * PUBLIC:     u_int32_t, db_pgno_t, void **, u_int32_t *));
00076  */
00077 int
00078 CDB___db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
00079         DB *dbp;
00080         DBT *dbt;
00081         u_int32_t tlen;
00082         db_pgno_t pgno;
00083         void **bpp;
00084         u_int32_t *bpsz;
00085 {
00086         DB_ENV *dbenv;
00087         PAGE *h;
00088         db_indx_t bytes;
00089         u_int32_t curoff, needed, start;
00090         u_int8_t *p, *src;
00091         int ret;
00092 
00093         dbenv = dbp->dbenv;
00094 
00095         /*
00096          * Check if the buffer is big enough; if it is not and we are
00097          * allowed to malloc space, then we'll malloc it.  If we are
00098          * not (DB_DBT_USERMEM), then we'll set the dbt and return
00099          * appropriately.
00100          */
00101         if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
00102                 start = dbt->doff;
00103                 needed = dbt->dlen;
00104         } else {
00105                 start = 0;
00106                 needed = tlen;
00107         }
00108 
00109         /* Allocate any necessary memory. */
00110         if (F_ISSET(dbt, DB_DBT_USERMEM)) {
00111                 if (needed > dbt->ulen) {
00112                         dbt->size = needed;
00113                         return (ENOMEM);
00114                 }
00115         } else if (F_ISSET(dbt, DB_DBT_MALLOC)) {
00116                 if ((ret = CDB___os_malloc(dbenv,
00117                     needed, dbp->db_malloc, &dbt->data)) != 0)
00118                         return (ret);
00119         } else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
00120                 if ((ret = CDB___os_realloc(dbenv,
00121                     needed, dbp->db_realloc, &dbt->data)) != 0)
00122                         return (ret);
00123         } else if (*bpsz == 0 || *bpsz < needed) {
00124                 if ((ret = CDB___os_realloc(dbenv, needed, NULL, bpp)) != 0)
00125                         return (ret);
00126                 *bpsz = needed;
00127                 dbt->data = *bpp;
00128         } else
00129                 dbt->data = *bpp;
00130 
00131         /*
00132          * Step through the linked list of pages, copying the data on each
00133          * one into the buffer.  Never copy more than the total data length.
00134          */
00135         dbt->size = needed;
00136         for (curoff = 0, p = dbt->data; pgno != PGNO_INVALID && needed > 0;) {
00137                 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
00138                         (void)CDB___db_pgerr(dbp, pgno);
00139                         return (ret);
00140                 }
00141                 /* Check if we need any bytes from this page. */
00142                 if (curoff + OV_LEN(h) >= start) {
00143                         src = (u_int8_t *)h + P_OVERHEAD;
00144                         bytes = OV_LEN(h);
00145                         if (start > curoff) {
00146                                 src += start - curoff;
00147                                 bytes -= start - curoff;
00148                         }
00149                         if (bytes > needed)
00150                                 bytes = needed;
00151                         memcpy(p, src, bytes);
00152                         p += bytes;
00153                         needed -= bytes;
00154                 }
00155                 curoff += OV_LEN(h);
00156                 pgno = h->next_pgno;
00157                 CDB_memp_fput(dbp->mpf, h, 0);
00158         }
00159         return (0);
00160 }
00161 
00162 /*
00163  * CDB___db_poff --
00164  *      Put an offpage item.
00165  *
00166  * PUBLIC: int CDB___db_poff __P((DBC *, const DBT *, db_pgno_t *));
00167  */
00168 int
00169 CDB___db_poff(dbc, dbt, pgnop)
00170         DBC *dbc;
00171         const DBT *dbt;
00172         db_pgno_t *pgnop;
00173 {
00174         DB *dbp;
00175         PAGE *pagep, *lastp;
00176         DB_LSN new_lsn, null_lsn;
00177         DBT tmp_dbt;
00178         db_indx_t pagespace;
00179         u_int32_t sz;
00180         u_int8_t *p;
00181         int ret;
00182 
00183         /*
00184          * Allocate pages and copy the key/data item into them.  Calculate the
00185          * number of bytes we get for pages we fill completely with a single
00186          * item.
00187          */
00188         dbp = dbc->dbp;
00189         pagespace = P_MAXSPACE(dbp->pgsize);
00190 
00191         lastp = NULL;
00192         for (p = dbt->data,
00193             sz = dbt->size; sz > 0; p += pagespace, sz -= pagespace) {
00194                 /*
00195                  * Reduce pagespace so we terminate the loop correctly and
00196                  * don't copy too much data.
00197                  */
00198                 if (sz < pagespace)
00199                         pagespace = sz;
00200 
00201                 /*
00202                  * Allocate and initialize a new page and copy all or part of
00203                  * the item onto the page.  If sz is less than pagespace, we
00204                  * have a partial record.
00205                  */
00206                 if ((ret = CDB___db_new(dbc, (P_OVERFLOW | dbp->tags), &pagep)) != 0)
00207                         return (ret);
00208                 if (DB_LOGGING(dbc)) {
00209                         tmp_dbt.data = p;
00210                         tmp_dbt.size = pagespace;
00211                         ZERO_LSN(null_lsn);
00212                         if ((ret = CDB___db_big_log(dbp->dbenv, dbc->txn,
00213                             &new_lsn, 0, DB_ADD_BIG, dbp->log_fileid,
00214                             PGNO(pagep), lastp ? PGNO(lastp) : PGNO_INVALID,
00215                             PGNO_INVALID, &tmp_dbt, &LSN(pagep),
00216                             lastp == NULL ? &null_lsn : &LSN(lastp),
00217                             &null_lsn)) != 0)
00218                                 return (ret);
00219 
00220                         /* Move lsn onto page. */
00221                         if (lastp)
00222                                 LSN(lastp) = new_lsn;
00223                         LSN(pagep) = new_lsn;
00224                 }
00225 
00226                 P_INIT(pagep, dbp->pgsize,
00227                     PGNO(pagep), PGNO_INVALID, PGNO_INVALID, 0, P_OVERFLOW, dbp->tags);
00228                 OV_LEN(pagep) = pagespace;
00229                 OV_REF(pagep) = 1;
00230                 memcpy((u_int8_t *)pagep + P_OVERHEAD, p, pagespace);
00231 
00232                 /*
00233                  * If this is the first entry, update the user's info.
00234                  * Otherwise, update the entry on the last page filled
00235                  * in and release that page.
00236                  */
00237                 if (lastp == NULL)
00238                         *pgnop = PGNO(pagep);
00239                 else {
00240                         lastp->next_pgno = PGNO(pagep);
00241                         pagep->prev_pgno = PGNO(lastp);
00242                         (void)CDB_memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY);
00243                 }
00244                 lastp = pagep;
00245         }
00246         (void)CDB_memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY);
00247         return (0);
00248 }
00249 
00250 /*
00251  * CDB___db_ovref --
00252  *      Increment/decrement the reference count on an overflow page.
00253  *
00254  * PUBLIC: int CDB___db_ovref __P((DBC *, db_pgno_t, int32_t));
00255  */
00256 int
00257 CDB___db_ovref(dbc, pgno, adjust)
00258         DBC *dbc;
00259         db_pgno_t pgno;
00260         int32_t adjust;
00261 {
00262         DB *dbp;
00263         PAGE *h;
00264         int ret;
00265 
00266         dbp = dbc->dbp;
00267         if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
00268                 (void)CDB___db_pgerr(dbp, pgno);
00269                 return (ret);
00270         }
00271 
00272         if (DB_LOGGING(dbc))
00273                 if ((ret = CDB___db_ovref_log(dbp->dbenv, dbc->txn,
00274                     &LSN(h), 0, dbp->log_fileid, h->pgno, adjust,
00275                     &LSN(h))) != 0)
00276                         return (ret);
00277         OV_REF(h) += adjust;
00278 
00279         (void)CDB_memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY);
00280         return (0);
00281 }
00282 
00283 /*
00284  * CDB___db_doff --
00285  *      Delete an offpage chain of overflow pages.
00286  *
00287  * PUBLIC: int CDB___db_doff __P((DBC *, db_pgno_t));
00288  */
00289 int
00290 CDB___db_doff(dbc, pgno)
00291         DBC *dbc;
00292         db_pgno_t pgno;
00293 {
00294         DB *dbp;
00295         PAGE *pagep;
00296         DB_LSN null_lsn;
00297         DBT tmp_dbt;
00298         int ret;
00299 
00300         dbp = dbc->dbp;
00301         do {
00302                 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) {
00303                         (void)CDB___db_pgerr(dbp, pgno);
00304                         return (ret);
00305                 }
00306 
00307                 /*
00308                  * If it's an overflow page and it's referenced by more than
00309                  * one key/data item, decrement the reference count and return.
00310                  */
00311                 if (TYPE(pagep) == P_OVERFLOW && OV_REF(pagep) > 1) {
00312                         (void)CDB_memp_fput(dbp->mpf, pagep, 0);
00313                         return (CDB___db_ovref(dbc, pgno, -1));
00314                 }
00315 
00316                 if (DB_LOGGING(dbc)) {
00317                         tmp_dbt.data = (u_int8_t *)pagep + P_OVERHEAD;
00318                         tmp_dbt.size = OV_LEN(pagep);
00319                         ZERO_LSN(null_lsn);
00320                         if ((ret = CDB___db_big_log(dbp->dbenv, dbc->txn,
00321                             &LSN(pagep), 0, DB_REM_BIG, dbp->log_fileid,
00322                             PGNO(pagep), PREV_PGNO(pagep), NEXT_PGNO(pagep),
00323                             &tmp_dbt, &LSN(pagep), &null_lsn, &null_lsn)) != 0)
00324                                 return (ret);
00325                 }
00326                 pgno = pagep->next_pgno;
00327                 if ((ret = CDB___db_free(dbc, pagep)) != 0)
00328                         return (ret);
00329         } while (pgno != PGNO_INVALID);
00330 
00331         return (0);
00332 }
00333 
00334 /*
00335  * CDB___db_moff --
00336  *      Match on overflow pages.
00337  *
00338  * Given a starting page number and a key, return <0, 0, >0 to indicate if the
00339  * key on the page is less than, equal to or greater than the key specified.
00340  * We optimize this by doing chunk at a time comparison unless the user has
00341  * specified a comparison function.  In this case, we need to materialize
00342  * the entire object and call their comparison routine.
00343  *
00344  * PUBLIC: int CDB___db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t,
00345  * PUBLIC:     int (*)(const DBT *, const DBT *), int *));
00346  */
00347 int
00348 CDB___db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp)
00349         DB *dbp;
00350         const DBT *dbt;
00351         db_pgno_t pgno;
00352         u_int32_t tlen;
00353         int (*cmpfunc) __P((const DBT *, const DBT *));
00354         int *cmpp;
00355 {
00356         PAGE *pagep;
00357         DBT local_dbt;
00358         void *buf;
00359         u_int32_t bufsize, cmp_bytes, key_left;
00360         u_int8_t *p1, *p2;
00361         int ret;
00362 
00363         /*
00364          * If there is a user-specified comparison function, build a
00365          * contiguous copy of the key, and call it.
00366          */
00367         if (cmpfunc != NULL) {
00368                 memset(&local_dbt, 0, sizeof(local_dbt));
00369                 buf = NULL;
00370                 bufsize = 0;
00371 
00372                 if ((ret = CDB___db_goff(dbp,
00373                     &local_dbt, tlen, pgno, &buf, &bufsize)) != 0)
00374                         return (ret);
00375                 /* Pass the key as the first argument */
00376                 *cmpp = cmpfunc(dbt, &local_dbt);
00377                 CDB___os_free(buf, bufsize);
00378                 return (0);
00379         }
00380 
00381         /* While there are both keys to compare. */
00382         for (*cmpp = 0, p1 = dbt->data,
00383             key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) {
00384                 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0)
00385                         return (ret);
00386 
00387                 cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left;
00388                 tlen -= cmp_bytes;
00389                 key_left -= cmp_bytes;
00390                 for (p2 =
00391                     (u_int8_t *)pagep + P_OVERHEAD; cmp_bytes-- > 0; ++p1, ++p2)
00392                         if (*p1 != *p2) {
00393                                 *cmpp = (long)*p1 - (long)*p2;
00394                                 break;
00395                         }
00396                 pgno = NEXT_PGNO(pagep);
00397                 if ((ret = CDB_memp_fput(dbp->mpf, pagep, 0)) != 0)
00398                         return (ret);
00399                 if (*cmpp != 0)
00400                         return (0);
00401         }
00402         if (key_left > 0)               /* DBT is longer than the page key. */
00403                 *cmpp = 1;
00404         else if (tlen > 0)              /* DBT is shorter than the page key. */
00405                 *cmpp = -1;
00406         else
00407                 *cmpp = 0;
00408 
00409         return (0);
00410 }
00411 
00412 /*
00413  * CDB___db_vrfy_overflow --
00414  *      Verify overflow page.
00415  *
00416  * PUBLIC: int CDB___db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
00417  * PUBLIC:     u_int32_t));
00418  */
00419 int
00420 CDB___db_vrfy_overflow(dbp, vdp, h, pgno, flags)
00421         DB *dbp;
00422         VRFY_DBINFO *vdp;
00423         PAGE *h;
00424         db_pgno_t pgno;
00425         u_int32_t flags;
00426 {
00427         VRFY_PAGEINFO *pip;
00428         int isbad, ret, t_ret;
00429 
00430         isbad = 0;
00431         if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00432                 return (ret);
00433 
00434         if ((ret = CDB___db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
00435                 if (ret == DB_VERIFY_BAD)
00436                         isbad = 1;
00437                 else
00438                         goto err;
00439         }
00440 
00441         pip->refcount = OV_REF(h);
00442         if (pip->refcount < 1) {
00443                 EPRINT((dbp->dbenv, "Overflow page %lu has zero reference count",
00444                     pgno));
00445                 isbad = 1;
00446         }
00447 
00448         /* Just store for now. */
00449         pip->olen = HOFFSET(h);
00450 
00451 err:    if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
00452                 ret = t_ret;
00453         return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
00454 }
00455 
00456 /*
00457  * CDB___db_vrfy_ovfl_structure --
00458  *      Walk a list of overflow pages, avoiding cycles and marking
00459  *      pages seen.
00460  *
00461  * PUBLIC: int CDB___db_vrfy_ovfl_structure
00462  * PUBLIC:     __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t));
00463  */
00464 int
00465 CDB___db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags)
00466         DB *dbp;
00467         VRFY_DBINFO *vdp;
00468         db_pgno_t pgno;
00469         u_int32_t tlen;
00470         u_int32_t flags;
00471 {
00472         DB *pgset;
00473         VRFY_PAGEINFO *pip;
00474         db_pgno_t next, prev;
00475         int isbad, p, ret, t_ret;
00476         u_int32_t refcount;
00477 
00478         pgset = vdp->pgset;
00479         DB_ASSERT(pgset != NULL);
00480         isbad = 0;
00481 
00482         /* This shouldn't happen, but just to be sure. */
00483         if (!IS_VALID_PGNO(pgno))
00484                 return (DB_VERIFY_BAD);
00485 
00486         /*
00487          * Check the first prev_pgno;  it ought to be PGNO_INVALID,
00488          * since there's no prev page.
00489          */
00490         if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00491                 return (ret);
00492 
00493         /* The refcount is stored on the first overflow page. */
00494         refcount = pip->refcount;
00495 
00496         if (pip->type != P_OVERFLOW) {
00497                 EPRINT((dbp->dbenv,
00498                     "Overflow page %lu of invalid type", pgno, pip->type));
00499                 ret = DB_VERIFY_BAD;
00500                 goto err;               /* Unsafe to continue. */
00501         }
00502 
00503         prev = pip->prev_pgno;
00504         if (prev != PGNO_INVALID) {
00505                 EPRINT((dbp->dbenv,
00506                     "First overflow page %lu has a prev_pgno", pgno));
00507                 isbad = 1;
00508         }
00509 
00510         for (;;) {
00511                 /*
00512                  * This is slightly gross.  Btree leaf pages reference
00513                  * individual overflow trees multiple times if the overflow page
00514                  * is the key to a duplicate set.  The reference count does not
00515                  * reflect this multiple referencing.  Thus, if this is called
00516                  * during the structure verification of a btree leaf page, we
00517                  * check to see whether we've seen it from a leaf page before
00518                  * and, if we have, adjust our count of how often we've seen it
00519                  * accordingly.
00520                  *
00521                  * (This will screw up if it's actually referenced--and
00522                  * correctly refcounted--from two different leaf pages, but
00523                  * that's a very unlikely brokenness that we're not checking for
00524                  * anyway.)
00525                  */
00526 
00527                 if (LF_ISSET(ST_OVFL_LEAF)) {
00528                         if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) {
00529                                 if ((ret =
00530                                     CDB___db_vrfy_pgset_dec(pgset, pgno)) != 0)
00531                                         goto err;
00532                         } else
00533                                 F_SET(pip, VRFY_OVFL_LEAFSEEN);
00534                 }
00535 
00536                 if ((ret = CDB___db_vrfy_pgset_get(pgset, pgno, &p)) != 0)
00537                         goto err;
00538 
00539                 /*
00540                  * We may have seen this elsewhere, if the overflow entry
00541                  * has been promoted to an internal page.
00542                  */
00543                 if ((u_int32_t)p > refcount) {
00544                         EPRINT((dbp->dbenv,
00545                             "Page %lu encountered twice in overflow traversal",
00546                             pgno));
00547                         ret = DB_VERIFY_BAD;
00548                         goto err;
00549                 }
00550                 if ((ret = CDB___db_vrfy_pgset_inc(pgset, pgno)) != 0)
00551                         goto err;
00552 
00553                 /* Keep a running tab on how much of the item we've seen. */
00554                 tlen -= pip->olen;
00555 
00556                 next = pip->next_pgno;
00557 
00558                 /* Are we there yet? */
00559                 if (next == PGNO_INVALID)
00560                         break;
00561 
00562                 /*
00563                  * We've already checked this when we saved it, but just
00564                  * to be sure...
00565                  */
00566                 if (!IS_VALID_PGNO(next)) {
00567                         DB_ASSERT(0);
00568                         EPRINT((dbp->dbenv,
00569                             "Overflow page %lu has bad next_pgno",
00570                             pgno));
00571                         ret = DB_VERIFY_BAD;
00572                         goto err;
00573                 }
00574 
00575                 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 ||
00576                     (ret = CDB___db_vrfy_getpageinfo(vdp, next, &pip)) != 0)
00577                         return (ret);
00578                 if (pip->prev_pgno != pgno) {
00579                         EPRINT((dbp->dbenv,
00580                             "Overflow page %lu has bogus prev_pgno value",
00581                             next));
00582                         isbad = 1;
00583                         /*
00584                          * It's safe to continue because we have separate
00585                          * cycle detection.
00586                          */
00587                 }
00588 
00589                 pgno = next;
00590         }
00591 
00592         if (tlen > 0) {
00593                 isbad = 1;
00594                 EPRINT((dbp->dbenv,
00595                     "Overflow item incomplete on page %lu", pgno));
00596         }
00597 
00598 err:    if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
00599                 ret = t_ret;
00600         return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
00601 }
00602 
00603 /*
00604  * CDB___db_safe_goff --
00605  *      Get an overflow item, very carefully, from an untrusted database,
00606  *      in the context of the salvager.
00607  *
00608  * PUBLIC: int CDB___db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t,
00609  * PUBLIC:     DBT *, void **, u_int32_t));
00610  */
00611 int
00612 CDB___db_safe_goff(dbp, vdp, pgno, dbt, buf, flags)
00613         DB *dbp;
00614         VRFY_DBINFO *vdp;
00615         db_pgno_t pgno;
00616         DBT *dbt;
00617         void **buf;
00618         u_int32_t flags;
00619 {
00620         PAGE *h;
00621         int ret, err_ret;
00622         u_int32_t bytesgot, bytes;
00623         u_int8_t *src, *dest;
00624 
00625         ret = DB_VERIFY_BAD;
00626         err_ret = 0;
00627         bytesgot = bytes = 0;
00628 
00629         while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) {
00630                 /*
00631                  * Mark that we're looking at this page;  if we've seen it
00632                  * already, quit.
00633                  */
00634                 if ((ret = CDB___db_salvage_markdone(vdp, pgno)) != 0)
00635                         break;
00636 
00637                 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
00638                         break;
00639 
00640                 /*
00641                  * Make sure it's really an overflow page, unless we're
00642                  * being aggressive, in which case we pretend it is.
00643                  */
00644                 if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) {
00645                         ret = DB_VERIFY_BAD;
00646                         break;
00647                 }
00648 
00649                 src = (u_int8_t *)h + P_OVERHEAD;
00650                 bytes = OV_LEN(h);
00651 
00652                 if (bytes + P_OVERHEAD > dbp->pgsize)
00653                         bytes = dbp->pgsize - P_OVERHEAD;
00654 
00655                 if ((ret = CDB___os_realloc(dbp->dbenv,
00656                     bytesgot + bytes, 0, buf)) != 0)
00657                         break;
00658 
00659                 dest = (u_int8_t *)*buf + bytesgot;
00660                 bytesgot += bytes;
00661 
00662                 memcpy(dest, src, bytes);
00663 
00664                 pgno = NEXT_PGNO(h);
00665                 /* Not much we can do here--we don't want to quit. */
00666                 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
00667                         err_ret = ret;
00668         }
00669 
00670         if (ret == 0) {
00671                 dbt->size = bytesgot;
00672                 dbt->data = *buf;
00673         }
00674 
00675         return ((err_ret != 0 && ret == 0) ? err_ret : ret);
00676 }

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