1b30be337df2e67944108734c4e52a5a46158a8f
[kopensolaris-gnu/glibc.git] / db2 / hash / hash_rec.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997
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.13 (Sleepycat) 9/15/97";
51 #endif /* not lint */
52
53 #ifndef NO_SYSTEM_INCLUDES
54 #include <sys/types.h>
55
56 #include <errno.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #endif
60
61 #include "db_int.h"
62 #include "shqueue.h"
63 #include "db_page.h"
64 #include "hash.h"
65 #include "btree.h"
66 #include "log.h"
67 #include "db_dispatch.h"
68 #include "common_ext.h"
69
70 /*
71  * __ham_insdel_recover --
72  *
73  * PUBLIC: int __ham_insdel_recover
74  * PUBLIC:     __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
75  */
76 int
77 __ham_insdel_recover(logp, dbtp, lsnp, redo, info)
78         DB_LOG *logp;
79         DBT *dbtp;
80         DB_LSN *lsnp;
81         int redo;
82         void *info;
83 {
84         __ham_insdel_args *argp;
85         DB *mdbp, *file_dbp;
86         DB_MPOOLFILE *mpf;
87         HTAB *hashp;
88         PAGE *pagep;
89         u_int32_t op;
90         int cmp_n, cmp_p, getmeta, ret;
91
92         getmeta = 0;
93         hashp = NULL;                           /* XXX: shut the compiler up. */
94         REC_PRINT(__ham_insdel_print);
95         REC_INTRO(__ham_insdel_read);
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                         *lsnp = argp->prev_lsn;
107                         ret = 0;
108                         goto out;
109                 } else if ((ret = memp_fget(mpf, &argp->pgno,
110                     DB_MPOOL_CREATE, &pagep)) != 0)
111                         goto out;
112
113
114         hashp = (HTAB *)file_dbp->internal;
115         GET_META(file_dbp, hashp);
116         getmeta = 1;
117
118         cmp_n = log_compare(lsnp, &LSN(pagep));
119         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
120         /*
121          * Two possible things going on:
122          * redo a delete/undo a put: delete the item from the page.
123          * redo a put/undo a delete: add the item to the page.
124          * If we are undoing a delete, then the information logged is the
125          * entire entry off the page, not just the data of a dbt.  In
126          * this case, we want to copy it back onto the page verbatim.
127          * We do this by calling __putitem with the type H_OFFPAGE instead
128          * of H_KEYDATA.
129          */
130         op = OPCODE_OF(argp->opcode);
131
132         if ((op == DELPAIR && cmp_n == 0 && !redo) ||
133             (op == PUTPAIR && cmp_p == 0 && redo)) {
134                 /* Need to redo a PUT or undo a delete. */
135                 __ham_putitem(pagep, &argp->key,
136                     !redo || PAIR_ISKEYBIG(argp->opcode) ?
137                     H_OFFPAGE : H_KEYDATA);
138                 __ham_putitem(pagep, &argp->data,
139                     !redo || PAIR_ISDATABIG(argp->opcode) ?
140                     H_OFFPAGE : H_KEYDATA);
141
142                 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
143                 if ((ret = __ham_put_page(file_dbp, pagep, 1)) != 0)
144                         goto out;
145
146         } else if ((op == DELPAIR && cmp_p == 0 && redo)
147             || (op == PUTPAIR && cmp_n == 0 && !redo)) {
148                 /* Need to undo a put or redo a delete. */
149                 __ham_dpair(file_dbp, pagep, argp->ndx);
150                 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
151                 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
152                         goto out;
153         } else
154                 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
155                         goto out;
156
157         /* Return the previous LSN. */
158         *lsnp = argp->prev_lsn;
159
160 out:    if (getmeta)
161                 RELEASE_META(file_dbp, hashp);
162         REC_CLOSE;
163 }
164
165 /*
166  * __ham_newpage_recover --
167  *      This log message is used when we add/remove overflow pages.  This
168  *      message takes care of the pointer chains, not the data on the pages.
169  *
170  * PUBLIC: int __ham_newpage_recover
171  * PUBLIC:     __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
172  */
173 int
174 __ham_newpage_recover(logp, dbtp, lsnp, redo, info)
175         DB_LOG *logp;
176         DBT *dbtp;
177         DB_LSN *lsnp;
178         int redo;
179         void *info;
180 {
181         __ham_newpage_args *argp;
182         DB *mdbp, *file_dbp;
183         DB_MPOOLFILE *mpf;
184         HTAB *hashp;
185         PAGE *pagep;
186         int cmp_n, cmp_p, change, getmeta, ret;
187
188         getmeta = 0;
189         hashp = NULL;                           /* XXX: shut the compiler up. */
190         REC_PRINT(__ham_newpage_print);
191         REC_INTRO(__ham_newpage_read);
192
193         ret = memp_fget(mpf, &argp->new_pgno, 0, &pagep);
194         if (ret != 0)
195                 if (!redo) {
196                         /*
197                          * We are undoing and the page doesn't exist.  That
198                          * is equivalent to having a pagelsn of 0, so we
199                          * would not have to undo anything.  In this case,
200                          * don't bother creating a page.
201                          */
202                         ret = 0;
203                         goto ppage;
204                 } else if ((ret = memp_fget(mpf, &argp->new_pgno,
205                     DB_MPOOL_CREATE, &pagep)) != 0)
206                         goto out;
207
208         hashp = (HTAB *)file_dbp->internal;
209         GET_META(file_dbp, hashp);
210         getmeta = 1;
211
212         /*
213          * There are potentially three pages we need to check: the one
214          * that we created/deleted, the one before it and the one after
215          * it.
216          */
217
218         cmp_n = log_compare(lsnp, &LSN(pagep));
219         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
220         change = 0;
221
222         if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
223             (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
224                 /* Redo a create new page or undo a delete new page. */
225                 P_INIT(pagep, file_dbp->pgsize, argp->new_pgno,
226                     argp->prev_pgno, argp->next_pgno, 0, P_HASH);
227                 change = 1;
228         } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
229             (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
230                 /*
231                  * Redo a delete or undo a create new page.  All we
232                  * really need to do is change the LSN.
233                  */
234                 change = 1;
235         }
236
237         if (!change) {
238                 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
239                         goto out;
240         } else {
241                 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
242                 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
243                         goto out;
244         }
245
246         /* Now do the prev page. */
247 ppage:  if (argp->prev_pgno != PGNO_INVALID) {
248                 ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep);
249
250                 if (ret != 0)
251                         if (!redo) {
252                                 /*
253                                  * We are undoing and the page doesn't exist.
254                                  * That is equivalent to having a pagelsn of 0,
255                                  * so we would not have to undo anything.  In
256                                  * this case, don't bother creating a page.
257                                  */
258                                 ret = 0;
259                                 goto npage;
260                         } else if ((ret =
261                             memp_fget(mpf, &argp->prev_pgno,
262                             DB_MPOOL_CREATE, &pagep)) != 0)
263                                 goto out;
264
265                 cmp_n = log_compare(lsnp, &LSN(pagep));
266                 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
267                 change = 0;
268
269                 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
270                     (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
271                         /* Redo a create new page or undo a delete new page. */
272                         pagep->next_pgno = argp->new_pgno;
273                         change = 1;
274                 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
275                     (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
276                         /* Redo a delete or undo a create new page. */
277                         pagep->next_pgno = argp->next_pgno;
278                         change = 1;
279                 }
280
281                 if (!change) {
282                         if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
283                                 goto out;
284                 } else {
285                         LSN(pagep) = redo ? *lsnp : argp->prevlsn;
286                         if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
287                                 goto out;
288                 }
289         }
290
291         /* Now time to do the next page */
292 npage:  if (argp->next_pgno != PGNO_INVALID) {
293                 ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep);
294
295                 if (ret != 0)
296                         if (!redo) {
297                                 /*
298                                  * We are undoing and the page doesn't exist.
299                                  * That is equivalent to having a pagelsn of 0,
300                                  * so we would not have to undo anything.  In
301                                  * this case, don't bother creating a page.
302                                  */
303                                 *lsnp = argp->prev_lsn;
304                                 ret = 0;
305                                 goto out;
306                         } else if ((ret =
307                             memp_fget(mpf, &argp->next_pgno,
308                             DB_MPOOL_CREATE, &pagep)) != 0)
309                                 goto out;
310
311                 cmp_n = log_compare(lsnp, &LSN(pagep));
312                 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
313                 change = 0;
314
315                 if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
316                     (cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
317                         /* Redo a create new page or undo a delete new page. */
318                         pagep->prev_pgno = argp->new_pgno;
319                         change = 1;
320                 } else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
321                     (cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
322                         /* Redo a delete or undo a create new page. */
323                         pagep->prev_pgno = argp->prev_pgno;
324                         change = 1;
325                 }
326
327                 if (!change) {
328                         if ((ret =
329                             __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
330                                 goto out;
331                 } else {
332                         LSN(pagep) = redo ? *lsnp : argp->nextlsn;
333                         if ((ret =
334                             __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
335                                 goto out;
336                 }
337         }
338         *lsnp = argp->prev_lsn;
339
340 out:    if (getmeta)
341                 RELEASE_META(file_dbp, hashp);
342         REC_CLOSE;
343 }
344
345
346 /*
347  * __ham_replace_recover --
348  *      This log message refers to partial puts that are local to a single
349  *      page.  You can think of them as special cases of the more general
350  *      insdel log message.
351  *
352  * PUBLIC: int __ham_replace_recover
353  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
354  */
355 int
356 __ham_replace_recover(logp, dbtp, lsnp, redo, info)
357         DB_LOG *logp;
358         DBT *dbtp;
359         DB_LSN *lsnp;
360         int redo;
361         void *info;
362 {
363         __ham_replace_args *argp;
364         DB *mdbp, *file_dbp;
365         DB_MPOOLFILE *mpf;
366         DBT dbt;
367         HTAB *hashp;
368         PAGE *pagep;
369         int32_t grow;
370         int change, cmp_n, cmp_p, getmeta, ret;
371         u_int8_t *hk;
372
373         getmeta = 0;
374         hashp = NULL;                           /* XXX: shut the compiler up. */
375         REC_PRINT(__ham_replace_print);
376         REC_INTRO(__ham_replace_read);
377
378         ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
379         if (ret != 0)
380                 if (!redo) {
381                         /*
382                          * We are undoing and the page doesn't exist.  That
383                          * is equivalent to having a pagelsn of 0, so we
384                          * would not have to undo anything.  In this case,
385                          * don't bother creating a page.
386                          */
387                         *lsnp = argp->prev_lsn;
388                         ret = 0;
389                         goto out;
390                 } else if ((ret = memp_fget(mpf, &argp->pgno,
391                     DB_MPOOL_CREATE, &pagep)) != 0)
392                         goto out;
393
394         hashp = (HTAB *)file_dbp->internal;
395         GET_META(file_dbp, hashp);
396         getmeta = 1;
397
398         cmp_n = log_compare(lsnp, &LSN(pagep));
399         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
400
401         if (cmp_p == 0 && redo) {
402                 change = 1;
403                 /* Reapply the change as specified. */
404                 dbt.data = argp->newitem.data;
405                 dbt.size = argp->newitem.size;
406                 grow = argp->newitem.size - argp->olditem.size;
407                 LSN(pagep) = *lsnp;
408         } else if (cmp_n == 0 && !redo) {
409                 change = 1;
410                 /* Undo the already applied change. */
411                 dbt.data = argp->olditem.data;
412                 dbt.size = argp->olditem.size;
413                 grow = argp->olditem.size - argp->newitem.size;
414                 LSN(pagep) = argp->pagelsn;
415         } else {
416                 change = 0;
417                 grow = 0;
418         }
419
420         if (change) {
421                 __ham_onpage_replace(pagep,
422                     file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt);
423                 if (argp->makedup) {
424                         hk = P_ENTRY(pagep, argp->ndx);
425                         if (redo)
426                                 HPAGE_PTYPE(hk) = H_DUPLICATE;
427                         else
428                                 HPAGE_PTYPE(hk) = H_KEYDATA;
429                 }
430         }
431
432         if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
433                 goto out;
434
435         *lsnp = argp->prev_lsn;
436
437 out:    if (getmeta)
438                 RELEASE_META(file_dbp, hashp);
439         REC_CLOSE;
440 }
441
442 /*
443  * __ham_newpgno_recover --
444  *      This log message is used when allocating or deleting an overflow
445  *      page.  It takes care of modifying the meta data.
446  *
447  * PUBLIC: int __ham_newpgno_recover
448  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
449  */
450 int
451 __ham_newpgno_recover(logp, dbtp, lsnp, redo, info)
452         DB_LOG *logp;
453         DBT *dbtp;
454         DB_LSN *lsnp;
455         int redo;
456          void *info;
457 {
458         __ham_newpgno_args *argp;
459         DB *mdbp, *file_dbp;
460         DB_MPOOLFILE *mpf;
461         HTAB *hashp;
462         PAGE *pagep;
463         int change, cmp_n, cmp_p, getmeta, ret;
464
465         getmeta = 0;
466         hashp = NULL;                           /* XXX: shut the compiler up. */
467         REC_PRINT(__ham_newpgno_print);
468         REC_INTRO(__ham_newpgno_read);
469
470         hashp = (HTAB *)file_dbp->internal;
471         GET_META(file_dbp, hashp);
472         getmeta = 1;
473
474         /*
475          * There are two phases to the recovery here.  First we need
476          * to update the meta data; then we need to update the page.
477          * We'll do the meta-data first.
478          */
479         cmp_n = log_compare(lsnp, &hashp->hdr->lsn);
480         cmp_p = log_compare(&hashp->hdr->lsn, &argp->metalsn);
481
482         change = 0;
483         if ((cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) ||
484             (cmp_n == 0 && !redo && argp->opcode == DELPGNO)) {
485                 /* Need to redo an allocation or undo a deletion. */
486                 hashp->hdr->last_freed = argp->free_pgno;
487                 if (redo && argp->old_pgno != 0) /* Must be ALLOCPGNO */
488                         hashp->hdr->spares[hashp->hdr->ovfl_point]++;
489                 change = 1;
490         } else if (cmp_p == 0 && redo && argp->opcode == DELPGNO) {
491                 /* Need to redo a deletion */
492                 hashp->hdr->last_freed = argp->pgno;
493                 change = 1;
494         } else if (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO) {
495                 /* undo an allocation. */
496                 if (argp->old_pgno == 0)
497                         hashp->hdr->last_freed = argp->pgno;
498                 else {
499                         hashp->hdr->spares[hashp->hdr->ovfl_point]--;
500                         hashp->hdr->last_freed = 0;
501                 }
502                 change = 1;
503         }
504         if (change) {
505                 hashp->hdr->lsn = redo ? *lsnp : argp->metalsn;
506                 F_SET(file_dbp, DB_HS_DIRTYMETA);
507         }
508
509
510         /* Now check the newly allocated/freed page. */
511         ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
512
513         if (ret != 0)
514                 if (!redo) {
515                         /*
516                          * We are undoing and the page doesn't exist.  That
517                          * is equivalent to having a pagelsn of 0, so we
518                          * would not have to undo anything.  In this case,
519                          * don't bother creating a page.
520                          */
521                         *lsnp = argp->prev_lsn;
522                         ret = 0;
523                         goto out;
524                 } else if ((ret = memp_fget(mpf, &argp->pgno,
525                     DB_MPOOL_CREATE, &pagep)) != 0)
526                         goto out;
527
528         cmp_n = log_compare(lsnp, &LSN(pagep));
529         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
530
531         change = 0;
532         if (cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) {
533                 /* Need to redo an allocation. */
534                 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
535                     PGNO_INVALID, 0, argp->new_type);
536                 change = 1;
537         } else if (cmp_n == 0 && !redo && argp->opcode == DELPGNO) {
538                 /* Undoing a delete. */
539                 P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
540                     argp->old_pgno, 0, argp->old_type);
541                 change = 1;
542         } else if ((cmp_p == 0 && redo && argp->opcode == DELPGNO) ||
543             (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO)) {
544                 /* Need to redo a deletion or undo an allocation. */
545                 NEXT_PGNO(pagep) = argp->free_pgno;
546                 TYPE(pagep) = P_INVALID;
547                 change = 1;
548         }
549         if (change)
550                 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
551
552         if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
553                 goto out;
554
555         *lsnp = argp->prev_lsn;
556
557 out:    if (getmeta)
558                 RELEASE_META(file_dbp, hashp);
559         REC_CLOSE;
560
561 }
562
563 /*
564  * __ham_splitmeta_recover --
565  *      This is the meta-data part of the split.  Records the new and old
566  *      bucket numbers and the new/old mask information.
567  *
568  * PUBLIC: int __ham_splitmeta_recover
569  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
570  */
571 int
572 __ham_splitmeta_recover(logp, dbtp, lsnp, redo, info)
573         DB_LOG *logp;
574         DBT *dbtp;
575         DB_LSN *lsnp;
576         int redo;
577          void *info;
578 {
579         __ham_splitmeta_args *argp;
580         DB *mdbp, *file_dbp;
581         DB_MPOOLFILE *mpf;
582         HTAB *hashp;
583         int change, cmp_n, cmp_p, getmeta, ret;
584         u_int32_t pow;
585
586         getmeta = 0;
587         hashp = NULL;                           /* XXX: shut the compiler up. */
588         REC_PRINT(__ham_splitmeta_print);
589         REC_INTRO(__ham_splitmeta_read);
590
591         hashp = (HTAB *)file_dbp->internal;
592         GET_META(file_dbp, hashp);
593         getmeta = 1;
594
595         /*
596          * There are two phases to the recovery here.  First we need
597          * to update the meta data; then we need to update the page.
598          * We'll do the meta-data first.
599          */
600         cmp_n = log_compare(lsnp, &hashp->hdr->lsn);
601         cmp_p = log_compare(&hashp->hdr->lsn, &argp->metalsn);
602
603         change = 0;
604         if (cmp_p == 0 && redo) {
605                 /* Need to redo the split information. */
606                 hashp->hdr->max_bucket = argp->bucket + 1;
607                 pow = __db_log2(hashp->hdr->max_bucket + 1);
608                 if (pow > hashp->hdr->ovfl_point) {
609                         hashp->hdr->spares[pow] =
610                                 hashp->hdr->spares[hashp->hdr->ovfl_point];
611                         hashp->hdr->ovfl_point = pow;
612                 }
613                 if (hashp->hdr->max_bucket > hashp->hdr->high_mask) {
614                         hashp->hdr->low_mask = hashp->hdr->high_mask;
615                         hashp->hdr->high_mask =
616                             hashp->hdr->max_bucket | hashp->hdr->low_mask;
617                 }
618                 change = 1;
619         } else if (cmp_n == 0 && !redo) {
620                 /* Need to undo the split information. */
621                 hashp->hdr->max_bucket = argp->bucket;
622                 hashp->hdr->ovfl_point = argp->ovflpoint;
623                 hashp->hdr->spares[hashp->hdr->ovfl_point] = argp->spares;
624                 pow = 1 << __db_log2(hashp->hdr->max_bucket + 1);
625                 hashp->hdr->high_mask = pow - 1;
626                 hashp->hdr->low_mask = (pow >> 1) - 1;
627                 change = 1;
628         }
629         if (change) {
630                 hashp->hdr->lsn = redo ? *lsnp : argp->metalsn;
631                 F_SET(file_dbp, DB_HS_DIRTYMETA);
632         }
633         *lsnp = argp->prev_lsn;
634
635 out:    if (getmeta)
636                 RELEASE_META(file_dbp, hashp);
637         REC_CLOSE;
638 }
639
640 /*
641  * __ham_splitdata_recover --
642  *
643  * PUBLIC: int __ham_splitdata_recover
644  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
645  */
646 int
647 __ham_splitdata_recover(logp, dbtp, lsnp, redo, info)
648         DB_LOG *logp;
649         DBT *dbtp;
650         DB_LSN *lsnp;
651         int redo;
652          void *info;
653 {
654         __ham_splitdata_args *argp;
655         DB *mdbp, *file_dbp;
656         DB_MPOOLFILE *mpf;
657         HTAB *hashp;
658         PAGE *pagep;
659         int change, cmp_n, cmp_p, getmeta, ret;
660
661         getmeta = 0;
662         hashp = NULL;                           /* XXX: shut the compiler up. */
663         REC_PRINT(__ham_splitdata_print);
664         REC_INTRO(__ham_splitdata_read);
665
666         ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
667         if (ret != 0)
668                 if (!redo) {
669                         /*
670                          * We are undoing and the page doesn't exist.  That
671                          * is equivalent to having a pagelsn of 0, so we
672                          * would not have to undo anything.  In this case,
673                          * don't bother creating a page.
674                          */
675                         *lsnp = argp->prev_lsn;
676                         ret = 0;
677                         goto out;
678                 } else if ((ret = memp_fget(mpf, &argp->pgno,
679                     DB_MPOOL_CREATE, &pagep)) != 0)
680                         goto out;
681
682         hashp = (HTAB *)file_dbp->internal;
683         GET_META(file_dbp, hashp);
684         getmeta = 1;
685
686         cmp_n = log_compare(lsnp, &LSN(pagep));
687         cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
688
689         /*
690          * There are two types of log messages here, one for the old page
691          * and one for the new pages created.  The original image in the
692          * SPLITOLD record is used for undo.  The image in the SPLITNEW
693          * is used for redo.  We should never have a case where there is
694          * a redo operation and the SPLITOLD record is on disk, but not
695          * the SPLITNEW record.  Therefore, we only have work to do when
696          * redo NEW messages and undo OLD messages, but we have to update
697          * LSNs in both cases.
698          */
699         change = 0;
700         if (cmp_p == 0 && redo) {
701                 if (argp->opcode == SPLITNEW)
702                         /* Need to redo the split described. */
703                         memcpy(pagep, argp->pageimage.data,
704                             argp->pageimage.size);
705                 LSN(pagep) = *lsnp;
706                 change = 1;
707         } else if (cmp_n == 0 && !redo) {
708                 if (argp->opcode == SPLITOLD) {
709                         /* Put back the old image. */
710                         memcpy(pagep, argp->pageimage.data,
711                             argp->pageimage.size);
712                 } else
713                         P_INIT(pagep, file_dbp->pgsize, argp->pgno,
714                             PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
715                 LSN(pagep) = argp->pagelsn;
716                 change = 1;
717         }
718         if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
719                 goto out;
720
721         *lsnp = argp->prev_lsn;
722
723 out:    if (getmeta)
724                 RELEASE_META(file_dbp, hashp);
725         REC_CLOSE;
726 }
727
728 /*
729  * __ham_ovfl_recover --
730  *      This message is generated when we initialize a set of overflow pages.
731  *
732  * PUBLIC: int __ham_ovfl_recover
733  * PUBLIC:     __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
734  */
735 int
736 __ham_ovfl_recover(logp, dbtp, lsnp, redo, info)
737         DB_LOG *logp;
738         DBT *dbtp;
739         DB_LSN *lsnp;
740         int redo;
741         void *info;
742 {
743         __ham_ovfl_args *argp;
744         DB *mdbp, *file_dbp;
745         DB_MPOOLFILE *mpf;
746         HTAB *hashp;
747         PAGE *pagep;
748         db_pgno_t max_pgno, pgno;
749         int cmp_n, cmp_p, getmeta, ret;
750
751         getmeta = 0;
752         hashp = NULL;                           /* XXX: shut the compiler up. */
753         REC_PRINT(__ham_ovfl_print);
754         REC_INTRO(__ham_ovfl_read);
755
756         hashp = (HTAB *)file_dbp->internal;
757         GET_META(file_dbp, hashp);
758         getmeta = 1;
759         file_dbp = NULL;
760
761         cmp_n = log_compare(lsnp, &hashp->hdr->lsn);
762         cmp_p = log_compare(&hashp->hdr->lsn, &argp->metalsn);
763
764         if (cmp_p == 0 && redo) {
765                 /* Redo the allocation. */
766                 hashp->hdr->last_freed = argp->start_pgno;
767                 hashp->hdr->spares[argp->npages  - 1] += argp->npages;
768                 hashp->hdr->lsn = *lsnp;
769                 F_SET(file_dbp, DB_HS_DIRTYMETA);
770         } else if (cmp_n == 0 && !redo) {
771                 hashp->hdr->last_freed = argp->free_pgno;
772                 hashp->hdr->spares[argp->npages  - 1] -= argp->npages;
773                 hashp->hdr->lsn = argp->metalsn;
774                 F_SET(file_dbp, DB_HS_DIRTYMETA);
775         }
776
777         max_pgno = argp->start_pgno + argp->npages - 1;
778         ret = 0;
779         for (pgno = argp->start_pgno; pgno <= max_pgno; pgno++) {
780                 ret = memp_fget(mpf, &pgno, 0, &pagep);
781                 if (ret != 0) {
782                         if (redo && (ret = memp_fget(mpf, &pgno,
783                             DB_MPOOL_CREATE, &pagep)) != 0)
784                                 goto out;
785                         else if (!redo) {
786                                 (void)__ham_put_page(file_dbp, pagep, 0);
787                                 continue;
788                         }
789                 }
790                 if (redo && log_compare((const DB_LSN *)lsnp,
791                     (const DB_LSN *)&LSN(pagep)) > 0) {
792                         P_INIT(pagep, file_dbp->pgsize, pgno, PGNO_INVALID,
793                             pgno == max_pgno ? argp->free_pgno : pgno + 1,
794                             0, P_HASH);
795                         LSN(pagep) = *lsnp;
796                         ret = __ham_put_page(file_dbp, pagep, 1);
797                 } else if (!redo) {
798                         ZERO_LSN(pagep->lsn);
799                         ret = __ham_put_page(file_dbp, pagep, 1);
800                 } else
801                         ret = __ham_put_page(file_dbp, pagep, 0);
802                 if (ret)
803                         goto out;
804         }
805
806         *lsnp = argp->prev_lsn;
807 out:    if (getmeta)
808                 RELEASE_META(file_dbp, hashp);
809         REC_CLOSE;
810 }