1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998 5 * Sleepycat Software. All rights reserved. 6 */ 7 /* 8 * Copyright (c) 1990, 1993, 1994, 1995, 1996 9 * Keith Bostic. All rights reserved. 10 */ 11 /* 12 * Copyright (c) 1990, 1993, 1994, 1995 13 * The Regents of the University of California. All rights reserved. 14 * 15 * This code is derived from software contributed to Berkeley by 16 * Mike Olson. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 3. All advertising materials mentioning features or use of this software 27 * must display the following acknowledgement: 28 * This product includes software developed by the University of 29 * California, Berkeley and its contributors. 30 * 4. Neither the name of the University nor the names of its contributors 31 * may be used to endorse or promote products derived from this software 32 * without specific prior written permission. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 */ 46 47 #include "config.h" 48 49 #ifndef lint 50 static const char sccsid[] = "@(#)bt_page.c 10.17 (Sleepycat) 1/3/99"; 51 #endif /* not lint */ 52 53 #ifndef NO_SYSTEM_INCLUDES 54 #include <sys/types.h> 55 56 #include <errno.h> 57 #include <string.h> 58 #endif 59 60 #include "db_int.h" 61 #include "db_page.h" 62 #include "btree.h" 63 64 /* 65 * __bam_new -- 66 * Get a new page, preferably from the freelist. 67 * 68 * PUBLIC: int __bam_new __P((DBC *, u_int32_t, PAGE **)); 69 */ 70 int 71 __bam_new(dbc, type, pagepp) 72 DBC *dbc; 73 u_int32_t type; 74 PAGE **pagepp; 75 { 76 BTMETA *meta; 77 DB *dbp; 78 DB_LOCK metalock; 79 PAGE *h; 80 db_pgno_t pgno; 81 int ret; 82 83 dbp = dbc->dbp; 84 meta = NULL; 85 h = NULL; 86 metalock = LOCK_INVALID; 87 88 pgno = PGNO_METADATA; 89 if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_WRITE, &metalock)) != 0) 90 goto err; 91 if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) 92 goto err; 93 94 if (meta->free == PGNO_INVALID) { 95 if ((ret = memp_fget(dbp->mpf, &pgno, DB_MPOOL_NEW, &h)) != 0) 96 goto err; 97 ZERO_LSN(h->lsn); 98 h->pgno = pgno; 99 } else { 100 pgno = meta->free; 101 if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 102 goto err; 103 meta->free = h->next_pgno; 104 } 105 106 /* Log the change. */ 107 if (DB_LOGGING(dbc)) { 108 if ((ret = __bam_pg_alloc_log(dbp->dbenv->lg_info, dbc->txn, 109 &meta->lsn, 0, dbp->log_fileid, &meta->lsn, &h->lsn, 110 h->pgno, (u_int32_t)type, meta->free)) != 0) 111 goto err; 112 LSN(h) = LSN(meta); 113 } 114 115 (void)memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY); 116 (void)__BT_TLPUT(dbc, metalock); 117 118 P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, PGNO_INVALID, 0, type); 119 *pagepp = h; 120 return (0); 121 122 err: if (h != NULL) 123 (void)memp_fput(dbp->mpf, h, 0); 124 if (meta != NULL) 125 (void)memp_fput(dbp->mpf, meta, 0); 126 if (metalock != LOCK_INVALID) 127 (void)__BT_TLPUT(dbc, metalock); 128 return (ret); 129 } 130 131 /* 132 * __bam_lput -- 133 * The standard lock put call. 134 * 135 * PUBLIC: int __bam_lput __P((DBC *, DB_LOCK)); 136 */ 137 int 138 __bam_lput(dbc, lock) 139 DBC *dbc; 140 DB_LOCK lock; 141 { 142 return (__BT_LPUT(dbc, lock)); 143 } 144 145 /* 146 * __bam_free -- 147 * Add a page to the head of the freelist. 148 * 149 * PUBLIC: int __bam_free __P((DBC *, PAGE *)); 150 */ 151 int 152 __bam_free(dbc, h) 153 DBC *dbc; 154 PAGE *h; 155 { 156 BTMETA *meta; 157 DB *dbp; 158 DBT ldbt; 159 DB_LOCK metalock; 160 db_pgno_t pgno; 161 u_int32_t dirty_flag; 162 int ret, t_ret; 163 164 dbp = dbc->dbp; 165 166 /* 167 * Retrieve the metadata page and insert the page at the head of 168 * the free list. If either the lock get or page get routines 169 * fail, then we need to put the page with which we were called 170 * back because our caller assumes we take care of it. 171 */ 172 dirty_flag = 0; 173 pgno = PGNO_METADATA; 174 if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_WRITE, &metalock)) != 0) 175 goto err; 176 if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) { 177 (void)__BT_TLPUT(dbc, metalock); 178 goto err; 179 } 180 181 /* Log the change. */ 182 if (DB_LOGGING(dbc)) { 183 memset(&ldbt, 0, sizeof(ldbt)); 184 ldbt.data = h; 185 ldbt.size = P_OVERHEAD; 186 if ((ret = __bam_pg_free_log(dbp->dbenv->lg_info, 187 dbc->txn, &meta->lsn, 0, dbp->log_fileid, h->pgno, 188 &meta->lsn, &ldbt, meta->free)) != 0) { 189 (void)memp_fput(dbp->mpf, (PAGE *)meta, 0); 190 (void)__BT_TLPUT(dbc, metalock); 191 return (ret); 192 } 193 LSN(h) = LSN(meta); 194 } 195 196 /* 197 * The page should have nothing interesting on it, re-initialize it, 198 * leaving only the page number and the LSN. 199 */ 200 #ifdef DIAGNOSTIC 201 { db_pgno_t __pgno; DB_LSN __lsn; 202 __pgno = h->pgno; 203 __lsn = h->lsn; 204 memset(h, 0xdb, dbp->pgsize); 205 h->pgno = __pgno; 206 h->lsn = __lsn; 207 } 208 #endif 209 P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, meta->free, 0, P_INVALID); 210 211 /* Link the page on the metadata free list. */ 212 meta->free = h->pgno; 213 214 /* Discard the metadata page. */ 215 ret = memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY); 216 if ((t_ret = __BT_TLPUT(dbc, metalock)) != 0) 217 ret = t_ret; 218 219 /* Discard the caller's page reference. */ 220 dirty_flag = DB_MPOOL_DIRTY; 221 err: if ((t_ret = memp_fput(dbp->mpf, h, dirty_flag)) != 0 && ret == 0) 222 ret = t_ret; 223 224 /* 225 * XXX 226 * We have to unlock the caller's page in the caller! 227 */ 228 return (ret); 229 } 230 231 #ifdef DEBUG 232 /* 233 * __bam_lt -- 234 * Print out the list of locks currently held by a cursor. 235 * 236 * PUBLIC: int __bam_lt __P((DBC *)); 237 */ 238 int 239 __bam_lt(dbc) 240 DBC *dbc; 241 { 242 DB *dbp; 243 DB_LOCKREQ req; 244 245 dbp = dbc->dbp; 246 if (F_ISSET(dbp, DB_AM_LOCKING)) { 247 req.op = DB_LOCK_DUMP; 248 lock_vec(dbp->dbenv->lk_info, dbc->locker, 0, &req, 1, NULL); 249 } 250 return (0); 251 } 252 #endif 253 254 /* 255 * __bam_lget -- 256 * The standard lock get call. 257 * 258 * PUBLIC: int __bam_lget 259 * PUBLIC: __P((DBC *, int, db_pgno_t, db_lockmode_t, DB_LOCK *)); 260 */ 261 int 262 __bam_lget(dbc, do_couple, pgno, mode, lockp) 263 DBC *dbc; 264 int do_couple; 265 db_pgno_t pgno; 266 db_lockmode_t mode; 267 DB_LOCK *lockp; 268 { 269 DB *dbp; 270 DB_LOCKREQ couple[2]; 271 int ret; 272 273 dbp = dbc->dbp; 274 275 if (!F_ISSET(dbp, DB_AM_LOCKING)) { 276 *lockp = LOCK_INVALID; 277 return (0); 278 } 279 280 dbc->lock.pgno = pgno; 281 282 /* 283 * If the object not currently locked, acquire the lock and return, 284 * otherwise, lock couple. If we fail and it's not a system error, 285 * convert to EAGAIN. 286 */ 287 if (do_couple) { 288 couple[0].op = DB_LOCK_GET; 289 couple[0].obj = &dbc->lock_dbt; 290 couple[0].mode = mode; 291 couple[1].op = DB_LOCK_PUT; 292 couple[1].lock = *lockp; 293 294 if (dbc->txn == NULL) 295 ret = lock_vec(dbp->dbenv->lk_info, 296 dbc->locker, 0, couple, 2, NULL); 297 else 298 ret = lock_tvec(dbp->dbenv->lk_info, 299 dbc->txn, 0, couple, 2, NULL); 300 if (ret != 0) { 301 /* If we fail, discard the lock we held. */ 302 __BT_LPUT(dbc, *lockp); 303 304 return (ret < 0 ? EAGAIN : ret); 305 } 306 *lockp = couple[0].lock; 307 } else { 308 if (dbc->txn == NULL) 309 ret = lock_get(dbp->dbenv->lk_info, 310 dbc->locker, 0, &dbc->lock_dbt, mode, lockp); 311 else 312 ret = lock_tget(dbp->dbenv->lk_info, 313 dbc->txn, 0, &dbc->lock_dbt, mode, lockp); 314 return (ret < 0 ? EAGAIN : ret); 315 } 316 return (0); 317 } 318