locking
[nvi.git] / common / log.c
blob047b45692c723da24205696b8439878c87c0cf6b
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: log.c,v 10.18 2000/07/22 14:52:36 skimo Exp $ (Berkeley) $Date: 2000/07/22 14:52:36 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/stat.h>
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>
28 #include "common.h"
31 * The log consists of records, each containing a type byte and a variable
32 * length byte string, as follows:
34 * LOG_CURSOR_INIT MARK
35 * LOG_CURSOR_END MARK
36 * LOG_LINE_APPEND db_recno_t char *
37 * LOG_LINE_DELETE db_recno_t char *
38 * LOG_LINE_INSERT db_recno_t char *
39 * LOG_LINE_RESET_F db_recno_t char *
40 * LOG_LINE_RESET_B db_recno_t char *
41 * LOG_MARK LMARK
43 * We do before image physical logging. This means that the editor layer
44 * MAY NOT modify records in place, even if simply deleting or overwriting
45 * characters. Since the smallest unit of logging is a line, we're using
46 * up lots of space. This may eventually have to be reduced, probably by
47 * doing logical logging, which is a much cooler database phrase.
49 * The implementation of the historic vi 'u' command, using roll-forward and
50 * roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record,
51 * followed by a number of other records, followed by a LOG_CURSOR_END record.
52 * LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B
53 * record, and is the line before the change. The second is LOG_LINE_RESET_F,
54 * and is the line after the change. Roll-back is done by backing up to the
55 * first LOG_CURSOR_INIT record before a change. Roll-forward is done in a
56 * similar fashion.
58 * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
59 * record for a line different from the current one. It should be noted that
60 * this means that a subsequent 'u' command will make a change based on the
61 * new position of the log's cursor. This is okay, and, in fact, historic vi
62 * behaved that way.
65 static int vi_log_get __P((SCR *sp, db_recno_t *lnop, size_t *size));
66 static int log_cursor1 __P((SCR *, int));
67 static void log_err __P((SCR *, char *, int));
68 #if defined(DEBUG) && 0
69 static void log_trace __P((SCR *, char *, db_recno_t, u_char *));
70 #endif
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); \
79 * log_init --
80 * Initialize the logging subsystem.
82 * PUBLIC: int log_init __P((SCR *, EXF *));
84 int
85 log_init(sp, ep)
86 SCR *sp;
87 EXF *ep;
90 * !!!
91 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
93 * Initialize the buffer. The logging subsystem has its own
94 * buffers because the global ones are almost by definition
95 * going to be in use when the log runs.
97 sp->wp->l_lp = NULL;
98 sp->wp->l_len = 0;
99 ep->l_cursor.lno = 1; /* XXX Any valid recno. */
100 ep->l_cursor.cno = 0;
101 ep->l_high = ep->l_cur = 1;
103 if (db_create(&ep->log, sp->gp->env, 0) != 0 ||
104 ep->log->open(ep->log, NULL, NULL, DB_RECNO, DB_CREATE | DB_THREAD,
105 S_IRUSR | S_IWUSR) != 0) {
106 msgq(sp, M_SYSERR, "009|Log file");
107 F_SET(ep, F_NOLOG);
108 return (1);
111 //LOCK_INIT(sp->wp, ep);
113 return (0);
117 * log_end --
118 * Close the logging subsystem.
120 * PUBLIC: int log_end __P((SCR *, EXF *));
123 log_end(sp, ep)
124 SCR *sp;
125 EXF *ep;
128 * !!!
129 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
131 //LOCK_END(sp->wp, ep);
132 if (ep->log != NULL) {
133 (void)(ep->log->close)(ep->log,DB_NOSYNC);
134 ep->log = NULL;
136 if (sp->wp->l_lp != NULL) {
137 free(sp->wp->l_lp);
138 sp->wp->l_lp = NULL;
140 sp->wp->l_len = 0;
141 ep->l_cursor.lno = 1; /* XXX Any valid recno. */
142 ep->l_cursor.cno = 0;
143 ep->l_high = ep->l_cur = 1;
144 return (0);
148 * log_cursor --
149 * Log the current cursor position, starting an event.
151 * PUBLIC: int log_cursor __P((SCR *));
154 log_cursor(sp)
155 SCR *sp;
157 EXF *ep;
159 ep = sp->ep;
160 if (F_ISSET(ep, F_NOLOG))
161 return (0);
164 * If any changes were made since the last cursor init,
165 * put out the ending cursor record.
167 if (ep->l_cursor.lno == OOBLNO) {
168 printf("own: %p, this: %p\n", ep->l_win, sp->wp);
169 if (ep->l_win != sp->wp)
170 return 0;
171 ep->l_cursor.lno = sp->lno;
172 ep->l_cursor.cno = sp->cno;
173 puts("end");
174 return (log_cursor1(sp, LOG_CURSOR_END));
176 ep->l_cursor.lno = sp->lno;
177 ep->l_cursor.cno = sp->cno;
178 return (0);
182 * log_cursor1 --
183 * Actually push a cursor record out.
185 static int
186 log_cursor1(sp, type)
187 SCR *sp;
188 int type;
190 DBT data, key;
191 EXF *ep;
193 ep = sp->ep;
196 if (type == LOG_CURSOR_INIT &&
197 LOCK_TRY(sp->wp, ep))
198 return 1;
201 BINC_RET(sp, sp->wp->l_lp, sp->wp->l_len, sizeof(u_char) + sizeof(MARK));
202 sp->wp->l_lp[0] = type;
203 memmove(sp->wp->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
205 memset(&key, 0, sizeof(key));
206 key.data = &ep->l_cur;
207 key.size = sizeof(db_recno_t);
208 memset(&data, 0, sizeof(data));
209 data.data = sp->wp->l_lp;
210 data.size = sizeof(u_char) + sizeof(MARK);
211 if (ep->log->put(ep->log, NULL, &key, &data, 0) == -1)
212 LOG_ERR;
214 puts(type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end");
215 #if defined(DEBUG) && 0
216 vtrace(sp, "%lu: %s: %u/%u\n", ep->l_cur,
217 type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
218 sp->lno, sp->cno);
219 #endif
220 /* Reset high water mark. */
221 ep->l_high = ++ep->l_cur;
224 if (type == LOG_CURSOR_END)
225 LOCK_UNLOCK(sp->wp, ep);
227 return (0);
231 * log_line --
232 * Log a line change.
234 * PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
237 log_line(sp, lno, action)
238 SCR *sp;
239 db_recno_t lno;
240 u_int action;
242 DBT data, key;
243 EXF *ep;
244 size_t len;
245 CHAR_T *lp;
246 db_recno_t lcur;
248 ep = sp->ep;
249 if (F_ISSET(ep, F_NOLOG))
250 return (0);
253 * XXX
255 * Kluge for vi. Clear the EXF undo flag so that the
256 * next 'u' command does a roll-back, regardless.
258 F_CLR(ep, F_UNDO);
260 /* Put out one initial cursor record per set of changes. */
261 if (ep->l_cursor.lno != OOBLNO) {
262 puts("begin");
263 if (log_cursor1(sp, LOG_CURSOR_INIT))
264 return (1);
265 ep->l_cursor.lno = OOBLNO;
266 ep->l_win = sp->wp;
267 } else if (ep->l_win != sp->wp) {
268 printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
269 return 1;
273 * Put out the changes. If it's a LOG_LINE_RESET_B call, it's a
274 * special case, avoid the caches. Also, if it fails and it's
275 * line 1, it just means that the user started with an empty file,
276 * so fake an empty length line.
278 if (action == LOG_LINE_RESET_B) {
279 if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) {
280 static CHAR_T nul = 0;
281 if (lno != 1) {
282 db_err(sp, lno);
283 return (1);
285 len = 0;
286 lp = &nul;
288 } else
289 if (db_get(sp, lno, DBG_FATAL, &lp, &len))
290 return (1);
291 BINC_RET(sp,
292 sp->wp->l_lp, sp->wp->l_len,
293 len * sizeof(CHAR_T) + sizeof(u_char) + sizeof(db_recno_t));
294 sp->wp->l_lp[0] = action;
295 memmove(sp->wp->l_lp + sizeof(u_char), &lno, sizeof(db_recno_t));
296 MEMMOVEW(sp->wp->l_lp + sizeof(u_char) + sizeof(db_recno_t), lp, len);
298 lcur = ep->l_cur;
299 memset(&key, 0, sizeof(key));
300 key.data = &lcur;
301 key.size = sizeof(db_recno_t);
302 memset(&data, 0, sizeof(data));
303 data.data = sp->wp->l_lp;
304 data.size = len * sizeof(CHAR_T) +
305 sizeof(u_char) + sizeof(db_recno_t);
306 if (ep->log->put(ep->log, NULL, &key, &data, 0) == -1)
307 LOG_ERR;
309 #if defined(DEBUG) && 0
310 switch (action) {
311 case LOG_LINE_APPEND:
312 vtrace(sp, "%u: log_line: append: %lu {%u}\n",
313 ep->l_cur, lno, len);
314 break;
315 case LOG_LINE_DELETE:
316 vtrace(sp, "%lu: log_line: delete: %lu {%u}\n",
317 ep->l_cur, lno, len);
318 break;
319 case LOG_LINE_INSERT:
320 vtrace(sp, "%lu: log_line: insert: %lu {%u}\n",
321 ep->l_cur, lno, len);
322 break;
323 case LOG_LINE_RESET_F:
324 vtrace(sp, "%lu: log_line: reset_f: %lu {%u}\n",
325 ep->l_cur, lno, len);
326 break;
327 case LOG_LINE_RESET_B:
328 vtrace(sp, "%lu: log_line: reset_b: %lu {%u}\n",
329 ep->l_cur, lno, len);
330 break;
332 #endif
333 /* Reset high water mark. */
334 ep->l_high = ++ep->l_cur;
336 return (0);
340 * log_mark --
341 * Log a mark position. For the log to work, we assume that there
342 * aren't any operations that just put out a log record -- this
343 * would mean that undo operations would only reset marks, and not
344 * cause any other change.
346 * PUBLIC: int log_mark __P((SCR *, LMARK *));
349 log_mark(sp, lmp)
350 SCR *sp;
351 LMARK *lmp;
353 DBT data, key;
354 EXF *ep;
356 ep = sp->ep;
357 if (F_ISSET(ep, F_NOLOG))
358 return (0);
360 /* Put out one initial cursor record per set of changes. */
361 if (ep->l_cursor.lno != OOBLNO) {
362 puts("begin");
363 if (log_cursor1(sp, LOG_CURSOR_INIT))
364 return (1);
365 ep->l_cursor.lno = OOBLNO;
366 ep->l_win = sp->wp;
369 BINC_RET(sp, sp->wp->l_lp,
370 sp->wp->l_len, sizeof(u_char) + sizeof(LMARK));
371 sp->wp->l_lp[0] = LOG_MARK;
372 memmove(sp->wp->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
374 memset(&key, 0, sizeof(key));
375 key.data = &ep->l_cur;
376 key.size = sizeof(db_recno_t);
377 memset(&data, 0, sizeof(data));
378 data.data = sp->wp->l_lp;
379 data.size = sizeof(u_char) + sizeof(LMARK);
380 if (ep->log->put(ep->log, NULL, &key, &data, 0) == -1)
381 LOG_ERR;
383 #if defined(DEBUG) && 0
384 vtrace(sp, "%lu: mark %c: %lu/%u\n",
385 ep->l_cur, lmp->name, lmp->lno, lmp->cno);
386 #endif
387 /* Reset high water mark. */
388 ep->l_high = ++ep->l_cur;
389 return (0);
393 * vi_log_get --
394 * Get a line from the log in log buffer.
396 static int
397 vi_log_get(SCR *sp, db_recno_t *lnop, size_t *size)
399 DBT key, data;
400 size_t nlen;
401 EXF *ep;
403 ep = sp->ep;
405 nlen = 1024;
406 retry:
407 BINC_RET(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
409 memset(&key, 0, sizeof(key));
410 key.data = lnop; /* Initialize db request. */
411 key.size = sizeof(db_recno_t);
412 memset(&data, 0, sizeof(data));
413 data.data = sp->wp->l_lp;
414 data.ulen = sp->wp->l_len;
415 data.flags = DB_DBT_USERMEM;
416 switch (ep->log->get(ep->log, NULL, &key, &data, 0)) {
417 case ENOMEM:
418 nlen = data.size;
419 goto retry;
420 case 0:
421 *size = data.size;
422 return 0;
423 default:
424 return 1;
429 * Log_backward --
430 * Roll the log backward one operation.
432 * PUBLIC: int log_backward __P((SCR *, MARK *));
435 log_backward(sp, rp)
436 SCR *sp;
437 MARK *rp;
439 EXF *ep;
440 LMARK lm;
441 MARK m;
442 db_recno_t lno;
443 int didop;
444 u_char *p;
445 size_t size;
447 ep = sp->ep;
448 if (F_ISSET(ep, F_NOLOG)) {
449 msgq(sp, M_ERR,
450 "010|Logging not being performed, undo not possible");
451 return (1);
454 if (ep->l_cur == 1) {
455 msgq(sp, M_BERR, "011|No changes to undo");
456 return (1);
459 F_SET(ep, F_NOLOG); /* Turn off logging. */
461 for (didop = 0;;) {
462 --ep->l_cur;
463 if (vi_log_get(sp, &ep->l_cur, &size))
464 LOG_ERR;
465 #if defined(DEBUG) && 0
466 log_trace(sp, "log_backward", ep->l_cur, data.data);
467 #endif
468 switch (*(p = (u_char *)sp->wp->l_lp)) {
469 case LOG_CURSOR_INIT:
470 if (didop) {
471 memmove(rp, p + sizeof(u_char), sizeof(MARK));
472 F_CLR(ep, F_NOLOG);
473 return (0);
475 break;
476 case LOG_CURSOR_END:
477 break;
478 case LOG_LINE_APPEND:
479 case LOG_LINE_INSERT:
480 didop = 1;
481 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
482 if (db_delete(sp, lno))
483 goto err;
484 ++sp->rptlines[L_DELETED];
485 break;
486 case LOG_LINE_DELETE:
487 didop = 1;
488 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
489 if (db_insert(sp, lno,
490 (CHAR_T *)(p + sizeof(u_char) +
491 sizeof(db_recno_t)),
492 (size - sizeof(u_char) - sizeof(db_recno_t))
493 / sizeof(CHAR_T)))
494 goto err;
495 ++sp->rptlines[L_ADDED];
496 break;
497 case LOG_LINE_RESET_F:
498 break;
499 case LOG_LINE_RESET_B:
500 didop = 1;
501 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
502 if (db_set(sp, lno,
503 (CHAR_T *)(p + sizeof(u_char) +
504 sizeof(db_recno_t)),
505 (size - sizeof(u_char) - sizeof(db_recno_t))
506 / sizeof(CHAR_T)))
507 goto err;
508 if (sp->rptlchange != lno) {
509 sp->rptlchange = lno;
510 ++sp->rptlines[L_CHANGED];
512 break;
513 case LOG_MARK:
514 didop = 1;
515 memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
516 m.lno = lm.lno;
517 m.cno = lm.cno;
518 if (mark_set(sp, lm.name, &m, 0))
519 goto err;
520 break;
521 default:
522 abort();
526 err: F_CLR(ep, F_NOLOG);
527 return (1);
531 * Log_setline --
532 * Reset the line to its original appearance.
534 * XXX
535 * There's a bug in this code due to our not logging cursor movements
536 * unless a change was made. If you do a change, move off the line,
537 * then move back on and do a 'U', the line will be restored to the way
538 * it was before the original change.
540 * PUBLIC: int log_setline __P((SCR *));
543 log_setline(sp)
544 SCR *sp;
546 EXF *ep;
547 LMARK lm;
548 MARK m;
549 db_recno_t lno;
550 u_char *p;
551 size_t size;
553 ep = sp->ep;
554 if (F_ISSET(ep, F_NOLOG)) {
555 msgq(sp, M_ERR,
556 "012|Logging not being performed, undo not possible");
557 return (1);
560 if (ep->l_cur == 1)
561 return (1);
563 F_SET(ep, F_NOLOG); /* Turn off logging. */
565 for (;;) {
566 --ep->l_cur;
567 if (vi_log_get(sp, &ep->l_cur, &size))
568 LOG_ERR;
569 #if defined(DEBUG) && 0
570 log_trace(sp, "log_setline", ep->l_cur, data.data);
571 #endif
572 switch (*(p = (u_char *)sp->wp->l_lp)) {
573 case LOG_CURSOR_INIT:
574 memmove(&m, p + sizeof(u_char), sizeof(MARK));
575 if (m.lno != sp->lno || ep->l_cur == 1) {
576 F_CLR(ep, F_NOLOG);
577 return (0);
579 break;
580 case LOG_CURSOR_END:
581 memmove(&m, p + sizeof(u_char), sizeof(MARK));
582 if (m.lno != sp->lno) {
583 ++ep->l_cur;
584 F_CLR(ep, F_NOLOG);
585 return (0);
587 break;
588 case LOG_LINE_APPEND:
589 case LOG_LINE_INSERT:
590 case LOG_LINE_DELETE:
591 case LOG_LINE_RESET_F:
592 break;
593 case LOG_LINE_RESET_B:
594 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
595 if (lno == sp->lno &&
596 db_set(sp, lno, (CHAR_T *)(p + sizeof(u_char) +
597 sizeof(db_recno_t)), size - sizeof(u_char) -
598 sizeof(db_recno_t)))
599 goto err;
600 if (sp->rptlchange != lno) {
601 sp->rptlchange = lno;
602 ++sp->rptlines[L_CHANGED];
604 case LOG_MARK:
605 memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
606 m.lno = lm.lno;
607 m.cno = lm.cno;
608 if (mark_set(sp, lm.name, &m, 0))
609 goto err;
610 break;
611 default:
612 abort();
616 err: F_CLR(ep, F_NOLOG);
617 return (1);
621 * Log_forward --
622 * Roll the log forward one operation.
624 * PUBLIC: int log_forward __P((SCR *, MARK *));
627 log_forward(sp, rp)
628 SCR *sp;
629 MARK *rp;
631 EXF *ep;
632 LMARK lm;
633 MARK m;
634 db_recno_t lno;
635 int didop;
636 u_char *p;
637 size_t size;
639 ep = sp->ep;
640 if (F_ISSET(ep, F_NOLOG)) {
641 msgq(sp, M_ERR,
642 "013|Logging not being performed, roll-forward not possible");
643 return (1);
646 if (ep->l_cur == ep->l_high) {
647 msgq(sp, M_BERR, "014|No changes to re-do");
648 return (1);
651 F_SET(ep, F_NOLOG); /* Turn off logging. */
653 for (didop = 0;;) {
654 ++ep->l_cur;
655 if (vi_log_get(sp, &ep->l_cur, &size))
656 LOG_ERR;
657 #if defined(DEBUG) && 0
658 log_trace(sp, "log_forward", ep->l_cur, data.data);
659 #endif
660 switch (*(p = (u_char *)sp->wp->l_lp)) {
661 case LOG_CURSOR_END:
662 if (didop) {
663 ++ep->l_cur;
664 memmove(rp, p + sizeof(u_char), sizeof(MARK));
665 F_CLR(ep, F_NOLOG);
666 return (0);
668 break;
669 case LOG_CURSOR_INIT:
670 break;
671 /* XXXX LOG_LINE_APPEND and LOG_LINE_INSERT split
672 for now, because db_insert won't work for adding
673 last line
675 case LOG_LINE_APPEND:
676 didop = 1;
677 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
678 --lno;
679 if (db_append(sp, 1, lno,
680 (CHAR_T *)(p + sizeof(u_char) +
681 sizeof(db_recno_t)),
682 (size - sizeof(u_char) - sizeof(db_recno_t))
683 / sizeof(CHAR_T)))
684 goto err;
685 ++sp->rptlines[L_ADDED];
686 break;
687 case LOG_LINE_INSERT:
688 didop = 1;
689 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
690 if (db_insert(sp, lno,
691 (CHAR_T *)(p + sizeof(u_char) +
692 sizeof(db_recno_t)),
693 (size - sizeof(u_char) - sizeof(db_recno_t))
694 / sizeof(CHAR_T)))
695 goto err;
696 ++sp->rptlines[L_ADDED];
697 break;
698 case LOG_LINE_DELETE:
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 + sizeof(u_char) +
712 sizeof(db_recno_t)),
713 (size - sizeof(u_char) - sizeof(db_recno_t))
714 / sizeof(CHAR_T)))
715 goto err;
716 if (sp->rptlchange != lno) {
717 sp->rptlchange = lno;
718 ++sp->rptlines[L_CHANGED];
720 break;
721 case LOG_MARK:
722 didop = 1;
723 memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
724 m.lno = lm.lno;
725 m.cno = lm.cno;
726 if (mark_set(sp, lm.name, &m, 0))
727 goto err;
728 break;
729 default:
730 abort();
734 err: F_CLR(ep, F_NOLOG);
735 return (1);
739 * log_err --
740 * Try and restart the log on failure, i.e. if we run out of memory.
742 static void
743 log_err(sp, file, line)
744 SCR *sp;
745 char *file;
746 int line;
748 EXF *ep;
750 msgq(sp, M_SYSERR, "015|%s/%d: log put error", tail(file), line);
751 ep = sp->ep;
752 (void)ep->log->close(ep->log, DB_NOSYNC);
753 if (!log_init(sp, ep))
754 msgq(sp, M_ERR, "267|Log restarted");
757 #if defined(DEBUG) && 0
758 static void
759 log_trace(sp, msg, rno, p)
760 SCR *sp;
761 char *msg;
762 db_recno_t rno;
763 u_char *p;
765 LMARK lm;
766 MARK m;
767 db_recno_t lno;
769 switch (*p) {
770 case LOG_CURSOR_INIT:
771 memmove(&m, p + sizeof(u_char), sizeof(MARK));
772 vtrace(sp, "%lu: %s: C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
773 break;
774 case LOG_CURSOR_END:
775 memmove(&m, p + sizeof(u_char), sizeof(MARK));
776 vtrace(sp, "%lu: %s: C_END: %u/%u\n", rno, msg, m.lno, m.cno);
777 break;
778 case LOG_LINE_APPEND:
779 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
780 vtrace(sp, "%lu: %s: APPEND: %lu\n", rno, msg, lno);
781 break;
782 case LOG_LINE_INSERT:
783 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
784 vtrace(sp, "%lu: %s: INSERT: %lu\n", rno, msg, lno);
785 break;
786 case LOG_LINE_DELETE:
787 memmove(&lno, p + sizeof(u_char), sizeof(db_recno_t));
788 vtrace(sp, "%lu: %s: DELETE: %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();
807 #endif