#pragma ident "%Z%%M% %I% %E% SMI"
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#endif /* LIBC_SCCS and not lint */
/*
* PACKAGE: hashing
*
* DESCRIPTION:
* Page manipulation for hashing package.
*
* ROUTINES:
*
* External
* __get_page
* __add_ovflpage
* Internal
* overflow_page
* open_temp
*/
#ifdef DEBUG
#include <assert.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
#include "db-int.h"
#include "hash.h"
#include "page.h"
#include "extern.h"
#ifdef DEBUG_SLOW
#endif
{
int32_t i;
/* Check if we need to get a page. */
} else
return (-1);
}
}
/* Fetch next page. */
return (-1);
}
return (-1);
}
}
else
}
/*
* All of this information will be set incorrectly for big keys, but
* it will be ignored anyway.
*/
return (0);
}
{
return (0);
}
{
/*
* We don't throw out the page number since we might want to
* continue getting on this page.
*/
return (0);
}
{
}
/*
* just returns the page number and index of the bigkey pointer pair.
*/
{
int status;
return (status);
}
/*
* Put a non-big pair on a page.
*/
static void
PAGE8 *p;
{
/* Items on the page are 0-indexed. */
/* Adjust page info. */
}
/*
* Returns the index of the next non-bigkey pair after n on the page.
* Returns -1 if there are no more non-big things on the page.
*/
static indx_t
#ifdef __STDC__
#else
next_realkey(pagep, n)
u_int32_t n;
#endif
{
indx_t i;
return (i);
return (-1);
}
/*
* Returns the index of the previous non-bigkey pair after n on the page.
* Returns n if there are no previous non-big things on the page.
*/
static indx_t
#ifdef __STDC__
#else
prev_realkey(pagep, n)
u_int32_t n;
#endif
{
int32_t i;
/* Need a signed value to do the compare properly. */
for (i = n - 1; i > -1; i--)
return (i);
return (n);
}
/*
* Returns:
* 0 OK
* -1 error
*/
extern int32_t
{
short check_ndx;
int32_t n;
if (!pagep)
return (-1);
/*
* KLUGE: pgndx has gone one too far, because cursor points
* to the _next_ item. Use pgndx - 1.
*/
--ndx;
} else
#ifdef DEBUG
#endif
delta = 0;
} else {
/*
* Compute "delta", the amount we have to shift all of the
* offsets. To find the delta, we need to make sure that
*/
check_ndx--);
if (check_ndx < 0)
else
delta =
/*
* The hard case: we want to remove something other than
* the last item on the page. We need to shift data and
* offsets down.
*/
/*
* Move the data: src is the address of the last data
* item on the page.
*/
/*
* Length is the distance between where to start
* deleting and end of the data on the page.
*/
/*
* Dest is the location of the to-be-deleted item
* occupied - length.
*/
if (check_ndx < 0)
dest =
else
}
}
/* Adjust the offsets. */
#ifdef DEBUG
#endif
} else {
}
/* Adjust page metadata. */
/* Is this page now an empty overflow page? If so, free it. */
/*
* We need to go back to the first page in the chain and
* look for this page so that we can update the previous
* page's NEXT_PGNO field.
*/
empty_page = pagep;
if (!pagep)
return (-1);
#ifdef DEBUG
#endif
if (!pagep)
return (-1);
}
/*
* At this point, pagep should point to the page before the
* page to be deleted.
*/
}
}
return (0);
}
extern int32_t
{
u_int16_t n;
base_page = 1;
while (temp_pagep != 0) {
for (n = 0; n < NUM_ENT(temp_pagep); n++) {
if (__call_hash(hashp,
DATA_OFF(temp_pagep, n));
else
DATA_OFF(temp_pagep, n));
} else {
if (__call_hash(hashp,
NO_EXPAND, 1);
else
NO_EXPAND, 1);
}
}
/* Clear temp_page; if it's an overflow page, free it. */
if (!base_page)
else
base_page = 0;
if (next_pgno != INVALID_PGNO)
else
break;
}
return (0);
}
/*
* Add the given pair to the page.
*
*
* Returns:
* 0 ==> OK
* -1 ==> failure
*/
extern int32_t
#ifdef __STDC__
#else
#endif
{
do_expand = 0;
item_info->seek_found_page != 0 ?
if (!pagep)
return (-1);
/* Advance to first page in chain with room for item. */
/*
* This may not be the end of the chain, but the pair may fit
* anyway.
*/
break;
break;
if (!pagep)
return (-1);
}
!BIGPAIRFITS(pagep)) ||
do_expand = 1;
if (!pagep)
return (-1);
!BIGPAIRFITS(pagep)) ||
return (-1);
}
}
/* At this point, we know the page fits, so we just add it */
return (-1);
} else {
}
/*
* For splits, we are going to update item_info's page number
* field, so that we can easily return to the same page the
* next time we come in here. For other operations, this shouldn't
* matter, since adds are the last thing that happens before we
* return to the user program.
*/
if (!expanding)
/* Kludge: if this is a big page, then it's already been put. */
if (expanding)
item_info->caused_expand = 0;
else
switch (num_items) {
case NO_EXPAND:
item_info->caused_expand = 0;
break;
case UNKNOWN:
break;
default:
break;
}
return (0);
}
/*
* Special __addel used in big splitting; this one just puts the pointer
* to an already-allocated big page in the appropriate bucket.
*/
static int32_t
#ifdef __STDC__
#else
#endif
{
if (!pagep)
return (-1);
/*
* Note: in __addel(), we used item_info->pgno for the beginning of
* our search for space. Now, we use item_info->bucket, since we
* know that the space required by a big pair on the base page is
* quite small, and we may very well find that space early in the
* chain.
*/
/* Find first page in chain that has space for a big pair. */
if (BIGPAIRFITS(pagep))
break;
if (!pagep)
return (-1);
}
if (!BIGPAIRFITS(pagep)) {
if (!pagep)
return (-1);
#ifdef DEBUG
#endif
}
return (0);
}
/*
*
* Returns:
* pointer on success
* NULL on error
*/
extern PAGE16 *
{
/* Check if we are dynamically determining the fill factor. */
}
if (!ovfl_num)
return (NULL);
return (NULL);
return (NULL);
#ifdef HASH_STATISTICS
#endif
return (new_pagep);
}
/*
*
* Returns:
* pointer on success
* NULL on error
*/
extern PAGE16 *
#ifdef __STDC__
#else
const u_int32_t is_basepage;
#endif
{
if (!ovfl_num)
return (NULL);
return (NULL);
return (NULL);
if (is_basepage) {
} else
#ifdef HASH_STATISTICS
#endif
return (new_pagep);
}
static void
#ifdef __STDC__
#else
#endif
{
/*
* Note: since in the current version ADDR(pagep) == PREV_PGNO(pagep),
* make sure that ADDR(pagep) is set after resetting PREV_PGNO(pagep).
* We reset PREV_PGNO(pagep) just in case the macros are changed.
*/
return;
}
{
switch (addr_type) { /* Convert page number. */
case A_BUCKET:
break;
case A_OVFL:
case A_BITMAP:
break;
default:
break;
}
if (!pagep)
return (-1);
#if DEBUG_SLOW
#endif
return (0);
}
{
}
static u_int8_t
{
int32_t i;
return (1);
return (0);
}
void
void *pg_cookie;
void *page;
{
/*
* There are the following cases for swapping:
* 0) New page that may be unitialized.
* 1) Bucket page or overflow page. Either swap
* the header or initialize the page.
* 2) Bitmap page. Swap the whole page!
* 3) Header pages. Not handled here; these are written directly
* to the file.
*/
/* XXX check for !0 LSN */
return;
}
return;
for (i = 0; i < max; i++)
} else
}
void
void *pg_cookie;
void *page;
{
/*
* There are the following cases for swapping:
* 1) Bucket page or overflow page. Just swap the header.
* 2) Bitmap page. Swap the whole page!
* 3) Header pages. Not handled here; these are written directly
* to the file.
*/
return;
for (i = 0; i < max; i++)
} else
}
/*
*
* Returns:
* 0 ==> OK
* -1 ==>failure
*/
extern int32_t
{
#if DEBUG_SLOW
#endif
}
/*
* Returns:
* 0 indicates SUCCESS
* -1 indicates FAILURE
*/
extern PAGE16 *
{
switch (addr_type) { /* Convert page number. */
case A_BUCKET:
break;
case A_OVFL:
case A_BITMAP:
break;
default:
break;
}
#if DEBUG_SLOW
#endif
#ifdef DEBUG
#endif
return (pagep);
}
static void
{
u_int32_t i;
/* can leave type and filler alone, since they're 1-byte quantities */
}
}
static void
{
u_int32_t i;
}
/* can leave type and filler alone, since they're 1-byte quantities */
}
/*
* Initialize a new bitmap page. Bitmap pages are left in memory
* once they are read in.
*/
extern int32_t
{
/* make a new bitmap page */
return (1);
return (1);
return (0);
}
static u_int32_t
{
return (i);
}
return (i);
}
/*
* returns 0 on error
*/
static u_int16_t
{
#ifdef DEBUG2
#endif
/*
* Look through all the free maps to find the first free block.
* The compiler under -Wall will complain that freep may be used
* before being set, however, this loop will ALWAYS get executed
* at least once, so freep is guaranteed to be set.
*/
for (i = first_page; i <= free_page; i++) {
return (0);
if (i == free_page)
else
if (i == first_page) {
j = bit / BITS_PER_MAP;
} else {
bit = 0;
j = 0;
}
goto found;
}
/* No Free Page Found */
return (0);
}
offset = 1;
}
/* Check if we need to allocate a new bitmap page. */
free_page++;
return (0);
}
/*
* This is tricky. The 1 indicates that you want the new page
* allocated with 1 clear bit. Actually, you are going to
* allocate 2 pages from this map. The first is going to be
* the map page, the second is the overflow page we were
* looking for. The __ibitmap routine automatically, sets
* the first bit of itself to indicate that the bitmap itself
* is in use. We would explicitly set the second bit, but
* don't have to if we tell __ibitmap not to leave it clear
* in the first place.
*/
return (0);
#ifdef DEBUG2
free_bit = 2;
#endif
offset++;
(void)write(STDERR_FILENO,
return (0);
}
offset = 0;
}
} else {
/*
* Free_bit addresses the last used bit. Bump it to address
* the first available bit.
*/
free_bit++;
}
/* Calculate address of the new overflow page */
#ifdef DEBUG2
"OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n"),
#endif
return (0);
}
return (addr);
#ifdef DEBUG2
tmp2 = i;
#endif
/*
* Bits are addressed starting with 0, but overflow pages are addressed
* beginning at 1. Bit is a bit address number, so we need to increment
* it to convert it to a page number.
*/
/* Calculate the split number for this page */
return (0); /* Out of overflow pages */
#ifdef DEBUG2
"OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n"),
#endif
return (0);
}
/* Allocate and return the overflow page */
return (addr);
}
#ifdef DEBUG
int
int n;
{
int ret_val;
if (n != 0)
return (ret_val);
}
int n;
{
return (ret_val);
}
#endif /* DEBUG */
static indx_t
{
/*
* To convert page number to overflow address:
*
* 1. Find a starting split point -- use 0 since there are only
* 32 split points.
* 2^(sp+1) = hdr.spares[sp+1] > pgno. The overflow address will
* be located at sp.
* 3. return...
*/
break;
#ifdef DEBUG
#endif
return (ret_val);
}
/*
* Mark this overflow page as free.
*/
extern void
{
#ifdef DEBUG2
"Freeing %d\n"), addr);
#endif
#ifdef DEBUG
/*
* This had better never happen. It means we tried to read a bitmap
* that has already had overflow pages allocated off it, and we
* failed to read it from the file.
*/
if (!freep)
assert(0);
#endif
#ifdef DEBUG2
"FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n"),
#endif
}
static u_int32_t *
{
return (NULL);
}
#ifdef DEBUG_SLOW
static void
int inout;
{
static struct {
int times;
static int last;
int i, j;
inout = 0;
/* Find page in list. */
for (i = 0; i < last; i++)
break;
/* Not found. */
if (i == last) {
last++;
}
for (j = i; j < last; j++)
last--;
}
"Warning: pg %d has been out for %d times\n"),
}
#endif /* DEBUG_SLOW */