2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996-2009 Oracle. All rights reserved.
10 #include "dbinc/db_page.h"
11 #include "dbinc/btree.h"
13 #ifdef HAVE_COMPRESSION
15 static int __bam_compress_marshal_data __P((DB *, const DBT *, DBT *));
16 static int __bam_compress_set_dbt __P((DB *, DBT *, const void *, u_int32_t));
17 static int __bamc_compress_del_and_get_next __P((DBC *, DBT *, DBT *));
18 static int __bamc_compress_get_bothc __P((DBC *, DBT *, u_int32_t));
19 static int __bamc_compress_get_multiple_key __P((DBC *, DBT *, u_int32_t));
20 static int __bamc_compress_get_multiple __P((DBC *, DBT *, DBT *,u_int32_t));
21 static int __bamc_compress_get_next __P((DBC *, u_int32_t));
22 static int __bamc_compress_get_next_dup __P((DBC *, DBT *, u_int32_t));
23 static int __bamc_compress_get_next_nodup __P((DBC *, u_int32_t));
24 static int __bamc_compress_get_prev __P((DBC *, u_int32_t));
25 static int __bamc_compress_get_prev_dup __P((DBC *, u_int32_t));
26 static int __bamc_compress_get_prev_nodup __P((DBC *, u_int32_t));
27 static int __bamc_compress_get_set __P((DBC *,
28 DBT *, DBT *, u_int32_t, u_int32_t));
29 static int __bamc_compress_ibulk_del __P((DBC *, DBT *, u_int32_t));
30 static int __bamc_compress_idel __P((DBC *, u_int32_t));
31 static int __bamc_compress_iget __P((DBC *, DBT *, DBT *, u_int32_t));
32 static int __bamc_compress_iput __P((DBC *, DBT *, DBT *, u_int32_t));
33 static int __bamc_compress_relocate __P((DBC *));
34 static void __bamc_compress_reset __P((DBC *));
35 static int __bamc_compress_seek __P((DBC *,
36 const DBT *, const DBT *, u_int32_t));
37 static int __bamc_compress_store __P((DBC *,
38 DBT *, DBT*, DBT **, DBT **, DBT *, DBT *));
39 static int __bamc_next_decompress __P((DBC *));
40 static int __bamc_start_decompress __P((DBC *));
43 * Call __dbc_iget(), resizing DBTs if DB_BUFFER_SMALL is returned.
44 * We're always using a transient cursor when this macro is used, so
45 * we have to replace the OP with DB_CURRENT when we retry.
47 #define CMP_IGET_RETRY(ret, dbc, dbt1, dbt2, flags) do { \
48 DB_ASSERT((dbc)->env, F_ISSET((dbt1), DB_DBT_USERMEM)); \
49 DB_ASSERT((dbc)->env, F_ISSET((dbt2), DB_DBT_USERMEM)); \
50 if (((ret) =__dbc_iget((dbc), \
51 (dbt1), (dbt2), (flags))) == DB_BUFFER_SMALL) { \
52 if ((CMP_RESIZE_DBT((ret), (dbc)->env, (dbt1))) != 0) \
54 if ((CMP_RESIZE_DBT((ret), (dbc)->env, (dbt2))) != 0) \
56 (ret) = __dbc_iget((dbc), (dbt1), (dbt2), \
57 ((flags) & ~DB_OPFLAGS_MASK) | DB_CURRENT); \
61 #define CMP_INIT_DBT(dbt) do { \
67 (dbt)->flags = DB_DBT_USERMEM; \
68 (dbt)->app_data = NULL; \
71 #define CMP_FREE_DBT(env, dbt) do { \
72 DB_ASSERT((env), F_ISSET((dbt), DB_DBT_USERMEM)); \
73 __os_free((env), (dbt)->data); \
76 #define CMP_RESIZE_DBT(ret, env, dbt) \
77 (((dbt)->size > (dbt)->ulen) ? \
78 ((((ret) = __os_realloc((env), (dbt)->size, &(dbt)->data)) \
79 != 0) ? (ret) : (((dbt)->ulen = (dbt)->size), 0)) : 0)
82 __bam_compress_set_dbt(dbp, dbt, data, size)
91 DB_ASSERT(dbp->env, F_ISSET(dbt, DB_DBT_USERMEM));
94 if (CMP_RESIZE_DBT(ret, dbp->env, dbt) != 0)
97 memcpy(dbt->data, data, size);
101 /******************************************************************************/
104 * Very simple key/data stream to give __bamc_compress_merge_insert()
105 * a source of data to work on.
107 struct __bam_compress_stream;
108 typedef struct __bam_compress_stream BTREE_COMPRESS_STREAM;
109 struct __bam_compress_stream
111 int (*next)(BTREE_COMPRESS_STREAM *, DBT *, DBT *);
118 * These function prototypes can not go at the beginning because they rely on
119 * on BTREE_COMPRESS_STREAM defined above.
120 * The prototypes are required to avoid the Microsoft C++ compiler generating
121 * warnings about mismatching parameter lists.
123 static int __bam_cs_next_done __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
124 static int __bam_cs_single_next __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
125 static void __bam_cs_create_single
126 __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
127 static int __bam_cs_single_keyonly_next
128 __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
129 static void __bam_cs_create_single_keyonly
130 __P((BTREE_COMPRESS_STREAM *, DBT *));
131 static int __bam_cs_multiple_key_next
132 __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
133 static void __bam_cs_create_multiple_key __P((BTREE_COMPRESS_STREAM *, DBT *));
134 static int __bam_cs_multiple_next __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
135 static void __bam_cs_create_multiple
136 __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
137 static int __bam_cs_multiple_keyonly_next
138 __P((BTREE_COMPRESS_STREAM *, DBT *, DBT *));
139 static void __bam_cs_create_multiple_keyonly
140 __P((BTREE_COMPRESS_STREAM *, DBT *));
141 static int __bamc_compress_merge_insert
142 __P((DBC *, BTREE_COMPRESS_STREAM *, u_int32_t *, u_int32_t));
143 static int __bamc_compress_merge_delete
144 __P((DBC *, BTREE_COMPRESS_STREAM *, u_int32_t *));
145 static int __bamc_compress_merge_delete_dups
146 __P((DBC *, BTREE_COMPRESS_STREAM *, u_int32_t *));
148 /* BTREE_COMPRESS_STREAM->next() for when the data has finished. */
150 __bam_cs_next_done(stream, key, data)
151 BTREE_COMPRESS_STREAM *stream;
154 COMPQUIET(stream, NULL);
155 COMPQUIET(key, NULL);
156 COMPQUIET(data, NULL);
160 /* BTREE_COMPRESS_STREAM->next() for a single key/data pair. */
162 __bam_cs_single_next(stream, key, data)
163 BTREE_COMPRESS_STREAM *stream;
166 key->data = stream->key->data;
167 key->size = stream->key->size;
168 data->data = stream->data->data;
169 data->size = stream->data->size;
170 stream->next = __bam_cs_next_done;
174 /* Create a BTREE_COMPRESS_STREAM for a single key/data pair */
176 __bam_cs_create_single(stream, key, data)
177 BTREE_COMPRESS_STREAM *stream;
180 stream->next = __bam_cs_single_next;
185 /* BTREE_COMPRESS_STREAM->next() for a single key. */
187 __bam_cs_single_keyonly_next(stream, key, data)
188 BTREE_COMPRESS_STREAM *stream;
191 key->data = stream->key->data;
192 key->size = stream->key->size;
197 stream->next = __bam_cs_next_done;
201 /* Create a BTREE_COMPRESS_STREAM for a single key/data pair */
203 __bam_cs_create_single_keyonly(stream, key)
204 BTREE_COMPRESS_STREAM *stream;
207 stream->next = __bam_cs_single_keyonly_next;
212 * BTREE_COMPRESS_STREAM->next() for a single buffer in the DB_MULTIPLE_KEY
216 __bam_cs_multiple_key_next(stream, key, data)
217 BTREE_COMPRESS_STREAM *stream;
220 DB_MULTIPLE_KEY_NEXT(stream->kptr, stream->key, key->data, key->size,
221 data->data, data->size);
222 if (key->data == NULL) {
223 stream->next = __bam_cs_next_done;
230 * Create a BTREE_COMPRESS_STREAM for a single buffer in the DB_MULTIPLE_KEY
234 __bam_cs_create_multiple_key(stream, multiple)
235 BTREE_COMPRESS_STREAM *stream;
238 stream->next = __bam_cs_multiple_key_next;
239 stream->key = multiple;
240 DB_MULTIPLE_INIT(stream->kptr, stream->key);
243 /* BTREE_COMPRESS_STREAM->next() for two buffers in the DB_MULTIPLE format. */
245 __bam_cs_multiple_next(stream, key, data)
246 BTREE_COMPRESS_STREAM *stream;
249 DB_MULTIPLE_NEXT(stream->kptr, stream->key, key->data, key->size);
250 DB_MULTIPLE_NEXT(stream->dptr, stream->data, data->data, data->size);
251 if (key->data == NULL || data->data == NULL) {
252 stream->next = __bam_cs_next_done;
258 /* Create a BTREE_COMPRESS_STREAM for two buffers in the DB_MULTIPLE format. */
260 __bam_cs_create_multiple(stream, key, data)
261 BTREE_COMPRESS_STREAM *stream;
264 stream->next = __bam_cs_multiple_next;
267 DB_MULTIPLE_INIT(stream->kptr, stream->key);
268 DB_MULTIPLE_INIT(stream->dptr, stream->data);
272 * BTREE_COMPRESS_STREAM->next() for a single buffer in the DB_MULTIPLE
276 __bam_cs_multiple_keyonly_next(stream, key, data)
277 BTREE_COMPRESS_STREAM *stream;
280 DB_MULTIPLE_NEXT(stream->kptr, stream->key, key->data, key->size);
281 if (key->data == NULL) {
282 stream->next = __bam_cs_next_done;
293 * Create a BTREE_COMPRESS_STREAM for a single buffer in the DB_MULTIPLE
297 __bam_cs_create_multiple_keyonly(stream, key)
298 BTREE_COMPRESS_STREAM *stream;
301 stream->next = __bam_cs_multiple_keyonly_next;
303 DB_MULTIPLE_INIT(stream->kptr, stream->key);
306 /******************************************************************************/
309 * Marshal data in initial data format into destbuf, resizing destbuf if
313 __bam_compress_marshal_data(dbp, data, destbuf)
322 DB_ASSERT(dbp->env, F_ISSET(destbuf, DB_DBT_USERMEM));
324 destbuf->size = __db_compress_count_int(data->size);
325 destbuf->size += data->size;
326 if (CMP_RESIZE_DBT(ret, dbp->env, destbuf) != 0)
329 ptr = (u_int8_t*)destbuf->data;
330 ptr += __db_compress_int(ptr, data->size);
331 memcpy(ptr, data->data, data->size);
337 * Unmarshal initial data from source into data - does not copy, points
340 #define CMP_UNMARSHAL_DATA(src, dest) do { \
341 (dest)->data = ((u_int8_t*)(src)->data) + \
342 __db_decompress_int32((u_int8_t*)(src)->data, \
346 /******************************************************************************/
349 * __bam_compress_dupcmp --
350 * Duplicate comparison function for compressed BTrees.
352 * PUBLIC: int __bam_compress_dupcmp __P((DB *, const DBT *, const DBT *));
355 __bam_compress_dupcmp(db, a, b)
362 /* Decompress the initial data in a */
363 CMP_UNMARSHAL_DATA(a, &dcmp_a);
370 /* Decompress the initial data in b */
371 CMP_UNMARSHAL_DATA(b, &dcmp_b);
378 /* Call the user's duplicate compare function */
379 return ((BTREE *)db->bt_internal)->
380 compress_dup_compare(db, &dcmp_a, &dcmp_b);
384 * __bam_defcompress --
385 * Default compression routine.
387 * PUBLIC: int __bam_defcompress __P((DB *, const DBT *, const DBT *,
388 * PUBLIC: const DBT *, const DBT *, DBT *));
391 __bam_defcompress(dbp, prevKey, prevData, key, data, dest)
393 const DBT *prevKey, *prevData, *key, *data;
397 const u_int8_t *k, *p;
398 size_t len, prefix, suffix;
400 COMPQUIET(dbp, NULL);
402 k = (const u_int8_t*)key->data;
403 p = (const u_int8_t*)prevKey->data;
404 len = key->size > prevKey->size ? prevKey->size : key->size;
405 for (; len-- && *k == *p; ++k, ++p)
408 prefix = (size_t)(k - (u_int8_t*)key->data);
409 suffix = key->size - prefix;
411 if (prefix == prevKey->size && suffix == 0) {
412 /* It's a duplicate - do prefix compression on the value */
413 k = (const u_int8_t*)data->data;
414 p = (const u_int8_t*)prevData->data;
415 len = data->size > prevData->size ? prevData->size : data->size;
416 for (; len-- && *k == *p; ++k, ++p)
419 prefix = (size_t)(k - (u_int8_t*)data->data);
420 suffix = data->size - prefix;
422 /* Check that we have enough space in dest */
423 dest->size = (u_int32_t)(1 + __db_compress_count_int(prefix) +
424 __db_compress_count_int(suffix) + suffix);
425 if (dest->size > dest->ulen)
426 return (DB_BUFFER_SMALL);
428 /* Magic identifying byte */
429 ptr = (u_int8_t*)dest->data;
430 *ptr = CMP_INT_SPARE_VAL;
434 ptr += __db_compress_int(ptr, prefix);
437 ptr += __db_compress_int(ptr, suffix);
440 memcpy(ptr, k, suffix);
445 /* Check that we have enough space in dest */
446 dest->size = (u_int32_t)(__db_compress_count_int(prefix) +
447 __db_compress_count_int(suffix) +
448 __db_compress_count_int(data->size) + suffix + data->size);
449 if (dest->size > dest->ulen)
450 return (DB_BUFFER_SMALL);
453 ptr = (u_int8_t*)dest->data;
454 ptr += __db_compress_int(ptr, prefix);
457 ptr += __db_compress_int(ptr, suffix);
460 ptr += __db_compress_int(ptr, data->size);
463 memcpy(ptr, k, suffix);
467 memcpy(ptr, data->data, data->size);
473 * __bam_defdecompress --
474 * Default decompression routine.
476 * PUBLIC: int __bam_defdecompress __P((DB *, const DBT *, const DBT *, DBT *,
477 * PUBLIC: DBT *, DBT *));
480 __bam_defdecompress(dbp, prevKey, prevData, compressed, destKey, destData)
482 const DBT *prevKey, *prevData;
483 DBT *compressed, *destKey, *destData;
486 u_int32_t prefix, suffix, size;
488 COMPQUIET(dbp, NULL);
491 * Check for the magic identifying byte, that tells us that this is a
492 * compressed duplicate value.
494 s = (u_int8_t*)compressed->data;
495 if (*s == CMP_INT_SPARE_VAL) {
499 /* Unmarshal prefix and suffix */
500 size += __db_decompress_count_int(s);
501 if (size > compressed->size)
503 s += __db_decompress_int32(s, &prefix);
505 size += __db_decompress_count_int(s);
506 if (size > compressed->size)
508 s += __db_decompress_int32(s, &suffix);
510 /* Check destination lengths */
511 destKey->size = prevKey->size;
512 destData->size = prefix + suffix;
513 if (destKey->size > destKey->ulen ||
514 destData->size > destData->ulen)
515 return (DB_BUFFER_SMALL);
518 memcpy(destKey->data, prevKey->data, destKey->size);
520 /* Write the prefix */
521 if (prefix > prevData->size)
523 d = (u_int8_t*)destData->data;
524 memcpy(d, prevData->data, prefix);
527 /* Write the suffix */
529 if (size > compressed->size)
531 memcpy(d, s, suffix);
534 /* Return bytes read */
535 compressed->size = (u_int32_t)(s - (u_int8_t*)compressed->data);
539 /* Unmarshal prefix, suffix and data length */
540 size = __db_decompress_count_int(s);
541 if (size > compressed->size)
543 s += __db_decompress_int32(s, &prefix);
545 size += __db_decompress_count_int(s);
546 if (size > compressed->size)
548 s += __db_decompress_int32(s, &suffix);
550 size += __db_decompress_count_int(s);
551 if (size > compressed->size)
553 s += __db_decompress_int32(s, &destData->size);
555 /* Check destination lengths */
556 destKey->size = prefix + suffix;
557 if (destKey->size > destKey->ulen || destData->size > destData->ulen)
558 return (DB_BUFFER_SMALL);
560 /* Write the prefix */
561 if (prefix > prevKey->size)
563 d = (u_int8_t*)destKey->data;
564 memcpy(d, prevKey->data, prefix);
567 /* Write the suffix */
569 if (size > compressed->size)
571 memcpy(d, s, suffix);
575 size += destData->size;
576 if (size > compressed->size)
578 memcpy(destData->data, s, destData->size);
581 /* Return bytes read */
582 compressed->size = (u_int32_t)(s - (u_int8_t*)compressed->data);
586 /******************************************************************************/
589 * Set dbc up to start decompressing the compressed key/data pair, dbc->key1
590 * and dbc->compressed.
593 __bamc_start_decompress(dbc)
600 cp = (BTREE_CURSOR *)dbc->internal;
604 cp->currentKey = &cp->key1;
605 cp->currentData = &cp->data1;
606 cp->compcursor = (u_int8_t*)cp->compressed.data;
607 cp->compend = cp->compcursor + cp->compressed.size;
608 cp->prevcursor = NULL;
609 cp->prev2cursor = NULL;
611 /* Unmarshal the first data */
612 cp->compcursor += __db_decompress_int32(cp->compcursor, &datasize);
613 ret = __bam_compress_set_dbt(dbc->dbp,
614 cp->currentData, cp->compcursor, datasize);
617 cp->compcursor += datasize;
621 /* Decompress the next key/data pair from dbc->compressed. */
623 __bamc_next_decompress(dbc)
632 cp = (BTREE_CURSOR *)dbc->internal;
635 if (cp->compcursor >= cp->compend)
636 return (DB_NOTFOUND);
638 cp->prevKey = cp->currentKey;
639 cp->prevData = cp->currentData;
640 cp->prev2cursor = cp->prevcursor;
641 cp->prevcursor = cp->compcursor;
643 if (cp->currentKey == &cp->key1) {
644 cp->currentKey = &cp->key2;
645 cp->currentData = &cp->data2;
647 cp->currentKey = &cp->key1;
648 cp->currentData = &cp->data1;
651 compressed.flags = DB_DBT_USERMEM;
652 compressed.data = (void*)cp->compcursor;
653 compressed.ulen = compressed.size =
654 (u_int32_t)(cp->compend - cp->compcursor);
655 compressed.app_data = NULL;
657 while ((ret = ((BTREE *)db->bt_internal)->bt_decompress(db,
658 cp->prevKey, cp->prevData, &compressed,
659 cp->currentKey, cp->currentData)) == DB_BUFFER_SMALL) {
660 if (CMP_RESIZE_DBT(ret, dbc->env, cp->currentKey) != 0)
662 if (CMP_RESIZE_DBT(ret, dbc->env, cp->currentData) != 0)
667 cp->compcursor += compressed.size;
672 * Store key and data into destkey and destbuf, using the compression
676 __bamc_compress_store(dbc, key, data, prevKey, prevData, destkey, destbuf)
679 DBT **prevKey, **prevData;
680 DBT *destkey, *destbuf;
686 if ((ret = __bam_compress_set_dbt(dbc->dbp,
687 destkey, key->data, key->size)) != 0)
690 /* Marshal data - resize if it won't fit */
691 ret = __bam_compress_marshal_data(dbc->dbp, data, destbuf);
693 } else if (((BTREE_CURSOR *)dbc->internal)->ovflsize > destbuf->size) {
695 * Don't write more than cp->ovflsize bytes to the destination
696 * buffer - destbuf must be at least cp->ovflsize in size.
698 dest.flags = DB_DBT_USERMEM;
699 dest.data = (u_int8_t*)destbuf->data + destbuf->size;
701 ((BTREE_CURSOR *)dbc->internal)->ovflsize - destbuf->size;
703 dest.app_data = NULL;
705 ret = ((BTREE *)dbc->dbp->bt_internal)->bt_compress(
706 dbc->dbp, *prevKey, *prevData, key, data, &dest);
709 destbuf->size += dest.size;
711 ret = DB_BUFFER_SMALL;
722 * Move dbc->dbc to the correct position to start linear searching for
723 * seek_key/seek_data - the biggest key smaller than or equal to
724 * seek_key/seek_data.
727 __bamc_compress_seek(dbc, seek_key, seek_data, flags)
730 const DBT *seek_data;
739 cp = (BTREE_CURSOR *)dbc->internal;
741 if ((ret = __bam_compress_set_dbt(
742 dbp, &cp->key1, seek_key->data, seek_key->size)) != 0)
746 * We allow seek_data to be 0 for __bamc_compress_get_set() with
749 if (F_ISSET(dbp, DB_AM_DUPSORT) && seek_data != NULL) {
750 if ((ret = __bam_compress_marshal_data(
751 dbp, seek_data, &cp->compressed)) != 0)
754 method = DB_GET_BOTH_LTE;
758 CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, method | flags);
761 F_ISSET(dbp, DB_AM_DUPSORT) && seek_data == NULL &&
762 __db_compare_both(dbp, seek_key, 0, &cp->key1, 0) == 0) {
764 * Some entries for seek_key might be in the previous chunk,
765 * so we need to start searching there.
768 dbc, &cp->key1, &cp->compressed, DB_PREV | flags);
769 if (ret == DB_NOTFOUND) {
770 /* No previous, we must need the first entry */
772 dbc, &cp->key1, &cp->compressed, DB_FIRST | flags);
779 /* Reset the cursor to an uninitialized state */
781 __bamc_compress_reset(dbc)
786 cp = (BTREE_CURSOR *)dbc->internal;
797 F_CLR(cp, C_COMPRESS_DELETED|C_COMPRESS_MODIFIED);
801 * Duplicate the cursor and delete the current entry, move the original cursor
802 * on and then close the cursor we used to delete. We do that to make sure that
803 * the close method runs __bamc_physdel(), and actually gets rid of the deleted
807 __bamc_compress_del_and_get_next(dbc, nextk, nextc)
814 if ((ret = __dbc_dup(dbc, &dbc_n, DB_POSITION | DB_SHALLOW_DUP)) != 0)
816 F_SET(dbc_n, DBC_TRANSIENT);
818 if ((ret = __dbc_idel(dbc_n, 0)) != 0)
821 /* Read the next position */
822 CMP_IGET_RETRY(ret, dbc, nextk, nextc, DB_NEXT);
825 if ((ret_n = __dbc_close(dbc_n)) != 0 && ret == 0)
828 /* No need to relocate this cursor */
829 F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
835 * Duplicate the cursor, re-locate the position that this cursor pointed to
836 * using the duplicate (it may have been deleted), and then swap
837 * the cursors. We do that to make sure that the close method runs
838 * __bamc_physdel(), and gets rid of the entry that may have been deleted.
841 __bamc_compress_relocate(dbc)
845 BTREE_CURSOR *cp, *cp_n;
848 cp = (BTREE_CURSOR *)dbc->internal;
850 if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
852 F_SET(dbc_n, DBC_TRANSIENT);
854 cp_n = (BTREE_CURSOR *)dbc_n->internal;
856 if (F_ISSET(cp, C_COMPRESS_DELETED)) {
857 /* Find the position after the deleted entry again */
858 ret = __bamc_compress_get_set(
859 dbc_n, &cp->del_key, &cp->del_data, 0, 0);
860 if (ret == DB_NOTFOUND) {
861 __bamc_compress_reset(dbc_n);
866 F_SET(cp_n, C_COMPRESS_DELETED);
868 } else if (cp->currentKey != NULL) {
869 /* Find the current entry again */
870 ret = __bamc_compress_get_set(
871 dbc_n, cp->currentKey, cp->currentData,
872 F_ISSET(dbc->dbp, DB_AM_DUPSORT) ? DB_GET_BOTH : DB_SET, 0);
874 if (ret == DB_NOTFOUND) {
875 /* The current entry has been deleted */
876 if ((ret = __bam_compress_set_dbt(dbc_n->dbp,
878 cp->currentKey->data, cp->currentKey->size)) != 0)
880 if ((ret = __bam_compress_set_dbt(dbc_n->dbp,
881 &cp_n->del_data, cp->currentData->data,
882 cp->currentData->size)) != 0)
884 F_SET(cp_n, C_COMPRESS_DELETED);
891 /* Cleanup and cursor resolution. This also clears the
892 C_COMPRESS_MODIFIED flag. */
893 if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 && ret == 0)
899 /******************************************************************************/
901 #define CMP_STORE(key, data) do { \
902 while ((ret = __bamc_compress_store(dbc, (key), (data), \
903 &prevDestKey, &prevDestData, &destkey, &destbuf)) \
904 == DB_BUFFER_SMALL) { \
905 if ((ret = __dbc_iput(dbc, \
906 &destkey, &destbuf, DB_KEYLAST)) != 0) \
908 prevDestKey = NULL; \
909 prevDestData = NULL; \
914 /* Merge the sorted key/data pairs from stream into the compressed database. */
916 __bamc_compress_merge_insert(dbc, stream, countp, flags)
918 BTREE_COMPRESS_STREAM *stream;
922 DBT ikey1, ikey2, idata1, idata2, nextk, nextc, nextd, destkey, destbuf;
923 DBT *ikey, *idata, *prevIkey, *prevIdata, *prevDestKey, *prevDestData;
924 int ret, bulk_ret, cmp, nextExists, moreCompressed, iSmallEnough;
926 u_int32_t chunk_count;
932 cp = (BTREE_CURSOR *)dbc->internal;
936 memset(&ikey1, 0, sizeof(DBT));
937 memset(&ikey2, 0, sizeof(DBT));
938 memset(&idata1, 0, sizeof(DBT));
939 memset(&idata2, 0, sizeof(DBT));
941 CMP_INIT_DBT(&nextk);
942 CMP_INIT_DBT(&nextc);
943 memset(&nextd, 0, sizeof(DBT));
945 CMP_INIT_DBT(&destkey);
946 CMP_INIT_DBT(&destbuf);
947 if ((ret = __os_malloc(env, cp->ovflsize, &destbuf.data)) != 0)
949 destbuf.ulen = cp->ovflsize;
955 /* Get the first input key and data */
961 if (stream->next(stream, ikey, idata) == 0)
968 while (moreStream != 0) {
972 /* Seek the ikey/idata position */
973 ret = __bamc_compress_seek(dbc, ikey, idata, 0);
976 * Delete the key - we might overwrite it below
977 * but it's safer to just always delete it, and it
978 * doesn't seem significantly slower to do so.
980 ret = __bamc_compress_del_and_get_next(dbc, &nextk,
982 if (ret == DB_NOTFOUND) {
985 } else if (ret == 0) {
986 CMP_UNMARSHAL_DATA(&nextc, &nextd);
989 ret = __bamc_start_decompress(dbc);
990 } else if (ret == DB_NOTFOUND) {
993 /* Read the next position */
994 CMP_IGET_RETRY(ret, dbc, &nextk, &nextc, DB_FIRST);
995 if (ret == DB_NOTFOUND) {
998 } else if (ret == 0) {
999 CMP_UNMARSHAL_DATA(&nextc, &nextd);
1006 /* !nextExists || ikey/idata < nextk/nextd */
1009 while (moreCompressed != 0 || iSmallEnough != 0) {
1010 if (moreCompressed == 0)
1012 else if (iSmallEnough == 0)
1015 cmp = __db_compare_both(dbp, cp->currentKey,
1016 cp->currentData, ikey, idata);
1019 store_current: CMP_STORE(cp->currentKey, cp->currentData);
1027 if (cmp == 0 && bulk_ret == 0 &&
1028 F_ISSET(dbp, DB_AM_DUPSORT)) {
1029 bulk_ret = __db_duperr(dbp,
1033 * Continue until we store
1034 * the current chunk,
1035 * but don't insert any
1048 CMP_STORE(ikey, idata);
1054 * prevDestKey/prevDestData now point to
1055 * the same DBTs as ikey/idata. We don't
1056 * want to overwrite them, so swap them
1057 * to point to the other DBTs.
1059 if (ikey == &ikey1) {
1063 prevIdata = &idata1;
1068 prevIdata = &idata2;
1072 /* Get the next input key and data */
1074 stream, ikey, idata) == 0) {
1081 /* Check that the stream is sorted */
1082 DB_ASSERT(env, __db_compare_both(dbp,
1083 ikey, idata, prevIkey,
1087 /* Check for duplicates in the stream */
1088 } while (__db_compare_both(dbp, ikey, idata,
1089 prevIkey, prevIdata) == 0);
1092 * Check that !nextExists ||
1093 * ikey/idata < nextk/nextd
1095 if (moreStream != 0 && nextExists != 0 &&
1096 __db_compare_both(dbp, ikey,
1097 idata, &nextk, &nextd) >= 0)
1102 ret = __bamc_next_decompress(dbc);
1103 if (ret == DB_NOTFOUND) {
1106 } else if (ret != 0)
1112 if (prevDestKey != NULL) {
1113 if ((ret = __dbc_iput(
1114 dbc, &destkey, &destbuf, DB_KEYLAST)) != 0)
1118 *countp += chunk_count;
1122 prevDestData = NULL;
1128 CMP_FREE_DBT(env, &destkey);
1129 CMP_FREE_DBT(env, &destbuf);
1130 CMP_FREE_DBT(env, &nextk);
1131 CMP_FREE_DBT(env, &nextc);
1133 return (ret != 0 ? ret : bulk_ret);
1136 /******************************************************************************/
1138 /* Remove the sorted key/data pairs in stream from the compressed database. */
1140 __bamc_compress_merge_delete(dbc, stream, countp)
1142 BTREE_COMPRESS_STREAM *stream;
1145 DBT ikey, idata, nextk, nextc, nextd, destkey, destbuf, pdestkey;
1150 DBT *prevDestKey, *prevDestData;
1151 int ret, bulk_ret, cmp, moreCompressed, moreStream, nextExists;
1153 u_int32_t chunk_count;
1159 cp = (BTREE_CURSOR *)dbc->internal;
1163 memset(&ikey, 0, sizeof(DBT));
1164 memset(&idata, 0, sizeof(DBT));
1166 CMP_INIT_DBT(&nextk);
1167 CMP_INIT_DBT(&nextc);
1168 memset(&nextd, 0, sizeof(DBT));
1170 CMP_INIT_DBT(&pdestkey);
1171 CMP_INIT_DBT(&pdestdata);
1173 CMP_INIT_DBT(&destkey);
1174 CMP_INIT_DBT(&destbuf);
1175 if ((ret = __os_malloc(env, cp->ovflsize, &destbuf.data)) != 0)
1177 destbuf.ulen = cp->ovflsize;
1183 /* Get the first input key and data */
1185 if (stream->next(stream, &ikey, &idata) == 0)
1189 prevDestData = NULL;
1192 while (moreStream != 0) {
1196 /* Seek the ikey/idata position */
1197 if ((ret = __bamc_compress_seek(dbc, &ikey, &idata, 0)) != 0)
1201 * Delete the key - we might overwrite it below but it's safer
1202 * to just always delete it, and it doesn't seem significantly
1205 ret = __bamc_compress_del_and_get_next(dbc, &nextk, &nextc);
1206 if (ret == DB_NOTFOUND) {
1209 } else if (ret == 0) {
1210 CMP_UNMARSHAL_DATA(&nextc, &nextd);
1214 if ((ret = __bamc_start_decompress(dbc)) != 0)
1217 /* !nextExists || ikey/idata < nextk/nextd */
1220 while (moreCompressed != 0 || iSmallEnough != 0) {
1221 if (moreCompressed == 0)
1223 else if (iSmallEnough == 0)
1226 cmp = __db_compare_both(dbp, cp->currentKey,
1227 cp->currentData, &ikey, &idata);
1230 if ((ret = __bamc_compress_store(dbc,
1231 cp->currentKey, cp->currentData,
1232 &prevDestKey, &prevDestData,
1233 &destkey, &destbuf)) != 0)
1236 if ((ret = __bam_compress_set_dbt(dbp,
1237 &pdestkey, cp->currentKey->data,
1238 cp->currentKey->size)) != 0)
1240 if ((ret = __bam_compress_set_dbt(dbp,
1241 &pdestdata, cp->currentData->data,
1242 cp->currentData->size)) != 0)
1244 prevDestKey = &pdestkey;
1245 prevDestData = &pdestdata;
1249 * Continue until we store the current
1250 * chunk, but don't delete any more
1253 bulk_ret = DB_NOTFOUND;
1264 /* Get the next input key and data */
1265 if (stream->next(stream, &ikey, &idata) == 0) {
1271 /* Check that the stream is sorted */
1272 DB_ASSERT(env, moreStream == 0 ||
1273 __db_compare_both(dbp, &ikey, &idata,
1274 &pikey, &pidata) >= 0);
1278 * Check that !nextExists ||
1279 * ikey/idata < nextk/nextd
1281 if (moreStream != 0 && nextExists != 0 &&
1282 __db_compare_both(dbp, &ikey,
1283 &idata, &nextk, &nextd) >= 0)
1288 ret = __bamc_next_decompress(dbc);
1289 if (ret == DB_NOTFOUND) {
1292 } else if (ret != 0)
1297 if (prevDestKey != NULL) {
1298 if ((ret = __dbc_iput(
1299 dbc, &destkey, &destbuf, DB_KEYLAST)) != 0)
1303 *countp += chunk_count;
1307 prevDestData = NULL;
1313 CMP_FREE_DBT(env, &destkey);
1314 CMP_FREE_DBT(env, &destbuf);
1315 CMP_FREE_DBT(env, &pdestkey);
1316 CMP_FREE_DBT(env, &pdestdata);
1317 CMP_FREE_DBT(env, &nextk);
1318 CMP_FREE_DBT(env, &nextc);
1320 return (ret != 0 ? ret : bulk_ret);
1324 * Remove the sorted keys in stream along with all duplicate values from
1325 * the compressed database.
1328 __bamc_compress_merge_delete_dups(dbc, stream, countp)
1330 BTREE_COMPRESS_STREAM *stream;
1334 DBT ikey, nextk, noread, destkey, destbuf, pdestkey, pdestdata;
1338 DBT *prevDestKey, *prevDestData;
1339 int ret, ret_n, bulk_ret, cmp, moreCompressed, moreStream, nextExists;
1340 int iSmallEnough, ifound;
1341 u_int32_t chunk_count;
1347 cp = (BTREE_CURSOR *)dbc->internal;
1351 memset(&ikey, 0, sizeof(DBT));
1353 CMP_INIT_DBT(&nextk);
1355 memset(&noread, 0, sizeof(DBT));
1356 noread.flags = DB_DBT_PARTIAL | DB_DBT_USERMEM;
1358 CMP_INIT_DBT(&pdestkey);
1359 CMP_INIT_DBT(&pdestdata);
1361 CMP_INIT_DBT(&destkey);
1362 CMP_INIT_DBT(&destbuf);
1363 if ((ret = __os_malloc(env, cp->ovflsize, &destbuf.data)) != 0)
1365 destbuf.ulen = cp->ovflsize;
1371 /* Get the first input key and data */
1373 if (stream->next(stream, &ikey, NULL) == 0)
1378 prevDestData = NULL;
1383 while (moreStream != 0) {
1384 if (iSmallEnough != 0) {
1385 if (nextExists == 0) {
1387 * We've finished deleting the last key
1391 bulk_ret = DB_NOTFOUND;
1397 /* Move to the next chunk */
1399 ret, dbc, &cp->key1, &cp->compressed, DB_CURRENT);
1400 if (ret == DB_NOTFOUND) {
1403 } else if (ret != 0)
1406 /* Seek the ikey position */
1408 __bamc_compress_seek(dbc, &ikey, NULL, 0)) != 0)
1415 * Delete the key - we might overwrite it below but it's
1416 * safer to just always delete it, and it doesn't seem
1417 * significantly slower to do so.
1419 ret = __bamc_compress_del_and_get_next(dbc, &nextk, &noread);
1420 if (ret == DB_NOTFOUND) {
1423 } else if (ret != 0)
1426 if ((ret = __bamc_start_decompress(dbc)) != 0)
1429 /* !nextExists || ikey <= nextk */
1432 while (moreCompressed != 0) {
1433 if (moreCompressed == 0)
1435 else if (iSmallEnough == 0)
1438 cmp = __db_compare_both(
1439 dbp, cp->currentKey, NULL, &ikey, NULL);
1442 if ((ret = __bamc_compress_store(dbc,
1443 cp->currentKey, cp->currentData,
1445 &prevDestData, &destkey, &destbuf)) != 0)
1448 if ((ret = __bam_compress_set_dbt(dbp,
1449 &pdestkey, cp->currentKey->data,
1450 cp->currentKey->size)) != 0)
1452 if ((ret = __bam_compress_set_dbt(dbp,
1453 &pdestdata, cp->currentData->data,
1454 cp->currentData->size)) != 0)
1456 prevDestKey = &pdestkey;
1457 prevDestData = &pdestdata;
1458 } else if (cmp > 0) {
1461 * Continue until we store the
1462 * current chunk, but don't delete
1465 bulk_ret = DB_NOTFOUND;
1475 /* Get the next input key */
1476 if (stream->next(stream, &ikey, NULL) == 0) {
1483 /* Check that the stream is sorted */
1484 DB_ASSERT(env, moreStream == 0 ||
1485 __db_compare_both(dbp, &ikey, NULL,
1486 &pikey, NULL) >= 0);
1489 /* Check that !nextExists || ikey <= nextk */
1490 if (moreStream != 0 && nextExists != 0 &&
1491 __db_compare_both(dbp,
1492 &ikey, NULL, &nextk, NULL) > 0)
1494 } else /* cmp == 0 */
1498 ret = __bamc_next_decompress(dbc);
1499 if (ret == DB_NOTFOUND) {
1502 } else if (ret != 0)
1507 if (prevDestKey != NULL) {
1509 * Do the DBC->put() with a duplicate cursor, so that
1510 * the main cursor's position isn't changed - we might
1511 * need it to be the same in order to use DB_CURRENT
1514 if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
1516 F_SET(dbc_n, DBC_TRANSIENT);
1518 ret = __dbc_iput(dbc_n, &destkey, &destbuf, DB_KEYLAST);
1520 if ((ret_n = __dbc_close(dbc_n)) != 0 && ret == 0)
1527 *countp += chunk_count;
1531 prevDestData = NULL;
1537 CMP_FREE_DBT(env, &destkey);
1538 CMP_FREE_DBT(env, &destbuf);
1539 CMP_FREE_DBT(env, &pdestkey);
1540 CMP_FREE_DBT(env, &pdestdata);
1541 CMP_FREE_DBT(env, &nextk);
1543 return (ret != 0 ? ret : bulk_ret);
1546 /******************************************************************************/
1548 /* Implements DB_PREV and DB_LAST for __bamc_compress_get() */
1550 __bamc_compress_get_prev(dbc, flags)
1559 cp = (BTREE_CURSOR *)dbc->internal;
1561 F_CLR(cp, C_COMPRESS_DELETED);
1563 if (cp->prevKey != NULL) {
1564 /* Return the stored previous key */
1565 cp->currentKey = cp->prevKey;
1566 cp->currentData = cp->prevData;
1567 cp->compcursor = cp->prevcursor;
1570 cp->prevcursor = cp->prev2cursor;
1571 cp->prev2cursor = 0;
1573 if (cp->currentKey == NULL) {
1574 /* No current key, so fetch the last key */
1576 tofind = (u_int32_t)-1;
1577 } else if (cp->prevcursor == 0) {
1579 * The current key is at the begining of the
1580 * compressed block, so get the last key from the
1584 tofind = (u_int32_t)-1;
1587 * We have to search for the previous key in the
1590 flags |= DB_CURRENT;
1591 tofind = (u_int32_t)
1592 (cp->prevcursor - (u_int8_t*)cp->compressed.data);
1595 CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, flags);
1599 /* Decompress until we reach tofind */
1600 ret = __bamc_start_decompress(dbc);
1601 while (ret == 0 && tofind > (u_int32_t)
1602 (cp->compcursor - (u_int8_t*)cp->compressed.data)) {
1603 ret = __bamc_next_decompress(dbc);
1606 if (ret == DB_NOTFOUND)
1613 /* Implements DB_PREV_DUP for __bamc_compress_get() */
1615 __bamc_compress_get_prev_dup(dbc, flags)
1625 cp = (BTREE_CURSOR *)dbc->internal;
1627 t = (BTREE *)dbp->bt_internal;
1629 if (cp->currentKey == 0)
1632 /* If this is a deleted entry, del_key is already set, otherwise we
1633 have to set it now */
1634 if (!F_ISSET(cp, C_COMPRESS_DELETED)) {
1635 if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
1636 cp->currentKey->data, cp->currentKey->size)) != 0)
1640 if ((ret = __bamc_compress_get_prev(dbc, flags)) != 0)
1643 if (t->bt_compare(dbp, cp->currentKey, &cp->del_key) != 0)
1644 return (DB_NOTFOUND);
1649 /* Implements DB_PREV_NODUP for __bamc_compress_get() */
1651 __bamc_compress_get_prev_nodup(dbc, flags)
1660 cp = (BTREE_CURSOR *)dbc->internal;
1662 t = (BTREE *)dbp->bt_internal;
1664 if (cp->currentKey == 0)
1665 return (__bamc_compress_get_prev(dbc, flags));
1668 * If this is a deleted entry, del_key is already set, otherwise we
1669 * have to set it now.
1671 if (!F_ISSET(cp, C_COMPRESS_DELETED))
1672 if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
1673 cp->currentKey->data, cp->currentKey->size)) != 0)
1677 * Linear search for the next non-duplicate key - this is
1678 * especially inefficient for DB_PREV_NODUP, since we have to
1679 * decompress from the begining of the chunk to find previous
1680 * key/data pairs. Instead we could check for key equality as we
1684 if ((ret = __bamc_compress_get_prev(dbc, flags)) != 0)
1686 while (t->bt_compare(dbp, cp->currentKey, &cp->del_key) == 0);
1691 /* Implements DB_NEXT and DB_FIRST for __bamc_compress_get() */
1693 __bamc_compress_get_next(dbc, flags)
1700 cp = (BTREE_CURSOR *)dbc->internal;
1702 if (F_ISSET(cp, C_COMPRESS_DELETED)) {
1703 if (cp->currentKey == 0)
1704 return (DB_NOTFOUND);
1705 F_CLR(cp, C_COMPRESS_DELETED);
1707 } else if (cp->currentKey) {
1708 ret = __bamc_next_decompress(dbc);
1709 if (ret != DB_NOTFOUND)
1716 CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, flags);
1717 if (ret == DB_NOTFOUND) {
1719 * Reset the cursor, so that
1720 * __bamc_compress_get_multiple_key will end up pointing
1721 * to the right place
1723 __bamc_compress_reset(dbc);
1724 return (DB_NOTFOUND);
1725 } else if (ret != 0)
1728 ret = __bamc_start_decompress(dbc);
1733 /* Implements DB_NEXT_DUP for __bamc_compress_get() */
1735 __bamc_compress_get_next_dup(dbc, key, flags)
1745 cp = (BTREE_CURSOR *)dbc->internal;
1747 t = (BTREE *)dbp->bt_internal;
1749 if (cp->currentKey == 0)
1752 if (F_ISSET(cp, C_COMPRESS_DELETED)) {
1754 * Check that the next entry has the same key as the
1757 if (cp->currentKey == 0)
1758 return (DB_NOTFOUND);
1759 F_CLR(cp, C_COMPRESS_DELETED);
1760 return (t->bt_compare(dbp,
1761 cp->currentKey, &cp->del_key) == 0 ? 0 : DB_NOTFOUND);
1764 /* Check that the next entry has the same key as the previous entry */
1765 ret = __bamc_next_decompress(dbc);
1766 if (ret == 0 && t->bt_compare(dbp, cp->currentKey, cp->prevKey) != 0)
1767 return (DB_NOTFOUND);
1768 if (ret != DB_NOTFOUND)
1772 /* Copy the current key to del_key */
1773 if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
1774 cp->currentKey->data, cp->currentKey->size)) != 0)
1779 /* Fetch the next chunk */
1780 CMP_IGET_RETRY(ret, dbc, &cp->key1, &cp->compressed, DB_NEXT | flags);
1781 if (ret == DB_NOTFOUND) {
1783 * Reset the cursor, so that __bamc_compress_get_multiple
1784 * will end up pointing to the right place
1786 __bamc_compress_reset(dbc);
1787 return (DB_NOTFOUND);
1788 } else if (ret != 0)
1791 if ((ret = __bamc_start_decompress(dbc)) != 0)
1794 /* Check the keys are the same */
1795 if (t->bt_compare(dbp, cp->currentKey, key) != 0)
1796 return (DB_NOTFOUND);
1801 /* Implements DB_NEXT_NODUP for __bamc_compress_get() */
1803 __bamc_compress_get_next_nodup(dbc, flags)
1812 cp = (BTREE_CURSOR *)dbc->internal;
1814 t = (BTREE *)dbp->bt_internal;
1816 if (cp->currentKey == 0)
1817 return (__bamc_compress_get_next(dbc, flags));
1820 * If this is a deleted entry, del_key is already set, otherwise
1821 * we have to set it now
1823 if (!F_ISSET(cp, C_COMPRESS_DELETED))
1824 if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
1825 cp->currentKey->data, cp->currentKey->size)) != 0)
1828 /* Linear search for the next non-duplicate key */
1830 if ((ret = __bamc_compress_get_next(dbc, flags)) != 0)
1832 while (t->bt_compare(dbp, cp->currentKey, &cp->del_key) == 0);
1838 * Implements DB_SET, DB_SET_RANGE, DB_GET_BOTH, and DB_GET_BOTH_RANGE
1839 * for __bamc_compress_get()
1842 __bamc_compress_get_set(dbc, key, data, method, flags)
1853 cp = (BTREE_CURSOR *)dbc->internal;
1856 if (method == DB_SET || method == DB_SET_RANGE)
1859 F_CLR(cp, C_COMPRESS_DELETED);
1861 ret = __bamc_compress_seek(dbc, key, data, flags);
1862 if (ret == DB_NOTFOUND)
1863 CMP_IGET_RETRY(ret, dbc,
1864 &cp->key1, &cp->compressed, DB_FIRST | flags);
1868 /* Decompress and perform a linear search for the key */
1870 ret = __bamc_start_decompress(dbc);
1871 while (ret == 0 && (cmp = __db_compare_both(dbp,
1872 cp->currentKey, cp->currentData, key, data)) < 0) {
1873 ret = __bamc_next_decompress(dbc);
1874 if (ret == DB_NOTFOUND) {
1875 CMP_IGET_RETRY(ret, dbc,
1876 &cp->key1, &cp->compressed, DB_NEXT | flags);
1878 ret = __bamc_start_decompress(dbc);
1884 case DB_GET_BOTH_RANGE:
1886 * We need to exactly match the key, and if cmp != 0 we
1887 * might not have - so check again here.
1890 __db_compare_both(dbp, cp->currentKey, 0, key, 0) != 0) {
1891 /* We didn't find the key */
1896 if (ret == 0 && (cmp != 0 || (!F_ISSET(dbp, DB_AM_DUPSORT) &&
1897 __bam_defcmp(dbp, cp->currentData, data) != 0))) {
1898 /* We didn't find the key/data pair */
1903 DB_ASSERT(dbp->env, method == 0 || method == DB_SET_RANGE);
1909 /* Implements DB_GET_BOTHC for __bamc_compress_get() */
1911 __bamc_compress_get_bothc(dbc, data, flags)
1920 cp = (BTREE_CURSOR *)dbc->internal;
1923 /* Check that the data we are looking for comes after the current
1925 if (__db_compare_both(dbp, cp->currentKey,
1926 cp->currentData, cp->currentKey, data) >= 0)
1927 return (DB_NOTFOUND);
1930 /* Perform a linear search for the data in the current chunk */
1931 while ((ret = __bamc_next_decompress(dbc)) == 0 &&
1932 (cmp = __db_compare_both(
1933 dbp, cp->currentKey, cp->currentData, cp->prevKey, data)) < 0)
1937 return (cmp == 0 ? 0 : DB_NOTFOUND);
1938 if (ret != DB_NOTFOUND)
1941 /* Copy the current key to del_key */
1942 if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
1943 cp->currentKey->data, cp->currentKey->size)) != 0)
1946 /* Search for the data using DB_GET_BOTH */
1947 return __bamc_compress_get_set(
1948 dbc, &cp->del_key, data, DB_GET_BOTH, flags);
1951 /* Implements DB_MULTIPLE_KEY for __bamc_compress_get() */
1953 __bamc_compress_get_multiple_key(dbc, data, flags)
1959 u_int8_t *writekey, *writedata;
1964 cp = (BTREE_CURSOR *)dbc->internal;
1966 DB_MULTIPLE_WRITE_INIT(mptr, data);
1967 DB_MULTIPLE_KEY_RESERVE_NEXT(mptr, data, writekey, cp->currentKey->size,
1968 writedata, cp->currentData->size);
1969 if (writekey == NULL) {
1970 data->size = cp->currentKey->size + cp->currentData->size +
1971 4 * sizeof(u_int32_t);
1972 return DB_BUFFER_SMALL;
1974 DB_ASSERT(dbc->dbp->env, writedata != NULL);
1976 memcpy(writekey, cp->currentKey->data, cp->currentKey->size);
1977 memcpy(writedata, cp->currentData->data, cp->currentData->size);
1979 while ((ret = __bamc_compress_get_next(dbc, flags)) == 0) {
1980 DB_MULTIPLE_KEY_RESERVE_NEXT(mptr, data, writekey,
1981 cp->currentKey->size, writedata, cp->currentData->size);
1982 if (writekey == NULL)
1984 DB_ASSERT(dbc->dbp->env, writedata != NULL);
1987 * We could choose to optimize this by just storing one
1988 * copy of a key for each set of duplicate data.
1990 memcpy(writekey, cp->currentKey->data, cp->currentKey->size);
1991 memcpy(writedata, cp->currentData->data, cp->currentData->size);
1994 if (ret == DB_NOTFOUND)
1999 * Rewind to the previous key/data, since we can't fit
2000 * this one in the buffer
2002 ret = __bamc_compress_get_prev(dbc, flags);
2007 /* Implements DB_MULTIPLE for __bamc_compress_get() */
2009 __bamc_compress_get_multiple(dbc, key, data, flags)
2015 u_int8_t *writedata;
2020 cp = (BTREE_CURSOR *)dbc->internal;
2024 DB_MULTIPLE_WRITE_INIT(mptr, data);
2025 DB_MULTIPLE_RESERVE_NEXT(mptr, data, writedata, cp->currentData->size);
2026 data->size += cp->currentData->size + 2 * sizeof(u_int32_t);
2027 if (writedata == NULL)
2028 return DB_BUFFER_SMALL;
2030 memcpy(writedata, cp->currentData->data, cp->currentData->size);
2032 while ((ret = __bamc_compress_get_next_dup(dbc, key, flags)) == 0) {
2033 DB_MULTIPLE_RESERVE_NEXT(
2034 mptr, data, writedata, cp->currentData->size);
2035 data->size += cp->currentData->size + 2 * sizeof(u_int32_t);
2036 if (writedata == NULL) {
2037 /* DBC_FROM_DB_GET indicates we need to fit all the
2038 * duplicates into the buffer or return DB_BUFFER_SMALL.
2041 if (F_ISSET(dbc, DBC_FROM_DB_GET))
2042 return DB_BUFFER_SMALL;
2046 memcpy(writedata, cp->currentData->data, cp->currentData->size);
2049 if (ret == DB_NOTFOUND)
2054 * Rewind to the previous key/data, as that's now our current
2057 ret = __bamc_compress_get_prev(dbc, flags);
2063 * __bamc_compress_iget --
2064 * Get using a compressed cursor. (internal)
2067 __bamc_compress_iget(dbc, key, data, flags)
2073 u_int32_t multiple, method;
2077 cp = (BTREE_CURSOR *)dbc->internal;
2081 multiple = flags & (DB_MULTIPLE|DB_MULTIPLE_KEY);
2082 method = flags & DB_OPFLAGS_MASK;
2083 flags = flags & ~(DB_OPFLAGS_MASK|DB_MULTIPLE|DB_MULTIPLE_KEY);
2087 if (F_ISSET(cp, C_COMPRESS_DELETED))
2089 else if (cp->currentKey == NULL)
2093 __bamc_compress_reset(dbc);
2094 ret = __bamc_compress_get_next(dbc, flags);
2097 ret = __bamc_compress_get_next(dbc, flags);
2100 ret = __bamc_compress_get_next_dup(dbc, 0, flags);
2103 ret = __bamc_compress_get_next_nodup(dbc, flags);
2106 __bamc_compress_reset(dbc);
2107 ret = __bamc_compress_get_prev(dbc, flags);
2110 ret = __bamc_compress_get_prev(dbc, flags);
2113 ret = __bamc_compress_get_prev_dup(dbc, flags);
2116 ret = __bamc_compress_get_prev_nodup(dbc, flags);
2120 dbc->dbp->bt_internal)->bt_compare == __bam_defcmp)
2121 F_SET(key, DB_DBT_ISSET);
2124 ret = __bamc_compress_get_set(dbc, key, 0, method, flags);
2127 if (!F_ISSET(dbc->dbp, DB_AM_DUPSORT) || ((BTREE *)dbc->dbp->
2128 bt_internal)->compress_dup_compare == __bam_defcmp)
2129 F_SET(data, DB_DBT_ISSET);
2131 case DB_GET_BOTH_RANGE:
2133 dbc->dbp->bt_internal)->bt_compare == __bam_defcmp)
2134 F_SET(key, DB_DBT_ISSET);
2135 ret = __bamc_compress_get_set(dbc, key, data, method, flags);
2138 ret = __bamc_compress_get_bothc(dbc, data, flags);
2141 ret = __db_unknown_flag(dbp->env, "__bamc_compress_iget",
2151 if (!F_ISSET(key, DB_DBT_ISSET))
2152 ret = __db_retcopy(dbc->env, key,
2153 cp->currentKey->data, cp->currentKey->size,
2154 &dbc->rkey->data, &dbc->rkey->ulen);
2155 if (!F_ISSET(data, DB_DBT_ISSET) && ret == 0)
2156 ret = __db_retcopy(dbc->env, data,
2157 cp->currentData->data, cp->currentData->size,
2158 &dbc->rdata->data, &dbc->rdata->ulen);
2161 if (!F_ISSET(key, DB_DBT_ISSET))
2162 ret = __db_retcopy(dbc->env, key,
2163 cp->currentKey->data, cp->currentKey->size,
2164 &dbc->rkey->data, &dbc->rkey->ulen);
2167 __bamc_compress_get_multiple(dbc, key, data, flags);
2169 case DB_MULTIPLE_KEY:
2170 ret = __bamc_compress_get_multiple_key(dbc, data, flags);
2173 ret = __db_unknown_flag(dbp->env, "__bamc_compress_iget",
2179 F_CLR(key, DB_DBT_ISSET);
2180 F_CLR(data, DB_DBT_ISSET);
2186 * __bamc_compress_get --
2187 * Get using a compressed cursor.
2189 * PUBLIC: int __bamc_compress_get __P((DBC *, DBT *, DBT *, u_int32_t));
2192 __bamc_compress_get(dbc, key, data, flags)
2199 u_int32_t tmp_flags;
2201 switch (flags & DB_OPFLAGS_MASK) {
2210 if (F_ISSET((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED)
2211 && (ret = __bamc_compress_relocate(dbc)) != 0)
2213 tmp_flags = DB_POSITION;
2216 F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
2221 if (F_ISSET(dbc, DBC_TRANSIENT))
2224 if ((ret = __dbc_dup(dbc, &dbc_n, tmp_flags)) != 0)
2228 * We don't care about preserving the cursor's position on
2231 F_SET(dbc_n, DBC_TRANSIENT);
2233 COPY_RET_MEM(dbc, dbc_n);
2236 if ((ret = __bamc_compress_iget(dbc_n, key, data, flags)) != 0)
2240 /* Cleanup and cursor resolution. */
2241 if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
2242 (ret == 0 || ret == DB_BUFFER_SMALL))
2248 * __bamc_compress_iput --
2249 * Put using a compressed cursor (internal)
2252 __bamc_compress_iput(dbc, key, data, flags)
2259 DBT kcpy, pdata, empty;
2260 BTREE_COMPRESS_STREAM stream;
2265 cp = (BTREE_CURSOR *)dbc->internal;
2269 memset(&pdata, 0, sizeof(DBT));
2270 memset(&empty, 0, sizeof(DBT));
2272 multi = LF_ISSET(DB_MULTIPLE|DB_MULTIPLE_KEY);
2273 LF_CLR(DB_MULTIPLE|DB_MULTIPLE_KEY);
2277 if (cp->currentKey == 0 || F_ISSET(cp, C_COMPRESS_DELETED)) {
2282 if (F_ISSET(data, DB_DBT_PARTIAL)) {
2283 if ((ret = __db_buildpartial(
2284 dbp, cp->currentData, data, &pdata)) != 0)
2289 if (F_ISSET(dbp, DB_AM_DUPSORT) &&
2290 ((BTREE *)dbp->bt_internal)->compress_dup_compare(
2291 dbp, cp->currentData, data) != 0) {
2293 "Existing data sorts differently from put data");
2297 CMP_INIT_DBT(&kcpy);
2298 if ((ret = __bam_compress_set_dbt(dbp,
2299 &kcpy, cp->currentKey->data, cp->currentKey->size)) != 0)
2302 __bam_cs_create_single(&stream, &kcpy, data);
2303 ret = __bamc_compress_merge_insert(dbc, &stream, NULL, flags);
2306 /* Position the cursor on the entry written */
2307 ret = __bamc_compress_get_set(
2308 dbc, &kcpy, data, DB_GET_BOTH_RANGE, 0);
2310 CMP_FREE_DBT(env, &kcpy);
2315 case DB_OVERWRITE_DUP:
2318 if (F_ISSET(data, DB_DBT_PARTIAL)) {
2319 if ((ret = __bamc_compress_get_set(dbc, key,
2320 data, DB_SET, 0)) != 0 &&
2323 if ((ret = __db_buildpartial(dbp,
2324 ret == DB_NOTFOUND ? &empty :
2325 cp->currentData, data, &pdata)) != 0)
2330 __bam_cs_create_single(&stream, key, data);
2331 ret = __bamc_compress_merge_insert(
2332 dbc, &stream, NULL, flags);
2335 /* Position the cursor on the entry written */
2336 ret = __bamc_compress_get_set(
2337 dbc, key, data, DB_GET_BOTH_RANGE, 0);
2340 __bam_cs_create_multiple(&stream, key, data);
2341 ret = __bamc_compress_merge_insert(
2342 dbc, &stream, &key->doff, flags);
2344 case DB_MULTIPLE_KEY:
2345 __bam_cs_create_multiple_key(&stream, key);
2346 ret = __bamc_compress_merge_insert(
2347 dbc, &stream, &key->doff, flags);
2350 return (__db_unknown_flag(
2351 dbp->env, "__bamc_compress_iput", multi));
2354 case DB_NOOVERWRITE:
2355 /* Check key doesn't already exist */
2356 ret = __bamc_compress_get_set(dbc, key, 0, DB_SET, 0);
2357 if (ret != DB_NOTFOUND) {
2363 if (F_ISSET(data, DB_DBT_PARTIAL)) {
2364 if ((ret = __db_buildpartial(
2365 dbp, &empty, data, &pdata)) != 0)
2370 __bam_cs_create_single(&stream, key, data);
2371 ret = __bamc_compress_merge_insert(dbc, &stream, NULL, flags);
2374 /* Position the cursor on the entry written */
2375 ret = __bamc_compress_get_set(
2376 dbc, key, data, DB_GET_BOTH_RANGE, 0);
2379 return (__db_unknown_flag(
2380 dbp->env, "__bamc_compress_iput", flags));
2384 if (pdata.data != NULL)
2385 __os_free(env, pdata.data);
2390 * __bamc_compress_put --
2391 * Put using a compressed cursor.
2393 * PUBLIC: int __bamc_compress_put __P((DBC *, DBT *, DBT *, u_int32_t));
2396 __bamc_compress_put(dbc, key, data, flags)
2404 if (F_ISSET((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED)) {
2405 if ((flags & DB_OPFLAGS_MASK) == DB_CURRENT &&
2406 (ret = __bamc_compress_relocate(dbc)) != 0)
2408 F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
2411 if (F_ISSET(dbc, DBC_TRANSIENT))
2414 if ((ret = __dbc_dup(dbc, &dbc_n,
2415 (flags & DB_OPFLAGS_MASK) == DB_CURRENT ?
2416 DB_POSITION : 0)) != 0)
2420 * We don't care about preserving the cursor's position on
2423 F_SET(dbc_n, DBC_TRANSIENT);
2426 if ((ret = __bamc_compress_iput(dbc_n, key, data, flags)) != 0)
2430 /* Cleanup and cursor resolution. */
2431 if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
2432 (ret == 0 || ret == DB_BUFFER_SMALL))
2438 * __bamc_compress_idel --
2439 * Del using a compressed cursor. (internal)
2442 __bamc_compress_idel(dbc, flags)
2447 BTREE_COMPRESS_STREAM stream;
2451 COMPQUIET(flags, 0);
2454 cp = (BTREE_CURSOR *)dbc->internal;
2456 if (F_ISSET(cp, C_COMPRESS_DELETED))
2458 if (cp->currentKey == 0)
2461 if ((ret = __bam_compress_set_dbt(dbp, &cp->del_key,
2462 cp->currentKey->data, cp->currentKey->size)) != 0)
2464 if ((ret = __bam_compress_set_dbt(dbp, &cp->del_data,
2465 cp->currentData->data, cp->currentData->size)) != 0)
2468 __bam_cs_create_single(&stream, &cp->del_key, &cp->del_data);
2469 if ((ret = __bamc_compress_merge_delete(dbc, &stream, NULL)) != 0)
2472 /* Position the cursor on the entry after the key/data deleted */
2473 ret = __bamc_compress_get_set(dbc, &cp->del_key, &cp->del_data, 0, 0);
2474 if (ret == DB_NOTFOUND) {
2475 __bamc_compress_reset(dbc);
2477 } else if (ret != 0)
2480 /* Mark current as being deleted */
2481 F_SET(cp, C_COMPRESS_DELETED);
2488 * __bamc_compress_del --
2489 * Del using a compressed cursor.
2491 * PUBLIC: int __bamc_compress_del __P((DBC *, u_int32_t));
2494 __bamc_compress_del(dbc, flags)
2501 if (F_ISSET((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED) &&
2502 (ret = __bamc_compress_relocate(dbc)) != 0)
2505 if (F_ISSET(dbc, DBC_TRANSIENT))
2508 if ((ret = __dbc_dup(dbc, &dbc_n, DB_POSITION)) != 0)
2512 * We don't care about preserving the cursor's position on
2515 F_SET(dbc_n, DBC_TRANSIENT);
2517 COPY_RET_MEM(dbc, dbc_n);
2520 if ((ret = __bamc_compress_idel(dbc_n, flags)) != 0)
2524 /* Cleanup and cursor resolution. */
2525 if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
2526 (ret == 0 || ret == DB_BUFFER_SMALL))
2532 * __bamc_compress_ibulk_del --
2533 * Bulk del using a compressed cursor. (internal)
2536 __bamc_compress_ibulk_del(dbc, key, flags)
2541 BTREE_COMPRESS_STREAM stream;
2545 __bam_cs_create_single_keyonly(&stream, key);
2546 return (__bamc_compress_merge_delete_dups(dbc, &stream, NULL));
2548 __bam_cs_create_multiple_keyonly(&stream, key);
2549 return (__bamc_compress_merge_delete_dups(
2550 dbc, &stream, &key->doff));
2551 case DB_MULTIPLE_KEY:
2552 __bam_cs_create_multiple_key(&stream, key);
2553 return (__bamc_compress_merge_delete(dbc, &stream, &key->doff));
2558 return (__db_unknown_flag(
2559 dbc->env, "__bamc_compress_ibulk_del", flags));
2563 * __bamc_compress_bulk_del --
2564 * Bulk del using a compressed cursor.
2566 * PUBLIC: int __bamc_compress_bulk_del __P((DBC *, DBT *, u_int32_t));
2569 __bamc_compress_bulk_del(dbc, key, flags)
2577 F_CLR((BTREE_CURSOR *)dbc->internal, C_COMPRESS_MODIFIED);
2579 if (F_ISSET(dbc, DBC_TRANSIENT))
2582 if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
2586 * We don't care about preserving the cursor's position on
2589 F_SET(dbc_n, DBC_TRANSIENT);
2592 if ((ret = __bamc_compress_ibulk_del(dbc_n, key, flags)) != 0)
2596 /* Cleanup and cursor resolution. */
2597 if ((t_ret = __dbc_cleanup(dbc, dbc_n, ret)) != 0 &&
2598 (ret == 0 || ret == DB_BUFFER_SMALL))
2604 * __bamc_compress_count --
2605 * Count using a compressed cursor.
2607 * PUBLIC: int __bamc_compress_count __P((DBC *, db_recno_t *));
2610 __bamc_compress_count(dbc, countp)
2620 cp = (BTREE_CURSOR *)dbc->internal;
2623 * If the current entry is deleted use del_key, otherwise use
2626 if (F_ISSET(cp, C_COMPRESS_DELETED))
2629 key = cp->currentKey;
2631 /* Duplicate the cursor */
2632 if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
2635 /* We don't care about preserving the cursor's position on error */
2636 F_SET(dbc_n, DBC_TRANSIENT);
2638 /* Find the first duplicate */
2639 if ((ret = __bamc_compress_get_set(dbc_n, key, 0, DB_SET, 0)) != 0)
2643 /* Count subsequent duplicates */
2644 while ((ret = __bamc_compress_get_next_dup(dbc_n, key, 0)) == 0)
2647 if (ret == DB_NOTFOUND)
2655 if ((t_ret = __dbc_close(dbc_n)) != 0 && ret == 0)
2662 * __bamc_compress_cmp --
2663 * Compare which compressed value is pointed to.
2665 * PUBLIC: int __bamc_compress_cmp __P((DBC *, DBC *, int *));
2668 __bamc_compress_cmp(dbc, other_dbc, result)
2669 DBC *dbc, *other_dbc;
2673 BTREE_CURSOR *cp, *ocp;
2676 * At this point, we already know that the cursors point to the same
2681 cp = (BTREE_CURSOR *)dbc->internal;
2682 ocp = (BTREE_CURSOR *)other_dbc->internal;
2684 if (F_ISSET(cp, C_COMPRESS_DELETED))
2685 if (F_ISSET(ocp, C_COMPRESS_DELETED))
2686 *result = __db_compare_both(
2687 dbp, &cp->del_key, &cp->del_data,
2688 &ocp->del_key, &ocp->del_data) == 0 ? 0 : 1;
2690 if (ocp->currentKey == 0)
2693 *result = __db_compare_both(
2694 dbp, &cp->del_key, &cp->del_data,
2695 ocp->currentKey, ocp->currentData) == 0 ? 0 : 1;
2698 if (cp->currentKey == 0)
2701 if (F_ISSET(ocp, C_COMPRESS_DELETED))
2702 *result = __db_compare_both(
2703 dbp, cp->currentKey, cp->currentData,
2704 &ocp->del_key, &ocp->del_data) == 0 ? 0 : 1;
2706 if (ocp->currentKey == 0)
2709 *result = __db_compare_both(
2710 dbp, cp->currentKey, cp->currentData,
2711 ocp->currentKey, ocp->currentData) == 0 ? 0 : 1;
2718 "Both cursors must be initialized before calling DBC->cmp.");
2723 * __bamc_compress_dup --
2724 * Duplicate the compression specific part of a btree cursor.
2726 * PUBLIC: int __bamc_compress_dup __P((DBC *, DBC *, u_int32_t));
2729 __bamc_compress_dup(orig_dbc, new_dbc, flags)
2730 DBC *orig_dbc, *new_dbc;
2735 BTREE_CURSOR *orig, *new;
2739 orig = (BTREE_CURSOR *)orig_dbc->internal;
2740 new = (BTREE_CURSOR *)new_dbc->internal;
2742 if (orig->currentKey != NULL && !LF_ISSET(DB_SHALLOW_DUP)) {
2743 new->currentKey = &new->key1;
2744 new->currentData = &new->data1;
2746 if ((ret = __bam_compress_set_dbt(dbp, new->currentKey,
2747 orig->currentKey->data, orig->currentKey->size)) != 0)
2749 if ((ret = __bam_compress_set_dbt(dbp, new->currentData,
2750 orig->currentData->data, orig->currentData->size)) != 0)
2753 if (orig->prevKey) {
2754 new->prevKey = &new->key2;
2755 new->prevData = &new->data2;
2757 if ((ret = __bam_compress_set_dbt(dbp, new->prevKey,
2758 orig->prevKey->data, orig->prevKey->size)) != 0)
2760 if ((ret = __bam_compress_set_dbt(dbp, new->prevData,
2761 orig->prevData->data, orig->prevData->size)) != 0)
2765 if ((ret = __bam_compress_set_dbt(dbp, &new->compressed,
2766 orig->compressed.data, orig->compressed.size)) != 0)
2769 new->compcursor = (u_int8_t*)new->compressed.data +
2770 (orig->compcursor - (u_int8_t*)orig->compressed.data);
2771 new->compend = (u_int8_t*)new->compressed.data +
2772 (orig->compend - (u_int8_t*)orig->compressed.data);
2773 new->prevcursor = orig->prevcursor == NULL ? NULL :
2774 (u_int8_t*)new->compressed.data + (orig->prevcursor -
2775 (u_int8_t*)orig->compressed.data);
2776 new->prev2cursor = orig->prev2cursor == NULL ? NULL :
2777 (u_int8_t*)new->compressed.data + (orig->prev2cursor -
2778 (u_int8_t*)orig->compressed.data);
2780 if (F_ISSET(orig, C_COMPRESS_DELETED)) {
2781 if ((ret = __bam_compress_set_dbt(dbp, &new->del_key,
2782 orig->del_key.data, orig->del_key.size)) != 0)
2784 if ((ret = __bam_compress_set_dbt(dbp, &new->del_data,
2785 orig->del_data.data, orig->del_data.size)) != 0)
2794 * __bam_compress_salvage --
2795 * Salvage the compressed data from the key/data pair
2797 * PUBLIC: int __bam_compress_salvage __P((DB *, VRFY_DBINFO *,
2798 * PUBLIC: void *, int (*)(void *, const void *), DBT *, DBT *));
2801 __bam_compress_salvage(dbp, vdp, handle, callback, key, data)
2805 int (*callback) __P((void *, const void *));
2808 DBT key1, key2, data1, data2, compressed;
2809 DBT *currentKey, *currentData, *prevKey, *prevData;
2812 u_int8_t *compcursor, *compend;
2813 u_int32_t datasize, size;
2817 memset(&key1, 0, sizeof(DBT));
2818 memset(&key2, 0, sizeof(DBT));
2819 memset(&data1, 0, sizeof(DBT));
2820 memset(&data2, 0, sizeof(DBT));
2821 memset(&compressed, 0, sizeof(DBT));
2823 key1.flags = DB_DBT_USERMEM;
2824 key2.flags = DB_DBT_USERMEM;
2825 data1.flags = DB_DBT_USERMEM;
2826 data2.flags = DB_DBT_USERMEM;
2827 compressed.flags = DB_DBT_USERMEM;
2832 currentData = &data2;
2833 compcursor = (u_int8_t*)data->data;
2834 compend = compcursor + data->size;
2836 if (data->size == 0) {
2837 ret = DB_VERIFY_FATAL;
2841 /* Unmarshal the first data */
2842 size = __db_decompress_count_int(compcursor);
2843 if (size == 0xFF || compcursor + size > compend) {
2844 ret = DB_VERIFY_FATAL;
2847 compcursor += __db_decompress_int32(compcursor, &datasize);
2849 if (compcursor + datasize > compend) {
2850 ret = DB_VERIFY_FATAL;
2853 if ((ret = __bam_compress_set_dbt(
2854 dbp, currentData, compcursor, datasize)) != 0)
2856 compcursor += datasize;
2858 /* Output first data (first key has already been output by our caller */
2859 if ((ret = __db_vrfy_prdbt(
2860 currentData, 0, " ", handle, callback, 0, vdp)) != 0)
2863 while (compcursor < compend) {
2864 prevKey = currentKey;
2865 prevData = currentData;
2867 if (currentKey == &key1) {
2869 currentData = &data2;
2872 currentData = &data1;
2875 compressed.data = (void*)compcursor;
2876 compressed.ulen = compressed.size =
2877 (u_int32_t)(compend - compcursor);
2879 /* Decompress the next key/data pair */
2880 while ((ret = ((BTREE *)dbp->bt_internal)->bt_decompress(
2881 dbp, prevKey, prevData,
2882 &compressed, currentKey, currentData)) == DB_BUFFER_SMALL) {
2883 if (CMP_RESIZE_DBT(ret, env, currentKey) != 0)
2885 if (CMP_RESIZE_DBT(ret, env, currentData) != 0)
2889 if (ret == EINVAL) {
2890 ret = DB_VERIFY_FATAL;
2896 compcursor += compressed.size;
2898 if (compcursor > compend) {
2899 ret = DB_VERIFY_FATAL;
2903 /* Output the next key/data pair */
2904 if ((ret = __db_vrfy_prdbt(
2905 currentKey, 0, " ", handle, callback, 0, vdp)) != 0)
2907 if ((ret = __db_vrfy_prdbt(
2908 currentData, 0, " ", handle, callback, 0, vdp)) != 0)
2915 * Make sure we output a data value for the key that's
2916 * already been output
2919 compressed, "UNKNOWN_DATA", sizeof("UNKNOWN_DATA") - 1);
2920 if ((t_ret = __db_vrfy_prdbt(
2921 &compressed, 0, " ", handle, callback, 0, vdp)) != 0)
2926 __os_free(env, key1.data);
2927 __os_free(env, key2.data);
2928 __os_free(env, data1.data);
2929 __os_free(env, data2.data);
2934 * __bam_compress_count --
2935 * Calculate key and entry counts for the compressed BTree
2937 * PUBLIC: int __bam_compress_count __P((DBC *, u_int32_t *, u_int32_t *));
2940 __bam_compress_count(dbc, nkeysp, ndatap)
2942 u_int32_t *nkeysp, *ndatap;
2945 u_int32_t nkeys, ndata;
2952 t = (BTREE *)dbp->bt_internal;
2954 /* Duplicate the cursor */
2955 if ((ret = __dbc_dup(dbc, &dbc_n, 0)) != 0)
2958 /* We don't care about preserving the cursor's position on error */
2959 F_SET(dbc_n, DBC_TRANSIENT);
2961 cp_n = (BTREE_CURSOR *)dbc_n->internal;
2966 CMP_IGET_RETRY(ret, dbc_n, &cp_n->key1, &cp_n->compressed, DB_FIRST);
2970 if ((ret = __bamc_start_decompress(dbc_n)) != 0)
2977 ret = __bamc_next_decompress(dbc_n);
2978 if (ret == DB_NOTFOUND) {
2979 if (cp_n->currentKey == &cp_n->key1) {
2981 * Make sure that the previous key isn't
2982 * overwritten when we fetch the next chunk.
2984 if ((ret = __bam_compress_set_dbt(dbp,
2985 &cp_n->key2, cp_n->key1.data,
2986 cp_n->key1.size)) != 0)
2990 CMP_IGET_RETRY(ret, dbc_n, &cp_n->key1,
2991 &cp_n->compressed, DB_NEXT);
2995 ret = __bamc_start_decompress(dbc_n);
2997 cp_n->prevKey = &cp_n->key2;
3003 if (t->bt_compare(dbp, cp_n->currentKey, cp_n->prevKey) != 0)
3008 if (ret == DB_NOTFOUND)
3011 if ((t_ret = __dbc_close(dbc_n)) != 0 && ret == 0)