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

db_reclaim.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_reclaim.c,v 12.2 2005/06/16 20:21:14 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <string.h>
00015 #endif
00016 
00017 #include "db_int.h"
00018 #include "dbinc/db_page.h"
00019 #include "dbinc/db_shash.h"
00020 #include "dbinc/btree.h"
00021 #include "dbinc/mp.h"
00022 
00023 /*
00024  * __db_traverse_big
00025  *      Traverse a chain of overflow pages and call the callback routine
00026  * on each one.  The calling convention for the callback is:
00027  *      callback(dbp, page, cookie, did_put),
00028  * where did_put is a return value indicating if the page in question has
00029  * already been returned to the mpool.
00030  *
00031  * PUBLIC: int __db_traverse_big __P((DB *,
00032  * PUBLIC:     db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *));
00033  */
00034 int
00035 __db_traverse_big(dbp, pgno, callback, cookie)
00036         DB *dbp;
00037         db_pgno_t pgno;
00038         int (*callback) __P((DB *, PAGE *, void *, int *));
00039         void *cookie;
00040 {
00041         DB_MPOOLFILE *mpf;
00042         PAGE *p;
00043         int did_put, ret;
00044 
00045         mpf = dbp->mpf;
00046 
00047         do {
00048                 did_put = 0;
00049                 if ((ret = __memp_fget(mpf, &pgno, 0, &p)) != 0)
00050                         return (ret);
00051                 /*
00052                  * If we are freeing pages only process the overflow
00053                  * chain if the head of the chain has a refcount of 1.
00054                  */
00055                 pgno = NEXT_PGNO(p);
00056                 if (callback == __db_truncate_callback && OV_REF(p) != 1)
00057                         pgno = PGNO_INVALID;
00058                 if ((ret = callback(dbp, p, cookie, &did_put)) == 0 &&
00059                     !did_put)
00060                         ret = __memp_fput(mpf, p, 0);
00061         } while (ret == 0 && pgno != PGNO_INVALID);
00062 
00063         return (ret);
00064 }
00065 
00066 /*
00067  * __db_reclaim_callback
00068  * This is the callback routine used during a delete of a subdatabase.
00069  * we are traversing a btree or hash table and trying to free all the
00070  * pages.  Since they share common code for duplicates and overflow
00071  * items, we traverse them identically and use this routine to do the
00072  * actual free.  The reason that this is callback is because hash uses
00073  * the same traversal code for statistics gathering.
00074  *
00075  * PUBLIC: int __db_reclaim_callback __P((DB *, PAGE *, void *, int *));
00076  */
00077 int
00078 __db_reclaim_callback(dbp, p, cookie, putp)
00079         DB *dbp;
00080         PAGE *p;
00081         void *cookie;
00082         int *putp;
00083 {
00084         int ret;
00085 
00086         /*
00087          * We don't want to log the free of the root with the subdb.
00088          * If we abort then the subdb may not be openable to undo
00089          * the free.
00090          */
00091 
00092         if ((dbp->type == DB_BTREE || dbp->type == DB_RECNO) &&
00093             PGNO(p) == ((BTREE *)dbp->bt_internal)->bt_root)
00094                 return (0);
00095         if ((ret = __db_free(cookie, p)) != 0)
00096                 return (ret);
00097         *putp = 1;
00098 
00099         return (0);
00100 }
00101 
00102 /*
00103  * __db_truncate_callback
00104  * This is the callback routine used during a truncate.
00105  * we are traversing a btree or hash table and trying to free all the
00106  * pages.
00107  *
00108  * PUBLIC: int __db_truncate_callback __P((DB *, PAGE *, void *, int *));
00109  */
00110 int
00111 __db_truncate_callback(dbp, p, cookie, putp)
00112         DB *dbp;
00113         PAGE *p;
00114         void *cookie;
00115         int *putp;
00116 {
00117         DB_MPOOLFILE *mpf;
00118         DBT ddbt, ldbt;
00119         db_indx_t indx, len, off, tlen, top;
00120         db_trunc_param *param;
00121         u_int8_t *hk, type;
00122         int ret;
00123 
00124         top = NUM_ENT(p);
00125         mpf = dbp->mpf;
00126         param = cookie;
00127         *putp = 1;
00128 
00129         switch (TYPE(p)) {
00130         case P_LBTREE:
00131                 /* Skip for off-page duplicates and deleted items. */
00132                 for (indx = 0; indx < top; indx += P_INDX) {
00133                         type = GET_BKEYDATA(dbp, p, indx + O_INDX)->type;
00134                         if (!B_DISSET(type) && B_TYPE(type) != B_DUPLICATE)
00135                                 ++param->count;
00136                 }
00137                 /* FALLTHROUGH */
00138         case P_IBTREE:
00139         case P_IRECNO:
00140         case P_INVALID:
00141                 if (dbp->type != DB_HASH &&
00142                     ((BTREE *)dbp->bt_internal)->bt_root == PGNO(p)) {
00143                         type = dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE;
00144                         goto reinit;
00145                 }
00146                 break;
00147         case P_OVERFLOW:
00148                 if (DBC_LOGGING(param->dbc)) {
00149                         if ((ret = __db_ovref_log(dbp, param->dbc->txn,
00150                             &LSN(p), 0, p->pgno, -1, &LSN(p))) != 0)
00151                                 return (ret);
00152                 } else
00153                         LSN_NOT_LOGGED(LSN(p));
00154                 if (--OV_REF(p) != 0)
00155                         *putp = 0;
00156                 break;
00157         case P_LRECNO:
00158                 for (indx = 0; indx < top; indx += O_INDX) {
00159                         type = GET_BKEYDATA(dbp, p, indx)->type;
00160                         if (!B_DISSET(type))
00161                                 ++param->count;
00162                 }
00163 
00164                 if (((BTREE *)dbp->bt_internal)->bt_root == PGNO(p)) {
00165                         type = P_LRECNO;
00166                         goto reinit;
00167                 }
00168                 break;
00169         case P_LDUP:
00170                 /* Correct for deleted items. */
00171                 for (indx = 0; indx < top; indx += O_INDX)
00172                         if (!B_DISSET(GET_BKEYDATA(dbp, p, indx)->type))
00173                                 ++param->count;
00174 
00175                 break;
00176         case P_HASH:
00177                 /* Correct for on-page duplicates and deleted items. */
00178                 for (indx = 0; indx < top; indx += P_INDX) {
00179                         switch (*H_PAIRDATA(dbp, p, indx)) {
00180                         case H_OFFDUP:
00181                                 break;
00182                         case H_OFFPAGE:
00183                         case H_KEYDATA:
00184                                 ++param->count;
00185                                 break;
00186                         case H_DUPLICATE:
00187                                 tlen = LEN_HDATA(dbp, p, 0, indx);
00188                                 hk = H_PAIRDATA(dbp, p, indx);
00189                                 for (off = 0; off < tlen;
00190                                     off += len + 2 * sizeof(db_indx_t)) {
00191                                         ++param->count;
00192                                         memcpy(&len,
00193                                             HKEYDATA_DATA(hk)
00194                                             + off, sizeof(db_indx_t));
00195                                 }
00196                                 break;
00197                         default:
00198                                 return (__db_pgfmt(dbp->dbenv, p->pgno));
00199                         }
00200                 }
00201                 /* Don't free the head of the bucket. */
00202                 if (PREV_PGNO(p) == PGNO_INVALID) {
00203                         type = P_HASH;
00204 
00205 reinit:                 *putp = 0;
00206                         if (DBC_LOGGING(param->dbc)) {
00207                                 memset(&ldbt, 0, sizeof(ldbt));
00208                                 memset(&ddbt, 0, sizeof(ddbt));
00209                                 ldbt.data = p;
00210                                 ldbt.size = P_OVERHEAD(dbp);
00211                                 ldbt.size += p->entries * sizeof(db_indx_t);
00212                                 ddbt.data = (u_int8_t *)p + HOFFSET(p);
00213                                 ddbt.size = dbp->pgsize - HOFFSET(p);
00214                                 if ((ret = __db_pg_init_log(dbp,
00215                                     param->dbc->txn, &LSN(p), 0,
00216                                     p->pgno, &ldbt, &ddbt)) != 0)
00217                                         return (ret);
00218                         } else
00219                                 LSN_NOT_LOGGED(LSN(p));
00220 
00221                         P_INIT(p, dbp->pgsize, PGNO(p), PGNO_INVALID,
00222                             PGNO_INVALID, type == P_HASH ? 0 : 1, type);
00223                 }
00224                 break;
00225         default:
00226                 return (__db_pgfmt(dbp->dbenv, p->pgno));
00227         }
00228 
00229         if (*putp == 1) {
00230                 if ((ret = __db_free(param->dbc, p)) != 0)
00231                         return (ret);
00232         } else {
00233                 if ((ret = __memp_fput(mpf, p, DB_MPOOL_DIRTY)) != 0)
00234                         return (ret);
00235                 *putp = 1;
00236         }
00237 
00238         return (0);
00239 }

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