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 #include "config.h" 00008 00009 #ifndef lint 00010 static const char revid[] = "$Id: mp__bh_8c-source.html,v 1.1 2008年06月08日 10:20:39 sebdiaz Exp $"; 00011 #endif /* not lint */ 00012 00013 #ifndef NO_SYSTEM_INCLUDES 00014 #include <sys/types.h> 00015 00016 #include <errno.h> 00017 #include <string.h> 00018 #include <unistd.h> 00019 #endif 00020 00021 #include "db_int.h" 00022 #include "db_shash.h" 00023 #include "mp.h" 00024 #include "db_page.h" 00025 00026 #ifdef DEBUG 00027 #include "WordMonitor.h" 00028 #endif /* DEBUG */ 00029 00030 static int __memp_upgrade __P((DB_MPOOL *, DB_MPOOLFILE *, MPOOLFILE *)); 00031 00032 /* 00033 * CDB___memp_bhwrite -- 00034 * Write the page associated with a given bucket header. 00035 * 00036 * PUBLIC: int CDB___memp_bhwrite 00037 * PUBLIC: __P((DB_MPOOL *, MPOOLFILE *, BH *, int *, int *)); 00038 */ 00039 int 00040 CDB___memp_bhwrite(dbmp, mfp, bhp, restartp, wrotep) 00041 DB_MPOOL *dbmp; 00042 MPOOLFILE *mfp; 00043 BH *bhp; 00044 int *restartp, *wrotep; 00045 { 00046 DB_MPOOLFILE *dbmfp; 00047 DB_MPREG *mpreg; 00048 int incremented, ret; 00049 00050 if (restartp != NULL) 00051 *restartp = 0; 00052 if (wrotep != NULL) 00053 *wrotep = 0; 00054 incremented = 0; 00055 00056 /* 00057 * If the file has been removed or is a closed temporary file, Jump 00058 * right ahead and pretend that we've found the file we want-- the 00059 * page-write function knows how to handle the fact that we don't have 00060 * (or need!) any real file descriptor information. 00061 */ 00062 if (F_ISSET(mfp, MP_DEADFILE)) { 00063 dbmfp = NULL; 00064 goto found; 00065 } 00066 00067 /* 00068 * Walk the process' DB_MPOOLFILE list and find a file descriptor for 00069 * the file. We also check that the descriptor is open for writing. 00070 * If we find a descriptor on the file that's not open for writing, we 00071 * try and upgrade it to make it writeable. If that fails, we're done. 00072 */ 00073 MUTEX_THREAD_LOCK(dbmp->mutexp); 00074 for (dbmfp = TAILQ_FIRST(&dbmp->dbmfq); 00075 dbmfp != NULL; dbmfp = TAILQ_NEXT(dbmfp, q)) 00076 if (dbmfp->mfp == mfp) { 00077 if (F_ISSET(dbmfp, MP_READONLY) && 00078 __memp_upgrade(dbmp, dbmfp, mfp)) { 00079 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00080 return (0); 00081 } 00082 00083 /* 00084 * Increment the reference count -- see the comment in 00085 * CDB_memp_fclose(). 00086 */ 00087 ++dbmfp->ref; 00088 incremented = 1; 00089 break; 00090 } 00091 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00092 if (dbmfp != NULL) 00093 goto found; 00094 00095 /* 00096 * !!! 00097 * Don't try to attach to temporary files. There are two problems in 00098 * trying to do that. First, if we have different privileges than the 00099 * process that "owns" the temporary file, we might create the backing 00100 * disk file such that the owning process couldn't read/write its own 00101 * buffers, e.g., CDB_memp_trickle() running as root creating a file owned 00102 * as root, mode 600. Second, if the temporary file has already been 00103 * created, we don't have any way of finding out what its real name is, 00104 * and, even if we did, it was already unlinked (so that it won't be 00105 * left if the process dies horribly). This decision causes a problem, 00106 * however: if the temporary file consumes the entire buffer cache, 00107 * and the owner doesn't flush the buffers to disk, we could end up 00108 * with resource starvation, and the CDB_memp_trickle() thread couldn't do 00109 * anything about it. That's a pretty unlikely scenario, though. 00110 * 00111 * Note that we should never get here when the temporary file 00112 * in question has already been closed in another process, in which 00113 * case it should be marked MP_DEADFILE. 00114 */ 00115 if (F_ISSET(mfp, MP_TEMP)) { 00116 DB_ASSERT(!F_ISSET(mfp, MP_DEADFILE)); 00117 return (0); 00118 } 00119 00120 /* 00121 * It's not a page from a file we've opened. If the file requires 00122 * input/output processing, see if this process has ever registered 00123 * information as to how to write this type of file. If not, there's 00124 * nothing we can do. 00125 */ 00126 if (mfp->ftype != 0) { 00127 MUTEX_THREAD_LOCK(dbmp->mutexp); 00128 for (mpreg = LIST_FIRST(&dbmp->dbregq); 00129 mpreg != NULL; mpreg = LIST_NEXT(mpreg, q)) 00130 if (mpreg->ftype == mfp->ftype) 00131 break; 00132 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00133 if (mpreg == NULL) 00134 return (0); 00135 } 00136 00137 /* 00138 * Try and open the file, attaching to the underlying shared area. 00139 * Ignore any error, assume it's a permissions problem. 00140 * 00141 * XXX 00142 * There's no negative cache, so we may repeatedly try and open files 00143 * that we have previously tried (and failed) to open. 00144 */ 00145 if (CDB___memp_fopen(dbmp, mfp, R_ADDR(dbmp->reginfo, mfp->path_off), 00146 0, 0, mfp->stat.st_pagesize, 0, NULL, &dbmfp) != 0) 00147 return (0); 00148 00149 found: ret = CDB___memp_pgwrite(dbmp, dbmfp, bhp, restartp, wrotep); 00150 00151 if (incremented) { 00152 MUTEX_THREAD_LOCK(dbmp->mutexp); 00153 --dbmfp->ref; 00154 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00155 } 00156 00157 return (ret); 00158 } 00159 00160 /* 00161 * CDB___memp_pgread -- 00162 * Read a page from a file. 00163 * 00164 * PUBLIC: int CDB___memp_pgread __P((DB_MPOOLFILE *, BH *, int)); 00165 */ 00166 int 00167 CDB___memp_pgread(dbmfp, bhp, can_create) 00168 DB_MPOOLFILE *dbmfp; 00169 BH *bhp; 00170 int can_create; 00171 { 00172 DB_IO db_io; 00173 DB_ENV *dbenv; 00174 DB_MPOOL *dbmp; 00175 MPOOLFILE *mfp; 00176 size_t len, pagesize; 00177 size_t nr; 00178 int created, ret; 00179 00180 dbmp = dbmfp->dbmp; 00181 dbenv = dbmp->dbenv; 00182 mfp = dbmfp->mfp; 00183 pagesize = mfp->stat.st_pagesize; 00184 00185 F_SET(bhp, BH_LOCKED | BH_TRASH); 00186 MUTEX_LOCK(&bhp->mutex, dbenv->lockfhp); 00187 R_UNLOCK(dbenv, dbmp->reginfo); 00188 00189 /* 00190 * Temporary files may not yet have been created. We don't create 00191 * them now, we create them when the pages have to be flushed. 00192 */ 00193 nr = 0; 00194 if (F_ISSET(&dbmfp->fh, DB_FH_VALID)) { 00195 /* 00196 * Ignore read errors if we have permission to create the page. 00197 * Assume that the page doesn't exist, and that we'll create it 00198 * when we write it out. 00199 * 00200 * XXX 00201 * Theoretically, we could overwrite a page of data if it were 00202 * possible for a file to be successfully opened for reading 00203 * and then for the read to fail. Shouldn't ever happen, but 00204 * it might be worth checking to see if the offset is past the 00205 * known end-of-file. 00206 */ 00207 db_io.fhp = &dbmfp->fh; 00208 db_io.mutexp = dbmfp->mutexp; 00209 db_io.pagesize = db_io.bytes = pagesize; 00210 db_io.pgno = bhp->pgno; 00211 db_io.buf = bhp->buf; 00212 00213 if(F_ISSET(dbmfp, MP_CMPR)) { 00214 ret = CDB___memp_cmpr(dbmfp, bhp, &db_io, DB_IO_READ, &nr); 00215 } else { 00216 ret = CDB___os_io(dbenv, &db_io, DB_IO_READ, &nr); 00217 } 00218 #ifdef DEBUG 00219 if(ret == 0) { 00220 PAGE* pp = (PAGE*)db_io.buf; 00221 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_READ, 1); 00222 switch(TYPE(pp)) { 00223 case P_IBTREE: 00224 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_PAGE_IBTREE, 1); 00225 break; 00226 case P_LBTREE: 00227 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_PAGE_LBTREE, 1); 00228 break; 00229 default: 00230 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_PAGE_UNKNOWN, 1); 00231 break; 00232 } 00233 } 00234 #endif /* DEBUG */ 00235 } else 00236 ret = 0; 00237 00238 created = 0; 00239 if (nr < pagesize) { 00240 if (can_create) 00241 created = 1; 00242 else { 00243 /* 00244 * If we had a short read, ret may be 0. This may not 00245 * be an error -- in particular DB recovery processing 00246 * may request pages that have never been written to 00247 * disk, in which case we won't find the page. So, the 00248 * caller must know how to handle the error. 00249 */ 00250 if (ret == 0) 00251 ret = EIO; 00252 goto err; 00253 } 00254 } 00255 00256 /* 00257 * Clear any bytes we didn't read that need to be cleared. If we're 00258 * running in diagnostic mode, smash any bytes on the page that are 00259 * unknown quantities for the caller. 00260 */ 00261 if (nr != pagesize) { 00262 len = mfp->clear_len == 0 ? pagesize : mfp->clear_len; 00263 if (nr < len) 00264 memset(bhp->buf + nr, 0, len - nr); 00265 #ifdef DIAGNOSTIC 00266 if (nr > len) 00267 len = nr; 00268 if (len < pagesize) 00269 memset(bhp->buf + len, CLEAR_BYTE, pagesize - len); 00270 #endif 00271 } 00272 00273 /* Call any pgin function. */ 00274 ret = mfp->ftype == 0 ? 0 : CDB___memp_pg(dbmfp, bhp, 1); 00275 00276 /* Unlock the buffer and reacquire the region lock. */ 00277 err: MUTEX_UNLOCK(&bhp->mutex); 00278 R_LOCK(dbenv, dbmp->reginfo); 00279 00280 /* 00281 * If no errors occurred, the data is now valid, clear the BH_TRASH 00282 * flag; regardless, clear the lock bit and let other threads proceed. 00283 */ 00284 F_CLR(bhp, BH_LOCKED); 00285 if (ret == 0) { 00286 F_CLR(bhp, BH_TRASH); 00287 00288 /* Update the statistics. */ 00289 if (created) 00290 ++mfp->stat.st_page_create; 00291 else 00292 ++mfp->stat.st_page_in; 00293 } 00294 00295 return (ret); 00296 } 00297 00298 /* 00299 * CDB___memp_pgwrite -- 00300 * Write a page to a file. 00301 * 00302 * PUBLIC: int CDB___memp_pgwrite 00303 * PUBLIC: __P((DB_MPOOL *, DB_MPOOLFILE *, BH *, int *, int *)); 00304 */ 00305 int 00306 CDB___memp_pgwrite(dbmp, dbmfp, bhp, restartp, wrotep) 00307 DB_MPOOL *dbmp; 00308 DB_MPOOLFILE *dbmfp; 00309 BH *bhp; 00310 int *restartp, *wrotep; 00311 { 00312 DB_ENV *dbenv; 00313 DB_IO db_io; 00314 DB_LSN lsn; 00315 MPOOL *c_mp, *mp; 00316 MPOOLFILE *mfp; 00317 size_t nw; 00318 int callpgin, dosync, ret, syncfail; 00319 const char *fail; 00320 00321 dbenv = dbmp->dbenv; 00322 mp = dbmp->reginfo[0].primary; 00323 mfp = dbmfp == NULL ? NULL : dbmfp->mfp; 00324 00325 if (restartp != NULL) 00326 *restartp = 0; 00327 if (wrotep != NULL) 00328 *wrotep = 0; 00329 callpgin = 0; 00330 00331 /* 00332 * Check the dirty bit -- this buffer may have been written since we 00333 * decided to write it. 00334 */ 00335 if (!F_ISSET(bhp, BH_DIRTY)) { 00336 if (wrotep != NULL) 00337 *wrotep = 1; 00338 return (0); 00339 } 00340 00341 MUTEX_LOCK(&bhp->mutex, dbenv->lockfhp); 00342 00343 /* 00344 * If there were two writers, we may have just been waiting while the 00345 * other writer completed I/O on this buffer. Check the dirty bit one 00346 * more time. 00347 */ 00348 if (!F_ISSET(bhp, BH_DIRTY)) { 00349 MUTEX_UNLOCK(&bhp->mutex); 00350 00351 if (wrotep != NULL) 00352 *wrotep = 1; 00353 return (0); 00354 } 00355 00356 F_SET(bhp, BH_LOCKED); 00357 R_UNLOCK(dbenv, dbmp->reginfo); 00358 00359 if (restartp != NULL) 00360 *restartp = 1; 00361 00362 /* 00363 * It's possible that the underlying file doesn't exist, either 00364 * because of an outright removal or because it was a temporary 00365 * file that's been closed. 00366 * 00367 * !!! 00368 * Once we pass this point, we know that dbmfp and mfp aren't NULL, 00369 * and that we have a valid file reference. 00370 */ 00371 if (mfp == NULL || F_ISSET(mfp, MP_DEADFILE)) 00372 goto file_dead; 00373 00374 /* Copy the LSN off the page if we're going to need it. */ 00375 if (LOGGING_ON(dbenv) || F_ISSET(bhp, BH_WRITE)) 00376 memcpy(&lsn, bhp->buf + mfp->lsn_off, sizeof(DB_LSN)); 00377 00378 /* Ensure the appropriate log records are on disk. */ 00379 if (LOGGING_ON(dbenv) && (ret = CDB_log_flush(dbenv, &lsn)) != 0) 00380 goto err; 00381 00382 /* 00383 * Call any pgout function. We set the callpgin flag so that we flag 00384 * that the contents of the buffer will need to be passed through pgin 00385 * before they are reused. 00386 */ 00387 if (mfp->ftype == 0) 00388 ret = 0; 00389 else { 00390 callpgin = 1; 00391 if ((ret = CDB___memp_pg(dbmfp, bhp, 0)) != 0) 00392 goto err; 00393 } 00394 00395 /* Temporary files may not yet have been created. */ 00396 if (!F_ISSET(&dbmfp->fh, DB_FH_VALID)) { 00397 MUTEX_THREAD_LOCK(dbmp->mutexp); 00398 if (!F_ISSET(&dbmfp->fh, DB_FH_VALID) && 00399 ((ret = CDB___db_appname(dbenv, DB_APP_TMP, NULL, NULL, 00400 DB_OSO_CREATE | DB_OSO_EXCL | DB_OSO_TEMP, 00401 &dbmfp->fh, NULL)) != 0 || 00402 !F_ISSET(&dbmfp->fh, DB_FH_VALID))) { 00403 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00404 CDB___db_err(dbenv, 00405 "unable to create temporary backing file"); 00406 goto err; 00407 } 00408 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00409 } 00410 00411 /* Write the page. */ 00412 db_io.fhp = &dbmfp->fh; 00413 db_io.mutexp = dbmfp->mutexp; 00414 db_io.pagesize = db_io.bytes = mfp->stat.st_pagesize; 00415 db_io.pgno = bhp->pgno; 00416 db_io.buf = bhp->buf; 00417 #ifdef DEBUG 00418 { 00419 PAGE* pp = (PAGE*)db_io.buf; 00420 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_WRITE, 1); 00421 switch(TYPE(pp)) { 00422 case P_IBTREE: 00423 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_PAGE_IBTREE, 1); 00424 break; 00425 case P_LBTREE: 00426 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_PAGE_LBTREE, 1); 00427 break; 00428 default: 00429 word_monitor_add(DB_MONITOR(dbenv), WORD_MONITOR_PAGE_UNKNOWN, 1); 00430 break; 00431 } 00432 } 00433 #endif /* DEBUG */ 00434 if(F_ISSET(dbmfp, MP_CMPR)) { 00435 ret = CDB___memp_cmpr(dbmfp, bhp, &db_io, DB_IO_WRITE, &nw); 00436 } else { 00437 if(db_io.pgno == PGNO_BASE_MD) { 00438 /* 00439 * Write a copy of the DBMETA information at 256, 512, 00440 * 1024, 2048, 4096, ... up to the actually required page 00441 * size. This ensure that the DBMETA information will be 00442 * found without knowing the actual page size used in the 00443 * file. 00444 * !! Assume that PGNO_BASE_MD == 1 00445 */ 00446 size_t required = db_io.pagesize; 00447 size_t orig_bytes = db_io.bytes; 00448 db_io.bytes = DBMETASIZE; 00449 for(db_io.pagesize = DBMETASIZE; db_io.pagesize < required; db_io.pagesize <<= 1) { 00450 ret = CDB___os_io(dbenv, &db_io, DB_IO_WRITE, &nw); 00451 if(ret != 0 || nw != DBMETASIZE) 00452 break; 00453 } 00454 db_io.bytes = orig_bytes; 00455 db_io.pagesize = required; 00456 if(ret == 0) 00457 ret = CDB___os_io(dbenv, &db_io, DB_IO_WRITE, &nw); 00458 } else { 00459 ret = CDB___os_io(dbenv, &db_io, DB_IO_WRITE, &nw); 00460 } 00461 } 00462 if (ret != 0) { 00463 CDB___db_panic(dbenv, ret); 00464 fail = "write"; 00465 goto syserr; 00466 } 00467 if (nw != mfp->stat.st_pagesize) { 00468 ret = EIO; 00469 fail = "write"; 00470 goto syserr; 00471 } 00472 00473 file_dead: 00474 /* 00475 * !!! 00476 * Once we pass this point, dbmfp and mfp may be NULL, we may not have 00477 * a valid file reference. 00478 * 00479 * Unlock the buffer and reacquire the region lock. 00480 */ 00481 MUTEX_UNLOCK(&bhp->mutex); 00482 R_LOCK(dbenv, dbmp->reginfo); 00483 00484 /* 00485 * Clean up the flags based on a successful write. 00486 * 00487 * If we rewrote the page, it will need processing by the pgin 00488 * routine before reuse. 00489 */ 00490 if (callpgin) 00491 F_SET(bhp, BH_CALLPGIN); 00492 F_CLR(bhp, BH_DIRTY | BH_LOCKED); 00493 00494 /* 00495 * If we write a buffer for which a checkpoint is waiting, update 00496 * the count of pending buffers (both in the mpool as a whole and 00497 * for this file). If the count for this file goes to zero, set a 00498 * flag so we flush the writes. 00499 */ 00500 dosync = 0; 00501 if (F_ISSET(bhp, BH_WRITE)) { 00502 F_CLR(bhp, BH_WRITE); 00503 00504 --mp->lsn_cnt; 00505 if (mfp != NULL) 00506 dosync = --mfp->lsn_cnt == 0 ? 1 : 0; 00507 } 00508 00509 /* Update the page clean/dirty statistics. */ 00510 c_mp = BH_TO_CACHE(dbmp, bhp); 00511 ++c_mp->stat.st_page_clean; 00512 --c_mp->stat.st_page_dirty; 00513 00514 /* Update I/O statistics. */ 00515 if (mfp != NULL) 00516 ++mfp->stat.st_page_out; 00517 00518 /* 00519 * Do the sync after everything else has been updated, so any incoming 00520 * checkpoint doesn't see inconsistent information. 00521 * 00522 * XXX: 00523 * Don't lock the region around the sync, fsync(2) has no atomicity 00524 * issues. 00525 * 00526 * XXX: 00527 * We ignore errors from the sync -- it makes no sense to return an 00528 * error to the calling process, so set a flag causing the checkpoint 00529 * to be retried later. There is a possibility, of course, that a 00530 * subsequent checkpoint was started and that we're going to force it 00531 * to fail. That should be unlikely, and fixing it would be difficult. 00532 */ 00533 if (dosync) { 00534 R_UNLOCK(dbenv, dbmp->reginfo); 00535 syncfail = CDB___os_fsync(dbenv, &dbmfp->fh) != 0; 00536 R_LOCK(dbenv, dbmp->reginfo); 00537 if (syncfail) 00538 F_SET(mp, MP_LSN_RETRY); 00539 } 00540 00541 if (wrotep != NULL) 00542 *wrotep = 1; 00543 00544 return (0); 00545 00546 syserr: CDB___db_err(dbenv, "%s: %s failed for page %lu", 00547 CDB___memp_fn(dbmfp), fail, (u_long)bhp->pgno); 00548 00549 err: /* Unlock the buffer and reacquire the region lock. */ 00550 MUTEX_UNLOCK(&bhp->mutex); 00551 R_LOCK(dbenv, dbmp->reginfo); 00552 00553 /* 00554 * Clean up the flags based on a failure. 00555 * 00556 * The page remains dirty but we remove our lock. If we rewrote the 00557 * page, it will need processing by the pgin routine before reuse. 00558 */ 00559 if (callpgin) 00560 F_SET(bhp, BH_CALLPGIN); 00561 F_CLR(bhp, BH_LOCKED); 00562 00563 return (ret); 00564 } 00565 00566 /* 00567 * CDB___memp_pg -- 00568 * Call the pgin/pgout routine. 00569 * 00570 * PUBLIC: int CDB___memp_pg __P((DB_MPOOLFILE *, BH *, int)); 00571 */ 00572 int 00573 CDB___memp_pg(dbmfp, bhp, is_pgin) 00574 DB_MPOOLFILE *dbmfp; 00575 BH *bhp; 00576 int is_pgin; 00577 { 00578 DBT dbt, *dbtp; 00579 DB_MPOOL *dbmp; 00580 DB_MPREG *mpreg; 00581 MPOOLFILE *mfp; 00582 int ftype, ret; 00583 00584 dbmp = dbmfp->dbmp; 00585 mfp = dbmfp->mfp; 00586 00587 MUTEX_THREAD_LOCK(dbmp->mutexp); 00588 00589 ftype = mfp->ftype; 00590 for (mpreg = LIST_FIRST(&dbmp->dbregq); 00591 mpreg != NULL; mpreg = LIST_NEXT(mpreg, q)) { 00592 if (ftype != mpreg->ftype) 00593 continue; 00594 if (mfp->pgcookie_len == 0) 00595 dbtp = NULL; 00596 else { 00597 dbt.size = mfp->pgcookie_len; 00598 dbt.data = R_ADDR(dbmp->reginfo, mfp->pgcookie_off); 00599 dbtp = &dbt; 00600 } 00601 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00602 00603 if (is_pgin) { 00604 if (mpreg->pgin != NULL && 00605 (ret = mpreg->pgin(dbmp->dbenv, 00606 bhp->pgno, bhp->buf, dbtp)) != 0) 00607 goto err; 00608 } else 00609 if (mpreg->pgout != NULL && 00610 (ret = mpreg->pgout(dbmp->dbenv, 00611 bhp->pgno, bhp->buf, dbtp)) != 0) 00612 goto err; 00613 break; 00614 } 00615 00616 if (mpreg == NULL) 00617 MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00618 00619 return (0); 00620 00621 err: MUTEX_THREAD_UNLOCK(dbmp->mutexp); 00622 CDB___db_err(dbmp->dbenv, "%s: %s failed for page %lu", 00623 CDB___memp_fn(dbmfp), is_pgin ? "pgin" : "pgout", (u_long)bhp->pgno); 00624 return (ret); 00625 } 00626 00627 /* 00628 * CDB___memp_bhfree -- 00629 * Free a bucket header and its referenced data. 00630 * 00631 * PUBLIC: void CDB___memp_bhfree __P((DB_MPOOL *, BH *, int)); 00632 */ 00633 void 00634 CDB___memp_bhfree(dbmp, bhp, free_mem) 00635 DB_MPOOL *dbmp; 00636 BH *bhp; 00637 int free_mem; 00638 { 00639 DB_HASHTAB *dbht; 00640 MPOOL *c_mp, *mp; 00641 MPOOLFILE *mfp; 00642 int n_bucket, n_cache; 00643 00644 mp = dbmp->reginfo[0].primary; 00645 c_mp = BH_TO_CACHE(dbmp, bhp); 00646 n_cache = NCACHE(mp, bhp->pgno); 00647 n_bucket = NBUCKET(c_mp, bhp->mf_offset, bhp->pgno); 00648 dbht = R_ADDR(&dbmp->reginfo[n_cache], c_mp->htab); 00649 00650 /* Delete the buffer header from the hash bucket queue. */ 00651 SH_TAILQ_REMOVE(&dbht[n_bucket], bhp, hq, __bh); 00652 00653 /* Delete the buffer header from the LRU queue. */ 00654 SH_TAILQ_REMOVE(&c_mp->bhq, bhp, q, __bh); 00655 00656 /* 00657 * Find the underlying MPOOLFILE and decrement its reference count. 00658 * If this is its last reference, remove it. 00659 */ 00660 mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset); 00661 if (--mfp->ref_cnt == 0) 00662 CDB___memp_mf_discard(dbmp, mfp); 00663 00664 /* 00665 * If we're not reusing it immediately, free the buffer header 00666 * and data for real. 00667 */ 00668 CDB___memp_cmpr_free_chain(dbmp, bhp); 00669 if (free_mem) { 00670 --c_mp->stat.st_page_clean; 00671 CDB___db_shalloc_free(dbmp->reginfo[n_cache].addr, bhp); 00672 } 00673 } 00674 00675 /* 00676 * __memp_upgrade -- 00677 * Upgrade a file descriptor from readonly to readwrite. 00678 */ 00679 static int 00680 __memp_upgrade(dbmp, dbmfp, mfp) 00681 DB_MPOOL *dbmp; 00682 DB_MPOOLFILE *dbmfp; 00683 MPOOLFILE *mfp; 00684 { 00685 DB_FH fh; 00686 int ret; 00687 char *rpath; 00688 00689 /* 00690 * !!! 00691 * We expect the handle to already be locked. 00692 */ 00693 00694 /* Check to see if we've already upgraded. */ 00695 if (F_ISSET(dbmfp, MP_UPGRADE)) 00696 return (0); 00697 00698 /* Check to see if we've already failed. */ 00699 if (F_ISSET(dbmfp, MP_UPGRADE_FAIL)) 00700 return (1); 00701 00702 /* 00703 * Calculate the real name for this file and try to open it read/write. 00704 * We know we have a valid pathname for the file because it's the only 00705 * way we could have gotten a file descriptor of any kind. 00706 */ 00707 if ((ret = CDB___db_appname(dbmp->dbenv, DB_APP_DATA, 00708 NULL, R_ADDR(dbmp->reginfo, mfp->path_off), 0, NULL, &rpath)) != 0) 00709 return (ret); 00710 if (CDB___os_open(dbmp->dbenv, rpath, 0, 0, &fh) != 0) { 00711 F_SET(dbmfp, MP_UPGRADE_FAIL); 00712 ret = 1; 00713 } else { 00714 /* Swap the descriptors and set the upgrade flag. */ 00715 (void)CDB___os_closehandle(&dbmfp->fh); 00716 dbmfp->fh = fh; 00717 F_SET(dbmfp, MP_UPGRADE); 00718 ret = 0; 00719 } 00720 CDB___os_freestr(rpath); 00721 return (ret); 00722 }