2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * Big key/data handling for the hashing package.
54 #include <sys/types.h>
68 static int32_t collect_key
__P((HTAB
*, PAGE16
*, int32_t, db_pgno_t
*));
69 static int32_t collect_data
__P((HTAB
*, PAGE16
*, int32_t));
74 * You need to do an insert and the key/data pair is greater than
75 * MINFILL * the bucket size
82 __big_insert(hashp
, pagep
, key
, val
)
87 size_t key_size
, val_size
;
88 indx_t key_move_bytes
, val_move_bytes
;
89 int8_t *key_data
, *val_data
, base_page
;
91 key_data
= (int8_t *)key
->data
;
93 val_data
= (int8_t *)val
->data
;
96 NUM_ENT(pagep
) = NUM_ENT(pagep
) + 1;
98 for (base_page
= 1; key_size
+ val_size
;) {
101 __add_bigpage(hashp
, pagep
, NUM_ENT(pagep
) - 1, base_page
);
105 /* There's just going to be one entry on this page. */
108 /* Move the key's data. */
109 key_move_bytes
= MIN(FREESPACE(pagep
), key_size
);
110 /* Mark the page as to how much key & data is on this page. */
111 BIGKEYLEN(pagep
) = key_move_bytes
;
113 MIN(FREESPACE(pagep
) - key_move_bytes
, val_size
);
114 BIGDATALEN(pagep
) = val_move_bytes
;
116 /* Note big pages build beginning --> end, not vice versa. */
118 memmove(BIGKEY(pagep
), key_data
, key_move_bytes
);
120 memmove(BIGDATA(pagep
), val_data
, val_move_bytes
);
122 key_size
-= key_move_bytes
;
123 key_data
+= key_move_bytes
;
124 val_size
-= val_move_bytes
;
125 val_data
+= val_move_bytes
;
129 __put_page(hashp
, pagep
, A_RAW
, 1);
134 * Called when we need to delete a big pair.
142 __big_delete(HTAB
*hashp
, PAGE16
*pagep
, indx_t ndx
)
144 __big_delete(hashp
, pagep
, ndx
)
147 u_int32_t ndx
; /* Index of big pair on base page. */
152 /* Get first page with big key/data. */
153 pagep
= __get_page(hashp
, OADDR_TO_PAGE(DATA_OFF(pagep
, ndx
)), A_RAW
);
158 * Traverse through the pages, freeing the previous one (except
159 * the first) at each new page.
161 while (NEXT_PGNO(pagep
) != INVALID_PGNO
) {
163 pagep
= __get_page(hashp
, NEXT_PGNO(pagep
), A_RAW
);
166 __delete_page(hashp
, last_pagep
, A_OVFL
);
169 /* Free the last page in the chain. */
170 __delete_page(hashp
, pagep
, A_OVFL
);
175 * Given a key, indicates whether the big key at cursorp matches the
184 __find_bigpair(hashp
, cursorp
, key
, size
)
190 PAGE16
*pagep
, *hold_pagep
;
199 /* Chances are, hashp->cpage is the base page. */
201 pagep
= hold_pagep
= cursorp
->pagep
;
203 pagep
= __get_page(hashp
, cursorp
->pgno
, A_RAW
);
209 * Now, get the first page with the big stuff on it.
212 * KLUDGE: we know that cursor is looking at the _next_ item, so
213 * we have to look at pgndx - 1.
215 next_pgno
= OADDR_TO_PAGE(DATA_OFF(pagep
, (cursorp
->pgndx
- 1)));
217 __put_page(hashp
, pagep
, A_RAW
, 0);
218 pagep
= __get_page(hashp
, next_pgno
, A_RAW
);
222 /* While there are both keys to compare. */
223 while ((ksize
> 0) && (BIGKEYLEN(pagep
))) {
224 if (ksize
< KEY_OFF(pagep
, 0) ||
225 memcmp(BIGKEY(pagep
), kkey
, BIGKEYLEN(pagep
))) {
226 __put_page(hashp
, pagep
, A_RAW
, 0);
229 kkey
+= BIGKEYLEN(pagep
);
230 ksize
-= BIGKEYLEN(pagep
);
231 if (NEXT_PGNO(pagep
) != INVALID_PGNO
) {
232 next_pgno
= NEXT_PGNO(pagep
);
233 __put_page(hashp
, pagep
, A_RAW
, 0);
234 pagep
= __get_page(hashp
, next_pgno
, A_RAW
);
239 __put_page(hashp
, pagep
, A_RAW
, 0);
244 #ifdef HASH_STATISTICS
253 * Fill in the key and data for this big pair.
256 __big_keydata(hashp
, pagep
, key
, val
, ndx
)
267 __get_page(hashp
, OADDR_TO_PAGE(DATA_OFF(pagep
, ndx
)), A_RAW
);
270 key
->size
= collect_key(hashp
, key_pagep
, 0, &last_page
);
271 key
->data
= hashp
->bigkey_buf
;
272 __put_page(hashp
, key_pagep
, A_RAW
, 0);
277 /* Create an item_info to direct __big_return to the beginning pgno. */
279 return (__big_return(hashp
, &ii
, val
, 1));
283 * Return the big key on page, ndx.
287 __get_bigkey(HTAB
*hashp
, PAGE16
*pagep
, indx_t ndx
, DBT
*key
)
289 __get_bigkey(hashp
, pagep
, ndx
, key
)
299 __get_page(hashp
, OADDR_TO_PAGE(DATA_OFF(pagep
, ndx
)), A_RAW
);
302 key
->size
= collect_key(hashp
, key_pagep
, 0, NULL
);
303 key
->data
= hashp
->bigkey_buf
;
305 __put_page(hashp
, key_pagep
, A_RAW
, 0);
311 * Return the big key and data indicated in item_info.
314 __big_return(hashp
, item_info
, val
, on_bigkey_page
)
316 ITEM_INFO
*item_info
;
318 int32_t on_bigkey_page
;
323 if (!on_bigkey_page
) {
324 /* Get first page with big pair on it. */
325 pagep
= __get_page(hashp
,
326 OADDR_TO_PAGE(item_info
->data_off
), A_RAW
);
330 pagep
= __get_page(hashp
, item_info
->pgno
, A_RAW
);
335 /* Traverse through the bigkey pages until a page with data is found. */
336 while (!BIGDATALEN(pagep
)) {
337 next_pgno
= NEXT_PGNO(pagep
);
338 __put_page(hashp
, pagep
, A_RAW
, 0);
339 pagep
= __get_page(hashp
, next_pgno
, A_RAW
);
344 val
->size
= collect_data(hashp
, pagep
, 0);
347 val
->data
= (void *)hashp
->bigdata_buf
;
349 __put_page(hashp
, pagep
, A_RAW
, 0);
354 * Given a page with a big key on it, traverse through the pages counting data
355 * length, and collect all of the data on the way up. Store the key in
356 * hashp->bigkey_buf. last_page indicates to the calling function what the
357 * last page with key on it is; this will help if you later want to retrieve
360 * Does the work for __get_bigkey.
362 * Return total length of data; -1 if error.
365 collect_key(hashp
, pagep
, len
, last_page
)
369 db_pgno_t
*last_page
;
372 int32_t totlen
, retval
;
378 /* If this is the last page with key. */
379 if (BIGDATALEN(pagep
)) {
380 totlen
= len
+ BIGKEYLEN(pagep
);
381 if (hashp
->bigkey_buf
)
382 free(hashp
->bigkey_buf
);
383 hashp
->bigkey_buf
= (u_int8_t
*)malloc(totlen
);
384 if (!hashp
->bigkey_buf
)
386 memcpy(hashp
->bigkey_buf
+ len
,
387 BIGKEY(pagep
), BIGKEYLEN(pagep
));
389 *last_page
= ADDR(pagep
);
393 /* Key filled up all of last key page, so we've gone 1 too far. */
394 if (BIGKEYLEN(pagep
) == 0) {
395 if (hashp
->bigkey_buf
)
396 free(hashp
->bigkey_buf
);
397 hashp
->bigkey_buf
= (u_int8_t
*)malloc(len
);
398 return (hashp
->bigkey_buf
? len
: -1);
400 totlen
= len
+ BIGKEYLEN(pagep
);
402 /* Set pagep to the next page in the chain. */
404 *last_page
= ADDR(pagep
);
405 next_pgno
= NEXT_PGNO(pagep
);
406 next_pagep
= __get_page(hashp
, next_pgno
, A_RAW
);
410 save_addr
= ADDR(pagep
);
412 retval
= collect_key(hashp
, next_pagep
, totlen
, last_page
);
415 assert(save_addr
== ADDR(pagep
));
417 memcpy(hashp
->bigkey_buf
+ len
, BIGKEY(pagep
), BIGKEYLEN(pagep
));
418 __put_page(hashp
, next_pagep
, A_RAW
, 0);
424 * Given a page with big data on it, recur through the pages counting data
425 * length, and collect all of the data on the way up. Store the data in
426 * hashp->bigdata_buf.
428 * Does the work for __big_return.
430 * Return total length of data; -1 if error.
433 collect_data(hashp
, pagep
, len
)
439 int32_t totlen
, retval
;
445 /* If there is no next page. */
446 if (NEXT_PGNO(pagep
) == INVALID_PGNO
) {
447 if (hashp
->bigdata_buf
)
448 free(hashp
->bigdata_buf
);
449 totlen
= len
+ BIGDATALEN(pagep
);
450 hashp
->bigdata_buf
= (u_int8_t
*)malloc(totlen
);
451 if (!hashp
->bigdata_buf
)
453 memcpy(hashp
->bigdata_buf
+ totlen
- BIGDATALEN(pagep
),
454 BIGDATA(pagep
), BIGDATALEN(pagep
));
457 totlen
= len
+ BIGDATALEN(pagep
);
459 /* Set pagep to the next page in the chain. */
460 next_pgno
= NEXT_PGNO(pagep
);
461 next_pagep
= __get_page(hashp
, next_pgno
, A_RAW
);
466 save_addr
= ADDR(pagep
);
468 retval
= collect_data(hashp
, next_pagep
, totlen
);
470 assert(save_addr
== ADDR(pagep
));
472 memcpy(hashp
->bigdata_buf
+ totlen
- BIGDATALEN(pagep
),
473 BIGDATA(pagep
), BIGDATALEN(pagep
));
474 __put_page(hashp
, next_pagep
, A_RAW
, 0);