db_upg_opd.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:8k
- /*-
- * See the file LICENSE for redistribution information.
- *
- * Copyright (c) 1996, 1997, 1998, 1999, 2000
- * Sleepycat Software. All rights reserved.
- */
- #include "db_config.h"
- #ifndef lint
- static const char revid[] = "$Id: db_upg_opd.c,v 11.9 2000/11/30 00:58:33 ubell Exp $";
- #endif /* not lint */
- #ifndef NO_SYSTEM_INCLUDES
- #include <sys/types.h>
- #include <string.h>
- #endif
- #include "db_int.h"
- #include "db_page.h"
- #include "db_swap.h"
- #include "btree.h"
- #include "hash.h"
- #include "qam.h"
- static int __db_build_bi __P((DB *, DB_FH *, PAGE *, PAGE *, u_int32_t, int *));
- static int __db_build_ri __P((DB *, DB_FH *, PAGE *, PAGE *, u_int32_t, int *));
- static int __db_up_ovref __P((DB *, DB_FH *, db_pgno_t));
- #define GET_PAGE(dbp, fhp, pgno, page) {
- if ((ret = __os_seek(dbp->dbenv,
- fhp, (dbp)->pgsize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
- goto err;
- if ((ret = __os_read(dbp->dbenv,
- fhp, page, (dbp)->pgsize, &n)) != 0)
- goto err;
- }
- #define PUT_PAGE(dbp, fhp, pgno, page) {
- if ((ret = __os_seek(dbp->dbenv,
- fhp, (dbp)->pgsize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
- goto err;
- if ((ret = __os_write(dbp->dbenv,
- fhp, page, (dbp)->pgsize, &n)) != 0)
- goto err;
- }
- /*
- * __db_31_offdup --
- * Convert 3.0 off-page duplicates to 3.1 off-page duplicates.
- *
- * PUBLIC: int __db_31_offdup __P((DB *, char *, DB_FH *, int, db_pgno_t *));
- */
- int
- __db_31_offdup(dbp, real_name, fhp, sorted, pgnop)
- DB *dbp;
- char *real_name;
- DB_FH *fhp;
- int sorted;
- db_pgno_t *pgnop;
- {
- PAGE *ipage, *page;
- db_indx_t indx;
- db_pgno_t cur_cnt, i, next_cnt, pgno, *pgno_cur, pgno_last;
- db_pgno_t *pgno_next, pgno_max, *tmp;
- db_recno_t nrecs;
- size_t n;
- int level, nomem, ret;
- ipage = page = NULL;
- pgno_cur = pgno_next = NULL;
- /* Allocate room to hold a page. */
- if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &page)) != 0)
- goto err;
- /*
- * Walk the chain of 3.0 off-page duplicates. Each one is converted
- * in place to a 3.1 off-page duplicate page. If the duplicates are
- * sorted, they are converted to a Btree leaf page, otherwise to a
- * Recno leaf page.
- */
- for (nrecs = 0, cur_cnt = pgno_max = 0,
- pgno = *pgnop; pgno != PGNO_INVALID;) {
- if (pgno_max == cur_cnt) {
- pgno_max += 20;
- if ((ret = __os_realloc(dbp->dbenv, pgno_max *
- sizeof(db_pgno_t), NULL, &pgno_cur)) != 0)
- goto err;
- }
- pgno_cur[cur_cnt++] = pgno;
- GET_PAGE(dbp, fhp, pgno, page);
- nrecs += NUM_ENT(page);
- LEVEL(page) = LEAFLEVEL;
- TYPE(page) = sorted ? P_LDUP : P_LRECNO;
- /*
- * !!!
- * DB didn't zero the LSNs on off-page duplicates pages.
- */
- ZERO_LSN(LSN(page));
- PUT_PAGE(dbp, fhp, pgno, page);
- pgno = NEXT_PGNO(page);
- }
- /* If we only have a single page, it's easy. */
- if (cur_cnt > 1) {
- /*
- * pgno_cur is the list of pages we just converted. We're
- * going to walk that list, but we'll need to create a new
- * list while we do so.
- */
- if ((ret = __os_malloc(dbp->dbenv,
- cur_cnt * sizeof(db_pgno_t), NULL, &pgno_next)) != 0)
- goto err;
- /* Figure out where we can start allocating new pages. */
- if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
- goto err;
- /* Allocate room for an internal page. */
- if ((ret = __os_malloc(dbp->dbenv,
- dbp->pgsize, NULL, &ipage)) != 0)
- goto err;
- PGNO(ipage) = PGNO_INVALID;
- }
- /*
- * Repeatedly walk the list of pages, building internal pages, until
- * there's only one page at a level.
- */
- for (level = LEAFLEVEL + 1; cur_cnt > 1; ++level) {
- for (indx = 0, i = next_cnt = 0; i < cur_cnt;) {
- if (indx == 0) {
- P_INIT(ipage, dbp->pgsize, pgno_last,
- PGNO_INVALID, PGNO_INVALID,
- level, sorted ? P_IBTREE : P_IRECNO);
- ZERO_LSN(LSN(ipage));
- pgno_next[next_cnt++] = pgno_last++;
- }
- GET_PAGE(dbp, fhp, pgno_cur[i], page);
- /*
- * If the duplicates are sorted, put the first item on
- * the lower-level page onto a Btree internal page. If
- * the duplicates are not sorted, create an internal
- * Recno structure on the page. If either case doesn't
- * fit, push out the current page and start a new one.
- */
- nomem = 0;
- if (sorted) {
- if ((ret = __db_build_bi(
- dbp, fhp, ipage, page, indx, &nomem)) != 0)
- goto err;
- } else
- if ((ret = __db_build_ri(
- dbp, fhp, ipage, page, indx, &nomem)) != 0)
- goto err;
- if (nomem) {
- indx = 0;
- PUT_PAGE(dbp, fhp, PGNO(ipage), ipage);
- } else {
- ++indx;
- ++NUM_ENT(ipage);
- ++i;
- }
- }
- /*
- * Push out the last internal page. Set the top-level record
- * count if we've reached the top.
- */
- if (next_cnt == 1)
- RE_NREC_SET(ipage, nrecs);
- PUT_PAGE(dbp, fhp, PGNO(ipage), ipage);
- /* Swap the current and next page number arrays. */
- cur_cnt = next_cnt;
- tmp = pgno_cur;
- pgno_cur = pgno_next;
- pgno_next = tmp;
- }
- *pgnop = pgno_cur[0];
- err: if (pgno_cur != NULL)
- __os_free(pgno_cur, 0);
- if (pgno_next != NULL)
- __os_free(pgno_next, 0);
- if (ipage != NULL)
- __os_free(ipage, dbp->pgsize);
- if (page != NULL)
- __os_free(page, dbp->pgsize);
- return (ret);
- }
- /*
- * __db_build_bi --
- * Build a BINTERNAL entry for a parent page.
- */
- static int
- __db_build_bi(dbp, fhp, ipage, page, indx, nomemp)
- DB *dbp;
- DB_FH *fhp;
- PAGE *ipage, *page;
- u_int32_t indx;
- int *nomemp;
- {
- BINTERNAL bi, *child_bi;
- BKEYDATA *child_bk;
- u_int8_t *p;
- int ret;
- switch (TYPE(page)) {
- case P_IBTREE:
- child_bi = GET_BINTERNAL(page, 0);
- if (P_FREESPACE(ipage) < BINTERNAL_PSIZE(child_bi->len)) {
- *nomemp = 1;
- return (0);
- }
- ipage->inp[indx] =
- HOFFSET(ipage) -= BINTERNAL_SIZE(child_bi->len);
- p = P_ENTRY(ipage, indx);
- bi.len = child_bi->len;
- B_TSET(bi.type, child_bi->type, 0);
- bi.pgno = PGNO(page);
- bi.nrecs = __bam_total(page);
- memcpy(p, &bi, SSZA(BINTERNAL, data));
- p += SSZA(BINTERNAL, data);
- memcpy(p, child_bi->data, child_bi->len);
- /* Increment the overflow ref count. */
- if (B_TYPE(child_bi->type) == B_OVERFLOW)
- if ((ret = __db_up_ovref(dbp, fhp,
- ((BOVERFLOW *)(child_bi->data))->pgno)) != 0)
- return (ret);
- break;
- case P_LDUP:
- child_bk = GET_BKEYDATA(page, 0);
- switch (B_TYPE(child_bk->type)) {
- case B_KEYDATA:
- if (P_FREESPACE(ipage) <
- BINTERNAL_PSIZE(child_bk->len)) {
- *nomemp = 1;
- return (0);
- }
- ipage->inp[indx] =
- HOFFSET(ipage) -= BINTERNAL_SIZE(child_bk->len);
- p = P_ENTRY(ipage, indx);
- bi.len = child_bk->len;
- B_TSET(bi.type, child_bk->type, 0);
- bi.pgno = PGNO(page);
- bi.nrecs = __bam_total(page);
- memcpy(p, &bi, SSZA(BINTERNAL, data));
- p += SSZA(BINTERNAL, data);
- memcpy(p, child_bk->data, child_bk->len);
- break;
- case B_OVERFLOW:
- if (P_FREESPACE(ipage) <
- BINTERNAL_PSIZE(BOVERFLOW_SIZE)) {
- *nomemp = 1;
- return (0);
- }
- ipage->inp[indx] =
- HOFFSET(ipage) -= BINTERNAL_SIZE(BOVERFLOW_SIZE);
- p = P_ENTRY(ipage, indx);
- bi.len = BOVERFLOW_SIZE;
- B_TSET(bi.type, child_bk->type, 0);
- bi.pgno = PGNO(page);
- bi.nrecs = __bam_total(page);
- memcpy(p, &bi, SSZA(BINTERNAL, data));
- p += SSZA(BINTERNAL, data);
- memcpy(p, child_bk, BOVERFLOW_SIZE);
- /* Increment the overflow ref count. */
- if ((ret = __db_up_ovref(dbp, fhp,
- ((BOVERFLOW *)child_bk)->pgno)) != 0)
- return (ret);
- break;
- default:
- return (__db_pgfmt(dbp, PGNO(page)));
- }
- break;
- default:
- return (__db_pgfmt(dbp, PGNO(page)));
- }
- return (0);
- }
- /*
- * __db_build_ri --
- * Build a RINTERNAL entry for an internal parent page.
- */
- static int
- __db_build_ri(dbp, fhp, ipage, page, indx, nomemp)
- DB *dbp;
- DB_FH *fhp;
- PAGE *ipage, *page;
- u_int32_t indx;
- int *nomemp;
- {
- RINTERNAL ri;
- COMPQUIET(dbp, NULL);
- COMPQUIET(fhp, NULL);
- if (P_FREESPACE(ipage) < RINTERNAL_PSIZE) {
- *nomemp = 1;
- return (0);
- }
- ri.pgno = PGNO(page);
- ri.nrecs = __bam_total(page);
- ipage->inp[indx] = HOFFSET(ipage) -= RINTERNAL_SIZE;
- memcpy(P_ENTRY(ipage, indx), &ri, RINTERNAL_SIZE);
- return (0);
- }
- /*
- * __db_up_ovref --
- * Increment/decrement the reference count on an overflow page.
- */
- static int
- __db_up_ovref(dbp, fhp, pgno)
- DB *dbp;
- DB_FH *fhp;
- db_pgno_t pgno;
- {
- PAGE *page;
- size_t n;
- int ret;
- /* Allocate room to hold a page. */
- if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &page)) != 0)
- return (ret);
- GET_PAGE(dbp, fhp, pgno, page);
- ++OV_REF(page);
- PUT_PAGE(dbp, fhp, pgno, page);
- err: __os_free(page, dbp->pgsize);
- return (ret);
- }