📄 bt_cursor.c
字号:
if ((ret = __bam_c_prev(dbc)) != 0) return (ret); if (__bam_isopd(dbc, &pgno)) { cp = (BTREE_CURSOR *)dbc->internal; if ((ret = __db_c_newopd(dbc, pgno, cp->opd, &cp->opd)) != 0) return (ret); if ((ret = cp->opd->c_am_get(cp->opd, &key, &data, DB_LAST, NULL)) != 0) return (ret); } return (0);}/* * __bam_bulk -- Return bulk data from a btree. */static int__bam_bulk(dbc, data, flags) DBC *dbc; DBT *data; u_int32_t flags;{ BKEYDATA *bk; BOVERFLOW *bo; BTREE_CURSOR *cp; PAGE *pg; db_indx_t *inp, indx, pg_keyoff; int32_t *endp, key_off, *offp, *saveoffp; u_int8_t *dbuf, *dp, *np; u_int32_t key_size, size, space; int adj, is_key, need_pg, next_key, no_dup; int pagesize, rec_key, ret; ret = 0; key_off = 0; size = 0; pagesize = dbc->dbp->pgsize; cp = (BTREE_CURSOR *)dbc->internal; /* * dp tracks the beginging of the page in the buffer. * np is the next place to copy things into the buffer. * dbuf always stays at the beging of the buffer. */ dbuf = data->data; np = dp = dbuf; /* Keep track of space that is left. There is a termination entry */ space = data->ulen; space -= sizeof(*offp); /* Build the offset/size table from the end up. */ endp = (int32_t *)((u_int8_t *)dbuf + data->ulen); endp--; offp = endp; key_size = 0; /* * Distinguish between BTREE and RECNO. * There are no keys in RECNO. If MULTIPLE_KEY is specified * then we return the record numbers. * is_key indicates that multiple btree keys are returned. * rec_key is set if we are returning record numbers. * next_key is set if we are going after the next key rather than dup. */ if (dbc->dbtype == DB_BTREE) { is_key = LF_ISSET(DB_MULTIPLE_KEY) ? 1: 0; rec_key = 0; next_key = is_key && LF_ISSET(DB_OPFLAGS_MASK) != DB_NEXT_DUP; adj = 2; } else { is_key = 0; rec_key = LF_ISSET(DB_MULTIPLE_KEY) ? 1 : 0; next_key = LF_ISSET(DB_OPFLAGS_MASK) != DB_NEXT_DUP; adj = 1; } no_dup = LF_ISSET(DB_OPFLAGS_MASK) == DB_NEXT_NODUP;next_pg: indx = cp->indx; pg = cp->page; inp = P_INP(dbc->dbp, pg); /* The current page is not yet in the buffer. */ need_pg = 1; /* * Keep track of the offset of the current key on the page. * If we are returning keys, set it to 0 first so we force * the copy of the key to the buffer. */ pg_keyoff = 0; if (is_key == 0) pg_keyoff = inp[indx]; do { if (IS_DELETED(dbc->dbp, pg, indx)) { if (dbc->dbtype != DB_RECNO) continue; cp->recno++; /* * If we are not returning recnos then we * need to fill in every slot so the user * can calculate the record numbers. */ if (rec_key != 0) continue; space -= 2 * sizeof(*offp); /* Check if space as underflowed. */ if (space > data->ulen) goto back_up; /* Just mark the empty recno slots. */ *offp-- = 0; *offp-- = 0; continue; } /* * Check to see if we have a new key. * If so, then see if we need to put the * key on the page. If its already there * then we just point to it. */ if (is_key && pg_keyoff != inp[indx]) { bk = GET_BKEYDATA(dbc->dbp, pg, indx); if (B_TYPE(bk->type) == B_OVERFLOW) { bo = (BOVERFLOW *)bk; size = key_size = bo->tlen; if (key_size > space) goto get_key_space; if ((ret = __bam_bulk_overflow(dbc, bo->tlen, bo->pgno, np)) != 0) return (ret); space -= key_size; key_off = (int32_t)(np - dbuf); np += key_size; } else { if (need_pg) { dp = np; size = pagesize - HOFFSET(pg); if (space < size) {get_key_space: /* Nothing added, then error. */ if (offp == endp) { data->size = ALIGN(size + pagesize, sizeof(u_int32_t)); return (ENOMEM); } /* * We need to back up to the * last record put into the * buffer so that it is * CURRENT. */ if (indx != 0) indx -= P_INDX; else { if ((ret = __bam_get_prev( dbc)) != 0) return (ret); indx = cp->indx; pg = cp->page; } break; } /* * Move the data part of the page * to the buffer. */ memcpy(dp, (u_int8_t *)pg + HOFFSET(pg), size); need_pg = 0; space -= size; np += size; } key_size = bk->len; key_off = (int32_t)(inp[indx] - HOFFSET(pg) + dp - dbuf + SSZA(BKEYDATA, data)); pg_keyoff = inp[indx]; } } /* * Reserve space for the pointers and sizes. * Either key/data pair or just for a data item. */ space -= (is_key ? 4 : 2) * sizeof(*offp); if (rec_key) space -= sizeof(*offp); /* Check to see if space has underflowed. */ if (space > data->ulen) goto back_up; /* * Determine if the next record is in the * buffer already or if it needs to be copied in. * If we have an off page dup, then copy as many * as will fit into the buffer. */ bk = GET_BKEYDATA(dbc->dbp, pg, indx + adj - 1); if (B_TYPE(bk->type) == B_DUPLICATE) { bo = (BOVERFLOW *)bk; if (is_key) { *offp-- = key_off; *offp-- = key_size; } /* * We pass the offset of the current key. * On return we check to see if offp has * moved to see if any data fit. */ saveoffp = offp; if ((ret = __bam_bulk_duplicates(dbc, bo->pgno, dbuf, is_key ? offp + P_INDX : NULL, &offp, &np, &space, no_dup)) != 0) { if (ret == ENOMEM) { size = space; /* If nothing was added, then error. */ if (offp == saveoffp) { offp += 2; goto back_up; } goto get_space; } return (ret); } } else if (B_TYPE(bk->type) == B_OVERFLOW) { bo = (BOVERFLOW *)bk; size = bo->tlen; if (size > space) goto back_up; if ((ret = __bam_bulk_overflow(dbc, bo->tlen, bo->pgno, np)) != 0) return (ret); space -= size; if (is_key) { *offp-- = key_off; *offp-- = key_size; } else if (rec_key) *offp-- = cp->recno; *offp-- = (int32_t)(np - dbuf); np += size; *offp-- = size; } else { if (need_pg) { dp = np; size = pagesize - HOFFSET(pg); if (space < size) {back_up: /* * Back up the index so that the * last record in the buffer is CURRENT */ if (indx >= adj) indx -= adj; else { if ((ret = __bam_get_prev(dbc)) != 0 && ret != DB_NOTFOUND) return (ret); indx = cp->indx; pg = cp->page; } if (dbc->dbtype == DB_RECNO) cp->recno--;get_space: /* * See if we put anything in the * buffer or if we are doing a DBP->get * did we get all of the data. */ if (offp >= (is_key ? &endp[-1] : endp) || F_ISSET(dbc, DBC_TRANSIENT)) { data->size = ALIGN(size + data->ulen - space, sizeof(u_int32_t)); return (ENOMEM); } break; } memcpy(dp, (u_int8_t *)pg + HOFFSET(pg), size); need_pg = 0; space -= size; np += size; } /* * Add the offsets and sizes to the end of the buffer. * First add the key info then the data info. */ if (is_key) { *offp-- = key_off; *offp-- = key_size; } else if (rec_key) *offp-- = cp->recno; *offp-- = (int32_t)(inp[indx + adj - 1] - HOFFSET(pg) + dp - dbuf + SSZA(BKEYDATA, data)); *offp-- = bk->len; } if (dbc->dbtype == DB_RECNO) cp->recno++; else if (no_dup) { while (indx + adj < NUM_ENT(pg) && pg_keyoff == inp[indx + adj]) indx += adj; } /* * Stop when we either run off the page or we * move to the next key and we are not returning mulitple keys. */ } while ((indx += adj) < NUM_ENT(pg) && (next_key || pg_keyoff == inp[indx])); /* If we are off the page then try to the next page. */ if (ret == 0 && next_key && indx >= NUM_ENT(pg)) { cp->indx = indx; ret = __bam_c_next(dbc, 0, 1); if (ret == 0) goto next_pg; if (ret != DB_NOTFOUND) return (ret); } /* * If we did a DBP->get we must error if we did not return * all the data for the current key because there is * no way to know if we did not get it all, nor any * interface to fetch the balance. */ if (ret == 0 && F_ISSET(dbc, DBC_TRANSIENT) && pg_keyoff == inp[indx]) { data->size = (data->ulen - space) + size; return (ENOMEM); } /* * Must leave the index pointing at the last record fetched. * If we are not fetching keys, we may have stepped to the * next key. */ if (next_key || pg_keyoff == inp[indx]) cp->indx = indx; else cp->indx = indx - P_INDX; if (rec_key == 1) *offp = (u_int32_t) RECNO_OOB; else *offp = (u_int32_t) -1; return (0);}/* * __bam_bulk_overflow -- * Dump overflow record into the buffer. * The space requirements have already been checked. * PUBLIC: int __bam_bulk_overflow * PUBLIC: __P((DBC *, u_int32_t, db_pgno_t, u_int8_t *)); */int__bam_bulk_overflow(dbc, len, pgno, dp) DBC *dbc; u_int32_t len; db_pgno_t pgno; u_int8_t *dp;{ DBT dbt; memset(&dbt, 0, sizeof(dbt)); F_SET(&dbt, DB_DBT_USERMEM); dbt.ulen = len; dbt.data = (void *)dp; return (__db_goff(dbc->dbp, &dbt, len, pgno, NULL, NULL));}/* * __bam_bulk_duplicates -- * Put as many off page duplicates as will fit into the buffer. * This routine will adjust the cursor to reflect the position in * the overflow tree. * PUBLIC: int __bam_bulk_duplicates __P((DBC *, * PUBLIC: db_pgno_t, u_int8_t *, int32_t *, * PUBLIC: int32_t **, u_int8_t **, u_int32_t *, int)); */int__bam_bulk_duplicates(dbc, pgno, dbuf, keyoff, offpp, dpp, spacep, no_dup) DBC *dbc; db_pgno_t pgno; u_int8_t *dbuf; int32_t *keyoff, **offpp; u_int8_t **dpp; u_int32_t *spacep; int no_dup;{ DB *dbp; BKEYDATA *bk; BOVERFLOW *bo; BTREE_CURSOR *cp; DBC *opd; DBT key, data; PAGE *pg; db_indx_t indx, *inp; int32_t *offp; u_int32_t size, space; u_int8_t *dp, *np; int first, need_pg, pagesize, ret, t_ret; ret = 0; dbp = dbc->dbp; cp = (BTREE_CURSOR *)dbc->internal; opd = cp->opd; if (opd == NULL) { if ((ret = __db_c_newopd(dbc, pgno, NULL, &opd)) != 0) return (ret); cp->opd = opd; if ((ret = opd->c_am_get(opd, &key, &data, DB_FIRST, NULL)) != 0) return (ret); } pagesize = opd->dbp->pgsize; cp = (BTREE_CURSOR *)opd->internal; space = *spacep; /* Get current offset slot. */ offp = *offpp; /* * np is the next place to put data. * dp is the begining of the current page in the buffer. */ np = dp = *dpp; first = 1; indx = cp->indx; do { /* Fetch the current record. No initial move. */ if ((ret = __bam_c_next(opd, 0, 0)) != 0) break; pg = cp->page; indx = cp->indx; inp = P_INP(dbp, pg); /* We need to copy the page to the buffer. */ need_pg = 1; do { if (IS_DELETED(dbp, pg, indx)) goto contin; bk = GET_BKEYDATA(dbp, pg, indx); space -= 2 * sizeof(*offp); /* Allocate space for key if needed. */ if (first == 0 && keyoff != NULL) space -= 2 * sizeof(*offp); /* Did space underflow? */ if (space > *spacep) { ret = ENOMEM; if (first == 1) { space = *spacep + -(int32_t)space; if (need_pg) space += pagesize - HOFFSET(pg); } break; } if (B_TYPE(bk->type) == B_OVERFLOW) { bo = (BOVERFLOW *)bk; size = bo->tlen; if (size > space) { ret = ENOMEM; if (first == 1) { space = *spacep + size; } break; } if (first == 0 && keyoff != NULL) { *offp-- = keyoff[0]; *offp-- = keyoff[-1]; } if ((ret = __bam_bulk_overflow(dbc, bo->tlen, bo->pgno, np)) != 0) return (ret); space -= size; *offp-- = (int32_t)(np - dbuf); np += size; } else { if (need_pg) { dp = np; size = pagesize - HOFFSET(pg); if (space < size) { ret = ENOMEM; /* Return space required. */ if (first == 1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -