db

hash_rec.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) 1995, 1996
00009  * Margo Seltzer. All rights reserved.
00010  */
00011 /*
00012  * Copyright (c) 1995, 1996
00013  * The President and Fellows of Harvard University. All rights reserved.
00014  *
00015  * This code is derived from software contributed to Berkeley by
00016  * Margo Seltzer.
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: hash__rec_8c-source.html,v 1.1 2008年06月08日 10:19:37 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_shash.h"
00059 #include "btree.h"
00060 #include "hash.h"
00061 #include "lock.h"
00062 #include "log.h"
00063 #include "mp.h"
00064 
00065 static int __ham_alloc_pages __P((DB *, __ham_groupalloc_args *));
00066 static int __ham_free_pages __P((DB *, DBMETA *, __ham_groupalloc_args *));
00067 
00068 /*
00069  * CDB___ham_insdel_recover --
00070  *
00071  * PUBLIC: int CDB___ham_insdel_recover
00072  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00073  */
00074 int
00075 CDB___ham_insdel_recover(dbenv, dbtp, lsnp, op, info)
00076 DB_ENV *dbenv;
00077 DBT *dbtp;
00078 DB_LSN *lsnp;
00079 db_recops op;
00080 void *info;
00081 {
00082 __ham_insdel_args *argp;
00083 DB *file_dbp;
00084 DBC *dbc;
00085 DB_MPOOLFILE *mpf;
00086 PAGE *pagep;
00087 u_int32_t opcode;
00088 int cmp_n, cmp_p, getmeta, ret, type;
00089 
00090 COMPQUIET(info, NULL);
00091 
00092 getmeta = 0;
00093 REC_PRINT(CDB___ham_insdel_print);
00094 REC_INTRO(CDB___ham_insdel_read, 1);
00095 
00096 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00097 if (DB_UNDO(op)) {
00098 /*
00099  * We are undoing and the page doesn't exist. That
00100  * is equivalent to having a pagelsn of 0, so we
00101  * would not have to undo anything. In this case,
00102  * don't bother creating a page.
00103  */
00104 goto done;
00105 } else if ((ret = CDB_memp_fget(mpf, &argp->pgno,
00106 DB_MPOOL_CREATE, &pagep)) != 0)
00107 goto out;
00108 }
00109 
00110 if ((ret = CDB___ham_get_meta(dbc)) != 0)
00111 goto out;
00112 getmeta = 1;
00113 
00114 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00115 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00116 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00117 /*
00118  * Two possible things going on:
00119  * redo a delete/undo a put: delete the item from the page.
00120  * redo a put/undo a delete: add the item to the page.
00121  * If we are undoing a delete, then the information logged is the
00122  * entire entry off the page, not just the data of a dbt. In
00123  * this case, we want to copy it back onto the page verbatim.
00124  * We do this by calling __putitem with the type H_OFFPAGE instead
00125  * of H_KEYDATA.
00126  */
00127 opcode = OPCODE_OF(argp->opcode);
00128 
00129 if ((opcode == DELPAIR && cmp_n == 0 && DB_UNDO(op)) ||
00130 (opcode == PUTPAIR && cmp_p == 0 && DB_REDO(op))) {
00131 /*
00132  * Need to redo a PUT or undo a delete. If we are undoing a
00133  * delete, we've got to restore the item back to its original
00134  * position. That's a royal pain in the butt (because we do
00135  * not store item lengths on the page), but there's no choice.
00136  */
00137 if (opcode != DELPAIR ||
00138 argp->ndx == (u_int32_t)NUM_ENT(pagep)) {
00139 CDB___ham_putitem(pagep, &argp->key,
00140 DB_UNDO(op) || PAIR_ISKEYBIG(argp->opcode) ?
00141 H_OFFPAGE : H_KEYDATA);
00142 
00143 if (PAIR_ISDATADUP(argp->opcode))
00144 type = H_DUPLICATE;
00145 else if (DB_UNDO(op) || PAIR_ISDATABIG(argp->opcode))
00146 type = H_OFFPAGE;
00147 else
00148 type = H_KEYDATA;
00149 CDB___ham_putitem(pagep, &argp->data, type);
00150 } else
00151 (void) CDB___ham_reputpair(pagep, file_dbp->pgsize,
00152 argp->ndx, &argp->key, &argp->data);
00153 
00154 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00155 if ((ret = CDB___ham_put_page(file_dbp, pagep, 1)) != 0)
00156 goto out;
00157 
00158 } else if ((opcode == DELPAIR && cmp_p == 0 && DB_REDO(op))
00159 || (opcode == PUTPAIR && cmp_n == 0 && DB_UNDO(op))) {
00160 /* Need to undo a put or redo a delete. */
00161 CDB___ham_dpair(file_dbp, pagep, argp->ndx);
00162 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00163 if ((ret = CDB___ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
00164 goto out;
00165 } else
00166 if ((ret = CDB___ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
00167 goto out;
00168 
00169 /* Return the previous LSN. */
00170 done: *lsnp = argp->prev_lsn;
00171 ret = 0;
00172 
00173 out: if (getmeta)
00174 (void)CDB___ham_release_meta(dbc);
00175 REC_CLOSE;
00176 }
00177 
00178 /*
00179  * CDB___ham_newpage_recover --
00180  * This log message is used when we add/remove overflow pages. This
00181  * message takes care of the pointer chains, not the data on the pages.
00182  *
00183  * PUBLIC: int CDB___ham_newpage_recover
00184  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00185  */
00186 int
00187 CDB___ham_newpage_recover(dbenv, dbtp, lsnp, op, info)
00188 DB_ENV *dbenv;
00189 DBT *dbtp;
00190 DB_LSN *lsnp;
00191 db_recops op;
00192 void *info;
00193 {
00194 __ham_newpage_args *argp;
00195 DB *file_dbp;
00196 DBC *dbc;
00197 DB_MPOOLFILE *mpf;
00198 PAGE *pagep;
00199 int cmp_n, cmp_p, change, getmeta, ret;
00200 
00201 COMPQUIET(info, NULL);
00202 
00203 getmeta = 0;
00204 REC_PRINT(CDB___ham_newpage_print);
00205 REC_INTRO(CDB___ham_newpage_read, 1);
00206 
00207 if ((ret = CDB_memp_fget(mpf, &argp->new_pgno, 0, &pagep)) != 0) {
00208 if (DB_UNDO(op)) {
00209 /*
00210  * We are undoing and the page doesn't exist. That
00211  * is equivalent to having a pagelsn of 0, so we
00212  * would not have to undo anything. In this case,
00213  * don't bother creating a page.
00214  */
00215 ret = 0;
00216 goto ppage;
00217 } else if ((ret = CDB_memp_fget(mpf, &argp->new_pgno,
00218 DB_MPOOL_CREATE, &pagep)) != 0)
00219 goto out;
00220 }
00221 
00222 if ((ret = CDB___ham_get_meta(dbc)) != 0)
00223 goto out;
00224 getmeta = 1;
00225 
00226 /*
00227  * There are potentially three pages we need to check: the one
00228  * that we created/deleted, the one before it and the one after
00229  * it.
00230  */
00231 
00232 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00233 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00234 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00235 change = 0;
00236 
00237 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
00238 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
00239 /* Redo a create new page or undo a delete new page. */
00240 P_INIT(pagep, file_dbp->pgsize, argp->new_pgno,
00241 argp->prev_pgno, argp->next_pgno, 0, P_HASH, 0);
00242 change = 1;
00243 } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
00244 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
00245 /*
00246  * Redo a delete or undo a create new page. All we
00247  * really need to do is change the LSN.
00248  */
00249 change = 1;
00250 }
00251 
00252 if (!change) {
00253 if ((ret = CDB___ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
00254 goto out;
00255 } else {
00256 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
00257 if ((ret = CDB___ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
00258 goto out;
00259 }
00260 
00261 /* Now do the prev page. */
00262 ppage: if (argp->prev_pgno != PGNO_INVALID) {
00263 if ((ret = CDB_memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0) {
00264 if (DB_UNDO(op)) {
00265 /*
00266  * We are undoing and the page doesn't exist.
00267  * That is equivalent to having a pagelsn of 0,
00268  * so we would not have to undo anything. In
00269  * this case, don't bother creating a page.
00270  */
00271 ret = 0;
00272 goto npage;
00273 } else if ((ret =
00274 CDB_memp_fget(mpf, &argp->prev_pgno,
00275 DB_MPOOL_CREATE, &pagep)) != 0)
00276 goto out;
00277 }
00278 
00279 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00280 cmp_p = CDB_log_compare(&LSN(pagep), &argp->prevlsn);
00281 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn);
00282 change = 0;
00283 
00284 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
00285 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
00286 /* Redo a create new page or undo a delete new page. */
00287 pagep->next_pgno = argp->new_pgno;
00288 change = 1;
00289 } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
00290 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
00291 /* Redo a delete or undo a create new page. */
00292 pagep->next_pgno = argp->next_pgno;
00293 change = 1;
00294 }
00295 
00296 if (!change) {
00297 if ((ret =
00298 CDB___ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
00299 goto out;
00300 } else {
00301 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn;
00302 if ((ret =
00303 CDB___ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
00304 goto out;
00305 }
00306 }
00307 
00308 /* Now time to do the next page */
00309 npage: if (argp->next_pgno != PGNO_INVALID) {
00310 if ((ret = CDB_memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
00311 if (DB_UNDO(op)) {
00312 /*
00313  * We are undoing and the page doesn't exist.
00314  * That is equivalent to having a pagelsn of 0,
00315  * so we would not have to undo anything. In
00316  * this case, don't bother creating a page.
00317  */
00318 goto done;
00319 } else if ((ret =
00320 CDB_memp_fget(mpf, &argp->next_pgno,
00321 DB_MPOOL_CREATE, &pagep)) != 0)
00322 goto out;
00323 }
00324 
00325 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00326 cmp_p = CDB_log_compare(&LSN(pagep), &argp->nextlsn);
00327 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
00328 change = 0;
00329 
00330 if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
00331 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
00332 /* Redo a create new page or undo a delete new page. */
00333 pagep->prev_pgno = argp->new_pgno;
00334 change = 1;
00335 } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
00336 (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
00337 /* Redo a delete or undo a create new page. */
00338 pagep->prev_pgno = argp->prev_pgno;
00339 change = 1;
00340 }
00341 
00342 if (!change) {
00343 if ((ret =
00344 CDB___ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
00345 goto out;
00346 } else {
00347 LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn;
00348 if ((ret =
00349 CDB___ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
00350 goto out;
00351 }
00352 }
00353 done: *lsnp = argp->prev_lsn;
00354 ret = 0;
00355 
00356 out: if (getmeta)
00357 (void)CDB___ham_release_meta(dbc);
00358 REC_CLOSE;
00359 }
00360 
00361 /*
00362  * CDB___ham_replace_recover --
00363  * This log message refers to partial puts that are local to a single
00364  * page. You can think of them as special cases of the more general
00365  * insdel log message.
00366  *
00367  * PUBLIC: int CDB___ham_replace_recover
00368  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00369  */
00370 int
00371 CDB___ham_replace_recover(dbenv, dbtp, lsnp, op, info)
00372 DB_ENV *dbenv;
00373 DBT *dbtp;
00374 DB_LSN *lsnp;
00375 db_recops op;
00376 void *info;
00377 {
00378 __ham_replace_args *argp;
00379 DB *file_dbp;
00380 DBC *dbc;
00381 DB_MPOOLFILE *mpf;
00382 DBT dbt;
00383 PAGE *pagep;
00384 int32_t grow;
00385 int change, cmp_n, cmp_p, getmeta, ret;
00386 u_int8_t *hk;
00387 
00388 COMPQUIET(info, NULL);
00389 
00390 getmeta = 0;
00391 REC_PRINT(CDB___ham_replace_print);
00392 REC_INTRO(CDB___ham_replace_read, 1);
00393 
00394 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00395 if (DB_UNDO(op)) {
00396 /*
00397  * We are undoing and the page doesn't exist. That
00398  * is equivalent to having a pagelsn of 0, so we
00399  * would not have to undo anything. In this case,
00400  * don't bother creating a page.
00401  */
00402 goto done;
00403 } else if ((ret = CDB_memp_fget(mpf, &argp->pgno,
00404 DB_MPOOL_CREATE, &pagep)) != 0)
00405 goto out;
00406 }
00407 
00408 if ((ret = CDB___ham_get_meta(dbc)) != 0)
00409 goto out;
00410 getmeta = 1;
00411 
00412 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00413 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00414 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00415 
00416 memset(&dbt, 0, sizeof(dbt));
00417 if (cmp_p == 0 && DB_REDO(op)) {
00418 change = 1;
00419 /* Reapply the change as specified. */
00420 dbt.data = argp->newitem.data;
00421 dbt.size = argp->newitem.size;
00422 grow = argp->newitem.size - argp->olditem.size;
00423 LSN(pagep) = *lsnp;
00424 } else if (cmp_n == 0 && DB_UNDO(op)) {
00425 change = 1;
00426 /* Undo the already applied change. */
00427 dbt.data = argp->olditem.data;
00428 dbt.size = argp->olditem.size;
00429 grow = argp->olditem.size - argp->newitem.size;
00430 LSN(pagep) = argp->pagelsn;
00431 } else {
00432 change = 0;
00433 grow = 0;
00434 }
00435 
00436 if (change) {
00437 CDB___ham_onpage_replace(pagep,
00438 file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt);
00439 if (argp->makedup) {
00440 hk = P_ENTRY(pagep, argp->ndx);
00441 if (DB_REDO(op))
00442 HPAGE_PTYPE(hk) = H_DUPLICATE;
00443 else
00444 HPAGE_PTYPE(hk) = H_KEYDATA;
00445 }
00446 }
00447 
00448 if ((ret = CDB___ham_put_page(file_dbp, pagep, change)) != 0)
00449 goto out;
00450 
00451 done: *lsnp = argp->prev_lsn;
00452 ret = 0;
00453 
00454 out: if (getmeta)
00455 (void)CDB___ham_release_meta(dbc);
00456 REC_CLOSE;
00457 }
00458 
00459 /*
00460  * CDB___ham_splitdata_recover --
00461  *
00462  * PUBLIC: int CDB___ham_splitdata_recover
00463  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00464  */
00465 int
00466 CDB___ham_splitdata_recover(dbenv, dbtp, lsnp, op, info)
00467 DB_ENV *dbenv;
00468 DBT *dbtp;
00469 DB_LSN *lsnp;
00470 db_recops op;
00471 void *info;
00472 {
00473 __ham_splitdata_args *argp;
00474 DB *file_dbp;
00475 DBC *dbc;
00476 DB_MPOOLFILE *mpf;
00477 PAGE *pagep;
00478 int change, cmp_n, cmp_p, getmeta, ret;
00479 
00480 COMPQUIET(info, NULL);
00481 
00482 getmeta = 0;
00483 REC_PRINT(CDB___ham_splitdata_print);
00484 REC_INTRO(CDB___ham_splitdata_read, 1);
00485 
00486 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00487 if (DB_UNDO(op)) {
00488 /*
00489  * We are undoing and the page doesn't exist. That
00490  * is equivalent to having a pagelsn of 0, so we
00491  * would not have to undo anything. In this case,
00492  * don't bother creating a page.
00493  */
00494 goto done;
00495 } else if ((ret = CDB_memp_fget(mpf, &argp->pgno,
00496 DB_MPOOL_CREATE, &pagep)) != 0)
00497 goto out;
00498 }
00499 
00500 if ((ret = CDB___ham_get_meta(dbc)) != 0)
00501 goto out;
00502 getmeta = 1;
00503 
00504 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00505 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00506 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00507 
00508 /*
00509  * There are two types of log messages here, one for the old page
00510  * and one for the new pages created. The original image in the
00511  * SPLITOLD record is used for undo. The image in the SPLITNEW
00512  * is used for redo. We should never have a case where there is
00513  * a redo operation and the SPLITOLD record is on disk, but not
00514  * the SPLITNEW record. Therefore, we only have work to do when
00515  * redo NEW messages and undo OLD messages, but we have to update
00516  * LSNs in both cases.
00517  */
00518 change = 0;
00519 if (cmp_p == 0 && DB_REDO(op)) {
00520 if (argp->opcode == SPLITNEW)
00521 /* Need to redo the split described. */
00522 memcpy(pagep, argp->pageimage.data,
00523 argp->pageimage.size);
00524 LSN(pagep) = *lsnp;
00525 change = 1;
00526 } else if (cmp_n == 0 && DB_UNDO(op)) {
00527 if (argp->opcode == SPLITOLD) {
00528 /* Put back the old image. */
00529 memcpy(pagep, argp->pageimage.data,
00530 argp->pageimage.size);
00531 } else
00532 P_INIT(pagep, file_dbp->pgsize, argp->pgno,
00533 PGNO_INVALID, PGNO_INVALID, 0, P_HASH, 0);
00534 LSN(pagep) = argp->pagelsn;
00535 change = 1;
00536 }
00537 if ((ret = CDB___ham_put_page(file_dbp, pagep, change)) != 0)
00538 goto out;
00539 
00540 done: *lsnp = argp->prev_lsn;
00541 ret = 0;
00542 
00543 out: if (getmeta)
00544 (void)CDB___ham_release_meta(dbc);
00545 REC_CLOSE;
00546 }
00547 
00548 /*
00549  * CDB___ham_copypage_recover --
00550  * Recovery function for copypage.
00551  *
00552  * PUBLIC: int CDB___ham_copypage_recover
00553  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00554  */
00555 int
00556 CDB___ham_copypage_recover(dbenv, dbtp, lsnp, op, info)
00557 DB_ENV *dbenv;
00558 DBT *dbtp;
00559 DB_LSN *lsnp;
00560 db_recops op;
00561 void *info;
00562 {
00563 __ham_copypage_args *argp;
00564 DB *file_dbp;
00565 DBC *dbc;
00566 DB_MPOOLFILE *mpf;
00567 PAGE *pagep;
00568 int cmp_n, cmp_p, getmeta, modified, ret;
00569 
00570 COMPQUIET(info, NULL);
00571 
00572 getmeta = 0;
00573 REC_PRINT(CDB___ham_copypage_print);
00574 REC_INTRO(CDB___ham_copypage_read, 1);
00575 
00576 if ((ret = CDB___ham_get_meta(dbc)) != 0)
00577 goto out;
00578 getmeta = 1;
00579 modified = 0;
00580 
00581 /* This is the bucket page. */
00582 if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00583 if (DB_UNDO(op)) {
00584 /*
00585  * We are undoing and the page doesn't exist. That
00586  * is equivalent to having a pagelsn of 0, so we
00587  * would not have to undo anything. In this case,
00588  * don't bother creating a page.
00589  */
00590 ret = 0;
00591 goto donext;
00592 } else if ((ret = CDB_memp_fget(mpf, &argp->pgno,
00593 DB_MPOOL_CREATE, &pagep)) != 0)
00594 goto out;
00595 }
00596 
00597 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00598 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00599 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00600 
00601 if (cmp_p == 0 && DB_REDO(op)) {
00602 /* Need to redo update described. */
00603 memcpy(pagep, argp->page.data, argp->page.size);
00604 LSN(pagep) = *lsnp;
00605 modified = 1;
00606 } else if (cmp_n == 0 && DB_UNDO(op)) {
00607 /* Need to undo update described. */
00608 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
00609 argp->next_pgno, 0, P_HASH, 0);
00610 LSN(pagep) = argp->pagelsn;
00611 modified = 1;
00612 }
00613 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00614 goto out;
00615 
00616 donext: /* Now fix up the "next" page. */
00617 if ((ret = CDB_memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
00618 if (DB_UNDO(op)) {
00619 /*
00620  * We are undoing and the page doesn't exist. That
00621  * is equivalent to having a pagelsn of 0, so we
00622  * would not have to undo anything. In this case,
00623  * don't bother creating a page.
00624  */
00625 ret = 0;
00626 goto do_nn;
00627 } else if ((ret = CDB_memp_fget(mpf, &argp->next_pgno,
00628 DB_MPOOL_CREATE, &pagep)) != 0)
00629 goto out;
00630 }
00631 
00632 modified = 0;
00633 /* For REDO just update the LSN. For UNDO copy page back. */
00634 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00635 cmp_p = CDB_log_compare(&LSN(pagep), &argp->nextlsn);
00636 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
00637 if (cmp_p == 0 && DB_REDO(op)) {
00638 LSN(pagep) = *lsnp;
00639 modified = 1;
00640 } else if (cmp_n == 0 && DB_UNDO(op)) {
00641 /* Need to undo update described. */
00642 memcpy(pagep, argp->page.data, argp->page.size);
00643 modified = 1;
00644 }
00645 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00646 goto out;
00647 
00648 /* Now fix up the next's next page. */
00649 do_nn: if (argp->nnext_pgno == PGNO_INVALID)
00650 goto done;
00651 
00652 if ((ret = CDB_memp_fget(mpf, &argp->nnext_pgno, 0, &pagep)) != 0) {
00653 if (DB_UNDO(op)) {
00654 /*
00655  * We are undoing and the page doesn't exist. That
00656  * is equivalent to having a pagelsn of 0, so we
00657  * would not have to undo anything. In this case,
00658  * don't bother creating a page.
00659  */
00660 goto done;
00661 } else if ((ret = CDB_memp_fget(mpf, &argp->nnext_pgno,
00662 DB_MPOOL_CREATE, &pagep)) != 0)
00663 goto out;
00664 }
00665 
00666 modified = 0;
00667 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00668 cmp_p = CDB_log_compare(&LSN(pagep), &argp->nnextlsn);
00669 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nnextlsn);
00670 
00671 if (cmp_p == 0 && DB_REDO(op)) {
00672 /* Need to redo update described. */
00673 PREV_PGNO(pagep) = argp->pgno;
00674 LSN(pagep) = *lsnp;
00675 modified = 1;
00676 } else if (cmp_n == 0 && DB_UNDO(op)) {
00677 /* Need to undo update described. */
00678 PREV_PGNO(pagep) = argp->next_pgno;
00679 LSN(pagep) = argp->nnextlsn;
00680 modified = 1;
00681 }
00682 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00683 goto out;
00684 
00685 done: *lsnp = argp->prev_lsn;
00686 ret = 0;
00687 
00688 out: if (getmeta)
00689 (void)CDB___ham_release_meta(dbc);
00690 REC_CLOSE;
00691 }
00692 
00693 /*
00694  * CDB___ham_metagroup_recover --
00695  * Recovery function for metagroup.
00696  *
00697  * PUBLIC: int CDB___ham_metagroup_recover
00698  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00699  */
00700 int
00701 CDB___ham_metagroup_recover(dbenv, dbtp, lsnp, op, info)
00702 DB_ENV *dbenv;
00703 DBT *dbtp;
00704 DB_LSN *lsnp;
00705 db_recops op;
00706 void *info;
00707 {
00708 __ham_metagroup_args *argp;
00709 HASH_CURSOR *hcp;
00710 DB *file_dbp;
00711 DBC *dbc;
00712 DB_MPOOLFILE *mpf;
00713 PAGE *pagep;
00714 db_pgno_t last_pgno;
00715 int cmp_n, cmp_p, groupgrow, modified, ret;
00716 
00717 COMPQUIET(info, NULL);
00718 REC_PRINT(CDB___ham_metagroup_print);
00719 REC_INTRO(CDB___ham_metagroup_read, 1);
00720 
00721 /*
00722  * This logs the virtual create of pages pgno to pgno + bucket
00723  * Since the mpool page-allocation is not really able to be
00724  * transaction protected, we can never undo it. Even in an abort,
00725  * we have to allocate these pages to the hash table.
00726  * The log record contains:
00727  * bucket: new bucket being allocated.
00728  * pgno: page number of the new bucket.
00729  * if bucket is a power of 2, then we allocated a whole batch of
00730  * pages; if it's not, then we simply allocated one new page.
00731  */
00732 groupgrow =
00733 (u_int32_t)(1 << CDB___db_log2(argp->bucket + 1)) == argp->bucket + 1;
00734 
00735 last_pgno = argp->pgno;
00736 if (groupgrow)
00737 /* Read the last page. */
00738 last_pgno += argp->bucket;
00739 
00740 if ((ret = CDB_memp_fget(mpf, &last_pgno, DB_MPOOL_CREATE, &pagep)) != 0)
00741 goto out;
00742 
00743 modified = 0;
00744 cmp_n = CDB_log_compare(lsnp, &LSN(pagep));
00745 cmp_p = CDB_log_compare(&LSN(pagep), &argp->pagelsn);
00746 CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
00747 
00748 if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && DB_UNDO(op))) {
00749 /*
00750  * We need to make sure that we redo the allocation of the
00751  * pages.
00752  */
00753 if (DB_REDO(op))
00754 pagep->lsn = *lsnp;
00755 else
00756 pagep->lsn = argp->pagelsn;
00757 modified = 1;
00758 }
00759 if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00760 goto out;
00761 
00762 /* Now we have to update the meta-data page. */
00763 hcp = (HASH_CURSOR *)dbc->internal;
00764 if ((ret = CDB___ham_get_meta(dbc)) != 0)
00765 goto out;
00766 cmp_n = CDB_log_compare(lsnp, &hcp->hdr->dbmeta.lsn);
00767 cmp_p = CDB_log_compare(&hcp->hdr->dbmeta.lsn, &argp->metalsn);
00768 CHECK_LSN(op, cmp_p, &hcp->hdr->dbmeta.lsn, &argp->metalsn);
00769 if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && DB_UNDO(op))) {
00770 if (DB_REDO(op)) {
00771 /* Redo the actual updating of bucket counts. */
00772 ++hcp->hdr->max_bucket;
00773 if (groupgrow) {
00774 hcp->hdr->low_mask = hcp->hdr->high_mask;
00775 hcp->hdr->high_mask =
00776 (argp->bucket + 1) | hcp->hdr->low_mask;
00777 }
00778 hcp->hdr->dbmeta.lsn = *lsnp;
00779 } else {
00780 /* Undo the actual updating of bucket counts. */
00781 --hcp->hdr->max_bucket;
00782 if (groupgrow) {
00783 hcp->hdr->high_mask = hcp->hdr->low_mask;
00784 hcp->hdr->low_mask = hcp->hdr->high_mask >> 1;
00785 }
00786 hcp->hdr->dbmeta.lsn = argp->metalsn;
00787 }
00788 if (groupgrow &&
00789 hcp->hdr->spares[CDB___db_log2(argp->bucket + 1) + 1] ==
00790 PGNO_INVALID)
00791 hcp->hdr->spares[CDB___db_log2(argp->bucket + 1) + 1] =
00792 argp->pgno - argp->bucket - 1;
00793 F_SET(hcp, H_DIRTY);
00794 }
00795 if ((ret = CDB___ham_release_meta(dbc)) != 0)
00796 goto out;
00797 
00798 done: *lsnp = argp->prev_lsn;
00799 ret = 0;
00800 
00801 out: REC_CLOSE;
00802 }
00803 
00804 /*
00805  * CDB___ham_groupalloc_recover --
00806  * Recover the batch creation of a set of pages for a new database.
00807  *
00808  * PUBLIC: int CDB___ham_groupalloc_recover
00809  * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00810  */
00811 int
00812 CDB___ham_groupalloc_recover(dbenv, dbtp, lsnp, op, info)
00813 DB_ENV *dbenv;
00814 DBT *dbtp;
00815 DB_LSN *lsnp;
00816 db_recops op;
00817 void *info;
00818 {
00819 __ham_groupalloc_args *argp;
00820 DBMETA *mmeta;
00821 DB_MPOOLFILE *mpf;
00822 DB *file_dbp;
00823 DBC *dbc;
00824 db_pgno_t pgno;
00825 int cmp_n, cmp_p, modified, ret;
00826 
00827 modified = 0;
00828 COMPQUIET(info, NULL);
00829 REC_PRINT(CDB___ham_groupalloc_print);
00830 REC_INTRO(CDB___ham_groupalloc_read, 0);
00831 
00832 pgno = PGNO_BASE_MD;
00833 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &mmeta)) != 0) {
00834 if (DB_REDO(op)) {
00835 /* Page should have existed. */
00836 (void)CDB___db_pgerr(file_dbp, pgno);
00837 goto out;
00838 } else {
00839 ret = 0;
00840 goto done;
00841 }
00842 }
00843 
00844 cmp_n = CDB_log_compare(lsnp, &mmeta->alloc_lsn);
00845 cmp_p = CDB_log_compare(&mmeta->alloc_lsn, &argp->alloc_lsn);
00846 CHECK_LSN(op, cmp_p, &mmeta->alloc_lsn, &argp->alloc_lsn);
00847 
00848 /*
00849  * Basically, we used mpool to allocate a chunk of pages.
00850  * We need to either add those to a free list (in the undo
00851  * case) or initialize them (in the redo case).
00852  *
00853  * If we are redoing and this is a hash subdatabase, it's possible
00854  * that the pages were never allocated, so we'd better check for
00855  * that and handle it here.
00856  */
00857 
00858 if (DB_REDO(op)) {
00859 if ((ret = __ham_alloc_pages(file_dbp, argp)) != 0)
00860 goto out1;
00861 if (cmp_p == 0) {
00862 mmeta->alloc_lsn = *lsnp;
00863 if (CDB_log_compare(&LSN(mmeta), &argp->meta_lsn) == 0)
00864 LSN(mmeta) = *lsnp;
00865 modified = 1;
00866 }
00867 }
00868 
00869 /*
00870  * We must determine if this is the first allocation to be
00871  * undone. If the LSN is not right, then it must be the first.
00872  * If the LSN is correct, then look to see if the pages allocated
00873  * by this log record are at the head of the list. If so then we
00874  * have previously undone this allocation and we are starting over.
00875  * If not, we have not undone this allocation and some previous
00876  * undo of an allocation has put us in the right state. We
00877  * just undo the allocation by putting the pages on the free list.
00878  */
00879 else if (DB_UNDO(op)) {
00880 if (cmp_n != 0 ||
00881 (mmeta->free >= argp->start_pgno &&
00882 mmeta->free < argp->start_pgno + argp->num))
00883 mmeta->free = argp->free;
00884 if ((ret = __ham_free_pages(file_dbp, mmeta, argp)) != 0)
00885 goto out1;
00886 mmeta->alloc_lsn = argp->alloc_lsn;
00887 if (CDB_log_compare(lsnp, &LSN(mmeta)) == 0)
00888 LSN(mmeta) = argp->meta_lsn;
00889 modified = 1;
00890 }
00891 
00892 out1: if ((ret = CDB_memp_fput(mpf, mmeta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00893 goto out;
00894 
00895 done: if (ret == 0)
00896 *lsnp = argp->prev_lsn;
00897 
00898 out: REC_CLOSE;
00899 }
00900 
00901 /*
00902  * __ham_free_pages --
00903  *
00904  * Called during abort/undo of a file create. We create new pages in the file
00905  * using the MPOOL_NEW_GROUP flag. We then log the meta-data page with a
00906  * __crdel_metasub message. If we fail we need to take those newly allocated
00907  * pages and put them on a free list. Normally this would happen in the
00908  * recovery for CDB___db_new, but that doesn't get called in this case.
00909  * We do not look at LSNs here because we are forcing the pages to their
00910  * deallocated state. If they were reallocated after this, they
00911  * will get rolled forward later.
00912  */
00913 static int
00914 __ham_free_pages(dbp, mmeta, argp)
00915 DB *dbp;
00916 DBMETA *mmeta;
00917 __ham_groupalloc_args *argp;
00918 {
00919 DB_MPOOLFILE *mpf;
00920 PAGE *pagep;
00921 u_int32_t i;
00922 db_pgno_t last_free, pgno;
00923 int ret;
00924 
00925 mpf = dbp->mpf;
00926 last_free = mmeta->free;
00927 
00928 for (i = 0; i < argp->num; i++, last_free = pgno) {
00929 pgno = argp->start_pgno + i;
00930 if ((ret =
00931 CDB_memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
00932 (void)CDB___db_pgerr(dbp, pgno);
00933 return (ret);
00934 }
00935 
00936 /* Fix up the allocated page. */
00937 P_INIT(pagep,
00938 dbp->pgsize, pgno, PGNO_INVALID, last_free, 0, P_INVALID, 0);
00939 ZERO_LSN(pagep->lsn);
00940 
00941 if ((ret = CDB_memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0)
00942 return (ret);
00943 }
00944 
00945 mmeta->free = last_free;
00946 return (0);
00947 }
00948 
00949 /*
00950  * __ham_alloc_pages --
00951  *
00952  * Called during redo of a file create. We create new pages in the file
00953  * using the MPOOL_NEW_GROUP flag. We then log the meta-data page with a
00954  * __crdel_metasub message. If we manage to crash without the newly written
00955  * pages getting to disk (I'm not sure this can happen anywhere except our
00956  * test suite?!), then we need to go through a recreate the final pages.
00957  * Hash normally has holes in its files and handles them appropriately.
00958  */
00959 static int
00960 __ham_alloc_pages(dbp, argp)
00961 DB *dbp;
00962 __ham_groupalloc_args *argp;
00963 {
00964 DB_MPOOLFILE *mpf;
00965 PAGE *pagep;
00966 db_pgno_t pgno;
00967 int ret;
00968 
00969 mpf = dbp->mpf;
00970 
00971 /* Read the last page of the allocation. */
00972 pgno = argp->start_pgno + argp->num - 1;
00973 
00974 /* If the page exists, and it has been initialized, then we're done. */
00975 if ((ret = CDB_memp_fget(mpf, &pgno, 0, &pagep)) == 0) {
00976 if ((TYPE(pagep) == P_INVALID) && IS_ZERO_LSN(pagep->lsn))
00977 goto reinit_page;
00978 if ((ret = CDB_memp_fput(mpf, pagep, 0)) != 0)
00979 return (ret);
00980 return (0);
00981 }
00982 
00983 /*
00984  * Had to create the page. On some systems (read "Windows"),
00985  * you can find random garbage on pages to which you haven't
00986  * yet written. So, we have an os layer that will do the
00987  * right thing for group allocations. We call that directly
00988  * to make sure all the pages are allocated and then continue
00989  * merrily on our way with normal recovery.
00990  */
00991 if ((ret = CDB___os_fpinit(dbp->dbenv, &mpf->fh,
00992 argp->start_pgno, argp->num, dbp->pgsize)) != 0)
00993 return (ret);
00994 
00995 if ((ret = CDB_memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
00996 (void)CDB___db_pgerr(dbp, pgno);
00997 return (ret);
00998 }
00999 
01000 reinit_page:
01001 /* Initialize the newly allocated page. */
01002 P_INIT(pagep,
01003 dbp->pgsize, pgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH, 0);
01004 ZERO_LSN(pagep->lsn);
01005 
01006 if ((ret = CDB_memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0)
01007 return (ret);
01008 
01009 return (0);
01010 }

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

AltStyle によって変換されたページ (->オリジナル) /