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