1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
7 /*
8 * Copyright (c) 1995, 1996
9 * Margo Seltzer. All rights reserved.
10 */
11 /*
12 * Copyright (c) 1995, 1996
13 * The President and Fellows of Harvard University. All rights reserved.
14 *
15 * This code is derived from software contributed to Berkeley by
16 * Margo Seltzer.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the University of
29 * California, Berkeley and its contributors.
30 * 4. Neither the name of the University nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47 #include "config.h"
48
49 #ifndef lint
50 static const char sccsid[] = "@(#)hash_rec.c 10.22 (Sleepycat) 10/21/98";
51 #endif /* not lint */
52
53 #ifndef NO_SYSTEM_INCLUDES
54 #include <sys/types.h>
55
56 #include <errno.h>
57 #include <string.h>
58 #endif
59
60 #include "db_int.h"
61 #include "shqueue.h"
62 #include "db_page.h"
63 #include "hash.h"
64 #include "btree.h"
65 #include "log.h"
66 #include "common_ext.h"
67
68 /*
69 * __ham_insdel_recover --
70 *
71 * PUBLIC: int __ham_insdel_recover
72 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
73 */
74 int
__ham_insdel_recover(logp,dbtp,lsnp,redo,info)75 __ham_insdel_recover(logp, dbtp, lsnp, redo, info)
76 DB_LOG *logp;
77 DBT *dbtp;
78 DB_LSN *lsnp;
79 int redo;
80 void *info;
81 {
82 __ham_insdel_args *argp;
83 DB *file_dbp;
84 DBC *dbc;
85 HASH_CURSOR *hcp;
86 DB_MPOOLFILE *mpf;
87 PAGE *pagep;
88 u_int32_t op;
89 int cmp_n, cmp_p, getmeta, ret;
90
91 getmeta = 0;
92 hcp = NULL;
93 REC_PRINT(__ham_insdel_print);
94 REC_INTRO(__ham_insdel_read);
95 hcp = (HASH_CURSOR *)dbc->internal;
96
97 ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
98 if (ret != 0)
99 if (!redo) {
100 /*
101 * We are undoing and the page doesn't exist. That
102 * is equivalent to having a pagelsn of 0, so we
103 * would not have to undo anything. In this case,
104 * don't bother creating a page.
105 */
106 goto done;
107 } else if ((ret = memp_fget(mpf, &argp->pgno,
108 DB_MPOOL_CREATE, &pagep)) != 0)
109 goto out;
110
111
112 GET_META(file_dbp, hcp, ret);
113 if (ret != 0)
114 goto out;
115 getmeta = 1;
116
117 cmp_n = log_compare(lsnp, &LSN(pagep));
118 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
119 /*
120 * Two possible things going on:
121 * redo a delete/undo a put: delete the item from the page.
122 * redo a put/undo a delete: add the item to the page.
123 * If we are undoing a delete, then the information logged is the
124 * entire entry off the page, not just the data of a dbt. In
125 * this case, we want to copy it back onto the page verbatim.
126 * We do this by calling __putitem with the type H_OFFPAGE instead
127 * of H_KEYDATA.
128 */
129 op = OPCODE_OF(argp->opcode);
130
131 if ((op == DELPAIR && cmp_n == 0 && !redo) ||
132 (op == PUTPAIR && cmp_p == 0 && redo)) {
133 /*
134 * Need to redo a PUT or undo a delete. If we are undoing a
135 * delete, we've got to restore the item back to its original
136 * position. That's a royal pain in the butt (because we do
137 * not store item lengths on the page), but there's no choice.
138 */
139 if (op != DELPAIR ||
140 argp->ndx == (u_int32_t)H_NUMPAIRS(pagep)) {
141 __ham_putitem(pagep, &argp->key,
142 !redo || PAIR_ISKEYBIG(argp->opcode) ?
143 H_OFFPAGE : H_KEYDATA);
144 __ham_putitem(pagep, &argp->data,
145 !redo || PAIR_ISDATABIG(argp->opcode) ?
146 H_OFFPAGE : H_KEYDATA);
147 } else
148 (void) __ham_reputpair(pagep, hcp->hdr->pagesize,
149 argp->ndx, &argp->key, &argp->data);
150
151 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
152 if ((ret = __ham_put_page(file_dbp, pagep, 1)) != 0)
153 goto out;
154
155 } else if ((op == DELPAIR && cmp_p == 0 && redo)
156 || (op == PUTPAIR && cmp_n == 0 && !redo)) {
157 /* Need to undo a put or redo a delete. */
158 __ham_dpair(file_dbp, pagep, argp->ndx);
159 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
160 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
161 goto out;
162 } else
163 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
164 goto out;
165
166 /* Return the previous LSN. */
167 done: *lsnp = argp->prev_lsn;
168 ret = 0;
169
170 out: if (getmeta)
171 RELEASE_META(file_dbp, hcp);
172 REC_CLOSE;
173 }
174
175 /*
176 * __ham_newpage_recover --
177 * This log message is used when we add/remove overflow pages. This
178 * message takes care of the pointer chains, not the data on the pages.
179 *
180 * PUBLIC: int __ham_newpage_recover
181 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
182 */
183 int
__ham_newpage_recover(logp,dbtp,lsnp,redo,info)184 __ham_newpage_recover(logp, dbtp, lsnp, redo, info)
185 DB_LOG *logp;
186 DBT *dbtp;
187 DB_LSN *lsnp;
188 int redo;
189 void *info;
190 {
191 __ham_newpage_args *argp;
192 DB *file_dbp;
193 DBC *dbc;
194 HASH_CURSOR *hcp;
195 DB_MPOOLFILE *mpf;
196 PAGE *pagep;
197 int cmp_n, cmp_p, change, getmeta, ret;
198
199 getmeta = 0;
200 hcp = NULL;
201 REC_PRINT(__ham_newpage_print);
202 REC_INTRO(__ham_newpage_read);
203 hcp = (HASH_CURSOR *)dbc->internal;
204
205 ret = memp_fget(mpf, &argp->new_pgno, 0, &pagep);
206 if (ret != 0)
207 if (!redo) {
208 /*
209 * We are undoing and the page doesn't exist. That
210 * is equivalent to having a pagelsn of 0, so we
211 * would not have to undo anything. In this case,
212 * don't bother creating a page.
213 */
214 ret = 0;
215 goto ppage;
216 } else if ((ret = memp_fget(mpf, &argp->new_pgno,
217 DB_MPOOL_CREATE, &pagep)) != 0)
218 goto out;
219
220 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
221 if (ret != 0)
222 goto out;
223 getmeta = 1;
224
225 /*
226 * There are potentially three pages we need to check: the one
227 * that we created/deleted, the one before it and the one after
228 * it.
229 */
230
231 cmp_n = log_compare(lsnp, &LSN(pagep));
232 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
233 change = 0;
234
235 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
236 (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
237 /* Redo a create new page or undo a delete new page. */
238 P_INIT(pagep, file_dbp->pgsize, argp->new_pgno,
239 argp->prev_pgno, argp->next_pgno, 0, P_HASH);
240 change = 1;
241 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
242 (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
243 /*
244 * Redo a delete or undo a create new page. All we
245 * really need to do is change the LSN.
246 */
247 change = 1;
248 }
249
250 if (!change) {
251 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
252 goto out;
253 } else {
254 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
255 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
256 goto out;
257 }
258
259 /* Now do the prev page. */
260 ppage: if (argp->prev_pgno != PGNO_INVALID) {
261 ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep);
262
263 if (ret != 0)
264 if (!redo) {
265 /*
266 * We are undoing and the page doesn't exist.
267 * That is equivalent to having a pagelsn of 0,
268 * so we would not have to undo anything. In
269 * this case, don't bother creating a page.
270 */
271 ret = 0;
272 goto npage;
273 } else if ((ret =
274 memp_fget(mpf, &argp->prev_pgno,
275 DB_MPOOL_CREATE, &pagep)) != 0)
276 goto out;
277
278 cmp_n = log_compare(lsnp, &LSN(pagep));
279 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
280 change = 0;
281
282 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
283 (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
284 /* Redo a create new page or undo a delete new page. */
285 pagep->next_pgno = argp->new_pgno;
286 change = 1;
287 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
288 (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
289 /* Redo a delete or undo a create new page. */
290 pagep->next_pgno = argp->next_pgno;
291 change = 1;
292 }
293
294 if (!change) {
295 if ((ret =
296 __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
297 goto out;
298 } else {
299 LSN(pagep) = redo ? *lsnp : argp->prevlsn;
300 if ((ret =
301 __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
302 goto out;
303 }
304 }
305
306 /* Now time to do the next page */
307 npage: if (argp->next_pgno != PGNO_INVALID) {
308 ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep);
309
310 if (ret != 0)
311 if (!redo) {
312 /*
313 * We are undoing and the page doesn't exist.
314 * That is equivalent to having a pagelsn of 0,
315 * so we would not have to undo anything. In
316 * this case, don't bother creating a page.
317 */
318 goto done;
319 } else if ((ret =
320 memp_fget(mpf, &argp->next_pgno,
321 DB_MPOOL_CREATE, &pagep)) != 0)
322 goto out;
323
324 cmp_n = log_compare(lsnp, &LSN(pagep));
325 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
326 change = 0;
327
328 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
329 (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
330 /* Redo a create new page or undo a delete new page. */
331 pagep->prev_pgno = argp->new_pgno;
332 change = 1;
333 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
334 (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
335 /* Redo a delete or undo a create new page. */
336 pagep->prev_pgno = argp->prev_pgno;
337 change = 1;
338 }
339
340 if (!change) {
341 if ((ret =
342 __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
343 goto out;
344 } else {
345 LSN(pagep) = redo ? *lsnp : argp->nextlsn;
346 if ((ret =
347 __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
348 goto out;
349 }
350 }
351 done: *lsnp = argp->prev_lsn;
352 ret = 0;
353
354 out: if (getmeta)
355 RELEASE_META(file_dbp, hcp);
356 REC_CLOSE;
357 }
358
359
360 /*
361 * __ham_replace_recover --
362 * This log message refers to partial puts that are local to a single
363 * page. You can think of them as special cases of the more general
364 * insdel log message.
365 *
366 * PUBLIC: int __ham_replace_recover
367 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
368 */
369 int
__ham_replace_recover(logp,dbtp,lsnp,redo,info)370 __ham_replace_recover(logp, dbtp, lsnp, redo, info)
371 DB_LOG *logp;
372 DBT *dbtp;
373 DB_LSN *lsnp;
374 int redo;
375 void *info;
376 {
377 __ham_replace_args *argp;
378 DB *file_dbp;
379 DBC *dbc;
380 HASH_CURSOR *hcp;
381 DB_MPOOLFILE *mpf;
382 DBT dbt;
383 PAGE *pagep;
384 int32_t grow;
385 int change, cmp_n, cmp_p, getmeta, ret;
386 u_int8_t *hk;
387
388 getmeta = 0;
389 hcp = NULL;
390 REC_PRINT(__ham_replace_print);
391 REC_INTRO(__ham_replace_read);
392 hcp = (HASH_CURSOR *)dbc->internal;
393
394 ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
395 if (ret != 0)
396 if (!redo) {
397 /*
398 * We are undoing and the page doesn't exist. That
399 * is equivalent to having a pagelsn of 0, so we
400 * would not have to undo anything. In this case,
401 * don't bother creating a page.
402 */
403 goto done;
404 } else if ((ret = memp_fget(mpf, &argp->pgno,
405 DB_MPOOL_CREATE, &pagep)) != 0)
406 goto out;
407
408 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
409 if (ret != 0)
410 goto out;
411 getmeta = 1;
412
413 cmp_n = log_compare(lsnp, &LSN(pagep));
414 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
415
416 if (cmp_p == 0 && redo) {
417 change = 1;
418 /* Reapply the change as specified. */
419 dbt.data = argp->newitem.data;
420 dbt.size = argp->newitem.size;
421 grow = argp->newitem.size - argp->olditem.size;
422 LSN(pagep) = *lsnp;
423 } else if (cmp_n == 0 && !redo) {
424 change = 1;
425 /* Undo the already applied change. */
426 dbt.data = argp->olditem.data;
427 dbt.size = argp->olditem.size;
428 grow = argp->olditem.size - argp->newitem.size;
429 LSN(pagep) = argp->pagelsn;
430 } else {
431 change = 0;
432 grow = 0;
433 }
434
435 if (change) {
436 __ham_onpage_replace(pagep,
437 file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt);
438 if (argp->makedup) {
439 hk = P_ENTRY(pagep, argp->ndx);
440 if (redo)
441 HPAGE_PTYPE(hk) = H_DUPLICATE;
442 else
443 HPAGE_PTYPE(hk) = H_KEYDATA;
444 }
445 }
446
447 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
448 goto out;
449
450 done: *lsnp = argp->prev_lsn;
451 ret = 0;
452
453 out: if (getmeta)
454 RELEASE_META(file_dbp, hcp);
455 REC_CLOSE;
456 }
457
458 /*
459 * __ham_newpgno_recover --
460 * This log message is used when allocating or deleting an overflow
461 * page. It takes care of modifying the meta data.
462 *
463 * PUBLIC: int __ham_newpgno_recover
464 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
465 */
466 int
__ham_newpgno_recover(logp,dbtp,lsnp,redo,info)467 __ham_newpgno_recover(logp, dbtp, lsnp, redo, info)
468 DB_LOG *logp;
469 DBT *dbtp;
470 DB_LSN *lsnp;
471 int redo;
472 void *info;
473 {
474 __ham_newpgno_args *argp;
475 DB *file_dbp;
476 DBC *dbc;
477 HASH_CURSOR *hcp;
478 DB_MPOOLFILE *mpf;
479 PAGE *pagep;
480 int change, cmp_n, cmp_p, getmeta, ret;
481
482 getmeta = 0;
483 hcp = NULL;
484 REC_PRINT(__ham_newpgno_print);
485 REC_INTRO(__ham_newpgno_read);
486 hcp = (HASH_CURSOR *)dbc->internal;
487
488 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
489 if (ret != 0)
490 goto out;
491 getmeta = 1;
492
493 /*
494 * There are two phases to the recovery here. First we need
495 * to update the meta data; then we need to update the page.
496 * We'll do the meta-data first.
497 */
498 cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
499 cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
500
501 change = 0;
502 if ((cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) ||
503 (cmp_n == 0 && !redo && argp->opcode == DELPGNO)) {
504 /* Need to redo an allocation or undo a deletion. */
505 hcp->hdr->last_freed = argp->free_pgno;
506 if (redo && argp->old_pgno != 0) /* Must be ALLOCPGNO */
507 hcp->hdr->spares[hcp->hdr->ovfl_point]++;
508 change = 1;
509 } else if (cmp_p == 0 && redo && argp->opcode == DELPGNO) {
510 /* Need to redo a deletion */
511 hcp->hdr->last_freed = argp->pgno;
512 change = 1;
513 } else if (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO) {
514 /* undo an allocation. */
515 if (argp->old_pgno == 0)
516 hcp->hdr->last_freed = argp->pgno;
517 else {
518 hcp->hdr->spares[hcp->hdr->ovfl_point]--;
519 hcp->hdr->last_freed = 0;
520 }
521 change = 1;
522 }
523 if (change) {
524 hcp->hdr->lsn = redo ? *lsnp : argp->metalsn;
525 F_SET(hcp, H_DIRTY);
526 }
527
528
529 /* Now check the newly allocated/freed page. */
530 ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
531
532 if (ret != 0)
533 if (!redo) {
534 /*
535 * We are undoing and the page doesn't exist. That
536 * is equivalent to having a pagelsn of 0, so we
537 * would not have to undo anything. In this case,
538 * don't bother creating a page.
539 */
540 goto done;
541 } else if ((ret = memp_fget(mpf, &argp->pgno,
542 DB_MPOOL_CREATE, &pagep)) != 0)
543 goto out;
544
545 cmp_n = log_compare(lsnp, &LSN(pagep));
546 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
547
548 change = 0;
549 if (cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) {
550 /* Need to redo an allocation. */
551 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
552 PGNO_INVALID, 0, argp->new_type);
553 change = 1;
554 } else if (cmp_n == 0 && !redo && argp->opcode == DELPGNO) {
555 /* Undoing a delete. */
556 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
557 argp->old_pgno, 0, argp->old_type);
558 change = 1;
559 } else if ((cmp_p == 0 && redo && argp->opcode == DELPGNO) ||
560 (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO)) {
561 /* Need to redo a deletion or undo an allocation. */
562 NEXT_PGNO(pagep) = argp->free_pgno;
563 TYPE(pagep) = P_INVALID;
564 change = 1;
565 }
566 if (change)
567 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
568
569 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
570 goto out;
571
572 done: *lsnp = argp->prev_lsn;
573 ret = 0;
574
575 out: if (getmeta)
576 RELEASE_META(file_dbp, hcp);
577 REC_CLOSE;
578
579 }
580
581 /*
582 * __ham_splitmeta_recover --
583 * This is the meta-data part of the split. Records the new and old
584 * bucket numbers and the new/old mask information.
585 *
586 * PUBLIC: int __ham_splitmeta_recover
587 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
588 */
589 int
__ham_splitmeta_recover(logp,dbtp,lsnp,redo,info)590 __ham_splitmeta_recover(logp, dbtp, lsnp, redo, info)
591 DB_LOG *logp;
592 DBT *dbtp;
593 DB_LSN *lsnp;
594 int redo;
595 void *info;
596 {
597 __ham_splitmeta_args *argp;
598 DB *file_dbp;
599 DBC *dbc;
600 HASH_CURSOR *hcp;
601 DB_MPOOLFILE *mpf;
602 int change, cmp_n, cmp_p, getmeta, ret;
603 u_int32_t pow;
604
605 getmeta = 0;
606 hcp = NULL;
607 REC_PRINT(__ham_splitmeta_print);
608 REC_INTRO(__ham_splitmeta_read);
609 hcp = (HASH_CURSOR *)dbc->internal;
610
611 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
612 if (ret != 0)
613 goto out;
614 getmeta = 1;
615
616 /*
617 * There are two phases to the recovery here. First we need
618 * to update the meta data; then we need to update the page.
619 * We'll do the meta-data first.
620 */
621 cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
622 cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
623
624 change = 0;
625 if (cmp_p == 0 && redo) {
626 /* Need to redo the split information. */
627 hcp->hdr->max_bucket = argp->bucket + 1;
628 pow = __db_log2(hcp->hdr->max_bucket + 1);
629 if (pow > hcp->hdr->ovfl_point) {
630 hcp->hdr->spares[pow] =
631 hcp->hdr->spares[hcp->hdr->ovfl_point];
632 hcp->hdr->ovfl_point = pow;
633 }
634 if (hcp->hdr->max_bucket > hcp->hdr->high_mask) {
635 hcp->hdr->low_mask = hcp->hdr->high_mask;
636 hcp->hdr->high_mask =
637 hcp->hdr->max_bucket | hcp->hdr->low_mask;
638 }
639 change = 1;
640 } else if (cmp_n == 0 && !redo) {
641 /* Need to undo the split information. */
642 hcp->hdr->max_bucket = argp->bucket;
643 hcp->hdr->ovfl_point = argp->ovflpoint;
644 hcp->hdr->spares[hcp->hdr->ovfl_point] = argp->spares;
645 pow = 1 << __db_log2(hcp->hdr->max_bucket + 1);
646 hcp->hdr->high_mask = pow - 1;
647 hcp->hdr->low_mask = (pow >> 1) - 1;
648 change = 1;
649 }
650 if (change) {
651 hcp->hdr->lsn = redo ? *lsnp : argp->metalsn;
652 F_SET(hcp, H_DIRTY);
653 }
654
655 done: *lsnp = argp->prev_lsn;
656 ret = 0;
657
658 out: if (getmeta)
659 RELEASE_META(file_dbp, hcp);
660 REC_CLOSE;
661 }
662
663 /*
664 * __ham_splitdata_recover --
665 *
666 * PUBLIC: int __ham_splitdata_recover
667 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
668 */
669 int
__ham_splitdata_recover(logp,dbtp,lsnp,redo,info)670 __ham_splitdata_recover(logp, dbtp, lsnp, redo, info)
671 DB_LOG *logp;
672 DBT *dbtp;
673 DB_LSN *lsnp;
674 int redo;
675 void *info;
676 {
677 __ham_splitdata_args *argp;
678 DB *file_dbp;
679 DBC *dbc;
680 HASH_CURSOR *hcp;
681 DB_MPOOLFILE *mpf;
682 PAGE *pagep;
683 int change, cmp_n, cmp_p, getmeta, ret;
684
685 getmeta = 0;
686 hcp = NULL;
687 REC_PRINT(__ham_splitdata_print);
688 REC_INTRO(__ham_splitdata_read);
689 hcp = (HASH_CURSOR *)dbc->internal;
690
691 ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
692 if (ret != 0)
693 if (!redo) {
694 /*
695 * We are undoing and the page doesn't exist. That
696 * is equivalent to having a pagelsn of 0, so we
697 * would not have to undo anything. In this case,
698 * don't bother creating a page.
699 */
700 goto done;
701 } else if ((ret = memp_fget(mpf, &argp->pgno,
702 DB_MPOOL_CREATE, &pagep)) != 0)
703 goto out;
704
705 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
706 if (ret != 0)
707 goto out;
708 getmeta = 1;
709
710 cmp_n = log_compare(lsnp, &LSN(pagep));
711 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
712
713 /*
714 * There are two types of log messages here, one for the old page
715 * and one for the new pages created. The original image in the
716 * SPLITOLD record is used for undo. The image in the SPLITNEW
717 * is used for redo. We should never have a case where there is
718 * a redo operation and the SPLITOLD record is on disk, but not
719 * the SPLITNEW record. Therefore, we only have work to do when
720 * redo NEW messages and undo OLD messages, but we have to update
721 * LSNs in both cases.
722 */
723 change = 0;
724 if (cmp_p == 0 && redo) {
725 if (argp->opcode == SPLITNEW)
726 /* Need to redo the split described. */
727 memcpy(pagep, argp->pageimage.data,
728 argp->pageimage.size);
729 LSN(pagep) = *lsnp;
730 change = 1;
731 } else if (cmp_n == 0 && !redo) {
732 if (argp->opcode == SPLITOLD) {
733 /* Put back the old image. */
734 memcpy(pagep, argp->pageimage.data,
735 argp->pageimage.size);
736 } else
737 P_INIT(pagep, file_dbp->pgsize, argp->pgno,
738 PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
739 LSN(pagep) = argp->pagelsn;
740 change = 1;
741 }
742 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
743 goto out;
744
745 done: *lsnp = argp->prev_lsn;
746 ret = 0;
747
748 out: if (getmeta)
749 RELEASE_META(file_dbp, hcp);
750 REC_CLOSE;
751 }
752
753 /*
754 * __ham_ovfl_recover --
755 * This message is generated when we initialize a set of overflow pages.
756 *
757 * PUBLIC: int __ham_ovfl_recover
758 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
759 */
760 int
__ham_ovfl_recover(logp,dbtp,lsnp,redo,info)761 __ham_ovfl_recover(logp, dbtp, lsnp, redo, info)
762 DB_LOG *logp;
763 DBT *dbtp;
764 DB_LSN *lsnp;
765 int redo;
766 void *info;
767 {
768 __ham_ovfl_args *argp;
769 DB *file_dbp;
770 DBC *dbc;
771 HASH_CURSOR *hcp;
772 DB_MPOOLFILE *mpf;
773 PAGE *pagep;
774 db_pgno_t max_pgno, pgno;
775 int cmp_n, cmp_p, getmeta, ret;
776
777 getmeta = 0;
778 hcp = NULL;
779 REC_PRINT(__ham_ovfl_print);
780 REC_INTRO(__ham_ovfl_read);
781 hcp = (HASH_CURSOR *)dbc->internal;
782
783 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
784 if (ret != 0)
785 goto out;
786 getmeta = 1;
787
788 cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
789 cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
790
791 if (cmp_p == 0 && redo) {
792 /* Redo the allocation. */
793 hcp->hdr->last_freed = argp->start_pgno;
794 hcp->hdr->spares[argp->ovflpoint] += argp->npages;
795 hcp->hdr->lsn = *lsnp;
796 F_SET(hcp, H_DIRTY);
797 } else if (cmp_n == 0 && !redo) {
798 hcp->hdr->last_freed = argp->free_pgno;
799 hcp->hdr->spares[argp->ovflpoint] -= argp->npages;
800 hcp->hdr->lsn = argp->metalsn;
801 F_SET(hcp, H_DIRTY);
802 }
803
804 max_pgno = argp->start_pgno + argp->npages - 1;
805 ret = 0;
806 for (pgno = argp->start_pgno; pgno <= max_pgno; pgno++) {
807 if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) != 0) {
808 if (!redo) {
809 ret = 0;
810 continue;
811 }
812 if ((ret = memp_fget(mpf,
813 &pgno, DB_MPOOL_CREATE, &pagep)) != 0)
814 goto out;
815 }
816 if (redo && log_compare((const DB_LSN *)lsnp,
817 (const DB_LSN *)&LSN(pagep)) > 0) {
818 P_INIT(pagep, file_dbp->pgsize, pgno, PGNO_INVALID,
819 pgno == max_pgno ? argp->free_pgno : pgno + 1,
820 0, P_HASH);
821 LSN(pagep) = *lsnp;
822 ret = __ham_put_page(file_dbp, pagep, 1);
823 } else if (!redo) {
824 ZERO_LSN(pagep->lsn);
825 ret = __ham_put_page(file_dbp, pagep, 1);
826 } else
827 ret = __ham_put_page(file_dbp, pagep, 0);
828 if (ret)
829 goto out;
830 }
831
832 done: *lsnp = argp->prev_lsn;
833 ret = 0;
834
835 out: if (getmeta)
836 RELEASE_META(file_dbp, hcp);
837 REC_CLOSE;
838 }
839
840 /*
841 * __ham_copypage_recover --
842 * Recovery function for copypage.
843 *
844 * PUBLIC: int __ham_copypage_recover
845 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
846 */
847 int
__ham_copypage_recover(logp,dbtp,lsnp,redo,info)848 __ham_copypage_recover(logp, dbtp, lsnp, redo, info)
849 DB_LOG *logp;
850 DBT *dbtp;
851 DB_LSN *lsnp;
852 int redo;
853 void *info;
854 {
855 __ham_copypage_args *argp;
856 DB *file_dbp;
857 DBC *dbc;
858 HASH_CURSOR *hcp;
859 DB_MPOOLFILE *mpf;
860 PAGE *pagep;
861 int cmp_n, cmp_p, getmeta, modified, ret;
862
863 getmeta = 0;
864 hcp = NULL;
865 REC_PRINT(__ham_copypage_print);
866 REC_INTRO(__ham_copypage_read);
867 hcp = (HASH_CURSOR *)dbc->internal;
868
869 GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
870 if (ret != 0)
871 goto out;
872 getmeta = 1;
873 modified = 0;
874
875 /* This is the bucket page. */
876 ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
877 if (ret != 0)
878 if (!redo) {
879 /*
880 * We are undoing and the page doesn't exist. That
881 * is equivalent to having a pagelsn of 0, so we
882 * would not have to undo anything. In this case,
883 * don't bother creating a page.
884 */
885 ret = 0;
886 goto donext;
887 } else if ((ret = memp_fget(mpf, &argp->pgno,
888 DB_MPOOL_CREATE, &pagep)) != 0)
889 goto out;
890
891 cmp_n = log_compare(lsnp, &LSN(pagep));
892 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
893
894 if (cmp_p == 0 && redo) {
895 /* Need to redo update described. */
896 memcpy(pagep, argp->page.data, argp->page.size);
897 LSN(pagep) = *lsnp;
898 modified = 1;
899 } else if (cmp_n == 0 && !redo) {
900 /* Need to undo update described. */
901 P_INIT(pagep, hcp->hdr->pagesize, argp->pgno, PGNO_INVALID,
902 argp->next_pgno, 0, P_HASH);
903 LSN(pagep) = argp->pagelsn;
904 modified = 1;
905 }
906 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
907 goto out;
908
909 /* Now fix up the "next" page. */
910 donext: ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep);
911 if (ret != 0)
912 if (!redo) {
913 /*
914 * We are undoing and the page doesn't exist. That
915 * is equivalent to having a pagelsn of 0, so we
916 * would not have to undo anything. In this case,
917 * don't bother creating a page.
918 */
919 ret = 0;
920 goto do_nn;
921 } else if ((ret = memp_fget(mpf, &argp->next_pgno,
922 DB_MPOOL_CREATE, &pagep)) != 0)
923 goto out;
924
925 /* There is nothing to do in the REDO case; only UNDO. */
926
927 cmp_n = log_compare(lsnp, &LSN(pagep));
928 if (cmp_n == 0 && !redo) {
929 /* Need to undo update described. */
930 memcpy(pagep, argp->page.data, argp->page.size);
931 modified = 1;
932 }
933 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
934 goto out;
935
936 /* Now fix up the next's next page. */
937 do_nn: if (argp->nnext_pgno == PGNO_INVALID)
938 goto done;
939
940 ret = memp_fget(mpf, &argp->nnext_pgno, 0, &pagep);
941 if (ret != 0)
942 if (!redo) {
943 /*
944 * We are undoing and the page doesn't exist. That
945 * is equivalent to having a pagelsn of 0, so we
946 * would not have to undo anything. In this case,
947 * don't bother creating a page.
948 */
949 goto done;
950 } else if ((ret = memp_fget(mpf, &argp->nnext_pgno,
951 DB_MPOOL_CREATE, &pagep)) != 0)
952 goto out;
953
954 cmp_n = log_compare(lsnp, &LSN(pagep));
955 cmp_p = log_compare(&LSN(pagep), &argp->nnextlsn);
956
957 if (cmp_p == 0 && redo) {
958 /* Need to redo update described. */
959 PREV_PGNO(pagep) = argp->pgno;
960 LSN(pagep) = *lsnp;
961 modified = 1;
962 } else if (cmp_n == 0 && !redo) {
963 /* Need to undo update described. */
964 PREV_PGNO(pagep) = argp->next_pgno;
965 LSN(pagep) = argp->nnextlsn;
966 modified = 1;
967 }
968 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
969 goto out;
970
971 done: *lsnp = argp->prev_lsn;
972 ret = 0;
973
974 out: if (getmeta)
975 RELEASE_META(file_dbp, hcp);
976 REC_CLOSE;
977 }
978