/* * Called when bufp's page contains a partial key (index should be 1) * * All pages in the big key/data pair except bufp are freed. We cannot * free bufp because the page pointing to it is lost and we can't get rid * of its pointer. * * Returns: * 0 => OK *-1 => ERROR */ int __big_delete(HTAB *hashp, BUFHEAD *bufp) { BUFHEAD *last_bfp, *rbufp; uint16_t *bp, pageno; int key_done, n; size_t temp; rbufp = bufp; last_bfp = NULL; bp = (uint16_t *)(void *)bufp->page; pageno = 0; key_done = 0; while (!key_done || (bp[2] != FULL_KEY_DATA)) { if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) key_done = 1; /* * If there is freespace left on a FULL_KEY_DATA page, then * the data is short and fits entirely on this page, and this * is the last page. */ if (bp[2] == FULL_KEY_DATA && FREESPACE(bp)) break; pageno = bp[bp[0] - 1]; rbufp->flags |= BUF_MOD; rbufp = __get_buf(hashp, (uint32_t)pageno, rbufp, 0); if (last_bfp) __free_ovflpage(hashp, last_bfp); last_bfp = rbufp; if (!rbufp) return (-1); /* Error. */ bp = (uint16_t *)(void *)rbufp->page; } /* * If we get here then rbufp points to the last page of the big * key/data pair. Bufp points to the first one -- it should now be * empty pointing to the next page after this pair. Can't free it * because we don't have the page pointing to it. */ /* This is information from the last page of the pair. */ n = bp[0]; pageno = bp[n - 1]; /* Now, bp is the first page of the pair. */ bp = (uint16_t *)(void *)bufp->page; if (n > 2) { /* There is an overflow page. */ bp[1] = pageno; bp[2] = OVFLPAGE; bufp->ovfl = rbufp->ovfl; } else /* This is the last page. */ bufp->ovfl = NULL; n -= 2; bp[0] = n; temp = hashp->BSIZE - PAGE_META(n); _DBFIT(temp, uint16_t); FREESPACE(bp) = (uint16_t)temp; OFFSET(bp) = hashp->BSIZE; bufp->flags |= BUF_MOD; if (rbufp) __free_ovflpage(hashp, rbufp); if (last_bfp && last_bfp != rbufp) __free_ovflpage(hashp, last_bfp); hashp->NKEYS--; return (0); }
/* * Called when we encounter an overflow or big key/data page during split * handling. This is special cased since we have to begin checking whether * the key/data pairs fit on their respective pages and because we may need * overflow pages for both the old and new pages. * * The first page might be a page with regular key/data pairs in which case * we have a regular overflow condition and just need to go on to the next * page or it might be a big key/data pair in which case we need to fix the * big key/data pair. * * Returns: * 0 ==> success * -1 ==> failure */ static int ugly_split( HTAB *hashp, uint32_t obucket, /* Same as __split_page. */ BUFHEAD *old_bufp, BUFHEAD *new_bufp, int copyto, /* First byte on page which contains key/data values. */ int moved /* Number of pairs moved to new page. */ ) { BUFHEAD *bufp; /* Buffer header for ino */ uint16_t *ino; /* Page keys come off of */ uint16_t *np; /* New page */ uint16_t *op; /* Page keys go on to if they aren't moving */ size_t temp; BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */ DBT key, val; SPLIT_RETURN ret; uint16_t n, off, ov_addr, scopyto; char *cino; /* Character value of ino */ bufp = old_bufp; ino = (uint16_t *)(void *)old_bufp->page; np = (uint16_t *)(void *)new_bufp->page; op = (uint16_t *)(void *)old_bufp->page; last_bfp = NULL; scopyto = (uint16_t)copyto; /* ANSI */ n = ino[0] - 1; while (n < ino[0]) { if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) { if (__big_split(hashp, old_bufp, new_bufp, bufp, (int)bufp->addr, obucket, &ret)) return (-1); old_bufp = ret.oldp; if (!old_bufp) return (-1); op = (uint16_t *)(void *)old_bufp->page; new_bufp = ret.newp; if (!new_bufp) return (-1); np = (uint16_t *)(void *)new_bufp->page; bufp = ret.nextp; if (!bufp) return (0); cino = (char *)bufp->page; ino = (uint16_t *)(void *)cino; last_bfp = ret.nextp; } else if (ino[n + 1] == OVFLPAGE) { ov_addr = ino[n]; /* * Fix up the old page -- the extra 2 are the fields * which contained the overflow information. */ ino[0] -= (moved + 2); temp = sizeof(uint16_t) * (ino[0] + 3); _DIAGASSERT(scopyto >= temp); FREESPACE(ino) = (uint16_t)(scopyto - temp); OFFSET(ino) = scopyto; bufp = __get_buf(hashp, (uint32_t)ov_addr, bufp, 0); if (!bufp) return (-1); ino = (uint16_t *)(void *)bufp->page; n = 1; scopyto = hashp->BSIZE; moved = 0; if (last_bfp) __free_ovflpage(hashp, last_bfp); last_bfp = bufp; } /* Move regular sized pairs of there are any */ off = hashp->BSIZE; for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) { cino = (char *)(void *)ino; key.data = (uint8_t *)cino + ino[n]; key.size = off - ino[n]; val.data = (uint8_t *)cino + ino[n + 1]; val.size = ino[n] - ino[n + 1]; off = ino[n + 1]; if (__call_hash(hashp, key.data, (int)key.size) == obucket) { /* Keep on old page */ if (PAIRFITS(op, (&key), (&val))) putpair((char *)(void *)op, &key, &val); else { old_bufp = __add_ovflpage(hashp, old_bufp); if (!old_bufp) return (-1); op = (uint16_t *)(void *)old_bufp->page; putpair((char *)(void *)op, &key, &val); } old_bufp->flags |= BUF_MOD; } else { /* Move to new page */ if (PAIRFITS(np, (&key), (&val))) putpair((char *)(void *)np, &key, &val); else { new_bufp = __add_ovflpage(hashp, new_bufp); if (!new_bufp) return (-1); np = (uint16_t *)(void *)new_bufp->page; putpair((char *)(void *)np, &key, &val); } new_bufp->flags |= BUF_MOD; } } } if (last_bfp) __free_ovflpage(hashp, last_bfp); return (0); }
static int ugly_split(HTAB *hashp, uint32 obucket, BUFHEAD *old_bufp, BUFHEAD *new_bufp, /* Same as __split_page. */ int copyto, int moved) /* int copyto; First byte on page which contains key/data values. */ /* int moved; Number of pairs moved to new page. */ { register BUFHEAD *bufp; /* Buffer header for ino */ register uint16 *ino; /* Page keys come off of */ register uint16 *np; /* New page */ register uint16 *op; /* Page keys go on to if they aren't moving */ uint32 loop_detection = 0; BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */ DBT key, val; SPLIT_RETURN ret; uint16 n, off, ov_addr, scopyto; char *cino; /* Character value of ino */ int status; bufp = old_bufp; ino = (uint16 *)old_bufp->page; np = (uint16 *)new_bufp->page; op = (uint16 *)old_bufp->page; last_bfp = NULL; scopyto = (uint16)copyto; /* ANSI */ n = ino[0] - 1; while (n < ino[0]) { /* this function goes nuts sometimes and never returns. * I havent found the problem yet but I need a solution * so if we loop too often we assume a database curruption error * :LJM */ loop_detection++; if (loop_detection > MAX_UGLY_SPLIT_LOOPS) return DATABASE_CORRUPTED_ERROR; if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) { if ((status = __big_split(hashp, old_bufp, new_bufp, bufp, bufp->addr, obucket, &ret))) return (status); old_bufp = ret.oldp; if (!old_bufp) return (-1); op = (uint16 *)old_bufp->page; new_bufp = ret.newp; if (!new_bufp) return (-1); np = (uint16 *)new_bufp->page; bufp = ret.nextp; if (!bufp) return (0); cino = (char *)bufp->page; ino = (uint16 *)cino; last_bfp = ret.nextp; } else if (ino[n + 1] == OVFLPAGE) { ov_addr = ino[n]; /* * Fix up the old page -- the extra 2 are the fields * which contained the overflow information. */ ino[0] -= (moved + 2); FREESPACE(ino) = scopyto - sizeof(uint16) * (ino[0] + 3); OFFSET(ino) = scopyto; bufp = __get_buf(hashp, ov_addr, bufp, 0); if (!bufp) return (-1); ino = (uint16 *)bufp->page; n = 1; scopyto = hashp->BSIZE; moved = 0; if (last_bfp) __free_ovflpage(hashp, last_bfp); last_bfp = bufp; } /* Move regular sized pairs of there are any */ off = hashp->BSIZE; for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) { cino = (char *)ino; key.data = (uint8 *)cino + ino[n]; key.size = off - ino[n]; val.data = (uint8 *)cino + ino[n + 1]; val.size = ino[n] - ino[n + 1]; off = ino[n + 1]; if (__call_hash(hashp, (char *)key.data, key.size) == obucket) { /* Keep on old page */ if (PAIRFITS(op, (&key), (&val))) putpair((char *)op, &key, &val); else { old_bufp = __add_ovflpage(hashp, old_bufp); if (!old_bufp) return (-1); op = (uint16 *)old_bufp->page; putpair((char *)op, &key, &val); } old_bufp->flags |= BUF_MOD; } else { /* Move to new page */ if (PAIRFITS(np, (&key), (&val))) putpair((char *)np, &key, &val); else { new_bufp = __add_ovflpage(hashp, new_bufp); if (!new_bufp) return (-1); np = (uint16 *)new_bufp->page; putpair((char *)np, &key, &val); } new_bufp->flags |= BUF_MOD; } } } if (last_bfp) __free_ovflpage(hashp, last_bfp); return (0); }