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