#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/btree.h"
#ifdef HAVE_COMPRESSION
static int __bam_compress_marshal_data __P((DB *, const DBT *, DBT *));
static int __bam_compress_set_dbt __P((DB *, DBT *, const void *, u_int32_t));
static int __bam_compress_check_sort_multiple_key __P((DB *, DBT *));
static int __bam_compress_check_sort_multiple __P((DB *, DBT *, DBT *));
static int __bam_compress_check_sort_multiple_keyonly __P((DB *, DBT *));
static int __bamc_compress_del_and_get_next __P((DBC *, DBT *, DBT *));
static int __bamc_compress_get_bothc __P((DBC *, DBT *, u_int32_t));
static int __bamc_compress_get_multiple_key __P((DBC *, DBT *, u_int32_t));
static int __bamc_compress_get_multiple __P((DBC *, DBT *, DBT *,u_int32_t));
static int __bamc_compress_get_next __P((DBC *, u_int32_t));
static int __bamc_compress_get_next_dup __P((DBC *, DBT *, u_int32_t));
static int __bamc_compress_get_next_nodup __P((DBC *, u_int32_t));
static int __bamc_compress_get_prev __P((DBC *, u_int32_t));
static int __bamc_compress_get_prev_dup __P((DBC *, u_int32_t));
static int __bamc_compress_get_prev_nodup __P((DBC *, u_int32_t));
static int __bamc_compress_get_set __P((DBC *,
DBT *, DBT *, u_int32_t, u_int32_t));
static int __bamc_compress_ibulk_del __P((DBC *, DBT *, u_int32_t));
static int __bamc_compress_idel __P((DBC *, u_int32_t));
static int __bamc_compress_iget __P((DBC *, DBT *, DBT *, u_int32_t));
static int __bamc_compress_iput __P((DBC *, DBT *, DBT *, u_int32_t));
static int __bamc_compress_relocate __P((DBC *));
static void __bamc_compress_reset __P((DBC *));
static int __bamc_compress_seek __P((DBC *,
const DBT *, const DBT *, u_int32_t));
static int __bamc_compress_store __P((DBC *,
DBT *, DBT*, DBT **, DBT **, DBT *, DBT *));
static int __bamc_next_decompress __P((DBC *));
static int __bamc_start_decompress __P((DBC *));
#define CMP_IGET_RETRY(ret, dbc, dbt1, dbt2, flags) do { \
DB_ASSERT((dbc)->env, F_ISSET((dbt1), DB_DBT_USERMEM)); \
DB_ASSERT((dbc)->env, F_ISSET((dbt2), DB_DBT_USERMEM)); \
if (((ret) =__dbc_iget((dbc), \
(dbt1), (dbt2), (flags))) == DB_BUFFER_SMALL) { \
if ((CMP_RESIZE_DBT((ret), (dbc)->env, (dbt1))) != 0) \
break; \
if ((CMP_RESIZE_DBT((ret), (dbc)->env, (dbt2))) != 0) \
break; \
(ret) = __dbc_iget((dbc), (dbt1), (dbt2), \
((flags) & ~DB_OPFLAGS_MASK) | DB_CURRENT); \
} \
} while (0)
#define CMP_INIT_DBT(dbt) do { \
(dbt)->data = NULL; \
(dbt)->size = 0; \
(dbt)->ulen = 0; \
(dbt)->doff = 0; \
(dbt)->dlen = 0; \
(dbt)->flags = DB_DBT_USERMEM; \
(dbt)->app_data = NULL; \
} while (0)
#define CMP_FREE_DBT(env, dbt) do { \
DB_ASSERT((env), F_ISSET((dbt), DB_DBT_USERMEM)); \
__os_free((env), (dbt)->data); \
} while (0)
#define CMP_RESIZE_DBT(ret, env, dbt) \
(((dbt)->size > (dbt)->ulen) ? \
((((ret) = __os_realloc((env), (dbt)->size, &(dbt)->data)) \
!= 0) ? (ret) : (((dbt)->ulen = (dbt)->size), 0)) : 0)
static int
__bam_compress_set_dbt(dbp, dbt, data, size)
DB *dbp;
DBT *dbt;
const void *data;
u_int32_t size;
{
int ret;
ret = 0;
DB_ASSERT(dbp->env, F_ISSET(dbt, DB_DBT_USERMEM));
dbt->size = size;
if (CMP_RESIZE_DBT(ret, dbp->env, dbt) != 0)
return (ret);
memcpy(dbt->data, data, size);
return (0);
}
struct __bam_compress_stream;
typedef struct __bam_compress_stream BTREE_COMPRESS_STREAM;
struct __bam_compress_stream
{
int (*next)(BTREE_COMPRESS_STREAM *, DBT *, DBT *);
void *kptr, *dptr;
DBT *key, *data;
};
static int __bam_cs_next_done __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static int __bam_cs_single_next __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static void __bam_cs_create_single
__P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static int __bam_cs_single_keyonly_next
__P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static void __bam_cs_create_single_keyonly
__P((BTREE_COMPRESS_STREAM *, DBT *));
static int __bam_cs_multiple_key_next
__P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static void __bam_cs_create_multiple_key __P((BTREE_COMPRESS_STREAM *, DBT *));
static int __bam_cs_multiple_next __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static void __bam_cs_create_multiple
__P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static int __bam_cs_multiple_keyonly_next
__P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
static void __bam_cs_create_multiple_keyonly
__P((BTREE_COMPRESS_STREAM *, DBT *));
static int __bamc_compress_merge_insert
__P((DBC *, BTREE_COMPRESS_STREAM *, u_int32_t *, u_int32_t));
static int __bamc_compress_merge_delete
__P((DBC *, BTREE_COMPRESS_STREAM *, u_int32_t *));
static int __bamc_compress_merge_delete_dups
__P((DBC *, BTREE_COMPRESS_STREAM *, u_int32_t *));
static int
__bam_cs_next_done(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
COMPQUIET(stream, NULL);
COMPQUIET(key, NULL);
COMPQUIET(data, NULL);
return (0);
}
static int
__bam_cs_single_next(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
key->data = stream->key->data;
key->size = stream->key->size;
data->data = stream->data->data;
data->size = stream->data->size;
stream->next = __bam_cs_next_done;
return (1);
}
static void
__bam_cs_create_single(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
stream->next = __bam_cs_single_next;
stream->key = key;
stream->data = data;
}
static int
__bam_cs_single_keyonly_next(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
key->data = stream->key->data;
key->size = stream->key->size;
if (data != NULL) {
data->data = NULL;
data->size = 0;
}
stream->next = __bam_cs_next_done;
return (1);
}
static void
__bam_cs_create_single_keyonly(stream, key)
BTREE_COMPRESS_STREAM *stream;
DBT *key;
{
stream->next = __bam_cs_single_keyonly_next;
stream->key = key;
}
static int
__bam_cs_multiple_key_next(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
DB_MULTIPLE_KEY_NEXT(stream->kptr, stream->key, key->data, key->size,
data->data, data->size);
if (key->data == NULL) {
stream->next = __bam_cs_next_done;
return (0);
}
return (1);
}
static void
__bam_cs_create_multiple_key(stream, multiple)
BTREE_COMPRESS_STREAM *stream;
DBT *multiple;
{
stream->next = __bam_cs_multiple_key_next;
stream->key = multiple;
DB_MULTIPLE_INIT(stream->kptr, stream->key);
}
static int
__bam_cs_multiple_next(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
DB_MULTIPLE_NEXT(stream->kptr, stream->key, key->data, key->size);
DB_MULTIPLE_NEXT(stream->dptr, stream->data, data->data, data->size);
if (key->data == NULL || data->data == NULL) {
stream->next = __bam_cs_next_done;
return (0);
}
return (1);
}
static void
__bam_cs_create_multiple(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
stream->next = __bam_cs_multiple_next;
stream->key = key;
stream->data = data;
DB_MULTIPLE_INIT(stream->kptr, stream->key);
DB_MULTIPLE_INIT(stream->dptr, stream->data);
}
static int
__bam_cs_multiple_keyonly_next(stream, key, data)
BTREE_COMPRESS_STREAM *stream;
DBT *key, *data;
{
DB_MULTIPLE_NEXT(stream->kptr, stream->key, key->data, key->size);
if (key->data == NULL) {
stream->next = __bam_cs_next_done;
return (0);
}
if (data != NULL) {
data->data = NULL;
data->size = 0;
}
return (1);
}
static void
__bam_cs_create_multiple_keyonly(stream, key)
BTREE_COMPRESS_STREAM *stream;
DBT *key;
{
stream->next = __bam_cs_multiple_keyonly_next;
stream->key = key;
DB_MULTIPLE_INIT(stream->kptr, stream->key);
}
static int
__bam_compress_marshal_data(dbp, data, destbuf)
DB *dbp;
const DBT *data;
DBT *destbuf;
{
int ret;
u_int8_t *ptr;
ret = 0;
DB_ASSERT(dbp->env, F_ISSET(destbuf, DB_DBT_USERMEM));
destbuf->size = __db_compress_count_int(data->size);
destbuf->size += data->size;
if (CMP_RESIZE_DBT(ret, dbp->env, destbuf) != 0)
return (ret);
ptr = (u_int8_t*)destbuf->data;
ptr += __db_compress_int(ptr, data->size);
memcpy(ptr, data->data, data->size);
return (0);
}
#define CMP_UNMARSHAL_DATA(src, dest) do { \
(dest)->data = ((u_int8_t*)(src)->data) + \
__db_decompress_int32((u_int8_t*)(src)->data, \
&(dest)->size); \
} while (0)
int
__bam_compress_dupcmp(db, a, b)
DB *db;
const DBT *a;
const DBT *b;
{
DBT dcmp_a, dcmp_b;
CMP_UNMARSHAL_DATA(a, &dcmp_a);
dcmp_a.ulen = 0;
dcmp_a.doff = 0;
dcmp_a.dlen = 0;
dcmp_a.flags = 0;
dcmp_a.app_data = 0;
CMP_UNMARSHAL_DATA(b, &dcmp_b);
dcmp_b.ulen = 0;
dcmp_b.doff = 0;
dcmp_b.dlen = 0;
dcmp_b.flags = 0;
dcmp_b.app_data = 0;
return ((BTREE *)db->bt_internal)->
compress_dup_compare(db, &dcmp_a, &dcmp_b);
}
int
__bam_defcompress(dbp, prevKey, prevData, key, data, dest)
DB *dbp;
const DBT *prevKey, *prevData, *key, *data;
DBT *dest;
{
u_int8_t *ptr;
const u_int8_t *k, *p;
size_t len, prefix, suffix;
COMPQUIET(dbp, NULL);
k = (const u_int8_t*)key->data;
p = (const u_int8_t*)prevKey->data;
len = key->size > prevKey->size ? prevKey->size : key->size;
for (; len-- && *k == *p; ++k, ++p)
continue;
prefix = (size_t)(k - (u_int8_t*)key->data);
suffix = key->size - prefix;
if (prefix == prevKey->size && suffix == 0) {
k = (const u_int8_t*)data->data;
p = (const u_int8_t*)prevData->data;
len = data->size > prevData->size ? prevData->size : data->size;
for (; len-- && *k == *p; ++k, ++p)
continue;
prefix = (size_t)(k - (u_int8_t*)data->data);
suffix = data->size - prefix;
dest->size = (u_int32_t)(1 + __db_compress_count_int(prefix) +
__db_compress_count_int(suffix) + suffix);
if (dest->size > dest->ulen)
return (DB_BUFFER_SMALL);
ptr = (u_int8_t*)dest->data;
*ptr = CMP_INT_SPARE_VAL;
++ptr;
ptr += __db_compress_int(ptr, prefix);
ptr += __db_compress_int(ptr, suffix);
memcpy(ptr, k, suffix);
return (0);
}
dest->size = (u_int32_t)(__db_compress_count_int(prefix) +
__db_compress_count_int(suffix) +
__db_compress_count_int(data->size) + suffix + data->size);
if (dest->size > dest->ulen)
return (DB_BUFFER_SMALL);
ptr = (u_int8_t*)dest->data;
ptr += __db_compress_int(ptr, prefix);
ptr += __db_compress_int(ptr, suffix);
ptr += __db_compress_int(ptr, data->size);
memcpy(ptr, k, suffix);
ptr += suffix;
memcpy(ptr, data->data, data->size);
return (0);
}
int
__bam_defdecompress(dbp, prevKey, prevData, compressed, destKey, destData)
DB *dbp;
const DBT *prevKey, *prevData;
DBT *compressed, *destKey, *destData;
{
u_int8_t *s, *d;
u_int32_t prefix, suffix, size;
COMPQUIET(dbp, NULL);
s = (u_int8_t*)compressed->data;
if (*s == CMP_INT_SPARE_VAL) {
++s;
size = 1;
size += __db_decompress_count_int(s);
if (size > compressed->size)
return (EINVAL);
s += __db_decompress_int32(s, &prefix);
size += __db_decompress_count_int(s);
if (size > compressed->size)
return (EINVAL);
s += __db_decompress_int32(s, &suffix);
destKey->size = prevKey->size;
destData->size = prefix + suffix;
if (destKey->size > destKey->ulen ||
destData->size > destData->ulen)
return (DB_BUFFER_SMALL);
memcpy(destKey->data, prevKey->data, destKey->size);
if (prefix > prevData->size)
return (EINVAL);
d = (u_int8_t*)destData->data;
memcpy(d, prevData->data, prefix);
d += prefix;
size += suffix;
if (size > compressed->size)
return (EINVAL);
memcpy(d, s, suffix);
s += suffix;
compressed->size = (u_int32_t)(s - (u_int8_t*)compressed->data);
return (0);
}
size = __db_decompress_count_int(s);
if (size > compressed->size)
return (EINVAL);
s += __db_decompress_int32(s, &prefix);
size += __db_decompress_count_int(s);
if (size > compressed->size)
return (EINVAL);
s += __db_decompress_int32(s, &suffix);
size += __db_decompress_count_int(s);
if (size > compressed->size)
return (EINVAL);
s += __db_decompress_int32(s, &destData->size);
destKey->size = prefix + suffix;
if (destKey->size > destKey->ulen || destData->size > destData->ulen)
return (DB_BUFFER_SMALL);
if (prefix > prevKey->size)
return (EINVAL);
d = (u_int8_t*)destKey->data;
memcpy(d, prevKey->data, prefix);
d += prefix;
size += suffix;
if (size > compressed->size)
return (EINVAL);
memcpy(d, s, suffix);
s += suffix;
size += destData->size;
if (size > compressed->size)
return (EINVAL);
memcpy(destData->data, s, destData->size);
s += destData->size;
compressed->size = (u_int32_t)(s - (u_int8_t*)compressed->data);
return (0);
}
static int
__bamc_start_decompress(dbc)
DBC *dbc;
{
BTREE_CURSOR *cp;
int ret;
u_int32_t datasize;
cp = (BTREE_CURSOR *)dbc->internal;
cp->prevKey = NULL;
cp->prevData = NULL;
cp->currentKey = &cp->key1;
cp->currentData = &cp->data1;
cp->compcursor = (u_int8_t*)cp->compressed.data;
cp->compend = cp->compcursor + cp->compressed.size;
cp->prevcursor = NULL;
cp->prev2cursor = NULL;
cp->compcursor += __db_decompress_int32(cp->compcursor, &datasize);
ret = __bam_compress_set_dbt(dbc->dbp,
cp->currentData, cp->compcursor, datasize);
if (ret == 0)
cp->compcursor += datasize;
return (ret);
}
static int
__bamc_next_decompress(dbc)
DBC *dbc;
{
DBT compressed;
int ret;
BTREE_CURSOR *cp;
DB *db;
ret = 0;
cp = (BTREE_CURSOR *)dbc->internal;
db = dbc->dbp;
if (cp->compcursor >= cp->compend)
return (DB_NOTFOUND);
cp->prevKey = cp->currentKey;
cp->prevData = cp->currentData;
cp->prev2cursor = cp->prevcursor;
cp->prevcursor = cp->compcursor;
if (cp->currentKey == &cp->key1) {
cp->currentKey = &cp->key2;
cp->currentData = &cp->data2;
} else {
cp->currentKey = &cp->key1;
cp->currentData = &cp->data1;
}
compressed.flags = DB_DBT_USERMEM;
compressed.data = (void*)cp->compcursor;
compressed.ulen = compressed.size =
(u_int32_t)(cp->compend - cp->compcursor);
compressed.app_data = NULL;
while ((ret = ((BTREE *)db->bt_internal)->bt_decompress(db,
cp->prevKey, cp->prevData, &compressed,
cp->currentKey, cp->currentData)) == DB_BUFFER_SMALL) {
if (CMP_RESIZE_DBT(ret, dbc->env, cp->currentKey) != 0)
break;
if (CMP_RESIZE_DBT(ret, dbc->env, cp->currentData) != 0)
break;
}
if (ret == 0)
cp->compcursor += compressed.size;
return (ret);
}
static int
__bamc_compress_store(dbc, key, data, prevKey, prevData, destkey, destbuf)
DBC *dbc;
DBT *key, *data;
DBT **prevKey, **prevData;
DBT *destkey, *destbuf;
{
int ret;
DBT dest;
if (*prevKey == 0) {
if ((ret = __bam_compress_set_dbt(dbc->dbp,
destkey, key->data, key->size)) != 0)
return (ret);
ret = __bam_compress_marshal_data(dbc->dbp, data, destbuf);
} else if (((BTREE_CURSOR *)dbc->internal)->ovflsize > destbuf->size) {
dest.flags = DB_DBT_USERMEM;
dest.data = (u_int8_t*)destbuf->data + destbuf->size;
dest.ulen =
((BTREE_CURSOR *)dbc->internal)->ovflsize - destbuf->size;
dest.size = 0;
dest.app_data = NULL;
ret = ((BTREE *)dbc->dbp->bt_internal)->bt_compress(
dbc->dbp, *prevKey, *prevData, key, data, &dest);
if (ret == 0)
destbuf->size += dest.size;
} else
ret = DB_BUFFER_SMALL;
if (ret == 0) {
*prevKey = key;
*prevData = data;
}
return (ret);
}
static int
__bamc_compress_seek(dbc, seek_key, seek_data, flags)
DBC *dbc;
const DBT *seek_key;
const DBT *seek_data;
u_int32_t flags;
{
int ret;
u_int32_t method;
DB *dbp;
BTREE_CURSOR *cp;
dbp = dbc->dbp;
cp = (BTREE_CURSOR *)dbc->internal;
if ((ret = __bam_compress_set_dbt(
dbp, &cp->key1, seek_key->data, seek_key->size)) != 0)
return (ret);
if (F_ISSET(dbp, DB_AM_DUPSORT) && seek_data != NULL) {
if ((ret = __bam_compress_marshal_data(
dbp, seek_data, &cp->compressed)) != 0)
return (ret);
method = DB_GET_BOTH_LTE;
} else
method = DB_SET_LTE;
CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, method | flags);
if (ret == 0 &&
F_ISSET(dbp, DB_AM_DUPSORT) && seek_data == NULL &&
__db_compare_both(dbp, seek_key, 0, &cp->key1, 0) == 0) {
CMP_IGET_RETRY(ret,
dbc, &cp->key1, &cp->compressed, DB_PREV | flags);
if (ret == DB_NOTFOUND) {
CMP_IGET_RETRY(ret,
dbc, &cp->key1, &cp->compressed, DB_FIRST | flags);
}
}
return (ret);
}
static void
__bamc_compress_reset(dbc)
DBC *dbc;
{
BTREE_CURSOR *cp;
cp = (BTREE_CURSOR *)dbc->internal;
cp->prevKey = 0;
cp->prevData = 0;
cp->currentKey = 0;
cp->currentData = 0;
cp->compcursor = 0;
cp->compend = 0;
cp->prevcursor = 0;
cp->prev2cursor = 0;
F_CLR(cp, C_COMPRESS_DELETED|C_COMPRESS_MODIFIED);
}
static int
__bamc_compress_del_and_get_next(dbc, nextk, nextc)
DBC *dbc;
DBT *nextk, *nextc;
{
int ret, ret_n;
DBC *dbc_n;
if ((ret = __dbc_dup(dbc, &dbc_n, DB_POSITION | DB_SHALLOW_DUP)) != 0)
return (ret);
F_SET(dbc_n, DBC_TRANSIENT);
if ((ret = __dbc_idel(dbc_n, 0)) != 0)
goto err;
CMP_IGET_RETRY(ret, dbc, nextk, nextc, DB_NEXT);
err:
if ((ret_n = __dbc_close(dbc_n)) != 0 && ret == 0)
ret = ret_n;
F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
return (ret);
}
static int
__bamc_compress_relocate(dbc)
DBC *dbc;
{
int ret, t_ret;
BTREE_CURSOR *cp, *cp_n;
DBC *dbc_n;
cp = (BTREE_CURSOR *)dbc->internal;
if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
return (ret);
F_SET(dbc_n, DBC_TRANSIENT);
cp_n = (BTREE_CURSOR *)dbc_n->internal;
if (F_ISSET(cp, C_COMPRESS_DELETED)) {
ret = __bamc_compress_get_set(
dbc_n, &cp->del_key, &cp->del_data, 0, 0);
if (ret == DB_NOTFOUND) {
__bamc_compress_reset(dbc_n);
ret = 0;
} else if (ret != 0)
goto err;
F_SET(cp_n, C_COMPRESS_DELETED);
} else if (cp->currentKey != NULL) {
ret = __bamc_compress_get_set(
dbc_n, cp->currentKey, cp->currentData,
F_ISSET(dbc->dbp, DB_AM_DUPSORT) ? DB_GET_BOTH : DB_SET, 0);
if (ret == DB_NOTFOUND) {
if ((ret = __bam_compress_set_dbt(dbc_n->dbp,
&cp_n->del_key,
cp->currentKey->data, cp->currentKey->size)) != 0)
return (ret);
if ((ret = __bam_compress_set_dbt(dbc_n->dbp,
&cp_n->del_data, cp->currentData->data,
cp->currentData->size)) != 0)
return (ret);
F_SET(cp_n, C_COMPRESS_DELETED);
ret = 0;
} else if (ret != 0)
goto err;
}
err:
if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
#define CMP_STORE(key, data) do { \
while ((ret = __bamc_compress_store(dbc, (key), (data), \
&prevDestKey, &prevDestData, &destkey, &destbuf)) \
== DB_BUFFER_SMALL) { \
if ((ret = __dbc_iput(dbc, \
&destkey, &destbuf, DB_KEYLAST)) != 0) \
goto end; \
prevDestKey = NULL; \
prevDestData = NULL; \
destbuf.size = 0; \
} \
} while (0)
static int
__bamc_compress_merge_insert(dbc, stream, countp, flags)
DBC *dbc;
BTREE_COMPRESS_STREAM *stream;
u_int32_t *countp;
u_int32_t flags;
{
DBT ikey1, ikey2, idata1, idata2, nextk, nextc, nextd, destkey, destbuf;
DBT *ikey, *idata, *prevIkey, *prevIdata, *prevDestKey, *prevDestData;
int ret, bulk_ret, cmp, nextExists, moreCompressed, iSmallEnough;
int moreStream;
u_int32_t chunk_count;
ENV *env;
BTREE_CURSOR *cp;
DB *dbp;
env = dbc->env;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
bulk_ret = 0;
memset(&ikey1, 0, sizeof(DBT));
memset(&ikey2, 0, sizeof(DBT));
memset(&idata1, 0, sizeof(DBT));
memset(&idata2, 0, sizeof(DBT));
CMP_INIT_DBT(&nextk);
CMP_INIT_DBT(&nextc);
memset(&nextd, 0, sizeof(DBT));
CMP_INIT_DBT(&destkey);
CMP_INIT_DBT(&destbuf);
if ((ret = __os_malloc(env, cp->ovflsize, &destbuf.data)) != 0)
goto end;
destbuf.ulen = cp->ovflsize;
if (countp != NULL)
*countp = 0;
chunk_count = 0;
ret = 0;
prevIkey = NULL;
prevIdata = NULL;
ikey = &ikey1;
idata = &idata1;
if (stream->next(stream, ikey, idata) == 0)
goto end;
prevDestKey = NULL;
prevDestData = NULL;
moreStream = 1;
while (moreStream != 0) {
nextExists = 1;
moreCompressed = 1;
ret = __bamc_compress_seek(dbc, ikey, idata, 0);
if (ret == 0) {
ret = __bamc_compress_del_and_get_next(dbc, &nextk,
&nextc);
if (ret == DB_NOTFOUND) {
ret = 0;
nextExists = 0;
} else if (ret == 0) {
CMP_UNMARSHAL_DATA(&nextc, &nextd);
} else
goto end;
ret = __bamc_start_decompress(dbc);
} else if (ret == DB_NOTFOUND) {
moreCompressed = 0;
CMP_IGET_RETRY(ret, dbc, &nextk, &nextc, DB_FIRST);
if (ret == DB_NOTFOUND) {
ret = 0;
nextExists = 0;
} else if (ret == 0) {
CMP_UNMARSHAL_DATA(&nextc, &nextd);
}
}
if (ret != 0)
goto end;
iSmallEnough = 1;
while (moreCompressed != 0 || iSmallEnough != 0) {
if (moreCompressed == 0)
cmp = 1;
else if (iSmallEnough == 0)
cmp = -1;
else
cmp = __db_compare_both(dbp, cp->currentKey,
cp->currentData, ikey, idata);
if (cmp < 0) {
store_current: CMP_STORE(cp->currentKey, cp->currentData);
if (ret != 0)
goto end;
} else {
switch (flags) {
case DB_KEYLAST:
case DB_KEYFIRST:
case DB_NODUPDATA:
if (cmp == 0 && bulk_ret == 0 &&
F_ISSET(dbp, DB_AM_DUPSORT)) {
bulk_ret = __db_duperr(dbp,
flags);
moreStream = 0;
iSmallEnough = 0;
goto store_current;
}
break;
default:
break;
}
CMP_STORE(ikey, idata);
if (ret != 0)
goto end;
++chunk_count;
if (ikey == &ikey1) {
ikey = &ikey2;
idata = &idata2;
prevIkey = &ikey1;
prevIdata = &idata1;
} else {
ikey = &ikey1;
idata = &idata1;
prevIkey = &ikey2;
prevIdata = &idata2;
}
do {
if (stream->next(
stream, ikey, idata) == 0) {
moreStream = 0;
iSmallEnough = 0;
break;
}
#ifdef DIAGNOSTIC
DB_ASSERT(env, __db_compare_both(dbp,
ikey, idata, prevIkey,
prevIdata) >= 0);
#endif
} while (__db_compare_both(dbp, ikey, idata,
prevIkey, prevIdata) == 0);
if (moreStream != 0 && nextExists != 0 &&
__db_compare_both(dbp, ikey,
idata, &nextk, &nextd) >= 0)
iSmallEnough = 0;
}
if (cmp <= 0) {
ret = __bamc_next_decompress(dbc);
if (ret == DB_NOTFOUND) {
moreCompressed = 0;
ret = 0;
} else if (ret != 0)
goto end;
}
}
if (prevDestKey != NULL) {
if ((ret = __dbc_iput(
dbc, &destkey, &destbuf, DB_KEYLAST)) != 0)
goto end;
if (countp != NULL)
*countp += chunk_count;
chunk_count = 0;
prevDestKey = NULL;
prevDestData = NULL;
destbuf.size = 0;
}
}
end:
CMP_FREE_DBT(env, &destkey);
CMP_FREE_DBT(env, &destbuf);
CMP_FREE_DBT(env, &nextk);
CMP_FREE_DBT(env, &nextc);
return (ret != 0 ? ret : bulk_ret);
}
static int
__bamc_compress_merge_delete(dbc, stream, countp)
DBC *dbc;
BTREE_COMPRESS_STREAM *stream;
u_int32_t *countp;
{
DBT ikey, idata, nextk, nextc, nextd, destkey, destbuf, pdestkey;
DBT pdestdata;
#ifdef DIAGNOSTIC
DBT pikey, pidata;
#endif
DBT *prevDestKey, *prevDestData;
int ret, bulk_ret, cmp, moreCompressed, moreStream, nextExists;
int iSmallEnough;
u_int32_t chunk_count;
ENV *env;
BTREE_CURSOR *cp;
DB *dbp;
env = dbc->env;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
bulk_ret = 0;
memset(&ikey, 0, sizeof(DBT));
memset(&idata, 0, sizeof(DBT));
CMP_INIT_DBT(&nextk);
CMP_INIT_DBT(&nextc);
memset(&nextd, 0, sizeof(DBT));
CMP_INIT_DBT(&pdestkey);
CMP_INIT_DBT(&pdestdata);
CMP_INIT_DBT(&destkey);
CMP_INIT_DBT(&destbuf);
if ((ret = __os_malloc(env, cp->ovflsize, &destbuf.data)) != 0)
goto end;
destbuf.ulen = cp->ovflsize;
if (countp != NULL)
*countp = 0;
chunk_count = 0;
ret = 0;
if (stream->next(stream, &ikey, &idata) == 0)
goto end;
prevDestKey = NULL;
prevDestData = NULL;
moreStream = 1;
while (moreStream != 0) {
nextExists = 1;
moreCompressed = 1;
if ((ret = __bamc_compress_seek(dbc, &ikey, &idata, 0)) != 0)
goto end;
ret = __bamc_compress_del_and_get_next(dbc, &nextk, &nextc);
if (ret == DB_NOTFOUND) {
ret = 0;
nextExists = 0;
} else if (ret == 0) {
CMP_UNMARSHAL_DATA(&nextc, &nextd);
} else
goto end;
if ((ret = __bamc_start_decompress(dbc)) != 0)
goto end;
iSmallEnough = 1;
while (moreCompressed != 0 || iSmallEnough != 0) {
if (moreCompressed == 0)
cmp = 1;
else if (iSmallEnough == 0)
cmp = -1;
else
cmp = __db_compare_both(dbp, cp->currentKey,
cp->currentData, &ikey, &idata);
if (cmp < 0) {
CMP_STORE(cp->currentKey, cp->currentData);
if (ret != 0)
goto end;
if ((ret = __bam_compress_set_dbt(dbp,
&pdestkey, cp->currentKey->data,
cp->currentKey->size)) != 0)
goto end;
if ((ret = __bam_compress_set_dbt(dbp,
&pdestdata, cp->currentData->data,
cp->currentData->size)) != 0)
goto end;
prevDestKey = &pdestkey;
prevDestData = &pdestdata;
} else {
if (cmp != 0) {
bulk_ret = DB_NOTFOUND;
moreStream = 0;
iSmallEnough = 0;
} else
++chunk_count;
#ifdef DIAGNOSTIC
pikey = ikey;
pidata = idata;
#endif
if (stream->next(stream, &ikey, &idata) == 0) {
moreStream = 0;
iSmallEnough = 0;
}
#ifdef DIAGNOSTIC
DB_ASSERT(env, moreStream == 0 ||
__db_compare_both(dbp, &ikey, &idata,
&pikey, &pidata) >= 0);
#endif
if (moreStream != 0 && nextExists != 0 &&
__db_compare_both(dbp, &ikey,
&idata, &nextk, &nextd) >= 0)
iSmallEnough = 0;
}
if (cmp <= 0) {
ret = __bamc_next_decompress(dbc);
if (ret == DB_NOTFOUND) {
moreCompressed = 0;
ret = 0;
} else if (ret != 0)
goto end;
}
}
if (prevDestKey != NULL) {
if ((ret = __dbc_iput(
dbc, &destkey, &destbuf, DB_KEYLAST)) != 0)
goto end;
if (countp)
*countp += chunk_count;
chunk_count = 0;
prevDestKey = NULL;
prevDestData = NULL;
destbuf.size = 0;
}
}
end:
CMP_FREE_DBT(env, &destkey);
CMP_FREE_DBT(env, &destbuf);
CMP_FREE_DBT(env, &pdestkey);
CMP_FREE_DBT(env, &pdestdata);
CMP_FREE_DBT(env, &nextk);
CMP_FREE_DBT(env, &nextc);
return (ret != 0 ? ret : bulk_ret);
}
static int
__bamc_compress_merge_delete_dups(dbc, stream, countp)
DBC *dbc;
BTREE_COMPRESS_STREAM *stream;
u_int32_t *countp;
{
DBC *dbc_n;
DBT ikey, nextk, noread, destkey, destbuf, pdestkey, pdestdata;
#ifdef DIAGNOSTIC
DBT pikey;
#endif
DBT *prevDestKey, *prevDestData;
int ret, ret_n, bulk_ret, cmp, moreCompressed, moreStream, nextExists;
int iSmallEnough, ifound;
u_int32_t chunk_count;
ENV *env;
BTREE_CURSOR *cp;
DB *dbp;
env = dbc->env;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
bulk_ret = 0;
memset(&ikey, 0, sizeof(DBT));
CMP_INIT_DBT(&nextk);
memset(&noread, 0, sizeof(DBT));
noread.flags = DB_DBT_PARTIAL | DB_DBT_USERMEM;
CMP_INIT_DBT(&pdestkey);
CMP_INIT_DBT(&pdestdata);
CMP_INIT_DBT(&destkey);
CMP_INIT_DBT(&destbuf);
if ((ret = __os_malloc(env, cp->ovflsize, &destbuf.data)) != 0)
goto end;
destbuf.ulen = cp->ovflsize;
if (countp != NULL)
*countp = 0;
chunk_count = 0;
ret = 0;
if (stream->next(stream, &ikey, NULL) == 0)
goto end;
ifound = 0;
prevDestKey = NULL;
prevDestData = NULL;
moreStream = 1;
iSmallEnough = 0;
nextExists = 0;
while (moreStream != 0) {
if (iSmallEnough != 0) {
if (nextExists == 0) {
if (ifound == 0) {
bulk_ret = DB_NOTFOUND;
} else
++chunk_count;
break;
}
CMP_IGET_RETRY(
ret, dbc, &cp->key1, &cp->compressed, DB_CURRENT);
if (ret == DB_NOTFOUND) {
ret = 0;
break;
} else if (ret != 0)
goto end;
} else
if ((ret =
__bamc_compress_seek(dbc, &ikey, NULL, 0)) != 0)
goto end;
nextExists = 1;
moreCompressed = 1;
ret = __bamc_compress_del_and_get_next(dbc, &nextk, &noread);
if (ret == DB_NOTFOUND) {
ret = 0;
nextExists = 0;
} else if (ret != 0)
goto end;
if ((ret = __bamc_start_decompress(dbc)) != 0)
goto end;
iSmallEnough = 1;
while (moreCompressed != 0) {
if (moreCompressed == 0)
cmp = 1;
else if (iSmallEnough == 0)
cmp = -1;
else
cmp = __db_compare_both(
dbp, cp->currentKey, NULL, &ikey, NULL);
if (cmp < 0) {
if ((ret = __bamc_compress_store(dbc,
cp->currentKey, cp->currentData,
&prevDestKey,
&prevDestData, &destkey, &destbuf)) != 0)
goto end;
if ((ret = __bam_compress_set_dbt(dbp,
&pdestkey, cp->currentKey->data,
cp->currentKey->size)) != 0)
goto end;
if ((ret = __bam_compress_set_dbt(dbp,
&pdestdata, cp->currentData->data,
cp->currentData->size)) != 0)
goto end;
prevDestKey = &pdestkey;
prevDestData = &pdestdata;
} else if (cmp > 0) {
if (ifound == 0) {
bulk_ret = DB_NOTFOUND;
moreStream = 0;
iSmallEnough = 0;
} else
++chunk_count;
#ifdef DIAGNOSTIC
pikey = ikey;
#endif
if (stream->next(stream, &ikey, NULL) == 0) {
moreStream = 0;
iSmallEnough = 0;
}
ifound = 0;
#ifdef DIAGNOSTIC
DB_ASSERT(env, moreStream == 0 ||
__db_compare_both(dbp, &ikey, NULL,
&pikey, NULL) >= 0);
#endif
if (moreStream != 0 && nextExists != 0 &&
__db_compare_both(dbp,
&ikey, NULL, &nextk, NULL) > 0)
iSmallEnough = 0;
} else
ifound = 1;
if (cmp <= 0) {
ret = __bamc_next_decompress(dbc);
if (ret == DB_NOTFOUND) {
moreCompressed = 0;
ret = 0;
} else if (ret != 0)
goto end;
}
}
if (prevDestKey != NULL) {
if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
goto end;
F_SET(dbc_n, DBC_TRANSIENT);
ret = __dbc_iput(dbc_n, &destkey, &destbuf, DB_KEYLAST);
if ((ret_n = __dbc_close(dbc_n)) != 0 && ret == 0)
ret = ret_n;
if (ret != 0)
goto end;
if (countp)
*countp += chunk_count;
chunk_count = 0;
prevDestKey = NULL;
prevDestData = NULL;
destbuf.size = 0;
}
}
end:
CMP_FREE_DBT(env, &destkey);
CMP_FREE_DBT(env, &destbuf);
CMP_FREE_DBT(env, &pdestkey);
CMP_FREE_DBT(env, &pdestdata);
CMP_FREE_DBT(env, &nextk);
return (ret != 0 ? ret : bulk_ret);
}
static int
__bamc_compress_get_prev(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
int ret;
u_int32_t tofind;
BTREE_CURSOR *cp;
ret = 0;
cp = (BTREE_CURSOR *)dbc->internal;
F_CLR(cp, C_COMPRESS_DELETED);
if (cp->prevKey != NULL) {
cp->currentKey = cp->prevKey;
cp->currentData = cp->prevData;
cp->compcursor = cp->prevcursor;
cp->prevKey = 0;
cp->prevData = 0;
cp->prevcursor = cp->prev2cursor;
cp->prev2cursor = 0;
} else {
if (cp->currentKey == NULL) {
flags |= DB_LAST;
tofind = (u_int32_t)-1;
} else if (cp->prevcursor == 0) {
flags |= DB_PREV;
tofind = (u_int32_t)-1;
} else {
flags |= DB_CURRENT;
tofind = (u_int32_t)
(cp->prevcursor - (u_int8_t*)cp->compressed.data);
}
CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, flags);
if (ret != 0)
return (ret);
ret = __bamc_start_decompress(dbc);
while (ret == 0 && tofind > (u_int32_t)
(cp->compcursor - (u_int8_t*)cp->compressed.data)) {
ret = __bamc_next_decompress(dbc);
}
if (ret == DB_NOTFOUND)
ret = 0;
}
return (ret);
}
static int
__bamc_compress_get_prev_dup(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
int ret;
BTREE_CURSOR *cp;
DB *dbp;
BTREE *t;
ret = 0;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
t = (BTREE *)dbp->bt_internal;
if (cp->currentKey == 0)
return (EINVAL);
if (!F_ISSET(cp, C_COMPRESS_DELETED)) {
if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
cp->currentKey->data, cp->currentKey->size)) != 0)
return (ret);
}
if ((ret = __bamc_compress_get_prev(dbc, flags)) != 0)
return (ret);
if (t->bt_compare(dbp, cp->currentKey, &cp->del_key) != 0)
return (DB_NOTFOUND);
return (0);
}
static int
__bamc_compress_get_prev_nodup(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
int ret;
BTREE_CURSOR *cp;
DB *dbp;
BTREE *t;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
t = (BTREE *)dbp->bt_internal;
if (cp->currentKey == 0)
return (__bamc_compress_get_prev(dbc, flags));
if (!F_ISSET(cp, C_COMPRESS_DELETED))
if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
cp->currentKey->data, cp->currentKey->size)) != 0)
return (ret);
do
if ((ret = __bamc_compress_get_prev(dbc, flags)) != 0)
return (ret);
while (t->bt_compare(dbp, cp->currentKey, &cp->del_key) == 0);
return (0);
}
static int
__bamc_compress_get_next(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
int ret;
BTREE_CURSOR *cp;
cp = (BTREE_CURSOR *)dbc->internal;
if (F_ISSET(cp, C_COMPRESS_DELETED)) {
if (cp->currentKey == 0)
return (DB_NOTFOUND);
F_CLR(cp, C_COMPRESS_DELETED);
return (0);
} else if (cp->currentKey) {
ret = __bamc_next_decompress(dbc);
if (ret != DB_NOTFOUND)
return (ret);
flags |= DB_NEXT;
} else
flags |= DB_FIRST;
CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, flags);
if (ret == DB_NOTFOUND) {
__bamc_compress_reset(dbc);
return (DB_NOTFOUND);
} else if (ret != 0)
return (ret);
ret = __bamc_start_decompress(dbc);
return (ret);
}
static int
__bamc_compress_get_next_dup(dbc, key, flags)
DBC *dbc;
DBT *key;
u_int32_t flags;
{
int ret;
BTREE_CURSOR *cp;
DB *dbp;
BTREE *t;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
t = (BTREE *)dbp->bt_internal;
if (F_ISSET(cp, C_COMPRESS_DELETED)) {
if (cp->currentKey == 0)
return (DB_NOTFOUND);
F_CLR(cp, C_COMPRESS_DELETED);
return (t->bt_compare(dbp,
cp->currentKey, &cp->del_key) == 0 ? 0 : DB_NOTFOUND);
} else if (cp->currentKey == 0)
return (EINVAL);
ret = __bamc_next_decompress(dbc);
if (ret == 0 && t->bt_compare(dbp, cp->currentKey, cp->prevKey) != 0)
return (DB_NOTFOUND);
if (ret != DB_NOTFOUND)
return (ret);
if (key == NULL) {
if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
cp->currentKey->data, cp->currentKey->size)) != 0)
return (ret);
key = &cp->del_key;
}
CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, DB_NEXT | flags);
if (ret == DB_NOTFOUND) {
__bamc_compress_reset(dbc);
return (DB_NOTFOUND);
} else if (ret != 0)
return (ret);
if ((ret = __bamc_start_decompress(dbc)) != 0)
return (ret);
if (t->bt_compare(dbp, cp->currentKey, key) != 0)
return (DB_NOTFOUND);
return (0);
}
static int
__bamc_compress_get_next_nodup(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
int ret;
BTREE_CURSOR *cp;
DB *dbp;
BTREE *t;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
t = (BTREE *)dbp->bt_internal;
if (cp->currentKey == 0)
return (__bamc_compress_get_next(dbc, flags));
if (!F_ISSET(cp, C_COMPRESS_DELETED))
if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
cp->currentKey->data, cp->currentKey->size)) != 0)
return (ret);
do
if ((ret = __bamc_compress_get_next(dbc, flags)) != 0)
return (ret);
while (t->bt_compare(dbp, cp->currentKey, &cp->del_key) == 0);
return (ret);
}
static int
__bamc_compress_get_set(dbc, key, data, method, flags)
DBC *dbc;
DBT *key;
DBT *data;
u_int32_t method;
u_int32_t flags;
{
int ret, cmp;
BTREE_CURSOR *cp;
DB *dbp;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
if (method == DB_SET || method == DB_SET_RANGE)
data = NULL;
F_CLR(cp, C_COMPRESS_DELETED);
ret = __bamc_compress_seek(dbc, key, data, flags);
if (ret == DB_NOTFOUND)
CMP_IGET_RETRY(ret, dbc,
&cp->key1, &cp->compressed, DB_FIRST | flags);
if (ret != 0)
return (ret);
cmp = 0;
ret = __bamc_start_decompress(dbc);
while (ret == 0 && (cmp = __db_compare_both(dbp,
cp->currentKey, cp->currentData, key, data)) < 0) {
ret = __bamc_next_decompress(dbc);
if (ret == DB_NOTFOUND) {
CMP_IGET_RETRY(ret, dbc,
&cp->key1, &cp->compressed, DB_NEXT | flags);
if (ret == 0)
ret = __bamc_start_decompress(dbc);
}
}
switch (method) {
case DB_SET:
case DB_GET_BOTH_RANGE:
if (ret == 0 &&
__db_compare_both(dbp, cp->currentKey, 0, key, 0) != 0) {
ret = DB_NOTFOUND;
}
break;
case DB_GET_BOTH:
if (ret == 0 && (cmp != 0 || (!F_ISSET(dbp, DB_AM_DUPSORT) &&
__bam_defcmp(dbp, cp->currentData, data) != 0))) {
ret = DB_NOTFOUND;
}
break;
default:
DB_ASSERT(dbp->env, method == 0 || method == DB_SET_RANGE);
}
return (ret);
}
static int
__bamc_compress_get_bothc(dbc, data, flags)
DBC *dbc;
DBT *data;
u_int32_t flags;
{
int ret, cmp;
BTREE_CURSOR *cp;
DB *dbp;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
if (__db_compare_both(dbp, cp->currentKey,
cp->currentData, cp->currentKey, data) >= 0)
return (DB_NOTFOUND);
cmp = 0;
while ((ret = __bamc_next_decompress(dbc)) == 0 &&
(cmp = __db_compare_both(
dbp, cp->currentKey, cp->currentData, cp->prevKey, data)) < 0)
continue;
if (ret == 0)
return (cmp == 0 ? 0 : DB_NOTFOUND);
if (ret != DB_NOTFOUND)
return (ret);
if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
cp->currentKey->data, cp->currentKey->size)) != 0)
return (ret);
return __bamc_compress_get_set(
dbc, &cp->del_key, data, DB_GET_BOTH, flags);
}
static int
__bamc_compress_get_multiple_key(dbc, data, flags)
DBC *dbc;
DBT *data;
u_int32_t flags;
{
int ret;
u_int8_t *writekey, *writedata;
void *mptr;
BTREE_CURSOR *cp;
ret = 0;
cp = (BTREE_CURSOR *)dbc->internal;
DB_MULTIPLE_WRITE_INIT(mptr, data);
DB_MULTIPLE_KEY_RESERVE_NEXT(mptr, data, writekey, cp->currentKey->size,
writedata, cp->currentData->size);
if (writekey == NULL) {
data->size = cp->currentKey->size + cp->currentData->size +
4 * sizeof(u_int32_t);
return DB_BUFFER_SMALL;
}
DB_ASSERT(dbc->dbp->env, writedata != NULL);
memcpy(writekey, cp->currentKey->data, cp->currentKey->size);
memcpy(writedata, cp->currentData->data, cp->currentData->size);
while ((ret = __bamc_compress_get_next(dbc, flags)) == 0) {
DB_MULTIPLE_KEY_RESERVE_NEXT(mptr, data, writekey,
cp->currentKey->size, writedata, cp->currentData->size);
if (writekey == NULL)
break;
DB_ASSERT(dbc->dbp->env, writedata != NULL);
memcpy(writekey, cp->currentKey->data, cp->currentKey->size);
memcpy(writedata, cp->currentData->data, cp->currentData->size);
}
if (ret == DB_NOTFOUND)
ret = 0;
if (ret == 0)
ret = __bamc_compress_get_prev(dbc, flags);
return (ret);
}
static int
__bamc_compress_get_multiple(dbc, key, data, flags)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
{
int ret;
u_int8_t *writedata;
void *mptr;
BTREE_CURSOR *cp;
ret = 0;
cp = (BTREE_CURSOR *)dbc->internal;
data->size = 0;
DB_MULTIPLE_WRITE_INIT(mptr, data);
DB_MULTIPLE_RESERVE_NEXT(mptr, data, writedata, cp->currentData->size);
data->size += cp->currentData->size + 2 * sizeof(u_int32_t);
if (writedata == NULL)
return DB_BUFFER_SMALL;
memcpy(writedata, cp->currentData->data, cp->currentData->size);
while ((ret = __bamc_compress_get_next_dup(dbc, key, flags)) == 0) {
DB_MULTIPLE_RESERVE_NEXT(
mptr, data, writedata, cp->currentData->size);
data->size += cp->currentData->size + 2 * sizeof(u_int32_t);
if (writedata == NULL) {
if (F_ISSET(dbc, DBC_FROM_DB_GET))
return DB_BUFFER_SMALL;
break;
}
memcpy(writedata, cp->currentData->data, cp->currentData->size);
}
if (ret == DB_NOTFOUND)
ret = 0;
if (ret == 0)
ret = __bamc_compress_get_prev(dbc, flags);
return (ret);
}
static int
__bamc_compress_iget(dbc, key, data, flags)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
{
int ret;
u_int32_t multiple, method;
BTREE_CURSOR *cp;
DB *dbp;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
ret = 0;
multiple = flags & (DB_MULTIPLE|DB_MULTIPLE_KEY);
method = flags & DB_OPFLAGS_MASK;
flags = flags & ~(DB_OPFLAGS_MASK|DB_MULTIPLE|DB_MULTIPLE_KEY);
switch (method) {
case DB_CURRENT:
if (F_ISSET(cp, C_COMPRESS_DELETED))
ret = DB_KEYEMPTY;
else if (cp->currentKey == NULL)
ret = EINVAL;
break;
case DB_FIRST:
__bamc_compress_reset(dbc);
ret = __bamc_compress_get_next(dbc, flags);
break;
case DB_NEXT:
ret = __bamc_compress_get_next(dbc, flags);
break;
case DB_NEXT_DUP:
ret = __bamc_compress_get_next_dup(dbc, 0, flags);
break;
case DB_NEXT_NODUP:
ret = __bamc_compress_get_next_nodup(dbc, flags);
break;
case DB_LAST:
__bamc_compress_reset(dbc);
ret = __bamc_compress_get_prev(dbc, flags);
break;
case DB_PREV:
ret = __bamc_compress_get_prev(dbc, flags);
break;
case DB_PREV_DUP:
ret = __bamc_compress_get_prev_dup(dbc, flags);
break;
case DB_PREV_NODUP:
ret = __bamc_compress_get_prev_nodup(dbc, flags);
break;
case DB_SET:
if (((BTREE *)
dbc->dbp->bt_internal)->bt_compare == __bam_defcmp)
F_SET(key, DB_DBT_ISSET);
case DB_SET_RANGE:
ret = __bamc_compress_get_set(dbc, key, 0, method, flags);
break;
case DB_GET_BOTH:
if (!F_ISSET(dbc->dbp, DB_AM_DUPSORT) || ((BTREE *)dbc->dbp->
bt_internal)->compress_dup_compare == __bam_defcmp)
F_SET(data, DB_DBT_ISSET);
case DB_GET_BOTH_RANGE:
if (((BTREE *)
dbc->dbp->bt_internal)->bt_compare == __bam_defcmp)
F_SET(key, DB_DBT_ISSET);
ret = __bamc_compress_get_set(dbc, key, data, method, flags);
break;
case DB_GET_BOTHC:
ret = __bamc_compress_get_bothc(dbc, data, flags);
break;
default:
ret = __db_unknown_flag(dbp->env, "__bamc_compress_iget",
method);
break;
}
if (ret != 0)
goto err;
switch (multiple) {
case 0:
if (!F_ISSET(key, DB_DBT_ISSET))
ret = __db_retcopy(dbc->env, key,
cp->currentKey->data, cp->currentKey->size,
&dbc->rkey->data, &dbc->rkey->ulen);
if (!F_ISSET(data, DB_DBT_ISSET) && ret == 0)
ret = __db_retcopy(dbc->env, data,
cp->currentData->data, cp->currentData->size,
&dbc->rdata->data, &dbc->rdata->ulen);
break;
case DB_MULTIPLE:
if (!F_ISSET(key, DB_DBT_ISSET))
ret = __db_retcopy(dbc->env, key,
cp->currentKey->data, cp->currentKey->size,
&dbc->rkey->data, &dbc->rkey->ulen);
if (ret == 0)
ret =
__bamc_compress_get_multiple(dbc, key, data, flags);
break;
case DB_MULTIPLE_KEY:
ret = __bamc_compress_get_multiple_key(dbc, data, flags);
break;
default:
ret = __db_unknown_flag(dbp->env, "__bamc_compress_iget",
multiple);
break;
}
err:
F_CLR(key, DB_DBT_ISSET);
F_CLR(data, DB_DBT_ISSET);
return (ret);
}
int
__bamc_compress_get(dbc, key, data, flags)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
{
DBC *dbc_n;
int ret, t_ret;
u_int32_t tmp_flags;
switch (flags & DB_OPFLAGS_MASK) {
case DB_CURRENT:
case DB_GET_BOTHC:
case DB_NEXT:
case DB_NEXT_DUP:
case DB_NEXT_NODUP:
case DB_PREV:
case DB_PREV_DUP:
case DB_PREV_NODUP:
if (F_ISSET((BTREE_CURSOR *)dbc->internal,
C_COMPRESS_MODIFIED) &&
(ret = __bamc_compress_relocate(dbc)) != 0)
return (ret);
tmp_flags = DB_POSITION;
break;
default:
F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
tmp_flags = 0;
break;
}
if (F_ISSET(dbc, DBC_TRANSIENT))
dbc_n = dbc;
else {
if ((ret = __dbc_dup(dbc, &dbc_n, tmp_flags)) != 0)
goto err;
F_SET(dbc_n, DBC_TRANSIENT);
COPY_RET_MEM(dbc, dbc_n);
}
if ((ret = __bamc_compress_iget(dbc_n, key, data, flags)) != 0)
goto err;
err:
if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
(ret == 0 || ret == DB_BUFFER_SMALL))
ret = t_ret;
return (ret);
}
static int
__bamc_compress_iput(dbc, key, data, flags)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
{
int ret;
u_int32_t multi;
DBT kcpy, pdata, empty;
BTREE_COMPRESS_STREAM stream;
BTREE_CURSOR *cp;
DB *dbp;
ENV *env;
cp = (BTREE_CURSOR *)dbc->internal;
dbp = dbc->dbp;
env = dbc->env;
memset(&pdata, 0, sizeof(DBT));
memset(&empty, 0, sizeof(DBT));
multi = LF_ISSET(DB_MULTIPLE|DB_MULTIPLE_KEY);
LF_CLR(DB_MULTIPLE|DB_MULTIPLE_KEY);
if (flags == 0)
flags = DB_KEYLAST;
switch (flags) {
case DB_CURRENT:
if (cp->currentKey == 0 || F_ISSET(cp, C_COMPRESS_DELETED)) {
ret = DB_NOTFOUND;
goto end;
}
if (F_ISSET(data, DB_DBT_PARTIAL)) {
if ((ret = __db_buildpartial(
dbp, cp->currentData, data, &pdata)) != 0)
goto end;
data = &pdata;
}
if (F_ISSET(dbp, DB_AM_DUPSORT) &&
((BTREE *)dbp->bt_internal)->compress_dup_compare(
dbp, cp->currentData, data) != 0) {
__db_errx(env, DB_STR("1032",
"Existing data sorts differently from put data"));
ret = EINVAL;
goto end;
}
CMP_INIT_DBT(&kcpy);
if ((ret = __bam_compress_set_dbt(dbp,
&kcpy, cp->currentKey->data, cp->currentKey->size)) != 0)
goto end;
__bam_cs_create_single(&stream, &kcpy, data);
ret = __bamc_compress_merge_insert(dbc, &stream, NULL, flags);
if (ret == 0)
ret = __bamc_compress_get_set(
dbc, &kcpy, data, DB_GET_BOTH_RANGE, 0);
CMP_FREE_DBT(env, &kcpy);
break;
case DB_KEYFIRST:
case DB_KEYLAST:
case DB_NODUPDATA:
case DB_OVERWRITE_DUP:
switch (multi) {
case 0:
if (F_ISSET(data, DB_DBT_PARTIAL)) {
if ((ret = __bamc_compress_get_set(dbc, key,
data, DB_SET, 0)) != 0 &&
ret != DB_NOTFOUND)
goto end;
if ((ret = __db_buildpartial(dbp,
ret == DB_NOTFOUND ? &empty :
cp->currentData, data, &pdata)) != 0)
goto end;
data = &pdata;
}
__bam_cs_create_single(&stream, key, data);
ret = __bamc_compress_merge_insert(
dbc, &stream, NULL, flags);
if (ret == 0)
ret = __bamc_compress_get_set(
dbc, key, data, DB_GET_BOTH_RANGE, 0);
break;
case DB_MULTIPLE:
if ((ret = __bam_compress_check_sort_multiple(dbp,
key, data)) != 0)
goto end;
__bam_cs_create_multiple(&stream, key, data);
ret = __bamc_compress_merge_insert(
dbc, &stream, &key->doff, flags);
break;
case DB_MULTIPLE_KEY:
if ((ret = __bam_compress_check_sort_multiple_key(dbp,
key)) != 0)
goto end;
__bam_cs_create_multiple_key(&stream, key);
ret = __bamc_compress_merge_insert(
dbc, &stream, &key->doff, flags);
break;
default:
return (__db_unknown_flag(
dbp->env, "__bamc_compress_iput", multi));
}
break;
case DB_NOOVERWRITE:
ret = __bamc_compress_get_set(dbc, key, 0, DB_SET, 0);
if (ret != DB_NOTFOUND) {
if (ret == 0)
ret = DB_KEYEXIST;
goto end;
}
if (F_ISSET(data, DB_DBT_PARTIAL)) {
if ((ret = __db_buildpartial(
dbp, &empty, data, &pdata)) != 0)
goto end;
data = &pdata;
}
__bam_cs_create_single(&stream, key, data);
ret = __bamc_compress_merge_insert(dbc, &stream, NULL, flags);
if (ret == 0)
ret = __bamc_compress_get_set(
dbc, key, data, DB_GET_BOTH_RANGE, 0);
break;
default:
return (__db_unknown_flag(
dbp->env, "__bamc_compress_iput", flags));
}
end:
if (pdata.data != NULL)
__os_free(env, pdata.data);
return (ret);
}
int
__bamc_compress_put(dbc, key, data, flags)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
{
DBC *dbc_n;
int ret, t_ret;
if (F_ISSET((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED)) {
if ((flags & DB_OPFLAGS_MASK) == DB_CURRENT &&
(ret = __bamc_compress_relocate(dbc)) != 0)
return (ret);
F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
}
if (F_ISSET(dbc, DBC_TRANSIENT))
dbc_n = dbc;
else {
if ((ret = __dbc_dup(dbc, &dbc_n,
(flags & DB_OPFLAGS_MASK) == DB_CURRENT ?
DB_POSITION : 0)) != 0)
goto err;
F_SET(dbc_n, DBC_TRANSIENT);
}
if ((ret = __bamc_compress_iput(dbc_n, key, data, flags)) != 0)
goto err;
err:
if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
(ret == 0 || ret == DB_BUFFER_SMALL))
ret = t_ret;
return (ret);
}
static int
__bamc_compress_idel(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
int ret;
BTREE_COMPRESS_STREAM stream;
DB *dbp;
BTREE_CURSOR *cp;
COMPQUIET(flags, 0);
dbp = dbc->dbp;
cp = (BTREE_CURSOR *)dbc->internal;
if (F_ISSET(cp, C_COMPRESS_DELETED))
return DB_KEYEMPTY;
if (cp->currentKey == 0)
return DB_NOTFOUND;
if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
cp->currentKey->data, cp->currentKey->size)) != 0)
goto err;
if ((ret = __bam_compress_set_dbt(dbp, &cp->del_data,
cp->currentData->data, cp->currentData->size)) != 0)
goto err;
__bam_cs_create_single(&stream, &cp->del_key, &cp->del_data);
if ((ret = __bamc_compress_merge_delete(dbc, &stream, NULL)) != 0)
goto err;
ret = __bamc_compress_get_set(dbc, &cp->del_key, &cp->del_data, 0, 0);
if (ret == DB_NOTFOUND) {
__bamc_compress_reset(dbc);
ret = 0;
} else if (ret != 0)
goto err;
F_SET(cp, C_COMPRESS_DELETED);
err:
return (ret);
}
int
__bamc_compress_del(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
int ret, t_ret;
DBC *dbc_n;
if (F_ISSET((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED) &&
(ret = __bamc_compress_relocate(dbc)) != 0)
return (ret);
if (F_ISSET(dbc, DBC_TRANSIENT))
dbc_n = dbc;
else {
if ((ret = __dbc_dup(dbc, &dbc_n, DB_POSITION)) != 0)
goto err;
F_SET(dbc_n, DBC_TRANSIENT);
COPY_RET_MEM(dbc, dbc_n);
}
if ((ret = __bamc_compress_idel(dbc_n, flags)) != 0)
goto err;
err:
if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
(ret == 0 || ret == DB_BUFFER_SMALL))
ret = t_ret;
return (ret);
}
static int
__bamc_compress_ibulk_del(dbc, key, flags)
DBC *dbc;
DBT *key;
u_int32_t flags;
{
int ret;
BTREE_COMPRESS_STREAM stream;
switch (flags) {
case 0:
__bam_cs_create_single_keyonly(&stream, key);
return (__bamc_compress_merge_delete_dups(dbc, &stream, NULL));
case DB_MULTIPLE:
if ((ret = __bam_compress_check_sort_multiple_keyonly(
dbc->dbp, key)) != 0)
return (ret);
__bam_cs_create_multiple_keyonly(&stream, key);
return (__bamc_compress_merge_delete_dups(
dbc, &stream, &key->doff));
case DB_MULTIPLE_KEY:
if ((ret = __bam_compress_check_sort_multiple_key(
dbc->dbp, key)) != 0)
return (ret);
__bam_cs_create_multiple_key(&stream, key);
return (__bamc_compress_merge_delete(dbc, &stream, &key->doff));
default:
break;
}
return (__db_unknown_flag(
dbc->env, "__bamc_compress_ibulk_del", flags));
}
int
__bamc_compress_bulk_del(dbc, key, flags)
DBC *dbc;
DBT *key;
u_int32_t flags;
{
int ret, t_ret;
DBC *dbc_n;
F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
if (F_ISSET(dbc, DBC_TRANSIENT))
dbc_n = dbc;
else {
if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
goto err;
F_SET(dbc_n, DBC_TRANSIENT);
}
if ((ret = __bamc_compress_ibulk_del(dbc_n, key, flags)) != 0)
goto err;
err:
if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
(ret == 0 || ret == DB_BUFFER_SMALL))
ret = t_ret;
return (ret);
}
int
__bamc_compress_count(dbc, countp)
DBC *dbc;
db_recno_t *countp;
{
int ret, t_ret;
db_recno_t count;
DBT *key;
DBC *dbc_n;
BTREE_CURSOR *cp;
cp = (BTREE_CURSOR *)dbc->internal;
if (F_ISSET(cp, C_COMPRESS_DELETED))
key = &cp->del_key;
else
key = cp->currentKey;
if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
return (ret);
F_SET(dbc_n, DBC_TRANSIENT);
if ((ret = __bamc_compress_get_set(dbc_n, key, 0, DB_SET, 0)) != 0)
goto err;
count = 1;
while ((ret = __bamc_compress_get_next_dup(dbc_n, key, 0)) == 0)
++count;
if (ret == DB_NOTFOUND)
ret = 0;
else if (ret != 0)
goto err;
*countp = count;
err:
if ((t_ret = __dbc_close(dbc_n)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
int
__bamc_compress_cmp(dbc, other_dbc, result)
DBC *dbc, *other_dbc;
int *result;
{
DB *dbp;
BTREE_CURSOR *cp, *ocp;
dbp = dbc->dbp;
cp = (BTREE_CURSOR *)dbc->internal;
ocp = (BTREE_CURSOR *)other_dbc->internal;
if (F_ISSET(cp, C_COMPRESS_DELETED))
if (F_ISSET(ocp, C_COMPRESS_DELETED))
*result = __db_compare_both(
dbp, &cp->del_key, &cp->del_data,
&ocp->del_key, &ocp->del_data) == 0 ? 0 : 1;
else {
if (ocp->currentKey == 0)
goto err;
*result = __db_compare_both(
dbp, &cp->del_key, &cp->del_data,
ocp->currentKey, ocp->currentData) == 0 ? 0 : 1;
}
else {
if (cp->currentKey == 0)
goto err;
if (F_ISSET(ocp, C_COMPRESS_DELETED))
*result = __db_compare_both(
dbp, cp->currentKey, cp->currentData,
&ocp->del_key, &ocp->del_data) == 0 ? 0 : 1;
else {
if (ocp->currentKey == 0)
goto err;
*result = __db_compare_both(
dbp, cp->currentKey, cp->currentData,
ocp->currentKey, ocp->currentData) == 0 ? 0 : 1;
}
}
return (0);
err:
__db_errx(dbc->env, DB_STR("1033",
"Both cursors must be initialized before calling DBC->cmp."));
return (EINVAL);
}
int
__bamc_compress_dup(orig_dbc, new_dbc, flags)
DBC *orig_dbc, *new_dbc;
u_int32_t flags;
{
int ret;
DB *dbp;
BTREE_CURSOR *orig, *new;
dbp = new_dbc->dbp;
orig = (BTREE_CURSOR *)orig_dbc->internal;
new = (BTREE_CURSOR *)new_dbc->internal;
if (orig->currentKey != NULL && !LF_ISSET(DB_SHALLOW_DUP)) {
new->currentKey = &new->key1;
new->currentData = &new->data1;
if ((ret = __bam_compress_set_dbt(dbp, new->currentKey,
orig->currentKey->data, orig->currentKey->size)) != 0)
return (ret);
if ((ret = __bam_compress_set_dbt(dbp, new->currentData,
orig->currentData->data, orig->currentData->size)) != 0)
return (ret);
if (orig->prevKey) {
new->prevKey = &new->key2;
new->prevData = &new->data2;
if ((ret = __bam_compress_set_dbt(dbp, new->prevKey,
orig->prevKey->data, orig->prevKey->size)) != 0)
return (ret);
if ((ret = __bam_compress_set_dbt(dbp, new->prevData,
orig->prevData->data, orig->prevData->size)) != 0)
return (ret);
}
if ((ret = __bam_compress_set_dbt(dbp, &new->compressed,
orig->compressed.data, orig->compressed.size)) != 0)
return (ret);
new->compcursor = (u_int8_t*)new->compressed.data +
(orig->compcursor - (u_int8_t*)orig->compressed.data);
new->compend = (u_int8_t*)new->compressed.data +
(orig->compend - (u_int8_t*)orig->compressed.data);
new->prevcursor = orig->prevcursor == NULL ? NULL :
(u_int8_t*)new->compressed.data + (orig->prevcursor -
(u_int8_t*)orig->compressed.data);
new->prev2cursor = orig->prev2cursor == NULL ? NULL :
(u_int8_t*)new->compressed.data + (orig->prev2cursor -
(u_int8_t*)orig->compressed.data);
if (F_ISSET(orig, C_COMPRESS_DELETED)) {
if ((ret = __bam_compress_set_dbt(dbp, &new->del_key,
orig->del_key.data, orig->del_key.size)) != 0)
return (ret);
if ((ret = __bam_compress_set_dbt(dbp, &new->del_data,
orig->del_data.data, orig->del_data.size)) != 0)
return (ret);
}
}
return (0);
}
int
__bam_compress_salvage(dbp, vdp, handle, callback, key, data)
DB *dbp;
VRFY_DBINFO *vdp;
void *handle;
int (*callback) __P((void *, const void *));
DBT *key, *data;
{
DBT key1, key2, data1, data2, compressed;
DBT *currentKey, *currentData, *prevKey, *prevData;
ENV *env;
int ret, t_ret;
u_int8_t *compcursor, *compend;
u_int32_t datasize, size;
env = dbp->env;
memset(&key1, 0, sizeof(DBT));
memset(&key2, 0, sizeof(DBT));
memset(&data1, 0, sizeof(DBT));
memset(&data2, 0, sizeof(DBT));
memset(&compressed, 0, sizeof(DBT));
key1.flags = DB_DBT_USERMEM;
key2.flags = DB_DBT_USERMEM;
data1.flags = DB_DBT_USERMEM;
data2.flags = DB_DBT_USERMEM;
compressed.flags = DB_DBT_USERMEM;
prevKey = NULL;
prevData = NULL;
currentKey = key;
currentData = &data2;
compcursor = (u_int8_t*)data->data;
compend = compcursor + data->size;
if (data->size == 0) {
ret = DB_VERIFY_FATAL;
goto unknown_data;
}
size = __db_decompress_count_int(compcursor);
if (size == 0xFF || compcursor + size > compend) {
ret = DB_VERIFY_FATAL;
goto unknown_data;
}
compcursor += __db_decompress_int32(compcursor, &datasize);
if (compcursor + datasize > compend) {
ret = DB_VERIFY_FATAL;
goto unknown_data;
}
if ((ret = __bam_compress_set_dbt(
dbp, currentData, compcursor, datasize)) != 0)
goto err;
compcursor += datasize;
if ((ret = __db_vrfy_prdbt(
currentData, 0, " ", handle, callback, 0, 0, vdp)) != 0)
goto err;
while (compcursor < compend) {
prevKey = currentKey;
prevData = currentData;
if (currentKey == &key1) {
currentKey = &key2;
currentData = &data2;
} else {
currentKey = &key1;
currentData = &data1;
}
compressed.data = (void*)compcursor;
compressed.ulen = compressed.size =
(u_int32_t)(compend - compcursor);
while ((ret = ((BTREE *)dbp->bt_internal)->bt_decompress(
dbp, prevKey, prevData,
&compressed, currentKey, currentData)) == DB_BUFFER_SMALL) {
if (CMP_RESIZE_DBT(ret, env, currentKey) != 0)
break;
if (CMP_RESIZE_DBT(ret, env, currentData) != 0)
break;
}
if (ret == EINVAL) {
ret = DB_VERIFY_FATAL;
goto err;
}
if (ret != 0)
goto err;
compcursor += compressed.size;
if (compcursor > compend) {
ret = DB_VERIFY_FATAL;
goto err;
}
if ((ret = __db_vrfy_prdbt(
currentKey, 0, " ", handle, callback, 0, 0, vdp)) != 0)
goto err;
if ((ret = __db_vrfy_prdbt(
currentData, 0, " ", handle, callback, 0, 0, vdp)) != 0)
goto err;
}
if (0) {
unknown_data:
DB_INIT_DBT(
compressed, "UNKNOWN_DATA", sizeof("UNKNOWN_DATA") - 1);
if ((t_ret = __db_vrfy_prdbt(
&compressed, 0, " ", handle, callback, 0, 0, vdp)) != 0)
ret = t_ret;
}
err:
__os_free(env, key1.data);
__os_free(env, key2.data);
__os_free(env, data1.data);
__os_free(env, data2.data);
return (ret);
}
int
__bam_compress_count(dbc, nkeysp, ndatap)
DBC *dbc;
u_int32_t *nkeysp, *ndatap;
{
int ret, t_ret;
u_int32_t nkeys, ndata;
DB *dbp;
BTREE *t;
DBC *dbc_n;
BTREE_CURSOR *cp_n;
dbp = dbc->dbp;
t = (BTREE *)dbp->bt_internal;
if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
return (ret);
F_SET(dbc_n, DBC_TRANSIENT);
cp_n = (BTREE_CURSOR *)dbc_n->internal;
nkeys = 0;
ndata = 0;
CMP_IGET_RETRY(ret, dbc_n, &cp_n->key1, &cp_n->compressed, DB_FIRST);
if (ret != 0)
goto err;
if ((ret = __bamc_start_decompress(dbc_n)) != 0)
goto err;
nkeys += 1;
for (;;) {
ndata += 1;
ret = __bamc_next_decompress(dbc_n);
if (ret == DB_NOTFOUND) {
if (cp_n->currentKey == &cp_n->key1) {
if ((ret = __bam_compress_set_dbt(dbp,
&cp_n->key2, cp_n->key1.data,
cp_n->key1.size)) != 0)
goto err;
}
CMP_IGET_RETRY(ret, dbc_n, &cp_n->key1,
&cp_n->compressed, DB_NEXT);
if (ret != 0)
goto err;
ret = __bamc_start_decompress(dbc_n);
cp_n->prevKey = &cp_n->key2;
}
if (ret != 0)
goto err;
if (t->bt_compare(dbp, cp_n->currentKey, cp_n->prevKey) != 0)
nkeys += 1;
}
err:
if (ret == DB_NOTFOUND)
ret = 0;
if ((t_ret = __dbc_close(dbc_n)) != 0 && ret == 0)
ret = t_ret;
if (ret == 0) {
if (nkeysp != NULL)
*nkeysp = nkeys;
if (ndatap != NULL)
*ndatap = ndata;
}
return (ret);
}
static int
__bam_compress_check_sort_multiple_key(dbp, key)
DB *dbp;
DBT *key;
{
#ifdef DIAGNOSTIC
void *kptr;
DBT key1, data1, key2, data2;
memset(&key1, 0, sizeof(DBT));
memset(&data1, 0, sizeof(DBT));
memset(&key2, 0, sizeof(DBT));
memset(&data2, 0, sizeof(DBT));
DB_MULTIPLE_INIT(kptr, key);
DB_MULTIPLE_KEY_NEXT(kptr, key,
key2.data, key2.size, data2.data, data2.size);
if (kptr == NULL)
return (0);
for (;;) {
DB_MULTIPLE_KEY_NEXT(kptr, key,
key1.data, key1.size, data1.data, data1.size);
if (kptr == NULL)
break;
if (__db_compare_both(dbp, &key1, &data1, &key2, &data2) < 0) {
__db_errx(dbp->env, DB_STR("1170",
"The key/data pairs in the buffer are not sorted."));
return (EINVAL);
}
key2.data = key1.data;
key2.size = key1.size;
data2.data = data1.data;
data2.size = data1.size;
}
#else
COMPQUIET(dbp, NULL);
COMPQUIET(key, NULL);
#endif
return (0);
}
static int
__bam_compress_check_sort_multiple(dbp, key, data)
DB *dbp;
DBT *key, *data;
{
#ifdef DIAGNOSTIC
void *kptr, *dptr;
DBT key1, data1, key2, data2;
memset(&key1, 0, sizeof(DBT));
memset(&data1, 0, sizeof(DBT));
memset(&key2, 0, sizeof(DBT));
memset(&data2, 0, sizeof(DBT));
DB_MULTIPLE_INIT(kptr, key);
DB_MULTIPLE_INIT(dptr, data);
DB_MULTIPLE_NEXT(kptr, key, key2.data, key2.size);
DB_MULTIPLE_NEXT(dptr, data, data2.data, data2.size);
if (kptr == NULL || dptr == NULL)
return (0);
for (;;) {
DB_MULTIPLE_NEXT(kptr, key, key1.data, key1.size);
DB_MULTIPLE_NEXT(dptr, data, data1.data, data1.size);
if (kptr == NULL || dptr == NULL)
break;
if (__db_compare_both(dbp, &key1, &data1, &key2, &data2) < 0) {
__db_errx(dbp->env, DB_STR("1171",
"The key/data pairs in the buffer are not sorted."));
return (EINVAL);
}
key2.data = key1.data;
key2.size = key1.size;
data2.data = data1.data;
data2.size = data1.size;
}
#else
COMPQUIET(dbp, NULL);
COMPQUIET(key, NULL);
COMPQUIET(data, NULL);
#endif
return (0);
}
static int
__bam_compress_check_sort_multiple_keyonly(dbp, key)
DB *dbp;
DBT *key;
{
#ifdef DIAGNOSTIC
void *kptr;
DBT key1, key2;
memset(&key1, 0, sizeof(DBT));
memset(&key2, 0, sizeof(DBT));
DB_MULTIPLE_INIT(kptr, key);
DB_MULTIPLE_NEXT(kptr, key, key2.data, key2.size);
if (kptr == NULL)
return (0);
for (;;) {
DB_MULTIPLE_NEXT(kptr, key, key1.data, key1.size);
if (kptr == NULL)
break;
if (__db_compare_both(dbp, &key1, NULL, &key2, NULL) < 0) {
__db_errx(dbp->env, DB_STR("1172",
"The DBT items in the buffer are not sorted"));
return (EINVAL);
}
key2.data = key1.data;
key2.size = key1.size;
}
#else
COMPQUIET(dbp, NULL);
COMPQUIET(key, NULL);
#endif
return (0);
}
#endif