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__meta_8c-source.html,v 1.1 2008年06月08日 10:17:51 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 "lock.h" 00060 #include "txn.h" 00061 #include "db_am.h" 00062 #include "btree.h" 00063 00064 /* 00065 * CDB___db_new -- 00066 * Get a new page, preferably from the freelist. 00067 * 00068 * PUBLIC: int CDB___db_new __P((DBC *, u_int32_t, PAGE **)); 00069 */ 00070 int 00071 CDB___db_new(dbc, type, pagepp) 00072 DBC *dbc; 00073 u_int32_t type; 00074 PAGE **pagepp; 00075 { 00076 DBMETA *meta; 00077 DB *dbp; 00078 DB_LOCK metalock; 00079 PAGE *h; 00080 db_pgno_t pgno; 00081 int ret; 00082 00083 dbp = dbc->dbp; 00084 meta = NULL; 00085 h = NULL; 00086 00087 pgno = PGNO_BASE_MD; 00088 if ((ret = CDB___db_lget(dbc, 00089 LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0) 00090 goto err; 00091 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) 00092 goto err; 00093 00094 if (meta->free == PGNO_INVALID) { 00095 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, DB_MPOOL_NEW, &h)) != 0) 00096 goto err; 00097 ZERO_LSN(h->lsn); 00098 h->pgno = pgno; 00099 } else { 00100 pgno = meta->free; 00101 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 00102 goto err; 00103 meta->free = h->next_pgno; 00104 (void)CDB_memp_fset(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY); 00105 } 00106 00107 /* Log the change. */ 00108 if (DB_LOGGING(dbc)) { 00109 if ((ret = __db_pg_alloc_log(dbp->dbenv, 00110 dbc->txn, &LSN(meta), 0, dbp->log_fileid, 00111 &LSN(meta), &meta->alloc_lsn, &h->lsn, h->pgno, 00112 (u_int32_t)type, meta->free)) != 0) 00113 goto err; 00114 LSN(h) = LSN(meta); 00115 meta->alloc_lsn = LSN(meta); 00116 } 00117 00118 (void)CDB_memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY); 00119 (void)__TLPUT(dbc, metalock); 00120 00121 P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, PGNO_INVALID, 0, type, 0); 00122 *pagepp = h; 00123 return (0); 00124 00125 err: if (h != NULL) 00126 (void)CDB_memp_fput(dbp->mpf, h, 0); 00127 if (meta != NULL) 00128 (void)CDB_memp_fput(dbp->mpf, meta, 0); 00129 (void)__TLPUT(dbc, metalock); 00130 return (ret); 00131 } 00132 00133 /* 00134 * CDB___db_free -- 00135 * Add a page to the head of the freelist. 00136 * 00137 * PUBLIC: int CDB___db_free __P((DBC *, PAGE *)); 00138 */ 00139 int 00140 CDB___db_free(dbc, h) 00141 DBC *dbc; 00142 PAGE *h; 00143 { 00144 DBMETA *meta; 00145 DB *dbp; 00146 DBT ldbt; 00147 DB_LOCK metalock; 00148 db_pgno_t pgno; 00149 u_int32_t dirty_flag; 00150 int ret, t_ret; 00151 00152 dbp = dbc->dbp; 00153 00154 /* 00155 * Retrieve the metadata page and insert the page at the head of 00156 * the free list. If either the lock get or page get routines 00157 * fail, then we need to put the page with which we were called 00158 * back because our caller assumes we take care of it. 00159 */ 00160 dirty_flag = 0; 00161 pgno = PGNO_BASE_MD; 00162 if ((ret = CDB___db_lget(dbc, 00163 LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0) 00164 goto err; 00165 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) { 00166 (void)__TLPUT(dbc, metalock); 00167 goto err; 00168 } 00169 00170 /* Log the change. */ 00171 if (DB_LOGGING(dbc)) { 00172 memset(&ldbt, 0, sizeof(ldbt)); 00173 ldbt.data = h; 00174 ldbt.size = P_OVERHEAD; 00175 if ((ret = __db_pg_free_log(dbp->dbenv, 00176 dbc->txn, &LSN(meta), 0, dbp->log_fileid, h->pgno, 00177 &LSN(meta), &meta->alloc_lsn, &ldbt, meta->free)) != 0) { 00178 (void)CDB_memp_fput(dbp->mpf, (PAGE *)meta, 0); 00179 (void)__TLPUT(dbc, metalock); 00180 return (ret); 00181 } 00182 LSN(h) = LSN(meta); 00183 meta->alloc_lsn = LSN(meta); 00184 } 00185 00186 P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, meta->free, 0, P_INVALID, 0); 00187 00188 /* Link the page on the metadata free list. */ 00189 meta->free = h->pgno; 00190 00191 /* Discard the metadata page. */ 00192 ret = CDB_memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY); 00193 if ((t_ret = __TLPUT(dbc, metalock)) != 0) 00194 ret = t_ret; 00195 00196 /* Discard the caller's page reference. */ 00197 dirty_flag = DB_MPOOL_DIRTY; 00198 err: if ((t_ret = CDB_memp_fput(dbp->mpf, h, dirty_flag)) != 0 && ret == 0) 00199 ret = t_ret; 00200 00201 /* 00202 * XXX 00203 * We have to unlock the caller's page in the caller! 00204 */ 00205 return (ret); 00206 } 00207 00208 #ifdef DEBUG 00209 /* 00210 * CDB___db_lprint -- 00211 * Print out the list of locks currently held by a cursor. 00212 * 00213 * PUBLIC: int CDB___db_lprint __P((DBC *)); 00214 */ 00215 int 00216 CDB___db_lprint(dbc) 00217 DBC *dbc; 00218 { 00219 DB *dbp; 00220 DB_LOCKREQ req; 00221 00222 dbp = dbc->dbp; 00223 00224 if (LOCKING_ON(dbp->dbenv)) { 00225 req.op = DB_LOCK_DUMP; 00226 CDB_lock_vec(dbp->dbenv, dbc->locker, 0, &req, 1, NULL); 00227 } 00228 return (0); 00229 } 00230 #endif 00231 00232 /* 00233 * CDB___db_lget -- 00234 * The standard lock get call. 00235 * 00236 * PUBLIC: int CDB___db_lget __P((DBC *, 00237 * PUBLIC: int, db_pgno_t, db_lockmode_t, int, DB_LOCK *)); 00238 */ 00239 int 00240 CDB___db_lget(dbc, flags, pgno, mode, lkflags, lockp) 00241 DBC *dbc; 00242 int flags, lkflags; 00243 db_pgno_t pgno; 00244 db_lockmode_t mode; 00245 DB_LOCK *lockp; 00246 { 00247 DB *dbp; 00248 DB_ENV *dbenv; 00249 DB_LOCKREQ couple[2]; 00250 int ret; 00251 00252 dbp = dbc->dbp; 00253 dbenv = dbp->dbenv; 00254 00255 /* 00256 * We do not always check if we're configured for locking before 00257 * calling CDB___db_lget to acquire the lock. 00258 */ 00259 if (LOCKING(dbenv) || !LOCKING_ON(dbenv) 00260 || (!LF_ISSET(LCK_ROLLBACK) && F_ISSET(dbc, DBC_RECOVER)) 00261 || (!LF_ISSET(LCK_ALWAYS) && F_ISSET(dbc, DBC_OPD))) { 00262 lockp->off = LOCK_INVALID; 00263 return (0); 00264 } 00265 00266 dbc->lock.pgno = pgno; 00267 if (lkflags & DB_LOCK_RECORD) 00268 dbc->lock.type = DB_RECORD_LOCK; 00269 else 00270 dbc->lock.type = DB_PAGE_LOCK; 00271 lkflags &= ~DB_LOCK_RECORD; 00272 00273 /* 00274 * If the transaction enclosing this cursor has DB_LOCK_NOWAIT set, 00275 * pass that along to the lock call. 00276 */ 00277 if (DB_NONBLOCK(dbc)) 00278 lkflags |= DB_LOCK_NOWAIT; 00279 00280 /* 00281 * If the object not currently locked, acquire the lock and return, 00282 * otherwise, lock couple. 00283 */ 00284 if (LF_ISSET(LCK_COUPLE)) { 00285 couple[0].op = DB_LOCK_GET; 00286 couple[0].obj = &dbc->lock_dbt; 00287 couple[0].mode = mode; 00288 couple[1].op = DB_LOCK_PUT; 00289 couple[1].lock = *lockp; 00290 00291 if ((ret = CDB_lock_vec(dbenv, 00292 dbc->locker, lkflags, couple, 2, NULL)) == 0) 00293 *lockp = couple[0].lock; 00294 } else 00295 ret = CDB_lock_get(dbenv, 00296 dbc->locker, lkflags, &dbc->lock_dbt, mode, lockp); 00297 00298 if (ret != 0) 00299 lockp->off = LOCK_INVALID; 00300 00301 return (ret); 00302 }