Update.
[glibc.git] / db2 / db / db_rec.c
blob1ef6f18e616e74f5b2b7df7df6ee363fbc64b0f4
1 /*-
2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
8 #include "config.h"
10 #ifndef lint
11 static const char sccsid[] = "@(#)db_rec.c 10.16 (Sleepycat) 4/28/98";
12 #endif /* not lint */
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
17 #include <string.h>
18 #endif
20 #include "db_int.h"
21 #include "shqueue.h"
22 #include "db_page.h"
23 #include "log.h"
24 #include "hash.h"
25 #include "btree.h"
28 * PUBLIC: int __db_addrem_recover
29 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
31 * This log message is generated whenever we add or remove a duplicate
32 * to/from a duplicate page. On recover, we just do the opposite.
34 int
35 __db_addrem_recover(logp, dbtp, lsnp, redo, info)
36 DB_LOG *logp;
37 DBT *dbtp;
38 DB_LSN *lsnp;
39 int redo;
40 void *info;
42 __db_addrem_args *argp;
43 DB *file_dbp, *mdbp;
44 DB_MPOOLFILE *mpf;
45 PAGE *pagep;
46 u_int32_t change;
47 int cmp_n, cmp_p, ret;
49 REC_PRINT(__db_addrem_print);
50 REC_INTRO(__db_addrem_read);
52 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
53 if (!redo) {
55 * We are undoing and the page doesn't exist. That
56 * is equivalent to having a pagelsn of 0, so we
57 * would not have to undo anything. In this case,
58 * don't bother creating a page.
60 *lsnp = argp->prev_lsn;
61 ret = 0;
62 goto out;
63 } else
64 if ((ret = memp_fget(mpf,
65 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
66 goto out;
69 cmp_n = log_compare(lsnp, &LSN(pagep));
70 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
71 change = 0;
72 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_DUP) ||
73 (cmp_n == 0 && !redo && argp->opcode == DB_REM_DUP)) {
75 /* Need to redo an add, or undo a delete. */
76 if ((ret = __db_pitem(file_dbp, pagep, argp->indx, argp->nbytes,
77 argp->hdr.size == 0 ? NULL : &argp->hdr,
78 argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
79 goto out;
81 change = DB_MPOOL_DIRTY;
83 } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_DUP) ||
84 (cmp_p == 0 && redo && argp->opcode == DB_REM_DUP)) {
85 /* Need to undo an add, or redo a delete. */
86 if ((ret = __db_ditem(file_dbp,
87 pagep, argp->indx, argp->nbytes)) != 0)
88 goto out;
89 change = DB_MPOOL_DIRTY;
92 if (change) {
93 if (redo)
94 LSN(pagep) = *lsnp;
95 else
96 LSN(pagep) = argp->pagelsn;
99 if ((ret = memp_fput(mpf, pagep, change)) == 0)
100 *lsnp = argp->prev_lsn;
102 out: REC_CLOSE;
106 * PUBLIC: int __db_split_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
109 __db_split_recover(logp, dbtp, lsnp, redo, info)
110 DB_LOG *logp;
111 DBT *dbtp;
112 DB_LSN *lsnp;
113 int redo;
114 void *info;
116 __db_split_args *argp;
117 DB *file_dbp, *mdbp;
118 DB_MPOOLFILE *mpf;
119 PAGE *pagep;
120 int change, cmp_n, cmp_p, ret;
122 REC_PRINT(__db_split_print);
123 REC_INTRO(__db_split_read);
125 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
126 if (!redo) {
128 * We are undoing and the page doesn't exist. That
129 * is equivalent to having a pagelsn of 0, so we
130 * would not have to undo anything. In this case,
131 * don't bother creating a page.
133 *lsnp = argp->prev_lsn;
134 ret = 0;
135 goto out;
136 } else
137 if ((ret = memp_fget(mpf,
138 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
139 goto out;
143 * There are two types of log messages here, one for the old page
144 * and one for the new pages created. The original image in the
145 * SPLITOLD record is used for undo. The image in the SPLITNEW
146 * is used for redo. We should never have a case where there is
147 * a redo operation and the SPLITOLD record is on disk, but not
148 * the SPLITNEW record. Therefore, we only redo NEW messages
149 * and only undo OLD messages.
152 change = 0;
153 cmp_n = log_compare(lsnp, &LSN(pagep));
154 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
155 if (cmp_p == 0 && redo) {
156 if (argp->opcode == DB_SPLITNEW) {
157 /* Need to redo the split described. */
158 memcpy(pagep,
159 argp->pageimage.data, argp->pageimage.size);
161 LSN(pagep) = *lsnp;
162 change = DB_MPOOL_DIRTY;
163 } else if (cmp_n == 0 && !redo) {
164 if (argp->opcode == DB_SPLITOLD) {
165 /* Put back the old image. */
166 memcpy(pagep,
167 argp->pageimage.data, argp->pageimage.size);
169 LSN(pagep) = argp->pagelsn;
170 change = DB_MPOOL_DIRTY;
172 if ((ret = memp_fput(mpf, pagep, change)) == 0)
173 *lsnp = argp->prev_lsn;
175 out: REC_CLOSE;
179 * PUBLIC: int __db_big_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
182 __db_big_recover(logp, dbtp, lsnp, redo, info)
183 DB_LOG *logp;
184 DBT *dbtp;
185 DB_LSN *lsnp;
186 int redo;
187 void *info;
189 __db_big_args *argp;
190 DB *file_dbp, *mdbp;
191 DB_MPOOLFILE *mpf;
192 PAGE *pagep;
193 u_int32_t change;
194 int cmp_n, cmp_p, ret;
196 REC_PRINT(__db_big_print);
197 REC_INTRO(__db_big_read);
199 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
200 if (!redo) {
202 * We are undoing and the page doesn't exist. That
203 * is equivalent to having a pagelsn of 0, so we
204 * would not have to undo anything. In this case,
205 * don't bother creating a page.
207 ret = 0;
208 goto ppage;
209 } else
210 if ((ret = memp_fget(mpf,
211 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
212 goto out;
216 * There are three pages we need to check. The one on which we are
217 * adding data, the previous one whose next_pointer may have
218 * been updated, and the next one whose prev_pointer may have
219 * been updated.
221 cmp_n = log_compare(lsnp, &LSN(pagep));
222 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
223 change = 0;
224 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
225 (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
226 /* We are either redo-ing an add, or undoing a delete. */
227 P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
228 argp->next_pgno, 0, P_OVERFLOW);
229 OV_LEN(pagep) = argp->dbt.size;
230 OV_REF(pagep) = 1;
231 memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data,
232 argp->dbt.size);
233 PREV_PGNO(pagep) = argp->prev_pgno;
234 change = DB_MPOOL_DIRTY;
235 } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_BIG) ||
236 (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
238 * We are either undo-ing an add or redo-ing a delete.
239 * The page is about to be reclaimed in either case, so
240 * there really isn't anything to do here.
242 change = DB_MPOOL_DIRTY;
244 if (change)
245 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
247 if ((ret = memp_fput(mpf, pagep, change)) != 0)
248 goto out;
250 /* Now check the previous page. */
251 ppage: if (argp->prev_pgno != PGNO_INVALID) {
252 change = 0;
253 if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0) {
254 if (!redo) {
256 * We are undoing and the page doesn't exist.
257 * That is equivalent to having a pagelsn of 0,
258 * so we would not have to undo anything. In
259 * this case, don't bother creating a page.
261 *lsnp = argp->prev_lsn;
262 ret = 0;
263 goto npage;
264 } else
265 if ((ret = memp_fget(mpf, &argp->prev_pgno,
266 DB_MPOOL_CREATE, &pagep)) != 0)
267 goto out;
270 cmp_n = log_compare(lsnp, &LSN(pagep));
271 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
273 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
274 (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
275 /* Redo add, undo delete. */
276 NEXT_PGNO(pagep) = argp->pgno;
277 change = DB_MPOOL_DIRTY;
278 } else if ((cmp_n == 0 &&
279 !redo && argp->opcode == DB_ADD_BIG) ||
280 (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
281 /* Redo delete, undo add. */
282 NEXT_PGNO(pagep) = argp->next_pgno;
283 change = DB_MPOOL_DIRTY;
285 if (change)
286 LSN(pagep) = redo ? *lsnp : argp->prevlsn;
287 if ((ret = memp_fput(mpf, pagep, change)) != 0)
288 goto out;
291 /* Now check the next page. Can only be set on a delete. */
292 npage: if (argp->next_pgno != PGNO_INVALID) {
293 change = 0;
294 if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
295 if (!redo) {
297 * We are undoing and the page doesn't exist.
298 * That is equivalent to having a pagelsn of 0,
299 * so we would not have to undo anything. In
300 * this case, don't bother creating a page.
302 *lsnp = argp->prev_lsn;
303 ret = 0;
304 goto out;
305 } else
306 if ((ret = memp_fget(mpf, &argp->next_pgno,
307 DB_MPOOL_CREATE, &pagep)) != 0)
308 goto out;
311 cmp_n = log_compare(lsnp, &LSN(pagep));
312 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
313 if (cmp_p == 0 && redo) {
314 PREV_PGNO(pagep) = PGNO_INVALID;
315 change = DB_MPOOL_DIRTY;
316 } else if (cmp_n == 0 && !redo) {
317 PREV_PGNO(pagep) = argp->pgno;
318 change = DB_MPOOL_DIRTY;
320 if (change)
321 LSN(pagep) = redo ? *lsnp : argp->nextlsn;
322 if ((ret = memp_fput(mpf, pagep, change)) != 0)
323 goto out;
326 *lsnp = argp->prev_lsn;
328 out: REC_CLOSE;
332 * __db_ovref_recover --
333 * Recovery function for __db_ovref().
335 * PUBLIC: int __db_ovref_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
338 __db_ovref_recover(logp, dbtp, lsnp, redo, info)
339 DB_LOG *logp;
340 DBT *dbtp;
341 DB_LSN *lsnp;
342 int redo;
343 void *info;
345 __db_ovref_args *argp;
346 DB *file_dbp, *mdbp;
347 DB_MPOOLFILE *mpf;
348 PAGE *pagep;
349 int modified, ret;
351 REC_PRINT(__db_ovref_print);
352 REC_INTRO(__db_ovref_read);
354 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
355 (void)__db_pgerr(file_dbp, argp->pgno);
356 goto out;
359 modified = 0;
360 if (log_compare(&LSN(pagep), &argp->lsn) == 0 && redo) {
361 /* Need to redo update described. */
362 OV_REF(pagep) += argp->adjust;
364 pagep->lsn = *lsnp;
365 modified = 1;
366 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
367 /* Need to undo update described. */
368 OV_REF(pagep) -= argp->adjust;
370 pagep->lsn = argp->lsn;
371 modified = 1;
373 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) == 0)
374 *lsnp = argp->prev_lsn;
376 out: REC_CLOSE;
380 * __db_relink_recover --
381 * Recovery function for relink.
383 * PUBLIC: int __db_relink_recover
384 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
387 __db_relink_recover(logp, dbtp, lsnp, redo, info)
388 DB_LOG *logp;
389 DBT *dbtp;
390 DB_LSN *lsnp;
391 int redo;
392 void *info;
394 __db_relink_args *argp;
395 DB *file_dbp, *mdbp;
396 DB_MPOOLFILE *mpf;
397 PAGE *pagep;
398 int modified, ret;
400 REC_PRINT(__db_relink_print);
401 REC_INTRO(__db_relink_read);
404 * There are three pages we need to check -- the page, and the
405 * previous and next pages, if they existed.
407 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
408 if (redo) {
409 (void)__db_pgerr(file_dbp, argp->pgno);
410 goto out;
412 goto next;
414 modified = 0;
415 if (log_compare(&LSN(pagep), &argp->lsn) == 0 && redo) {
416 /* Redo the relink. */
417 pagep->lsn = *lsnp;
418 modified = 1;
419 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
420 /* Undo the relink. */
421 pagep->next_pgno = argp->next;
422 pagep->prev_pgno = argp->prev;
424 pagep->lsn = argp->lsn;
425 modified = 1;
427 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
428 (void)__db_panic(file_dbp);
429 goto out;
432 next: if ((ret = memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
433 if (redo) {
434 (void)__db_pgerr(file_dbp, argp->next);
435 goto out;
437 goto prev;
439 modified = 0;
440 if (log_compare(&LSN(pagep), &argp->lsn_next) == 0 && redo) {
441 /* Redo the relink. */
442 pagep->prev_pgno = argp->prev;
444 pagep->lsn = *lsnp;
445 modified = 1;
446 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
447 /* Undo the relink. */
448 pagep->prev_pgno = argp->pgno;
450 pagep->lsn = argp->lsn_next;
451 modified = 1;
453 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
454 (void)__db_panic(file_dbp);
455 goto out;
458 prev: if ((ret = memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
459 if (redo) {
460 (void)__db_pgerr(file_dbp, argp->prev);
461 goto out;
463 goto done;
465 modified = 0;
466 if (log_compare(&LSN(pagep), &argp->lsn_prev) == 0 && redo) {
467 /* Redo the relink. */
468 pagep->next_pgno = argp->next;
470 pagep->lsn = *lsnp;
471 modified = 1;
472 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
473 /* Undo the relink. */
474 pagep->next_pgno = argp->pgno;
476 pagep->lsn = argp->lsn_prev;
477 modified = 1;
479 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
480 (void) __db_panic(file_dbp);
481 goto out;
484 done: *lsnp = argp->prev_lsn;
485 ret = 0;
487 out: REC_CLOSE;
491 * PUBLIC: int __db_addpage_recover
492 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
495 __db_addpage_recover(logp, dbtp, lsnp, redo, info)
496 DB_LOG *logp;
497 DBT *dbtp;
498 DB_LSN *lsnp;
499 int redo;
500 void *info;
502 __db_addpage_args *argp;
503 DB *file_dbp, *mdbp;
504 DB_MPOOLFILE *mpf;
505 PAGE *pagep;
506 u_int32_t change;
507 int cmp_n, cmp_p, ret;
509 REC_PRINT(__db_addpage_print);
510 REC_INTRO(__db_addpage_read);
513 * We need to check two pages: the old one and the new one onto
514 * which we're going to add duplicates. Do the old one first.
516 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
517 goto out;
519 change = 0;
520 cmp_n = log_compare(lsnp, &LSN(pagep));
521 cmp_p = log_compare(&LSN(pagep), &argp->lsn);
522 if (cmp_p == 0 && redo) {
523 NEXT_PGNO(pagep) = argp->nextpgno;
525 LSN(pagep) = *lsnp;
526 change = DB_MPOOL_DIRTY;
527 } else if (cmp_n == 0 && !redo) {
528 NEXT_PGNO(pagep) = PGNO_INVALID;
530 LSN(pagep) = argp->lsn;
531 change = DB_MPOOL_DIRTY;
533 if ((ret = memp_fput(mpf, pagep, change)) != 0)
534 goto out;
536 if ((ret = memp_fget(mpf, &argp->nextpgno, 0, &pagep)) != 0) {
537 if (!redo) {
539 * We are undoing and the page doesn't exist. That
540 * is equivalent to having a pagelsn of 0, so we
541 * would not have to undo anything. In this case,
542 * don't bother creating a page.
544 ret = 0;
545 goto out;
546 } else
547 if ((ret = memp_fget(mpf,
548 &argp->nextpgno, DB_MPOOL_CREATE, &pagep)) != 0)
549 goto out;
552 change = 0;
553 cmp_n = log_compare(lsnp, &LSN(pagep));
554 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
555 if (cmp_p == 0 && redo) {
556 PREV_PGNO(pagep) = argp->pgno;
558 LSN(pagep) = *lsnp;
559 change = DB_MPOOL_DIRTY;
560 } else if (cmp_n == 0 && !redo) {
561 PREV_PGNO(pagep) = PGNO_INVALID;
563 LSN(pagep) = argp->nextlsn;
564 change = DB_MPOOL_DIRTY;
566 ret = memp_fput(mpf, pagep, change);
568 out: if (ret == 0)
569 *lsnp = argp->prev_lsn;
570 REC_CLOSE;
574 * __db_debug_recover --
575 * Recovery function for debug.
577 * PUBLIC: int __db_debug_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
580 __db_debug_recover(logp, dbtp, lsnp, redo, info)
581 DB_LOG *logp;
582 DBT *dbtp;
583 DB_LSN *lsnp;
584 int redo;
585 void *info;
587 __db_debug_args *argp;
588 int ret;
590 COMPQUIET(redo, 0);
591 COMPQUIET(logp, NULL);
593 REC_PRINT(__db_debug_print);
594 REC_NOOP_INTRO(__db_debug_read);
596 *lsnp = argp->prev_lsn;
597 ret = 0;
599 REC_NOOP_CLOSE;
603 * __db_noop_recover --
604 * Recovery function for noop.
606 * PUBLIC: int __db_noop_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
609 __db_noop_recover(logp, dbtp, lsnp, redo, info)
610 DB_LOG *logp;
611 DBT *dbtp;
612 DB_LSN *lsnp;
613 int redo;
614 void *info;
616 __db_noop_args *argp;
617 DB *file_dbp, *mdbp;
618 DB_MPOOLFILE *mpf;
619 PAGE *pagep;
620 u_int32_t change;
621 int cmp_n, cmp_p, ret;
623 REC_PRINT(__db_noop_print);
624 REC_INTRO(__db_noop_read);
626 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
627 goto out;
629 cmp_n = log_compare(lsnp, &LSN(pagep));
630 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
631 change = 0;
632 if (cmp_p == 0 && redo) {
633 LSN(pagep) = *lsnp;
634 change = DB_MPOOL_DIRTY;
635 } else if (cmp_n == 0 && !redo) {
636 LSN(pagep) = argp->prevlsn;
637 change = DB_MPOOL_DIRTY;
639 *lsnp = argp->prev_lsn;
640 ret = memp_fput(mpf, pagep, change);
642 out: REC_CLOSE;