📄 db_overflow.c
字号:
* * Given a starting page number and a key, return <0, 0, >0 to indicate if the * key on the page is less than, equal to or greater than the key specified. * We optimize this by doing chunk at a time comparison unless the user has * specified a comparison function. In this case, we need to materialize * the entire object and call their comparison routine. * * PUBLIC: int __db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t, * PUBLIC: int (*)(DB *, const DBT *, const DBT *), int *)); */int__db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp) DB *dbp; const DBT *dbt; db_pgno_t pgno; u_int32_t tlen; int (*cmpfunc) __P((DB *, const DBT *, const DBT *)), *cmpp;{ DBT local_dbt; DB_MPOOLFILE *mpf; PAGE *pagep; void *buf; u_int32_t bufsize, cmp_bytes, key_left; u_int8_t *p1, *p2; int ret; mpf = dbp->mpf; /* * If there is a user-specified comparison function, build a * contiguous copy of the key, and call it. */ if (cmpfunc != NULL) { memset(&local_dbt, 0, sizeof(local_dbt)); buf = NULL; bufsize = 0; if ((ret = __db_goff(dbp, &local_dbt, tlen, pgno, &buf, &bufsize)) != 0) return (ret); /* Pass the key as the first argument */ *cmpp = cmpfunc(dbp, dbt, &local_dbt); __os_free(dbp->dbenv, buf); return (0); } /* While there are both keys to compare. */ for (*cmpp = 0, p1 = dbt->data, key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) { if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0) return (ret); cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left; tlen -= cmp_bytes; key_left -= cmp_bytes; for (p2 = (u_int8_t *)pagep + P_OVERHEAD(dbp); cmp_bytes-- > 0; ++p1, ++p2) if (*p1 != *p2) { *cmpp = (long)*p1 - (long)*p2; break; } pgno = NEXT_PGNO(pagep); if ((ret = mpf->put(mpf, pagep, 0)) != 0) return (ret); if (*cmpp != 0) return (0); } if (key_left > 0) /* DBT is longer than the page key. */ *cmpp = 1; else if (tlen > 0) /* DBT is shorter than the page key. */ *cmpp = -1; else *cmpp = 0; return (0);}/* * __db_vrfy_overflow -- * Verify overflow page. * * PUBLIC: int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, * PUBLIC: u_int32_t)); */int__db_vrfy_overflow(dbp, vdp, h, pgno, flags) DB *dbp; VRFY_DBINFO *vdp; PAGE *h; db_pgno_t pgno; u_int32_t flags;{ VRFY_PAGEINFO *pip; int isbad, ret, t_ret; isbad = 0; if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) return (ret); if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { if (ret == DB_VERIFY_BAD) isbad = 1; else goto err; } pip->refcount = OV_REF(h); if (pip->refcount < 1) { EPRINT((dbp->dbenv, "Page %lu: overflow page has zero reference count", (u_long)pgno)); isbad = 1; } /* Just store for now. */ pip->olen = HOFFSET(h);err: if ((t_ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0) ret = t_ret; return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);}/* * __db_vrfy_ovfl_structure -- * Walk a list of overflow pages, avoiding cycles and marking * pages seen. * * PUBLIC: int __db_vrfy_ovfl_structure * PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t)); */int__db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags) DB *dbp; VRFY_DBINFO *vdp; db_pgno_t pgno; u_int32_t tlen; u_int32_t flags;{ DB *pgset; VRFY_PAGEINFO *pip; db_pgno_t next, prev; int isbad, p, ret, t_ret; u_int32_t refcount; pgset = vdp->pgset; DB_ASSERT(pgset != NULL); isbad = 0; /* This shouldn't happen, but just to be sure. */ if (!IS_VALID_PGNO(pgno)) return (DB_VERIFY_BAD); /* * Check the first prev_pgno; it ought to be PGNO_INVALID, * since there's no prev page. */ if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) return (ret); /* The refcount is stored on the first overflow page. */ refcount = pip->refcount; if (pip->type != P_OVERFLOW) { EPRINT((dbp->dbenv, "Page %lu: overflow page of invalid type %lu", (u_long)pgno, (u_long)pip->type)); ret = DB_VERIFY_BAD; goto err; /* Unsafe to continue. */ } prev = pip->prev_pgno; if (prev != PGNO_INVALID) { EPRINT((dbp->dbenv, "Page %lu: first page in overflow chain has a prev_pgno %lu", (u_long)pgno, (u_long)prev)); isbad = 1; } for (;;) { /* * This is slightly gross. Btree leaf pages reference * individual overflow trees multiple times if the overflow page * is the key to a duplicate set. The reference count does not * reflect this multiple referencing. Thus, if this is called * during the structure verification of a btree leaf page, we * check to see whether we've seen it from a leaf page before * and, if we have, adjust our count of how often we've seen it * accordingly. * * (This will screw up if it's actually referenced--and * correctly refcounted--from two different leaf pages, but * that's a very unlikely brokenness that we're not checking for * anyway.) */ if (LF_ISSET(ST_OVFL_LEAF)) { if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) { if ((ret = __db_vrfy_pgset_dec(pgset, pgno)) != 0) goto err; } else F_SET(pip, VRFY_OVFL_LEAFSEEN); } if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0) goto err; /* * We may have seen this elsewhere, if the overflow entry * has been promoted to an internal page. */ if ((u_int32_t)p > refcount) { EPRINT((dbp->dbenv, "Page %lu: encountered twice in overflow traversal", (u_long)pgno)); ret = DB_VERIFY_BAD; goto err; } if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0) goto err; /* Keep a running tab on how much of the item we've seen. */ tlen -= pip->olen; /* Send feedback to the application about our progress. */ if (!LF_ISSET(DB_SALVAGE)) __db_vrfy_struct_feedback(dbp, vdp); next = pip->next_pgno; /* Are we there yet? */ if (next == PGNO_INVALID) break; /* * We've already checked this when we saved it, but just * to be sure... */ if (!IS_VALID_PGNO(next)) { DB_ASSERT(0); EPRINT((dbp->dbenv, "Page %lu: bad next_pgno %lu on overflow page", (u_long)pgno, (u_long)next)); ret = DB_VERIFY_BAD; goto err; } if ((ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 || (ret = __db_vrfy_getpageinfo(vdp, next, &pip)) != 0) return (ret); if (pip->prev_pgno != pgno) { EPRINT((dbp->dbenv, "Page %lu: bad prev_pgno %lu on overflow page (should be %lu)", (u_long)next, (u_long)pip->prev_pgno, (u_long)pgno)); isbad = 1; /* * It's safe to continue because we have separate * cycle detection. */ } pgno = next; } if (tlen > 0) { isbad = 1; EPRINT((dbp->dbenv, "Page %lu: overflow item incomplete", (u_long)pgno)); }err: if ((t_ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0) ret = t_ret; return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);}/* * __db_safe_goff -- * Get an overflow item, very carefully, from an untrusted database, * in the context of the salvager. * * PUBLIC: int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t, * PUBLIC: DBT *, void **, u_int32_t)); */int__db_safe_goff(dbp, vdp, pgno, dbt, buf, flags) DB *dbp; VRFY_DBINFO *vdp; db_pgno_t pgno; DBT *dbt; void **buf; u_int32_t flags;{ DB_MPOOLFILE *mpf; PAGE *h; int ret, t_ret; u_int32_t bytesgot, bytes; u_int8_t *src, *dest; mpf = dbp->mpf; h = NULL; ret = t_ret = 0; bytesgot = bytes = 0; while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) { /* * Mark that we're looking at this page; if we've seen it * already, quit. */ if ((ret = __db_salvage_markdone(vdp, pgno)) != 0) break; if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0) break; /* * Make sure it's really an overflow page, unless we're * being aggressive, in which case we pretend it is. */ if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) { ret = DB_VERIFY_BAD; break; } src = (u_int8_t *)h + P_OVERHEAD(dbp); bytes = OV_LEN(h); if (bytes + P_OVERHEAD(dbp) > dbp->pgsize) bytes = dbp->pgsize - P_OVERHEAD(dbp); if ((ret = __os_realloc(dbp->dbenv, bytesgot + bytes, buf)) != 0) break; dest = (u_int8_t *)*buf + bytesgot; bytesgot += bytes; memcpy(dest, src, bytes); pgno = NEXT_PGNO(h); if ((ret = mpf->put(mpf, h, 0)) != 0) break; h = NULL; } /* * If we're being aggressive, salvage a partial datum if there * was an error somewhere along the way. */ if (ret == 0 || LF_ISSET(DB_AGGRESSIVE)) { dbt->size = bytesgot; dbt->data = *buf; } /* If we broke out on error, don't leave pages pinned. */ if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0 && ret == 0) ret = t_ret; return (ret);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -