Update.
[glibc.git] / db2 / db / db_rec.c
blob48e09e6f232d73c07e87b88cd0b650e6b4bbb332
1 /*-
2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997
5 * Sleepycat Software. All rights reserved.
6 */
8 #include "config.h"
10 #ifndef lint
11 static const char sccsid[] = "@(#)db_rec.c 10.12 (Sleepycat) 1/8/98";
12 #endif /* not lint */
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
17 #endif
18 #include <ctype.h>
19 #include <errno.h>
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "db_int.h"
25 #include "shqueue.h"
26 #include "db_page.h"
27 #include "db_dispatch.h"
28 #include "log.h"
29 #include "hash.h"
30 #include "btree.h"
33 * PUBLIC: int __db_addrem_recover
34 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
36 * This log message is generated whenever we add or remove a duplicate
37 * to/from a duplicate page. On recover, we just do the opposite.
39 int
40 __db_addrem_recover(logp, dbtp, lsnp, redo, info)
41 DB_LOG *logp;
42 DBT *dbtp;
43 DB_LSN *lsnp;
44 int redo;
45 void *info;
47 __db_addrem_args *argp;
48 DB *file_dbp, *mdbp;
49 DB_MPOOLFILE *mpf;
50 PAGE *pagep;
51 int change, cmp_n, cmp_p, ret;
53 REC_PRINT(__db_addrem_print);
54 REC_INTRO(__db_addrem_read);
56 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
57 if (!redo) {
59 * We are undoing and the page doesn't exist. That
60 * is equivalent to having a pagelsn of 0, so we
61 * would not have to undo anything. In this case,
62 * don't bother creating a page.
64 *lsnp = argp->prev_lsn;
65 ret = 0;
66 goto out;
67 } else
68 if ((ret = memp_fget(mpf,
69 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
70 goto out;
73 cmp_n = log_compare(lsnp, &LSN(pagep));
74 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
75 change = 0;
76 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_DUP) ||
77 (cmp_n == 0 && !redo && argp->opcode == DB_REM_DUP)) {
79 /* Need to redo an add, or undo a delete. */
80 if ((ret = __db_pitem(file_dbp, pagep, argp->indx, argp->nbytes,
81 argp->hdr.size == 0 ? NULL : &argp->hdr,
82 argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
83 goto out;
85 change = DB_MPOOL_DIRTY;
87 } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_DUP) ||
88 (cmp_p == 0 && redo && argp->opcode == DB_REM_DUP)) {
89 /* Need to undo an add, or redo a delete. */
90 if ((ret = __db_ditem(file_dbp,
91 pagep, argp->indx, argp->nbytes)) != 0)
92 goto out;
93 change = DB_MPOOL_DIRTY;
96 if (change)
97 if (redo)
98 LSN(pagep) = *lsnp;
99 else
100 LSN(pagep) = argp->pagelsn;
102 if ((ret = memp_fput(mpf, pagep, change)) == 0)
103 *lsnp = argp->prev_lsn;
105 out: REC_CLOSE;
109 * PUBLIC: int __db_split_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
112 __db_split_recover(logp, dbtp, lsnp, redo, info)
113 DB_LOG *logp;
114 DBT *dbtp;
115 DB_LSN *lsnp;
116 int redo;
117 void *info;
119 __db_split_args *argp;
120 DB *file_dbp, *mdbp;
121 DB_MPOOLFILE *mpf;
122 PAGE *pagep;
123 int change, cmp_n, cmp_p, ret;
125 REC_PRINT(__db_split_print);
126 REC_INTRO(__db_split_read);
128 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
129 if (!redo) {
131 * We are undoing and the page doesn't exist. That
132 * is equivalent to having a pagelsn of 0, so we
133 * would not have to undo anything. In this case,
134 * don't bother creating a page.
136 *lsnp = argp->prev_lsn;
137 ret = 0;
138 goto out;
139 } else
140 if ((ret = memp_fget(mpf,
141 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
142 goto out;
146 * There are two types of log messages here, one for the old page
147 * and one for the new pages created. The original image in the
148 * SPLITOLD record is used for undo. The image in the SPLITNEW
149 * is used for redo. We should never have a case where there is
150 * a redo operation and the SPLITOLD record is on disk, but not
151 * the SPLITNEW record. Therefore, we only redo NEW messages
152 * and only undo OLD messages.
155 change = 0;
156 cmp_n = log_compare(lsnp, &LSN(pagep));
157 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
158 if (cmp_p == 0 && redo) {
159 if (argp->opcode == DB_SPLITNEW) {
160 /* Need to redo the split described. */
161 memcpy(pagep,
162 argp->pageimage.data, argp->pageimage.size);
164 LSN(pagep) = *lsnp;
165 change = DB_MPOOL_DIRTY;
166 } else if (cmp_n == 0 && !redo) {
167 if (argp->opcode == DB_SPLITOLD) {
168 /* Put back the old image. */
169 memcpy(pagep,
170 argp->pageimage.data, argp->pageimage.size);
172 LSN(pagep) = argp->pagelsn;
173 change = DB_MPOOL_DIRTY;
175 if ((ret = memp_fput(mpf, pagep, change)) == 0)
176 *lsnp = argp->prev_lsn;
178 out: REC_CLOSE;
182 * PUBLIC: int __db_big_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
185 __db_big_recover(logp, dbtp, lsnp, redo, info)
186 DB_LOG *logp;
187 DBT *dbtp;
188 DB_LSN *lsnp;
189 int redo;
190 void *info;
192 __db_big_args *argp;
193 DB *file_dbp, *mdbp;
194 DB_MPOOLFILE *mpf;
195 PAGE *pagep;
196 int change, cmp_n, cmp_p, ret;
198 REC_PRINT(__db_big_print);
199 REC_INTRO(__db_big_read);
201 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
202 if (!redo) {
204 * We are undoing and the page doesn't exist. That
205 * is equivalent to having a pagelsn of 0, so we
206 * would not have to undo anything. In this case,
207 * don't bother creating a page.
209 ret = 0;
210 goto ppage;
211 } else
212 if ((ret = memp_fget(mpf,
213 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
214 goto out;
218 * There are three pages we need to check. The one on which we are
219 * adding data, the previous one whose next_pointer may have
220 * been updated, and the next one whose prev_pointer may have
221 * been updated.
223 cmp_n = log_compare(lsnp, &LSN(pagep));
224 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
225 change = 0;
226 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
227 (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
228 /* We are either redo-ing an add, or undoing a delete. */
229 P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
230 argp->next_pgno, 0, P_OVERFLOW);
231 OV_LEN(pagep) = argp->dbt.size;
232 OV_REF(pagep) = 1;
233 memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data,
234 argp->dbt.size);
235 PREV_PGNO(pagep) = argp->prev_pgno;
236 change = DB_MPOOL_DIRTY;
237 } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_BIG) ||
238 (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
240 * We are either undo-ing an add or redo-ing a delete.
241 * The page is about to be reclaimed in either case, so
242 * there really isn't anything to do here.
244 change = DB_MPOOL_DIRTY;
246 if (change)
247 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
249 if ((ret = memp_fput(mpf, pagep, change)) != 0)
250 goto out;
252 /* Now check the previous page. */
253 ppage: if (argp->prev_pgno != PGNO_INVALID) {
254 change = 0;
255 if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0)
256 if (!redo) {
258 * We are undoing and the page doesn't exist.
259 * That is equivalent to having a pagelsn of 0,
260 * so we would not have to undo anything. In
261 * this case, don't bother creating a page.
263 *lsnp = argp->prev_lsn;
264 ret = 0;
265 goto npage;
266 } else
267 if ((ret = memp_fget(mpf, &argp->prev_pgno,
268 DB_MPOOL_CREATE, &pagep)) != 0)
269 goto out;
271 cmp_n = log_compare(lsnp, &LSN(pagep));
272 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
274 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
275 (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
276 /* Redo add, undo delete. */
277 NEXT_PGNO(pagep) = argp->pgno;
278 change = DB_MPOOL_DIRTY;
279 } else if ((cmp_n == 0 &&
280 !redo && argp->opcode == DB_ADD_BIG) ||
281 (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
282 /* Redo delete, undo add. */
283 NEXT_PGNO(pagep) = argp->next_pgno;
284 change = DB_MPOOL_DIRTY;
286 if (change)
287 LSN(pagep) = redo ? *lsnp : argp->prevlsn;
288 if ((ret = memp_fput(mpf, pagep, change)) != 0)
289 goto out;
292 /* Now check the next page. Can only be set on a delete. */
293 npage: if (argp->next_pgno != PGNO_INVALID) {
294 change = 0;
295 if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0)
296 if (!redo) {
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.
303 *lsnp = argp->prev_lsn;
304 ret = 0;
305 goto out;
306 } else
307 if ((ret = memp_fget(mpf, &argp->next_pgno,
308 DB_MPOOL_CREATE, &pagep)) != 0)
309 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 int change, cmp_n, cmp_p, ret;
508 REC_PRINT(__db_addpage_print);
509 REC_INTRO(__db_addpage_read);
512 * We need to check two pages: the old one and the new one onto
513 * which we're going to add duplicates. Do the old one first.
515 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
516 goto out;
518 change = 0;
519 cmp_n = log_compare(lsnp, &LSN(pagep));
520 cmp_p = log_compare(&LSN(pagep), &argp->lsn);
521 if (cmp_p == 0 && redo) {
522 NEXT_PGNO(pagep) = argp->nextpgno;
524 LSN(pagep) = *lsnp;
525 change = DB_MPOOL_DIRTY;
526 } else if (cmp_n == 0 && !redo) {
527 NEXT_PGNO(pagep) = PGNO_INVALID;
529 LSN(pagep) = argp->lsn;
530 change = DB_MPOOL_DIRTY;
532 if ((ret = memp_fput(mpf, pagep, change)) != 0)
533 goto out;
535 if ((ret = memp_fget(mpf, &argp->nextpgno, 0, &pagep)) != 0)
536 if (!redo) {
538 * We are undoing and the page doesn't exist. That
539 * is equivalent to having a pagelsn of 0, so we
540 * would not have to undo anything. In this case,
541 * don't bother creating a page.
543 ret = 0;
544 goto out;
545 } else
546 if ((ret = memp_fget(mpf,
547 &argp->nextpgno, DB_MPOOL_CREATE, &pagep)) != 0)
548 goto out;
550 change = 0;
551 cmp_n = log_compare(lsnp, &LSN(pagep));
552 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
553 if (cmp_p == 0 && redo) {
554 PREV_PGNO(pagep) = argp->pgno;
556 LSN(pagep) = *lsnp;
557 change = DB_MPOOL_DIRTY;
558 } else if (cmp_n == 0 && !redo) {
559 PREV_PGNO(pagep) = PGNO_INVALID;
561 LSN(pagep) = argp->nextlsn;
562 change = DB_MPOOL_DIRTY;
564 ret = memp_fput(mpf, pagep, change);
566 out: if (ret == 0)
567 *lsnp = argp->prev_lsn;
568 REC_CLOSE;
572 * __db_debug_recover --
573 * Recovery function for debug.
575 * PUBLIC: int __db_debug_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
578 __db_debug_recover(logp, dbtp, lsnp, redo, info)
579 DB_LOG *logp;
580 DBT *dbtp;
581 DB_LSN *lsnp;
582 int redo;
583 void *info;
585 __db_debug_args *argp;
586 int ret;
588 COMPQUIET(redo, 0);
589 COMPQUIET(logp, NULL);
591 REC_PRINT(__db_debug_print);
592 REC_NOOP_INTRO(__db_debug_read);
594 *lsnp = argp->prev_lsn;
595 ret = 0;
597 REC_NOOP_CLOSE;
601 * __db_noop_recover --
602 * Recovery function for noop.
604 * PUBLIC: int __db_noop_recover
605 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
608 __db_noop_recover(logp, dbtp, lsnp, redo, info)
609 DB_LOG *logp;
610 DBT *dbtp;
611 DB_LSN *lsnp;
612 int redo;
613 void *info;
615 __db_noop_args *argp;
616 int ret;
618 COMPQUIET(redo, 0);
619 COMPQUIET(logp, NULL);
621 REC_PRINT(__db_noop_print);
622 REC_NOOP_INTRO(__db_noop_read);
624 *lsnp = argp->prev_lsn;
625 ret = 0;
627 REC_NOOP_CLOSE;