diff options
Diffstat (limited to 'src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c')
| -rw-r--r-- | src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c b/src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c new file mode 100644 index 000000000000..4b95278f535f --- /dev/null +++ b/src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c @@ -0,0 +1,481 @@ +/*- + * 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 + * documentation and/or other materials provided with the distribution. + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)hash_bigkey.c 8.5 (Berkeley) 11/2/95"; +#endif /* LIBC_SCCS and not lint */ + +/* + * PACKAGE: hash + * DESCRIPTION: + * Big key/data handling for the hashing package. + * + * ROUTINES: + * External + * __big_keydata + * __big_split + * __big_insert + * __big_return + * __big_delete + * __find_last_page + * Internal + * collect_key + * collect_data + */ +#include <sys/types.h> + +#include <stdlib.h> +#include <string.h> + +#ifdef DEBUG +#include <assert.h> +#endif + +#include "db-int.h" +#include "hash.h" +#include "page.h" +#include "extern.h" + +static int32_t collect_key __P((HTAB *, PAGE16 *, int32_t, db_pgno_t *)); +static int32_t collect_data __P((HTAB *, PAGE16 *, int32_t)); + +/* + * Big_insert + * + * You need to do an insert and the key/data pair is greater than + * MINFILL * the bucket size + * + * Returns: + * 0 ==> OK + * -1 ==> ERROR + */ +int32_t +__big_insert(hashp, pagep, key, val) + HTAB *hashp; + PAGE16 *pagep; + const DBT *key, *val; +{ + size_t key_size, val_size; + indx_t key_move_bytes, val_move_bytes; + int8_t *key_data, *val_data, base_page; + + key_data = (int8_t *)key->data; + key_size = key->size; + val_data = (int8_t *)val->data; + val_size = val->size; + + NUM_ENT(pagep) = NUM_ENT(pagep) + 1; + + for (base_page = 1; key_size + val_size;) { + /* Add a page! */ + pagep = + __add_bigpage(hashp, pagep, NUM_ENT(pagep) - 1, base_page); + if (!pagep) + return (-1); + + /* There's just going to be one entry on this page. */ + NUM_ENT(pagep) = 1; + + /* Move the key's data. */ + key_move_bytes = MIN(FREESPACE(pagep), key_size); + /* Mark the page as to how much key & data is on this page. */ + BIGKEYLEN(pagep) = key_move_bytes; + val_move_bytes = + MIN(FREESPACE(pagep) - key_move_bytes, val_size); + BIGDATALEN(pagep) = val_move_bytes; + + /* Note big pages build beginning --> end, not vice versa. */ + if (key_move_bytes) + memmove(BIGKEY(pagep), key_data, key_move_bytes); + if (val_move_bytes) + memmove(BIGDATA(pagep), val_data, val_move_bytes); + + key_size -= key_move_bytes; + key_data += key_move_bytes; + val_size -= val_move_bytes; + val_data += val_move_bytes; + + base_page = 0; + } + __put_page(hashp, pagep, A_RAW, 1); + return (0); +} + +/* + * Called when we need to delete a big pair. + * + * Returns: + * 0 => OK + * -1 => ERROR + */ +int32_t +#ifdef __STDC__ +__big_delete(HTAB *hashp, PAGE16 *pagep, indx_t ndx) +#else +__big_delete(hashp, pagep, ndx) + HTAB *hashp; + PAGE16 *pagep; + u_int32_t ndx; /* Index of big pair on base page. */ +#endif +{ + PAGE16 *last_pagep; + + /* Get first page with big key/data. */ + pagep = __get_page(hashp, OADDR_TO_PAGE(DATA_OFF(pagep, ndx)), A_RAW); + if (!pagep) + return (-1); + + /* + * Traverse through the pages, freeing the previous one (except + * the first) at each new page. + */ + while (NEXT_PGNO(pagep) != INVALID_PGNO) { + last_pagep = pagep; + pagep = __get_page(hashp, NEXT_PGNO(pagep), A_RAW); + if (!pagep) + return (-1); + __delete_page(hashp, last_pagep, A_OVFL); + } + + /* Free the last page in the chain. */ + __delete_page(hashp, pagep, A_OVFL); + return (0); +} + +/* + * Given a key, indicates whether the big key at cursorp matches the + * given key. + * + * Returns: + * 1 = Found! + * 0 = Key not found + * -1 error + */ +int32_t +__find_bigpair(hashp, cursorp, key, size) + HTAB *hashp; + CURSOR *cursorp; + int8_t *key; + int32_t size; +{ + PAGE16 *pagep, *hold_pagep; + db_pgno_t next_pgno; + int32_t ksize; + int8_t *kkey; + + ksize = size; + kkey = key; + + hold_pagep = NULL; + /* Chances are, hashp->cpage is the base page. */ + if (cursorp->pagep) + pagep = hold_pagep = cursorp->pagep; + else { + pagep = __get_page(hashp, cursorp->pgno, A_RAW); + if (!pagep) + return (-1); + } + + /* + * Now, get the first page with the big stuff on it. + * + * XXX + * KLUDGE: we know that cursor is looking at the _next_ item, so + * we have to look at pgndx - 1. + */ + next_pgno = OADDR_TO_PAGE(DATA_OFF(pagep, (cursorp->pgndx - 1))); + if (!hold_pagep) + __put_page(hashp, pagep, A_RAW, 0); + pagep = __get_page(hashp, next_pgno, A_RAW); + if (!pagep) + return (-1); + + /* While there are both keys to compare. */ + while ((ksize > 0) && (BIGKEYLEN(pagep))) { + if (ksize < KEY_OFF(pagep, 0) || + memcmp(BIGKEY(pagep), kkey, BIGKEYLEN(pagep))) { + __put_page(hashp, pagep, A_RAW, 0); + return (0); + } + kkey += BIGKEYLEN(pagep); + ksize -= BIGKEYLEN(pagep); + if (NEXT_PGNO(pagep) != INVALID_PGNO) { + next_pgno = NEXT_PGNO(pagep); + __put_page(hashp, pagep, A_RAW, 0); + pagep = __get_page(hashp, next_pgno, A_RAW); + if (!pagep) + return (-1); + } + } + __put_page(hashp, pagep, A_RAW, 0); +#ifdef DEBUG + assert(ksize >= 0); +#endif + if (ksize != 0) { +#ifdef HASH_STATISTICS + ++hash_collisions; +#endif + return (0); + } else + return (1); +} + +/* + * Fill in the key and data for this big pair. + */ +int32_t +__big_keydata(hashp, pagep, key, val, ndx) + HTAB *hashp; + PAGE16 *pagep; + DBT *key, *val; + int32_t ndx; +{ + ITEM_INFO ii; + PAGE16 *key_pagep; + db_pgno_t last_page; + + key_pagep = + __get_page(hashp, OADDR_TO_PAGE(DATA_OFF(pagep, ndx)), A_RAW); + if (!key_pagep) + return (-1); + key->size = collect_key(hashp, key_pagep, 0, &last_page); + key->data = hashp->bigkey_buf; + __put_page(hashp, key_pagep, A_RAW, 0); + + if (key->size == (size_t)-1) + return (-1); + + /* Create an item_info to direct __big_return to the beginning pgno. */ + ii.pgno = last_page; + return (__big_return(hashp, &ii, val, 1)); +} + +/* + * Return the big key on page, ndx. + */ +int32_t +#ifdef __STDC__ +__get_bigkey(HTAB *hashp, PAGE16 *pagep, indx_t ndx, DBT *key) +#else +__get_bigkey(hashp, pagep, ndx, key) + HTAB *hashp; + PAGE16 *pagep; + u_int32_t ndx; + DBT *key; +#endif +{ + PAGE16 *key_pagep; + + key_pagep = + __get_page(hashp, OADDR_TO_PAGE(DATA_OFF(pagep, ndx)), A_RAW); + if (!key_pagep) + return (-1); + key->size = collect_key(hashp, key_pagep, 0, NULL); + key->data = hashp->bigkey_buf; + + __put_page(hashp, key_pagep, A_RAW, 0); + + return (0); +} + +/* + * Return the big key and data indicated in item_info. + */ +int32_t +__big_return(hashp, item_info, val, on_bigkey_page) + HTAB *hashp; + ITEM_INFO *item_info; + DBT *val; + int32_t on_bigkey_page; +{ + PAGE16 *pagep; + db_pgno_t next_pgno; + + if (!on_bigkey_page) { + /* Get first page with big pair on it. */ + pagep = __get_page(hashp, + OADDR_TO_PAGE(item_info->data_off), A_RAW); + if (!pagep) + return (-1); + } else { + pagep = __get_page(hashp, item_info->pgno, A_RAW); + if (!pagep) + return (-1); + } + + /* Traverse through the bigkey pages until a page with data is found. */ + while (!BIGDATALEN(pagep)) { + next_pgno = NEXT_PGNO(pagep); + __put_page(hashp, pagep, A_RAW, 0); + pagep = __get_page(hashp, next_pgno, A_RAW); + if (!pagep) + return (-1); + } + + val->size = collect_data(hashp, pagep, 0); + if (val->size < 1) + return (-1); + val->data = (void *)hashp->bigdata_buf; + + __put_page(hashp, pagep, A_RAW, 0); + return (0); +} + +/* + * Given a page with a big key on it, traverse through the pages counting data + * length, and collect all of the data on the way up. Store the key in + * hashp->bigkey_buf. last_page indicates to the calling function what the + * last page with key on it is; this will help if you later want to retrieve + * the data portion. + * + * Does the work for __get_bigkey. + * + * Return total length of data; -1 if error. + */ +static int32_t +collect_key(hashp, pagep, len, last_page) + HTAB *hashp; + PAGE16 *pagep; + int32_t len; + db_pgno_t *last_page; +{ + PAGE16 *next_pagep; + int32_t totlen, retval; + db_pgno_t next_pgno; +#ifdef DEBUG + db_pgno_t save_addr; +#endif + + /* If this is the last page with key. */ + if (BIGDATALEN(pagep)) { + totlen = len + BIGKEYLEN(pagep); + if (hashp->bigkey_buf) + free(hashp->bigkey_buf); + hashp->bigkey_buf = (u_int8_t *)malloc(totlen); + if (!hashp->bigkey_buf) + return (-1); + memcpy(hashp->bigkey_buf + len, + BIGKEY(pagep), BIGKEYLEN(pagep)); + if (last_page) + *last_page = ADDR(pagep); + return (totlen); + } + + /* Key filled up all of last key page, so we've gone 1 too far. */ + if (BIGKEYLEN(pagep) == 0) { + if (hashp->bigkey_buf) + free(hashp->bigkey_buf); + hashp->bigkey_buf = (u_int8_t *)malloc(len); + return (hashp->bigkey_buf ? len : -1); + } + totlen = len + BIGKEYLEN(pagep); + + /* Set pagep to the next page in the chain. */ + if (last_page) + *last_page = ADDR(pagep); + next_pgno = NEXT_PGNO(pagep); + next_pagep = __get_page(hashp, next_pgno, A_RAW); + if (!next_pagep) + return (-1); +#ifdef DEBUG + save_addr = ADDR(pagep); +#endif + retval = collect_key(hashp, next_pagep, totlen, last_page); + +#ifdef DEBUG + assert(save_addr == ADDR(pagep)); +#endif + memcpy(hashp->bigkey_buf + len, BIGKEY(pagep), BIGKEYLEN(pagep)); + __put_page(hashp, next_pagep, A_RAW, 0); + + return (retval); +} + +/* + * Given a page with big data on it, recur through the pages counting data + * length, and collect all of the data on the way up. Store the data in + * hashp->bigdata_buf. + * + * Does the work for __big_return. + * + * Return total length of data; -1 if error. + */ +static int32_t +collect_data(hashp, pagep, len) + HTAB *hashp; + PAGE16 *pagep; + int32_t len; +{ + PAGE16 *next_pagep; + int32_t totlen, retval; + db_pgno_t next_pgno; +#ifdef DEBUG + db_pgno_t save_addr; +#endif + + /* If there is no next page. */ + if (NEXT_PGNO(pagep) == INVALID_PGNO) { + if (hashp->bigdata_buf) + free(hashp->bigdata_buf); + totlen = len + BIGDATALEN(pagep); + hashp->bigdata_buf = (u_int8_t *)malloc(totlen); + if (!hashp->bigdata_buf) + return (-1); + memcpy(hashp->bigdata_buf + totlen - BIGDATALEN(pagep), + BIGDATA(pagep), BIGDATALEN(pagep)); + return (totlen); + } + totlen = len + BIGDATALEN(pagep); + + /* Set pagep to the next page in the chain. */ + next_pgno = NEXT_PGNO(pagep); + next_pagep = __get_page(hashp, next_pgno, A_RAW); + if (!next_pagep) + return (-1); + +#ifdef DEBUG + save_addr = ADDR(pagep); +#endif + retval = collect_data(hashp, next_pagep, totlen); +#ifdef DEBUG + assert(save_addr == ADDR(pagep)); +#endif + memcpy(hashp->bigdata_buf + totlen - BIGDATALEN(pagep), + BIGDATA(pagep), BIGDATALEN(pagep)); + __put_page(hashp, next_pagep, A_RAW, 0); + + return (retval); +} |
