#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)hash_bigkey.c 8.5 (Berkeley) 11/2/95";
#endif
#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));
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;) {
pagep =
__add_bigpage(hashp, pagep, NUM_ENT(pagep) - 1, base_page);
if (!pagep)
return (-1);
NUM_ENT(pagep) = 1;
key_move_bytes = MIN(FREESPACE(pagep), key_size);
BIGKEYLEN(pagep) = key_move_bytes;
val_move_bytes =
MIN(FREESPACE(pagep) - key_move_bytes, val_size);
BIGDATALEN(pagep) = val_move_bytes;
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);
}
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;
#endif
{
PAGE16 *last_pagep;
pagep = __get_page(hashp, OADDR_TO_PAGE(DATA_OFF(pagep, ndx)), A_RAW);
if (!pagep)
return (-1);
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);
}
__delete_page(hashp, pagep, A_OVFL);
return (0);
}
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;
u_int16_t bytes;
int8_t *kkey;
ksize = size;
kkey = key;
bytes = 0;
hold_pagep = NULL;
if (cursorp->pagep)
pagep = hold_pagep = cursorp->pagep;
else {
pagep = __get_page(hashp, cursorp->pgno, A_RAW);
if (!pagep)
return (-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 ((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);
}
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 == -1)
return (-1);
ii.pgno = last_page;
return (__big_return(hashp, &ii, val, 1));
}
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 (!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);
}
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) {
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);
}
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);
}
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 (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);
}
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);
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);
}
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 (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);
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);
}