log1.c revision 1.4
1/* $NetBSD: log1.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */ 2/*- 3 * Copyright (c) 1992, 1993, 1994 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 1992, 1993, 1994, 1995, 1996 6 * Keith Bostic. All rights reserved. 7 * 8 * See the LICENSE file for redistribution information. 9 */ 10 11#include "config.h" 12 13#include <sys/cdefs.h> 14#if 0 15#ifndef lint 16static const char sccsid[] = "Id: log.c,v 10.26 2002/03/02 23:12:13 skimo Exp (Berkeley) Date: 2002/03/02 23:12:13 "; 17#endif /* not lint */ 18#else 19__RCSID("$NetBSD: log1.c,v 1.4 2014/01/26 21:43:45 christos Exp $"); 20#endif 21 22#include <sys/types.h> 23#include <sys/queue.h> 24#include <sys/stat.h> 25 26#include <bitstring.h> 27#include <errno.h> 28#include <fcntl.h> 29#include <limits.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33 34#include "common.h" 35 36/* 37 * The log consists of records, each containing a type byte and a variable 38 * length byte string, as follows: 39 * 40 * LOG_CURSOR_INIT MARK 41 * LOG_CURSOR_END MARK 42 * LOG_LINE_APPEND_F db_recno_t char * 43 * LOG_LINE_APPEND_B db_recno_t char * 44 * LOG_LINE_DELETE_F db_recno_t char * 45 * LOG_LINE_DELETE_B db_recno_t char * 46 * LOG_LINE_RESET_F db_recno_t char * 47 * LOG_LINE_RESET_B db_recno_t char * 48 * LOG_MARK LMARK 49 * 50 * We do before image physical logging. This means that the editor layer 51 * MAY NOT modify records in place, even if simply deleting or overwriting 52 * characters. Since the smallest unit of logging is a line, we're using 53 * up lots of space. This may eventually have to be reduced, probably by 54 * doing logical logging, which is a much cooler database phrase. 55 * 56 * The implementation of the historic vi 'u' command, using roll-forward and 57 * roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record, 58 * followed by a number of other records, followed by a LOG_CURSOR_END record. 59 * LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B 60 * record, and is the line before the change. The second is LOG_LINE_RESET_F, 61 * and is the line after the change. Roll-back is done by backing up to the 62 * first LOG_CURSOR_INIT record before a change. Roll-forward is done in a 63 * similar fashion. 64 * 65 * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END 66 * record for a line different from the current one. It should be noted that 67 * this means that a subsequent 'u' command will make a change based on the 68 * new position of the log's cursor. This is okay, and, in fact, historic vi 69 * behaved that way. 70 */ 71 72static int log_cursor1 __P((SCR *, int)); 73static void log_err __P((SCR *, const char *, int)); 74#if defined(LOGDEBUG) && defined(TRACE) 75static void log_trace __P((SCR *, const char *, db_recno_t, u_char *)); 76#endif 77 78/* Try and restart the log on failure, i.e. if we run out of memory. */ 79#define LOG_ERR { \ 80 log_err(sp, __FILE__, __LINE__); \ 81 return (1); \ 82} 83 84/* offset of CHAR_T string in log needs to be aligned on some systems 85 * because it is passed to db_set as a string 86 */ 87typedef struct { 88 char data[sizeof(u_char) /* type */ + sizeof(db_recno_t)]; 89 CHAR_T str[1]; 90} log_t; 91#define CHAR_T_OFFSET ((char *)(((log_t*)0)->str) - (char *)0) 92 93/* 94 * log_init -- 95 * Initialize the logging subsystem. 96 * 97 * PUBLIC: int log_init __P((SCR *, EXF *)); 98 */ 99int 100log_init(SCR *sp, EXF *ep) 101{ 102 /* 103 * !!! 104 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. 105 * 106 * Initialize the buffer. The logging subsystem has its own 107 * buffers because the global ones are almost by definition 108 * going to be in use when the log runs. 109 */ 110 sp->wp->l_lp = NULL; 111 sp->wp->l_len = 0; 112 ep->l_cursor.lno = 1; /* XXX Any valid recno. */ 113 ep->l_cursor.cno = 0; 114 ep->l_high = ep->l_cur = 1; 115 116 ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR, 117 S_IRUSR | S_IWUSR, DB_RECNO, NULL); 118 if (ep->log == NULL) { 119 msgq(sp, M_SYSERR, "009|Log file"); 120 F_SET(ep, F_NOLOG); 121 return (1); 122 } 123 124 ep->l_win = NULL; 125 /*LOCK_INIT(sp->wp, ep);*/ 126 127 return (0); 128} 129 130/* 131 * log_end -- 132 * Close the logging subsystem. 133 * 134 * PUBLIC: int log_end __P((SCR *, EXF *)); 135 */ 136int 137log_end(SCR *sp, EXF *ep) 138{ 139 /* 140 * !!! 141 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. 142 */ 143 /*LOCK_END(sp->wp, ep);*/ 144 if (ep->log != NULL) { 145 (void)(ep->log->close)(ep->log); 146 ep->log = NULL; 147 } 148 if (sp->wp->l_lp != NULL) { 149 free(sp->wp->l_lp); 150 sp->wp->l_lp = NULL; 151 } 152 sp->wp->l_len = 0; 153 ep->l_cursor.lno = 1; /* XXX Any valid recno. */ 154 ep->l_cursor.cno = 0; 155 ep->l_high = ep->l_cur = 1; 156 return (0); 157} 158 159/* 160 * log_cursor -- 161 * Log the current cursor position, starting an event. 162 * 163 * PUBLIC: int log_cursor __P((SCR *)); 164 */ 165int 166log_cursor(SCR *sp) 167{ 168 EXF *ep; 169 170 ep = sp->ep; 171 if (F_ISSET(ep, F_NOLOG)) 172 return (0); 173 174 /* 175 * If any changes were made since the last cursor init, 176 * put out the ending cursor record. 177 */ 178 if (ep->l_cursor.lno == OOBLNO) { 179 if (ep->l_win && ep->l_win != sp->wp) 180 return 0; 181 ep->l_cursor.lno = sp->lno; 182 ep->l_cursor.cno = sp->cno; 183 ep->l_win = NULL; 184 return (log_cursor1(sp, LOG_CURSOR_END)); 185 } 186 ep->l_cursor.lno = sp->lno; 187 ep->l_cursor.cno = sp->cno; 188 return (0); 189} 190 191/* 192 * log_cursor1 -- 193 * Actually push a cursor record out. 194 */ 195static int 196log_cursor1(SCR *sp, int type) 197{ 198 DBT data, key; 199 EXF *ep; 200 201 ep = sp->ep; 202 203 /* 204 if (type == LOG_CURSOR_INIT && 205 LOCK_TRY(sp->wp, ep)) 206 return 1; 207 */ 208 209 BINC_RETC(sp, sp->wp->l_lp, sp->wp->l_len, sizeof(u_char) + sizeof(MARK)); 210 sp->wp->l_lp[0] = type; 211 memmove(sp->wp->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK)); 212 213 memset(&key, 0, sizeof(key)); 214 key.data = &ep->l_cur; 215 key.size = sizeof(db_recno_t); 216 memset(&data, 0, sizeof(data)); 217 data.data = sp->wp->l_lp; 218 data.size = sizeof(u_char) + sizeof(MARK); 219 if (ep->log->put(ep->log, &key, &data, 0) == -1) 220 LOG_ERR; 221 222#if defined(LOGDEBUG) && defined(TRACE) 223 vtrace("%lu: %s: %u/%u\n", ep->l_cur, 224 type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end", 225 sp->lno, sp->cno); 226#endif 227 /* Reset high water mark. */ 228 ep->l_high = ++ep->l_cur; 229 230 /* 231 if (type == LOG_CURSOR_END) 232 LOCK_UNLOCK(sp->wp, ep); 233 */ 234 return (0); 235} 236 237/* 238 * log_line -- 239 * Log a line change. 240 * 241 * PUBLIC: int log_line __P((SCR *, db_recno_t, u_int)); 242 */ 243int 244log_line(SCR *sp, db_recno_t lno, u_int action) 245{ 246 DBT data, key; 247 EXF *ep; 248 size_t len; 249 CHAR_T *lp; 250 db_recno_t lcur; 251 252 ep = sp->ep; 253 if (F_ISSET(ep, F_NOLOG)) 254 return (0); 255 256 /* 257 * XXX 258 * 259 * Kluge for vi. Clear the EXF undo flag so that the 260 * next 'u' command does a roll-back, regardless. 261 */ 262 F_CLR(ep, F_UNDO); 263 264 /* Put out one initial cursor record per set of changes. */ 265 if (ep->l_cursor.lno != OOBLNO) { 266 if (log_cursor1(sp, LOG_CURSOR_INIT)) 267 return (1); 268 ep->l_cursor.lno = OOBLNO; 269 ep->l_win = sp->wp; 270 } /*else if (ep->l_win != sp->wp) { 271 printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp); 272 return 1; 273 }*/ 274 275 switch (action) { 276 /* newly added for DB4 logging */ 277 case LOG_LINE_APPEND_B: 278 case LOG_LINE_DELETE_F: 279 return 0; 280 } 281 282 /* 283 * Put out the changes. If it's a LOG_LINE_RESET_B call, it's a 284 * special case, avoid the caches. Also, if it fails and it's 285 * line 1, it just means that the user started with an empty file, 286 * so fake an empty length line. 287 */ 288 if (action == LOG_LINE_RESET_B) { 289 if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) { 290 static CHAR_T nul = 0; 291 if (lno != 1) { 292 db_err(sp, lno); 293 return (1); 294 } 295 len = 0; 296 lp = &nul; 297 } 298 } else 299 if (db_get(sp, lno, DBG_FATAL, &lp, &len)) 300 return (1); 301 BINC_RETC(sp, 302 sp->wp->l_lp, sp->wp->l_len, 303 len * sizeof(CHAR_T) + CHAR_T_OFFSET); 304 sp->wp->l_lp[0] = action; 305 memmove(sp->wp->l_lp + sizeof(u_char), &lno, sizeof(db_recno_t)); 306 MEMMOVEW(sp->wp->l_lp + CHAR_T_OFFSET, lp, len); 307 308 lcur = ep->l_cur; 309 memset(&key, 0, sizeof(key)); 310 key.data = &lcur; 311 key.size = sizeof(db_recno_t); 312 memset(&data, 0, sizeof(data)); 313 data.data = sp->wp->l_lp; 314 data.size = len * sizeof(CHAR_T) + CHAR_T_OFFSET; 315 if (ep->log->put(ep->log, &key, &data, 0) == -1) 316 LOG_ERR; 317 318#if defined(LOGDEBUG) && defined(TRACE) 319 switch (action) { 320 case LOG_LINE_APPEND_F: 321 vtrace("%u: log_line: append_f: %lu {%u}\n", 322 ep->l_cur, lno, len); 323 break; 324 case LOG_LINE_APPEND_B: 325 vtrace("%u: log_line: append_b: %lu {%u}\n", 326 ep->l_cur, lno, len); 327 break; 328 case LOG_LINE_DELETE_F: 329 vtrace("%lu: log_line: delete_f: %lu {%u}\n", 330 ep->l_cur, lno, len); 331 break; 332 case LOG_LINE_DELETE_B: 333 vtrace("%lu: log_line: delete_b: %lu {%u}\n", 334 ep->l_cur, lno, len); 335 break; 336 case LOG_LINE_RESET_F: 337 vtrace("%lu: log_line: reset_f: %lu {%u}\n", 338 ep->l_cur, lno, len); 339 break; 340 case LOG_LINE_RESET_B: 341 vtrace("%lu: log_line: reset_b: %lu {%u}\n", 342 ep->l_cur, lno, len); 343 break; 344 } 345#endif 346 /* Reset high water mark. */ 347 ep->l_high = ++ep->l_cur; 348 349 return (0); 350} 351 352/* 353 * log_mark -- 354 * Log a mark position. For the log to work, we assume that there 355 * aren't any operations that just put out a log record -- this 356 * would mean that undo operations would only reset marks, and not 357 * cause any other change. 358 * 359 * PUBLIC: int log_mark __P((SCR *, LMARK *)); 360 */ 361int 362log_mark(SCR *sp, LMARK *lmp) 363{ 364 DBT data, key; 365 EXF *ep; 366 367 ep = sp->ep; 368 if (F_ISSET(ep, F_NOLOG)) 369 return (0); 370 371 /* Put out one initial cursor record per set of changes. */ 372 if (ep->l_cursor.lno != OOBLNO) { 373 if (log_cursor1(sp, LOG_CURSOR_INIT)) 374 return (1); 375 ep->l_cursor.lno = OOBLNO; 376 ep->l_win = sp->wp; 377 } 378 379 BINC_RETC(sp, sp->wp->l_lp, 380 sp->wp->l_len, sizeof(u_char) + sizeof(LMARK)); 381 sp->wp->l_lp[0] = LOG_MARK; 382 memmove(sp->wp->l_lp + sizeof(u_char), lmp, sizeof(LMARK)); 383 384 memset(&key, 0, sizeof(key)); 385 key.data = &ep->l_cur; 386 key.size = sizeof(db_recno_t); 387 memset(&data, 0, sizeof(data)); 388 data.data = sp->wp->l_lp; 389 data.size = sizeof(u_char) + sizeof(LMARK); 390 if (ep->log->put(ep->log, &key, &data, 0) == -1) 391 LOG_ERR; 392 393#if defined(LOGDEBUG) && defined(TRACE) 394 vtrace("%lu: mark %c: %lu/%u\n", 395 ep->l_cur, lmp->name, lmp->lno, lmp->cno); 396#endif 397 /* Reset high water mark. */ 398 ep->l_high = ++ep->l_cur; 399 return (0); 400} 401 402/* 403 * Log_backward -- 404 * Roll the log backward one operation. 405 * 406 * PUBLIC: int log_backward __P((SCR *, MARK *)); 407 */ 408int 409log_backward(SCR *sp, MARK *rp) 410{ 411 DBT key, data; 412 EXF *ep; 413 LMARK lm; 414 MARK m; 415 db_recno_t lno; 416 int didop; 417 u_char *p; 418 419 ep = sp->ep; 420 if (F_ISSET(ep, F_NOLOG)) { 421 msgq(sp, M_ERR, 422 "010|Logging not being performed, undo not possible"); 423 return (1); 424 } 425 426 if (ep->l_cur == 1) { 427 msgq(sp, M_BERR, "011|No changes to undo"); 428 return (1); 429 } 430 431 if (ep->l_win && ep->l_win != sp->wp) { 432 ex_emsg(sp, NULL, EXM_LOCKED); 433 return 1; 434 } 435 ep->l_win = sp->wp; 436 437 438 F_SET(ep, F_NOLOG); /* Turn off logging. */ 439 440 key.data = &ep->l_cur; /* Initialize db request. */ 441 key.size = sizeof(recno_t); 442 for (didop = 0;;) { 443 --ep->l_cur; 444 if (ep->log->get(ep->log, &key, &data, 0)) 445 LOG_ERR; 446#if defined(LOGDEBUG) && defined(TRACE) 447 log_trace(sp, "log_backward", ep->l_cur, data.data); 448#endif 449 switch (*(p = (u_char *)data.data)) { 450 case LOG_CURSOR_INIT: 451 if (didop) { 452 memmove(rp, p + sizeof(u_char), sizeof(MARK)); 453 F_CLR(ep, F_NOLOG); 454 ep->l_win = NULL; 455 return (0); 456 } 457 break; 458 case LOG_CURSOR_END: 459 break; 460 case LOG_LINE_APPEND_F: 461 didop = 1; 462 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 463 if (db_delete(sp, lno)) 464 goto err; 465 ++sp->rptlines[L_DELETED]; 466 break; 467 case LOG_LINE_DELETE_B: 468 didop = 1; 469 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 470 if (db_insert(sp, lno, 471 (CHAR_T *)(p + CHAR_T_OFFSET), 472 (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T))) 473 goto err; 474 ++sp->rptlines[L_ADDED]; 475 break; 476 case LOG_LINE_RESET_F: 477 break; 478 case LOG_LINE_RESET_B: 479 didop = 1; 480 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 481 if (db_set(sp, lno, 482 (CHAR_T *)(p + CHAR_T_OFFSET), 483 (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T))) 484 goto err; 485 if (sp->rptlchange != lno) { 486 sp->rptlchange = lno; 487 ++sp->rptlines[L_CHANGED]; 488 } 489 break; 490 case LOG_MARK: 491 didop = 1; 492 memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); 493 m.lno = lm.lno; 494 m.cno = lm.cno; 495 if (mark_set(sp, lm.name, &m, 0)) 496 goto err; 497 break; 498 default: 499 abort(); 500 } 501 } 502 503err: F_CLR(ep, F_NOLOG); 504 ep->l_win = NULL; 505 return (1); 506} 507 508/* 509 * Log_setline -- 510 * Reset the line to its original appearance. 511 * 512 * XXX 513 * There's a bug in this code due to our not logging cursor movements 514 * unless a change was made. If you do a change, move off the line, 515 * then move back on and do a 'U', the line will be restored to the way 516 * it was before the original change. 517 * 518 * PUBLIC: int log_setline __P((SCR *)); 519 */ 520int 521log_setline(SCR *sp) 522{ 523 DBT key, data; 524 EXF *ep; 525 LMARK lm; 526 MARK m; 527 db_recno_t lno; 528 u_char *p; 529 530 ep = sp->ep; 531 if (F_ISSET(ep, F_NOLOG)) { 532 msgq(sp, M_ERR, 533 "012|Logging not being performed, undo not possible"); 534 return (1); 535 } 536 537 if (ep->l_cur == 1) 538 return (1); 539 540 if (ep->l_win && ep->l_win != sp->wp) { 541 ex_emsg(sp, NULL, EXM_LOCKED); 542 return 1; 543 } 544 ep->l_win = sp->wp; 545 546 F_SET(ep, F_NOLOG); /* Turn off logging. */ 547 548 key.data = &ep->l_cur; /* Initialize db request. */ 549 key.size = sizeof(recno_t); 550 551 for (;;) { 552 --ep->l_cur; 553 if (ep->log->get(ep->log, &key, &data, 0)) 554 LOG_ERR; 555#if defined(LOGDEBUG) && defined(TRACE) 556 log_trace(sp, "log_setline", ep->l_cur, data.data); 557#endif 558 switch (*(p = (u_char *)data.data)) { 559 case LOG_CURSOR_INIT: 560 memmove(&m, p + sizeof(u_char), sizeof(MARK)); 561 if (m.lno != sp->lno || ep->l_cur == 1) { 562 F_CLR(ep, F_NOLOG); 563 ep->l_win = NULL; 564 return (0); 565 } 566 break; 567 case LOG_CURSOR_END: 568 memmove(&m, p + sizeof(u_char), sizeof(MARK)); 569 if (m.lno != sp->lno) { 570 ++ep->l_cur; 571 F_CLR(ep, F_NOLOG); 572 ep->l_win = NULL; 573 return (0); 574 } 575 break; 576 case LOG_LINE_APPEND_F: 577 case LOG_LINE_DELETE_B: 578 case LOG_LINE_RESET_F: 579 break; 580 case LOG_LINE_RESET_B: 581 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 582 if (lno == sp->lno && 583 db_set(sp, lno, (CHAR_T *)(p + CHAR_T_OFFSET), 584 (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T))) 585 goto err; 586 if (sp->rptlchange != lno) { 587 sp->rptlchange = lno; 588 ++sp->rptlines[L_CHANGED]; 589 } 590 case LOG_MARK: 591 memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); 592 m.lno = lm.lno; 593 m.cno = lm.cno; 594 if (mark_set(sp, lm.name, &m, 0)) 595 goto err; 596 break; 597 default: 598 abort(); 599 } 600 } 601 602err: F_CLR(ep, F_NOLOG); 603 ep->l_win = NULL; 604 return (1); 605} 606 607/* 608 * Log_forward -- 609 * Roll the log forward one operation. 610 * 611 * PUBLIC: int log_forward __P((SCR *, MARK *)); 612 */ 613int 614log_forward(SCR *sp, MARK *rp) 615{ 616 DBT key, data; 617 EXF *ep; 618 LMARK lm; 619 MARK m; 620 db_recno_t lno; 621 int didop; 622 u_char *p; 623 624 ep = sp->ep; 625 if (F_ISSET(ep, F_NOLOG)) { 626 msgq(sp, M_ERR, 627 "013|Logging not being performed, roll-forward not possible"); 628 return (1); 629 } 630 631 if (ep->l_cur == ep->l_high) { 632 msgq(sp, M_BERR, "014|No changes to re-do"); 633 return (1); 634 } 635 636 if (ep->l_win && ep->l_win != sp->wp) { 637 ex_emsg(sp, NULL, EXM_LOCKED); 638 return 1; 639 } 640 ep->l_win = sp->wp; 641 642 F_SET(ep, F_NOLOG); /* Turn off logging. */ 643 644 key.data = &ep->l_cur; /* Initialize db request. */ 645 key.size = sizeof(recno_t); 646 for (didop = 0;;) { 647 ++ep->l_cur; 648 if (ep->log->get(ep->log, &key, &data, 0)) 649 LOG_ERR; 650#if defined(LOGDEBUG) && defined(TRACE) 651 log_trace(sp, "log_forward", ep->l_cur, data.data); 652#endif 653 switch (*(p = (u_char *)data.data)) { 654 case LOG_CURSOR_END: 655 if (didop) { 656 ++ep->l_cur; 657 memmove(rp, p + sizeof(u_char), sizeof(MARK)); 658 F_CLR(ep, F_NOLOG); 659 ep->l_win = NULL; 660 return (0); 661 } 662 break; 663 case LOG_CURSOR_INIT: 664 break; 665 case LOG_LINE_APPEND_F: 666 didop = 1; 667 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 668 if (db_insert(sp, lno, 669 (CHAR_T *)(p + CHAR_T_OFFSET), 670 (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T))) 671 goto err; 672 ++sp->rptlines[L_ADDED]; 673 break; 674 case LOG_LINE_DELETE_B: 675 didop = 1; 676 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 677 if (db_delete(sp, lno)) 678 goto err; 679 ++sp->rptlines[L_DELETED]; 680 break; 681 case LOG_LINE_RESET_B: 682 break; 683 case LOG_LINE_RESET_F: 684 didop = 1; 685 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 686 if (db_set(sp, lno, 687 (CHAR_T *)(p + CHAR_T_OFFSET), 688 (data.size - CHAR_T_OFFSET) / sizeof(CHAR_T))) 689 goto err; 690 if (sp->rptlchange != lno) { 691 sp->rptlchange = lno; 692 ++sp->rptlines[L_CHANGED]; 693 } 694 break; 695 case LOG_MARK: 696 didop = 1; 697 memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); 698 m.lno = lm.lno; 699 m.cno = lm.cno; 700 if (mark_set(sp, lm.name, &m, 0)) 701 goto err; 702 break; 703 default: 704 abort(); 705 } 706 } 707 708err: F_CLR(ep, F_NOLOG); 709 ep->l_win = NULL; 710 return (1); 711} 712 713/* 714 * log_err -- 715 * Try and restart the log on failure, i.e. if we run out of memory. 716 */ 717static void 718log_err(SCR *sp, const char *file, int line) 719{ 720 EXF *ep; 721 722 msgq(sp, M_SYSERR, "015|%s/%d: log put error", tail(file), line); 723 ep = sp->ep; 724 (void)ep->log->close(ep->log); 725 if (!log_init(sp, ep)) 726 msgq(sp, M_ERR, "267|Log restarted"); 727} 728 729#if defined(LOGDEBUG) && defined(TRACE) 730static void 731log_trace(sp, msg, rno, p) 732 SCR *sp; 733 const char *msg; 734 db_recno_t rno; 735 u_char *p; 736{ 737 LMARK lm; 738 MARK m; 739 db_recno_t lno; 740 741 switch (*p) { 742 case LOG_CURSOR_INIT: 743 memmove(&m, p + sizeof(u_char), sizeof(MARK)); 744 vtrace("%lu: %s: C_INIT: %u/%u\n", rno, msg, m.lno, m.cno); 745 break; 746 case LOG_CURSOR_END: 747 memmove(&m, p + sizeof(u_char), sizeof(MARK)); 748 vtrace("%lu: %s: C_END: %u/%u\n", rno, msg, m.lno, m.cno); 749 break; 750 case LOG_LINE_APPEND_F: 751 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 752 vtrace("%lu: %s: APPEND_F: %lu\n", rno, msg, lno); 753 break; 754 case LOG_LINE_APPEND_B: 755 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 756 vtrace("%lu: %s: APPEND_B: %lu\n", rno, msg, lno); 757 break; 758 case LOG_LINE_DELETE_F: 759 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 760 vtrace("%lu: %s: DELETE_F: %lu\n", rno, msg, lno); 761 break; 762 case LOG_LINE_DELETE_B: 763 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 764 vtrace("%lu: %s: DELETE_B: %lu\n", rno, msg, lno); 765 break; 766 case LOG_LINE_RESET_F: 767 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 768 vtrace("%lu: %s: RESET_F: %lu\n", rno, msg, lno); 769 break; 770 case LOG_LINE_RESET_B: 771 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t)); 772 vtrace("%lu: %s: RESET_B: %lu\n", rno, msg, lno); 773 break; 774 case LOG_MARK: 775 memmove(&lm, p + sizeof(u_char), sizeof(LMARK)); 776 vtrace("%lu: %s: MARK: %u/%u\n", rno, msg, lm.lno, lm.cno); 777 break; 778 default: 779 abort(); 780 } 781} 782#endif 783