log.c revision 1.1.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
13 static 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
66 static int vi_log_get __P((SCR *sp, db_recno_t *lnop, size_t *size));
67 static int log_cursor1 __P((SCR *, int));
68 static void log_err __P((SCR *, char *, int));
69 #if defined(DEBUG) && 0
70 static 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 */
82 typedef 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 */
94 int
95 log_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 if (db_create(&ep->log, 0, 0) != 0 ||
112 db_open(ep->log, NULL, DB_RECNO,
113 DB_CREATE | VI_DB_THREAD, S_IRUSR | S_IWUSR) != 0) {
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 */
131 int
132 log_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, DB_NOSYNC);
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 */
160 int
161 log_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 */
190 static int
191 log_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, NULL, &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 */
238 int
239 log_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, NULL, &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 */
356 int
357 log_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, NULL, &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 * vi_log_get --
399 * Get a line from the log in log buffer.
400 */
401 static int
402 vi_log_get(SCR *sp, db_recno_t *lnop, size_t *size)
403 {
404 DBT key, data;
405 size_t nlen;
406 EXF *ep;
407
408 ep = sp->ep;
409
410 nlen = 1024;
411 retry:
412 BINC_RETC(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
413
414 memset(&key, 0, sizeof(key));
415 key.data = lnop; /* Initialize db request. */
416 key.size = sizeof(db_recno_t);
417 memset(&data, 0, sizeof(data));
418 data.data = sp->wp->l_lp;
419 data.ulen = sp->wp->l_len;
420 data.flags = DB_DBT_USERMEM;
421 switch (ep->log->get(ep->log, NULL, &key, &data, 0)) {
422 case ENOMEM:
423 nlen = data.size;
424 goto retry;
425 case 0:
426 *size = data.size;
427 return 0;
428 default:
429 return 1;
430 }
431 }
432
433 /*
434 * Log_backward --
435 * Roll the log backward one operation.
436 *
437 * PUBLIC: int log_backward __P((SCR *, MARK *));
438 */
439 int
440 log_backward(SCR *sp, MARK *rp)
441 {
442 EXF *ep;
443 LMARK lm;
444 MARK m;
445 db_recno_t lno;
446 int didop;
447 u_char *p;
448 size_t size;
449
450 ep = sp->ep;
451 if (F_ISSET(ep, F_NOLOG)) {
452 msgq(sp, M_ERR,
453 "010|Logging not being performed, undo not possible");
454 return (1);
455 }
456
457 if (ep->l_cur == 1) {
458 msgq(sp, M_BERR, "011|No changes to undo");
459 return (1);
460 }
461
462 if (ep->l_win && ep->l_win != sp->wp) {
463 ex_emsg(sp, NULL, EXM_LOCKED);
464 return 1;
465 }
466 ep->l_win = sp->wp;
467
468
469 F_SET(ep, F_NOLOG); /* Turn off logging. */
470
471 for (didop = 0;;) {
472 --ep->l_cur;
473 if (vi_log_get(sp, &ep->l_cur, &size))
474 LOG_ERR;
475 #if defined(DEBUG) && 0
476 log_trace(sp, "log_backward", ep->l_cur, data.data);
477 #endif
478 switch (*(p = (u_char *)sp->wp->l_lp)) {
479 case LOG_CURSOR_INIT:
480 if (didop) {
481 memmove(rp, p + sizeof(u_char), sizeof(MARK));
482 F_CLR(ep, F_NOLOG);
483 ep->l_win = NULL;
484 return (0);
485 }
486 break;
487 case LOG_CURSOR_END:
488 break;
489 case LOG_LINE_APPEND_F:
490 didop = 1;
491 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
492 if (db_delete(sp, lno))
493 goto err;
494 ++sp->rptlines[L_DELETED];
495 break;
496 case LOG_LINE_DELETE_B:
497 didop = 1;
498 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
499 if (db_insert(sp, lno,
500 (CHAR_T *)(p + CHAR_T_OFFSET),
501 (size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
502 goto err;
503 ++sp->rptlines[L_ADDED];
504 break;
505 case LOG_LINE_RESET_F:
506 break;
507 case LOG_LINE_RESET_B:
508 didop = 1;
509 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
510 if (db_set(sp, lno,
511 (CHAR_T *)(p + CHAR_T_OFFSET),
512 (size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
513 goto err;
514 if (sp->rptlchange != lno) {
515 sp->rptlchange = lno;
516 ++sp->rptlines[L_CHANGED];
517 }
518 break;
519 case LOG_MARK:
520 didop = 1;
521 memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
522 m.lno = lm.lno;
523 m.cno = lm.cno;
524 if (mark_set(sp, lm.name, &m, 0))
525 goto err;
526 break;
527 default:
528 abort();
529 }
530 }
531
532 err: F_CLR(ep, F_NOLOG);
533 ep->l_win = NULL;
534 return (1);
535 }
536
537 /*
538 * Log_setline --
539 * Reset the line to its original appearance.
540 *
541 * XXX
542 * There's a bug in this code due to our not logging cursor movements
543 * unless a change was made. If you do a change, move off the line,
544 * then move back on and do a 'U', the line will be restored to the way
545 * it was before the original change.
546 *
547 * PUBLIC: int log_setline __P((SCR *));
548 */
549 int
550 log_setline(SCR *sp)
551 {
552 EXF *ep;
553 LMARK lm;
554 MARK m;
555 db_recno_t lno;
556 u_char *p;
557 size_t size;
558
559 ep = sp->ep;
560 if (F_ISSET(ep, F_NOLOG)) {
561 msgq(sp, M_ERR,
562 "012|Logging not being performed, undo not possible");
563 return (1);
564 }
565
566 if (ep->l_cur == 1)
567 return (1);
568
569 if (ep->l_win && ep->l_win != sp->wp) {
570 ex_emsg(sp, NULL, EXM_LOCKED);
571 return 1;
572 }
573 ep->l_win = sp->wp;
574
575 F_SET(ep, F_NOLOG); /* Turn off logging. */
576
577 for (;;) {
578 --ep->l_cur;
579 if (vi_log_get(sp, &ep->l_cur, &size))
580 LOG_ERR;
581 #if defined(DEBUG) && 0
582 log_trace(sp, "log_setline", ep->l_cur, data.data);
583 #endif
584 switch (*(p = (u_char *)sp->wp->l_lp)) {
585 case LOG_CURSOR_INIT:
586 memmove(&m, p + sizeof(u_char), sizeof(MARK));
587 if (m.lno != sp->lno || ep->l_cur == 1) {
588 F_CLR(ep, F_NOLOG);
589 ep->l_win = NULL;
590 return (0);
591 }
592 break;
593 case LOG_CURSOR_END:
594 memmove(&m, p + sizeof(u_char), sizeof(MARK));
595 if (m.lno != sp->lno) {
596 ++ep->l_cur;
597 F_CLR(ep, F_NOLOG);
598 ep->l_win = NULL;
599 return (0);
600 }
601 break;
602 case LOG_LINE_APPEND_F:
603 case LOG_LINE_DELETE_B:
604 case LOG_LINE_RESET_F:
605 break;
606 case LOG_LINE_RESET_B:
607 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
608 if (lno == sp->lno &&
609 db_set(sp, lno, (CHAR_T *)(p + CHAR_T_OFFSET),
610 (size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
611 goto err;
612 if (sp->rptlchange != lno) {
613 sp->rptlchange = lno;
614 ++sp->rptlines[L_CHANGED];
615 }
616 case LOG_MARK:
617 memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
618 m.lno = lm.lno;
619 m.cno = lm.cno;
620 if (mark_set(sp, lm.name, &m, 0))
621 goto err;
622 break;
623 default:
624 abort();
625 }
626 }
627
628 err: F_CLR(ep, F_NOLOG);
629 ep->l_win = NULL;
630 return (1);
631 }
632
633 /*
634 * Log_forward --
635 * Roll the log forward one operation.
636 *
637 * PUBLIC: int log_forward __P((SCR *, MARK *));
638 */
639 int
640 log_forward(SCR *sp, MARK *rp)
641 {
642 EXF *ep;
643 LMARK lm;
644 MARK m;
645 db_recno_t lno;
646 int didop;
647 u_char *p;
648 size_t size;
649
650 ep = sp->ep;
651 if (F_ISSET(ep, F_NOLOG)) {
652 msgq(sp, M_ERR,
653 "013|Logging not being performed, roll-forward not possible");
654 return (1);
655 }
656
657 if (ep->l_cur == ep->l_high) {
658 msgq(sp, M_BERR, "014|No changes to re-do");
659 return (1);
660 }
661
662 if (ep->l_win && ep->l_win != sp->wp) {
663 ex_emsg(sp, NULL, EXM_LOCKED);
664 return 1;
665 }
666 ep->l_win = sp->wp;
667
668 F_SET(ep, F_NOLOG); /* Turn off logging. */
669
670 for (didop = 0;;) {
671 ++ep->l_cur;
672 if (vi_log_get(sp, &ep->l_cur, &size))
673 LOG_ERR;
674 #if defined(DEBUG) && 0
675 log_trace(sp, "log_forward", ep->l_cur, data.data);
676 #endif
677 switch (*(p = (u_char *)sp->wp->l_lp)) {
678 case LOG_CURSOR_END:
679 if (didop) {
680 ++ep->l_cur;
681 memmove(rp, p + sizeof(u_char), sizeof(MARK));
682 F_CLR(ep, F_NOLOG);
683 ep->l_win = NULL;
684 return (0);
685 }
686 break;
687 case LOG_CURSOR_INIT:
688 break;
689 case LOG_LINE_APPEND_F:
690 didop = 1;
691 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
692 if (db_insert(sp, lno,
693 (CHAR_T *)(p + CHAR_T_OFFSET),
694 (size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
695 goto err;
696 ++sp->rptlines[L_ADDED];
697 break;
698 case LOG_LINE_DELETE_B:
699 didop = 1;
700 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
701 if (db_delete(sp, lno))
702 goto err;
703 ++sp->rptlines[L_DELETED];
704 break;
705 case LOG_LINE_RESET_B:
706 break;
707 case LOG_LINE_RESET_F:
708 didop = 1;
709 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
710 if (db_set(sp, lno,
711 (CHAR_T *)(p + CHAR_T_OFFSET),
712 (size - CHAR_T_OFFSET) / sizeof(CHAR_T)))
713 goto err;
714 if (sp->rptlchange != lno) {
715 sp->rptlchange = lno;
716 ++sp->rptlines[L_CHANGED];
717 }
718 break;
719 case LOG_MARK:
720 didop = 1;
721 memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
722 m.lno = lm.lno;
723 m.cno = lm.cno;
724 if (mark_set(sp, lm.name, &m, 0))
725 goto err;
726 break;
727 default:
728 abort();
729 }
730 }
731
732 err: F_CLR(ep, F_NOLOG);
733 ep->l_win = NULL;
734 return (1);
735 }
736
737 /*
738 * log_err --
739 * Try and restart the log on failure, i.e. if we run out of memory.
740 */
741 static void
742 log_err(SCR *sp, char *file, int line)
743 {
744 EXF *ep;
745
746 msgq(sp, M_SYSERR, "015|%s/%d: log put error", tail(file), line);
747 ep = sp->ep;
748 (void)ep->log->close(ep->log, DB_NOSYNC);
749 if (!log_init(sp, ep))
750 msgq(sp, M_ERR, "267|Log restarted");
751 }
752
753 #if defined(DEBUG) && 0
754 static void
755 log_trace(sp, msg, rno, p)
756 SCR *sp;
757 char *msg;
758 db_recno_t rno;
759 u_char *p;
760 {
761 LMARK lm;
762 MARK m;
763 db_recno_t lno;
764
765 switch (*p) {
766 case LOG_CURSOR_INIT:
767 memmove(&m, p + sizeof(u_char), sizeof(MARK));
768 vtrace(sp, "%lu: %s: C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
769 break;
770 case LOG_CURSOR_END:
771 memmove(&m, p + sizeof(u_char), sizeof(MARK));
772 vtrace(sp, "%lu: %s: C_END: %u/%u\n", rno, msg, m.lno, m.cno);
773 break;
774 case LOG_LINE_APPEND_F:
775 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
776 vtrace(sp, "%lu: %s: APPEND_F: %lu\n", rno, msg, lno);
777 break;
778 case LOG_LINE_APPEND_B:
779 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
780 vtrace(sp, "%lu: %s: APPEND_B: %lu\n", rno, msg, lno);
781 break;
782 case LOG_LINE_DELETE_F:
783 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
784 vtrace(sp, "%lu: %s: DELETE_F: %lu\n", rno, msg, lno);
785 break;
786 case LOG_LINE_DELETE_B:
787 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
788 vtrace(sp, "%lu: %s: DELETE_B: %lu\n", rno, msg, lno);
789 break;
790 case LOG_LINE_RESET_F:
791 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
792 vtrace(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno);
793 break;
794 case LOG_LINE_RESET_B:
795 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
796 vtrace(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
797 break;
798 case LOG_MARK:
799 memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
800 vtrace(sp,
801 "%lu: %s: MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
802 break;
803 default:
804 abort();
805 }
806 }
807 #endif
808