The journal Reference Manual

Table of Contents

Next: , Previous: , Up: (dir)   [Contents][Index]

The journal Reference Manual

This is the journal Reference Manual, version 0.1.0, generated automatically by Declt version 3.0 "Montgomery Scott" on Sun May 15 05:05:10 2022 GMT+0.


Next: , Previous: , Up: Top   [Contents][Index]

1 Introduction

# Journal manual

###### \[in package JOURNAL with nicknames JRN\]
## JOURNAL ASDF System

- Version: 0.1.0
- Description: A library for logging, tracing, testing and persistence.
- Licence: MIT, see COPYING.
- Author: Gábor Melis 
- Homepage: [http://github.com/melisgl/journal](http://github.com/melisgl/journal)
- Bug tracker: [http://github.com/melisgl/journal/issues](http://github.com/melisgl/journal/issues)
- Source control: [GIT](https://github.com/melisgl/journal.git)

## Links

Here is the [official repository](https://github.com/melisgl/journal)
and the [HTML
documentation](http://melisgl.github.io/mgl-pax-world/journal-manual.html)
for the latest version.

## Portability

Tested on ABCL, CCL, CLISP, CMUCL, ECL, and SBCL. AllegroCL Express
edition runs out of heap while running the tests. On Lisps that seem
to lack support for disabling and enabling of interrupts, such as
ABCL and CLISP, durability is compromised, and any attempt to
SYNC-JOURNAL (see @SYNCHRONIZATION-STRATEGIES and @SAFETY) will be a
runtime error.

## Background

Logging, tracing, testing, and persistence are about what happened
during code execution. Recording machine-readable logs and traces
can be repurposed for white-box testing. More, when the code is
rerun, selected frames may return their recorded values without
executing the code, which could serve as a [mock][mock-object]
framework for writing tests. This ability to isolate external
interactions and to reexecute traces is sufficient to reconstruct
the state of a program, achieving simple persistence not unlike a
[journaling filesystem][journaling-fs] or [Event
Sourcing][event-sourcing].

[mock-object]: https://en.wikipedia.org/wiki/Mock_object 

[journaling-fs]: https://en.wikipedia.org/wiki/Journaling_file_system 

[event-sourcing]: https://martinfowler.com/eaaDev/EventSourcing.html 

Journal is the library to log, trace, test and persist. It has a
single macro at its heart: JOURNALED, which does pretty much what
was described. It can be thought of as generating two events around
its body: one that records the name and an argument list (as in a
function call), and another that records the return values. In
Lisp-like pseudocode:

```
(defmacro journaled (name args &body body)
  `(progn
     (record-event `(:in ,name :args ,args))
     (let ((,return-values (multiple-value-list (progn ,@body))))
       (record-event `(:out ,name :values ,return-values))
       (values-list ,return-values))))
```

The Journal library is this idea taken to its logical conclusion.

## Distinguishing features

##### As a logging facility

- Nested contexts and single messages

- Customizable content and format

- Human- or machine-readable output

```
#68200.234: ("some-context")
#68200.234:   Informative log message
#68200.250: => NIL
```

See @LOGGING for a complete example.

##### Compared to CL:TRACE

- Ability to handle @NON-LOCAL-EXITs

- Customizable content and format

- Optional timestamps, internal real- and run-time

```
(FOO 2.1)
  (1+ 2.1)
  => 3.1
=E "SIMPLE-ERROR" "The assertion (INTEGERP 3.1) failed."
```

See @TRACING for a complete example.

##### As a test framework

- White-box testing based on execution traces

- Isolation of external dependencies

- Record-and-replay testing

```
(define-file-bundle-test (test-user-registration :directory "registration")
  (let ((username (replayed ("ask-username")
                    (format t "Please type your username: ")
                    (read-line))))
    (add-user username)
    (assert (user-exists-p username))))
```

See @TESTING for a complete example.

##### As a solution for persistence

- Event Sourcing: replay interactions with the external world

- Unchanged control flow

- Easy to implement history, undo

```
(defun my-resumable-autosaving-game-with-history ()
  (with-bundle (bundle)
    (play-guess-my-number)))
```

See @PERSISTENCE for a complete example.

## Basics

The JOURNALED macro does both recording and replaying of events,
possibly at the same time. Recording is easy: events generated by
JOURNALED are simply written to a journal, which is a sequence of
events much like a file. What events are generated is described in
JOURNALED. @REPLAY is much more involved, thus it gets its own
section. The journals used for recording and replaying are specified
by WITH-JOURNALING or by WITH-BUNDLE.

The @JOURNALS-REFERENCE is presented later, but for most purposes
creating them (e.g. with MAKE-IN-MEMORY-JOURNAL, MAKE-FILE-JOURNAL)
and maybe querying their contents with LIST-EVENTS will suffice.
Some common cases of journal creation are handled by the convenience
function TO-JOURNAL.

Built on top of journals, @BUNDLES juggle repeated replay-and-record
cycles focussing on persistence.

- [generic-function] TO-JOURNAL DESIGNATOR

    Return the journal designated by DESIGNATOR or
    signal an error. The default implementation:
    
    - returns DESIGNATOR itself if it is of type JOURNAL,
    
    - returns a new IN-MEMORY-JOURNAL if DESIGNATOR is T,
    
    - returns a new FILE-JOURNAL if DESIGNATOR is a PATHNAME.


- [macro] WITH-JOURNALING (&KEY RECORD REPLAY REPLAY-EOJ-ERROR-P) &BODY BODY

    Turn recording and/or replaying of events on or off for the
    duration of BODY. Both RECORD and REPLAY should be a JOURNAL
    designator (in the sense of TO-JOURNAL) or NIL.
    
    If RECORD designates a JOURNAL, then events generated by enclosed
    JOURNALED @BLOCKs are written to that journal (with exceptions, see
    the LOG-RECORD argument of JOURNALED). If REPLAY designates a
    JOURNAL, then the generated events are matched against events from
    that journal according to the rules of @REPLAY.
    
    A JOURNAL-ERROR is signalled, if RECORD is a JOURNAL that has been
    previously recorded to by another WITH-JOURNALING (that is, if its
    JOURNAL-STATE is not :NEW), or if REPLAY is a JOURNAL that is not a
    complete recording of successful replay (i.e. its JOURNAL-STATE is
    not :COMPLETED). These checks are intended to catch mistakes that
    would render the new or existing records unusable for replay. When
    WITH-JOURNALING finishes, the RECORD journal is marked :COMPLETED or
    :FAILED in its JOURNAL-STATE.
    
    REPLAY-EOJ-ERROR-P controls whether an END-OF-JOURNAL is signalled
    when a new event is being matched to the replay journal from which
    there are no more events to read. If there was a JOURNALING-FAILURE
    or a REPLAY-FAILURE during execution, then END-OF-JOURNAL is not
    signalled.
    
    If BODY completes successfully, but REPLAY has unprocessed events,
    then signal REPLAY-INCOMPLETE.
    
    WITH-JOURNALING for different RECORD journals can be nested and run
    independently.

- [glossary-term] block

    A journaled block, or simply block, is a number of forms wrapped in
    JOURNALED. When a block is executed, a @FRAME is created.

- [glossary-term] frame

    A frame is an IN-EVENT, OUT-EVENT pair, which are created when a
    @BLOCK is entered and left, respectively.

- [function] RECORD-JOURNAL

    Return the journal in which events are currently being
    recorded (see WITH-JOURNALING and WITH-BUNDLE) or NIL.

- [function] REPLAY-JOURNAL

    Return the journal from which events are currently being
    replayed (see WITH-JOURNALING and WITH-BUNDLE) or NIL.

- [macro] JOURNALED (NAME &KEY (LOG-RECORD :RECORD) VERSION ARGS VALUES CONDITION INSERTABLE REPLAY-VALUES REPLAY-CONDITION) &BODY BODY

    JOURNALED generates events upon entering and leaving the dynamic
    extent of BODY (also known as the journaled @BLOCK), which we call
    the @IN-EVENTS and @OUT-EVENTS. Between generating the two events,
    BODY is typically executed normally (except for
    @REPLAYING-THE-OUTCOME).
    
    Where the generated events are written is determined by the :RECORD
    argument of the enclosing WITH-JOURNALING. If there is no enclosing
    WITH-JOURNALING and LOG-RECORD is NIL, then event recording is
    turned off and JOURNALED imposes minimal overhead.
    
    - NAME can be of any type except [NULL][type], not evaluated. For
      names, and for anything that gets written to a journal, a
      non-keyword symbol is a reasonable choice as it can be easily made
      unique. However, it also exposes the package structure, which
      might make reading stuff back more difficult. Keywords and strings
      do not have this problem.
    
    - ARGS can be of any type, but is typically a list.
    
    Also see in @LOG-RECORD in the @LOGGING section. For a description
    of VERSION, INSERTABLE, REPLAY-VALUES and REPLAY-CONDITION, see
    @JOURNALED-FOR-REPLAY.

### In-events

Upon entering a @BLOCK, JOURNALED generates an IN-EVENT,
which conceptually opens a new @FRAME. These in-events are created
from the NAME, VERSION and ARGS arguments of JOURNALED. For example,

```
(journaled (name :version version :args args) ...)
```

creates an event like this:

```
`(:in ,name :version ,version :args ,args)
```

where :VERSION and :ARGS may be omitted if they are NIL. Versions
are used for @REPLAY.

### Out-events

Upon leaving a @BLOCK, JOURNALED generates and OUT-EVENT, closing
the @FRAME opened by the corresponding in-event. These out-events
are property lists like this:

```
(:out foo :version 1 :values (42))
```

Their NAME and VERSION (`FOO` and `1` in the example) are the same
as in the in-event: they are the corresponding arguments of
JOURNALED. EXIT and OUTCOME are filled in differently depending on
how the block finished its execution.

- [type] EVENT-EXIT

    One of :VALUES, :CONDITION, :ERROR and :NLX. Indicates whether a
    journaled @BLOCK:
    
    - returned normally (:VALUES, see VALUES-OUTCOME),
    
    - unwound on an expected condition (:CONDITION, see CONDITION-OUTCOME),
    
    - unwound on an unexpected condition (:ERROR, see ERROR-OUTCOME),
    
    - unwound by performing a @NON-LOCAL-EXIT of some other kind such as
      a throw (:NLX, see NLX-OUTCOME).
    
    The first two are EXPECTED-OUTCOMEs, while the latter two are
    UNEXPECTED-OUTCOMEs.

- [glossary-term] values outcome

    If the JOURNALED @BLOCK returns normally, [EVENT-EXIT][type] is
    :VALUES and the outcome is the list of values returned:
    
    ```
    (journaled (foo) (values 7 t))
    ;; generates the out-event
    (:out foo :values (7 t))
    ```
    
    The list of return values of the block is transformed by the VALUES
    argument of JOURNALED, whose default is `#'IDENTITY`. Also see
    @WORKING-WITH-UNREADABLE-VALUES).

- [glossary-term] condition outcome

    If the @BLOCK unwound due to a condition, and JOURNALED's
    CONDITION argument (a function whose default is `(CONSTANTLY NIL)`)
    returns non-NIL when invoked on it, then [EVENT-EXIT][type] is
    :CONDITION and the outcome is this return value:
    
    ```
    (journaled (foo :condition (lambda (c) (prin1-to-string c)))
      (error "xxx"))
    ;; generates the out-event
    (:out foo :condition "xxx")
    ```
    
    Conditions thus recognized are those that can be considered to be
    part of normal execution. Just like return values, these expected
    conditions may be required to match what's in the replay journal.
    Furthermore, given a suitable REPLAY-CONDITION in JOURNALED, they
    may be replayed without running the @BLOCK.

- [glossary-term] error outcome

    If the JOURNALED @BLOCK unwound due to a condition, but
    JOURNALED's CONDITION argument returns NIL when invoked on it, then
    [EVENT-EXIT][type] is :ERROR and the outcome the string
    representations of the type of the condition and the condition
    itself.
    
    ```
    (journaled (foo)
      (error "xxx"))
    ;; generates the out-event
    (:out foo :error ("simple-error" "xxx"))
    ```
    
    The conversion to string is performed with PRINC in
    WITH-STANDARD-IO-SYNTAX. This scheme is intended to avoid leaking
    random implementation details into the journal, which would make
    `READ`ing it back difficult.
    
    In contrast with CONDITION-OUTCOMEs, error outcomes are what the
    code is not prepared to handle or replay in a meaningful way.

- [glossary-term] nlx outcome

    If the JOURNALED @BLOCK performed a @NON-LOCAL-EXIT that was not
    due to a condition, then [EVENT-EXIT][type] is :NLX and the outcome
    is NIL.
    
    ```
    (catch 'xxx
      (journaled (foo)
        (throw 'xxx nil)))
    ;; generates the out-event
    (:out foo :nlx nil)
    ```
    
    Note that CONDITION-OUTCOMEs and ERROR-OUTCOMEs are also due to
    @NON-LOCAL-EXITs, but are distinct from nlx outcomes.
    
    Currently, nlx outcomes are detected rather heuristically as there
    is no portable way to detect what really caused the unwinding of the
    stack.

There is a further grouping of outcomes into expected and unexpected.

- [glossary-term] expected outcome

    An OUT-EVENT is said to have an expected outcome if it had a
    VALUES-OUTCOME or a CONDITION-OUTCOME, or equivalently, when its
    [EVENT-EXIT][type] is :VALUES or :CONDITION.

- [glossary-term] unexpected outcome

    An OUT-EVENT is said to have an unexpected outcome if it had an
    ERROR-OUTCOME or an NLX-OUTCOME, or equivalently, when its
    [EVENT-EXIT][type] is :ERROR or :NLX.

### Working with unreadable values

The events recorded often need to be @READABLE. This is always
required with FILE-JOURNALs, often with IN-MEMORY-JOURNALs, but
never with PPRINT-JOURNALs. By choosing an appropriate identifier or
string representation of the unreadable object to journal, this is
not a problem in practice. JOURNALED provides the VALUES
hook for this purpose.

With EXTERNAL-EVENTs, whose outcome is replayed (see
@REPLAYING-THE-OUTCOME), we also need to be able to reverse the
transformation of VALUES, and this is what the
REPLAY-VALUES argument of JOURNALED is for.

Let's see a complete example.

```
(defclass user ()
  ((id :initarg :id :reader user-id)))

(defmethod print-object ((user user) stream)
  (print-unreadable-object (user stream :type t)
    (format stream "~S" (slot-value user 'id))))

(defvar *users* (make-hash-table))

(defun find-user (id)
  (gethash id *users*))

(defun add-user (id)
  (setf (gethash id *users*) (make-instance 'user :id id)))

(defvar *user7* (add-user 7))

(defun get-message ()
  (replayed (listen :values (values-> #'user-id)
                    :replay-values (values<- #'find-user))
    (values *user7* "hello")))

(jtrace user-id find-user get-message)

(let ((bundle (make-file-bundle "/tmp/user-example/")))
  (format t "Recording")
  (with-bundle (bundle)
    (get-message))
  (format t "~%Replaying")
  (with-bundle (bundle)
    (get-message)))
.. Recording
.. (GET-MESSAGE)
..   (USER-ID #)
..   => 7
.. => #, "hello"
.. Replaying
.. (GET-MESSAGE)
..   (FIND-USER 7)
..   => #, T
.. => #, "hello"
==> #
=> "hello"
```

The point of this example that for to be able to journal the return
values of `GET-MESSAGE`, the `USER` object must be transformed to
something @READABLE. On the `Recording` run, `(VALUES-> #'USER-ID)`
replaces the user object with its id in the EVENT-OUTCOME recorded,
but the original user object is returned.

When `Replaying`, the journaled OUT-EVENT is replayed (see
@REPLAYING-THE-OUTCOME):

```
(:OUT GET-MESSAGE :VERSION :INFINITY :VALUES (7 "hello"))
```

The user object is looked up according to :REPLAY-VALUES and is
returned along with `"hello"`.

- [function] VALUES-> &REST FNS

    A utility to create a function suitable as the VALUES
    argument of JOURNALED. The VALUES function is called with the list
    of values returned by the @BLOCK and returns a transformed set of
    values that may be recorded in a journal. While arbitrary
    transformations are allowed, `VALUES->` handles the common case of
    transforming individual elements of the list independently by
    calling the functions in FN with the values of the list of the same
    position.
    
    ```
    (funcall (values-> #'1+) '(7 :something))
    => (8 :SOMETHING)
    ```
    
    Note how `#'1+` is applied only to the first element of the values
    list. The list of functions is shorter than the values list, so
    `:SOMETHING` is not transformed. A value can be left explicitly
    untransformed by specifying #'IDENTITY or NIL as the function:
    
    ```
    (funcall (values-> #'1+ nil #'symbol-name)
             '(7 :something :another))
    => (8 :SOMETHING "ANOTHER")
    ```


- [function] VALUES<- &REST FNS

    The inverse of `VALUES->`, this returns a function suitable as
    the REPLAY-VALUES argument of JOURNALED. It does pretty much what
    `VALUES->` does, but the function returned returns the transformed
    list as multiple values instead of as a list.
    
    ```
    (funcall (values<- #'1-) '(8 :something))
    => 7
    => :SOMETHING
    ```


### Utilities

- [function] LIST-EVENTS &OPTIONAL (JOURNAL (RECORD-JOURNAL))

    Return a list of all the events in the journal designated by
    JOURNAL. Calls SYNC-JOURNAL first, to make sure that all writes are
    taken into account.

- [function] EVENTS-TO-FRAMES EVENTS

    Convert a flat list of events, such as those returned by LIST-EVENTS,
    to a nested list representing the @FRAMEs. Each frame is a list of
    the form `( * ?)`. Like in
    PRINT-EVENTS, EVENTS may be a JOURNAL.
    
    ```
    (events-to-frames '((:in foo :args (1 2))
                        (:in bar :args (7))
                        (:leaf "leaf")
                        (:out bar :values (8))
                        (:out foo :values (2))
                        (:in foo :args (3 4))
                        (:in bar :args (8))))
    => (((:IN FOO :ARGS (1 2))
         ((:IN BAR :ARGS (7))
          (:LEAF "leaf")
          (:OUT BAR :VALUES (8)))
         (:OUT FOO :VALUES (2)))
        ((:IN FOO :ARGS (3 4)) ((:IN BAR :ARGS (8)))))
    ```
    
    Note that, as in the above example, incomplete frames (those without
    an OUT-EVENT) are included in the output.

- [function] EXPECTED-TYPE TYPE

    Return a function suitable as the CONDITION argument of JOURNALED,
    which returns the type of its single argument as a string if it is
    of TYPE, else NIL.

### Pretty-printing

- [function] PRINT-EVENTS EVENTS &KEY STREAM

    Print EVENTS to STREAM as lists, starting a new line for each
    event and indenting them according to their nesting structure.
    EVENTS may be a JOURNAL, in which case LIST-EVENTS is called on it
    first.
    
    ```
    (print-events '((:in log :args ("first arg" 2))
                    (:in versioned :version 1 :args (3))
                    (:out versioned :version 1 :values (42 t))
                    (:out log :condition "a :CONDITION outcome")
                    (:in log-2)
                    (:out log-2 :nlx nil)
                    (:in external :version :infinity)
                    (:out external :version :infinity
                     :error ("ERROR" "an :ERROR outcome"))))
    ..
    .. (:IN LOG :ARGS ("first arg" 2))
    ..   (:IN VERSIONED :VERSION 1 :ARGS (3))
    ..   (:OUT VERSIONED :VERSION 1 :VALUES (42 T))
    .. (:OUT LOG :CONDITION "a :CONDITION outcome")
    .. (:IN LOG-2)
    .. (:OUT LOG-2 :NLX NIL)
    .. (:IN EXTERNAL :VERSION :INFINITY)
    .. (:OUT EXTERNAL :VERSION :INFINITY :ERROR ("ERROR" "an :ERROR outcome"))
    => ; No value
    ```


- [function] PPRINT-EVENTS EVENTS &KEY STREAM (PRETTIFIER 'PRETTIFY-EVENT)

    Like PRINT-EVENTS, but produces terser, more human readable
    output.
    
    ```
    (pprint-events '((:in log :args ("first arg" 2))
                     (:in versioned :version 1 :args (3))
                     (:leaf "This is a leaf, not a frame.")
                     (:out versioned :version 1 :values (42 t))
                     (:out log :condition "a :CONDITION outcome")
                     (:in log-2)
                     (:out log-2 :nlx nil)
                     (:in external :version :infinity)
                     (:out external :version :infinity
                      :error ("ERROR" "an :ERROR outcome"))))
    ..
    .. (LOG "first arg" 2)
    ..   (VERSIONED 3) v1
    ..     This is a leaf, not a frame.
    ..   => 42, T
    .. =C "a :CONDITION outcome"
    .. (LOG-2)
    .. =X
    .. (EXTERNAL) ext
    .. =E "ERROR" "an :ERROR outcome"
    => ; No value
    ```
    
    The function given as the PRETTIFIER argument formats individual
    events. The above output was produced with PRETTIFY-EVENT. For a
    description of PRETTIFIER's arguments see PRETTIFY-EVENT.

- [function] PRETTIFY-EVENT EVENT DEPTH STREAM

    Write EVENT to STREAM in a somewhat human-friendly format. This
    is the function PPRINT-JOURNAL, PPRINT-EVENTS, and @TRACING use by
    default. In addition to the basic example in PPRINT-EVENTS,
    @DECORATION on events is printed before normal, indented output like
    this:
    
    ```
    (pprint-events '((:leaf "About to sleep" :time "19:57:00" :function "FOO")))
    ..
    .. 19:57:00 FOO: About to sleep
    ```
    
    DEPTH is the nesting level of the EVENT. Top-level events have depth
    0. PRETTIFY-EVENT prints indents the output, after printing the
    decorations, by 2 spaces per depth.

Instead of collecting events and then printing them, events can
be pretty-printed to a stream as they generated. This is
accomplished with @PPRINT-JOURNALS, discussed in detail later, in
the following way:

```
(let ((journal (make-pprint-journal)))
  (with-journaling (:record journal)
    (journaled (foo) "Hello")))
..
.. (FOO)
.. => "Hello"
```

Note that @PPRINT-JOURNALS are not tied to WITH-JOURNALING and are
most often used for @LOGGING and @TRACING.

### Error handling

- [condition] JOURNALING-FAILURE SERIOUS-CONDITION

    Signalled during the dynamic extent of
    WITH-JOURNALING when an error threatens to leave the journaling
    mechanism in an inconsistent state. These include I/O errors
    encountered reading or writing journals by WITH-JOURNALING,
    JOURNALED, LOGGED, WITH-REPLAY-FILTER, SYNC-JOURNAL, but also
    STORAGE-CONDITIONs, assertion failures, and errors calling
    JOURNALED's VALUES and CONDITION function
    arguments. Crucially, this does not apply to non-local exits from
    other code, such as JOURNALED @BLOCKs, whose error handling is
    largely unaltered (see @OUT-EVENTS and @REPLAY-FAILURES).
    
    In general, any @NON-LOCAL-EXIT from critical parts of the code is
    turned into a JOURNALING-FAILURE to protect the integrity of the
    RECORD-JOURNAL. The condition that caused the unwinding is in
    JOURNALING-FAILURE-EMBEDDED-CONDITION, or NIL if it was a pure
    @NON-LOCAL-EXIT like THROW. This is a SERIOUS-CONDITION, not to be
    handled within WITH-JOURNALING.
    
    After a JOURNALING-FAILURE, the journaling mechanism cannot be
    trusted anymore. The REPLAY-JOURNAL might have failed a read and be
    out-of-sync. The RECORD-JOURNAL may have missing events (or even
    half-written events with FILE-JOURNALs without SYNC, see
    @SYNCHRONIZATION-STRATEGIES), and further writes to it would risk
    replayability, which is equivalent to database corruption. Thus,
    upon signalling JOURNALING-FAILURE, JOURNAL-STATE is set to
    
    - :COMPLETED if the journal is in state :RECORDING or :LOGGING and
      the transition to :RECORDING was reflected in storage,
    
    - else it is set to :FAILED.
    
    After a JOURNALING-FAILURE, any further attempt within the affected
    WITH-JOURNALING to use the critical machinery mentioned
    above (JOURNALED, LOGGED, etc) resignals the same journal failure
    condition. As a consequence, the record journal cannot be changed
    and the only way to recover is to leave WITH-JOURNALING. This does
    not affect processing in other threads, which by design cannot write
    to the record journal.
    
    Note that in contrast with JOURNALING-FAILURE and REPLAY-FAILURE,
    which necessitate leaving WITH-JOURNALING to recover from, the other
    conditions - JOURNAL-ERROR, and STREAMLET-ERROR - are subclasses of
    [ERROR][condition] as the their handling need not be so
    heavy-handed.

- [reader] JOURNALING-FAILURE-EMBEDDED-CONDITION JOURNALING-FAILURE (:EMBEDDED-CONDITION)

- [condition] RECORD-UNEXPECTED-OUTCOME

    Signalled (with SIGNAL: this is not an
    [ERROR][condition]) by JOURNALED when a VERSIONED-EVENT or an
    EXTERNAL-EVENT had an UNEXPECTED-OUTCOME while in JOURNAL-STATE
    :RECORDING. Upon signalling this condition, JOURNAL-STATE is set to
    :LOGGING, thus no more events can be recorded that will affect
    replay of the journal being recorded. The event that triggered this
    condition is recorded in state :LOGGING, with its version
    downgraded. Since @REPLAY (except INVOKED) is built on the
    assumption that control flow is deterministic, an unexpected outcome
    is significant because it makes this assumption to hold unlikely.
    
    Also see REPLAY-UNEXPECTED-OUTCOME.

- [condition] DATA-EVENT-LOSSAGE JOURNALING-FAILURE

    Signalled when a DATA-EVENT is about to be recorded
    in JOURNAL-STATE :MISMATCHED or :LOGGING. Since the data event will
    not be replayed that constitutes data loss.

- [condition] JOURNAL-ERROR ERROR

    Signalled by WITH-JOURNALING, WITH-BUNDLE and by
    @LOG-RECORD. It is also signalled by the low-level streamlet
    interface (see @STREAMLETS-REFERENCE).

- [condition] END-OF-JOURNAL JOURNAL-ERROR

    This might be signalled by the replay mechanism if
    WITH-JOURNALING's REPLAY-EOJ-ERROR-P is true. Unlike
    REPLAY-FAILUREs, this does not affect JOURNAL-STATE of
    RECORD-JOURNAL. At a lower level, it is signalled by READ-EVENT upon
    reading past the end of the JOURNAL if EOJ-ERROR-P.

## Logging

Before we get into the details, here is a self contained example
that demonstrates typical use.

```
(defvar *communication-log* nil)
(defvar *logic-log* nil)
(defvar *logic-log-level* 0)

(defun call-with-connection (port fn)
  (framed (call-with-connection :log-record *communication-log*
                                :args `(,port))
    (funcall fn)))

(defun fetch-data (key)
  (let ((value 42))
    (logged ((and (<= 1 *logic-log-level*) *logic-log*))
      "The value of ~S is ~S." key value)
    value))

(defun init-logging (&key (logic-log-level 1))
  (let* ((stream (open "/tmp/xxx.log"
                       :direction :output
                       :if-does-not-exist :create
                       :if-exists :append))
         (journal (make-pprint-journal
                   :stream (make-broadcast-stream
                            (make-synonym-stream '*standard-output*)
                            stream))))
    (setq *communication-log* journal)
    (setq *logic-log* journal)
    (setq *logic-log-level* logic-log-level)))

(init-logging)

(call-with-connection 8080 (lambda () (fetch-data :foo)))
..
.. (CALL-WITH-CONNECTION 8080)
..   The value of :FOO is 42.
.. => 42
=> 42

(setq *logic-log-level* 0)
(call-with-connection 8080 (lambda () (fetch-data :foo)))
..
.. (CALL-WITH-CONNECTION 8080)
.. => 42
=> 42

(ignore-errors
  (call-with-connection 8080 (lambda () (error "Something unexpected."))))
..
.. (CALL-WITH-CONNECTION 8080)
.. =E "SIMPLE-ERROR" "Something unexpected."
```

##### Default to muffling

Imagine a utility library called glib.

```
(defvar *glib-log* nil)
(defvar *patience* 1)

(defun sl33p (seconds)
  (logged (*glib-log*) "Sleeping for ~As." seconds)
  (sleep (* *patience* seconds)))
```

Glib follows the recommendation to have a special variable globally
bound to NIL by default. The value of `*GLIB-LOG*` is the journal to
which glib log messages will be routed. Since it's NIL, the log
messages are muffled, and to record any log message, we need to
change its value.

##### Routing logs to a journal

Let's send the logs to a PPRINT-JOURNAL:

```
(setq *glib-log* (make-pprint-journal
                  :log-decorator (make-log-decorator :time t)))
(sl33p 0.01)
..
.. 2020-08-31T12:45:23.827172+02:00: Sleeping for 0.01s.
```

That's a bit too wordy. For this tutorial, let's stick to less
verbose output:

```
(setq *glib-log* (make-pprint-journal))
(sl33p 0.01)
..
.. Sleeping for 0.01s.
```

To log to a file:

```
(setq *glib-log* (make-pprint-journal
                  :stream (open "/tmp/glib.log"
                                :direction :output
                                :if-does-not-exist :create
                                :if-exists :append)))
```

##### Capturing logs in WITH-JOURNALING's RECORD-JOURNAL

If we were recording a journal for replay and wanted to include glib
logs in the journal, we would do something like this:

```
(with-journaling (:record t)
  (let ((*glib-log* :record))
    (sl33p 0.01)
    (journaled (non-glib-stuff :version 1)))
  (list-events))
=> ((:LEAF "Sleeping for 0.01s.")
    (:IN NON-GLIB-STUFF :VERSION 1)
    (:OUT NON-GLIB-STUFF :VERSION 1 :VALUES (NIL)))
```

We could even `(SETQ *GLIB-LOG* :RECORD)` to make it so that glib
messages are included by default in the RECORD-JOURNAL. In this
example, the special `*GLIB-LOG*` acts like a log category for all
the log messages of the glib library (currently one).

##### Rerouting a category

Next, we route `*GLIB-LOG*` to wherever `*APP-LOG*` is pointing by
binding `*GLIB-LOG*` *to the symbol* `*APP-LOG*` (see @LOG-RECORD).

```
(defvar *app-log* nil)

(let ((*glib-log* '*app-log*))
  (setq *app-log* nil)
  (logged (*glib-log*) "This is not written anywhere.")
  (setq *app-log* (make-pprint-journal :pretty nil))
  (sl33p 0.01))
..
.. (:LEAF "Sleeping for 0.01s.")
```

Note how pretty-printing was turned off and we see the LEAF-EVENT
generated by LOGGED in its raw plist form.

##### Conditional routing

Finally, to make routing decisions conditional we need to change
`SL33P`:

```
(defvar *glib-log-level* 1)

(defun sl33p (seconds)
  (logged ((and (<= 2 *glib-log-level*) *glib-log*))
          "Sleeping for ~As." (* *patience* seconds))
  (sleep seconds))

;;; Check that it all works:
(let ((*glib-log-level* 1)
      (*glib-log* (make-pprint-journal)))
  (format t "~%With log-level ~A" *glib-log-level*)
  (sl33p 0.01)
  (setq *glib-log-level* 2)
  (format t "~%With log-level ~A" *glib-log-level*)
  (sl33p 0.01))
..
.. With log-level 1
.. With log-level 2
.. Sleeping for 0.01s.
```

##### Nested log contexts

LOGGED is for single messages. JOURNALED, or in this example FRAMED,
can provide nested context:

```
(defun callv (var value symbol &rest args)
  "Call SYMBOL-FUNCTION of SYMBOL with VAR dynamically bound to VALUE."
  (framed ("glib:callv" :log-record *glib-log*
                        :args `(,var ,value ,symbol ,@args))
    (progv (list var) (list value)
      (apply (symbol-function symbol) args))))

(callv '*print-base* 2 'print 10)
..
.. ("glib:callv" *PRINT-BASE* 2 PRINT 10)
.. 1010 
.. => 10
=> 10

(let ((*glib-log-level* 2))
  (callv '*patience* 7 'sl33p 0.01))
..
.. ("glib:callv" *PATIENCE* 7 SL33P 0.01)
..   Sleeping for 0.07s.
.. => NIL
```


### Customizing logs

Customizing the output format is possible if we don't necessarily
expect to be able to read the logs back programmatically. There is
an example in @TRACING, which is built on @PPRINT-JOURNALS.

Here, we discuss how to make logs more informative.

- [glossary-term] decoration

    JOURNAL-LOG-DECORATOR adds additional data to LOG-EVENTs as they
    are written to the journal. This data is called decoration and it is
    to capture the context in which the event was triggered. See
    MAKE-LOG-DECORATOR for a typical example. Decorations, since they
    can be on LOG-EVENTs only, do not affect @REPLAY. Decorations are
    most often used with @PRETTY-PRINTING.

- [accessor] JOURNAL-LOG-DECORATOR JOURNAL (:LOG-DECORATOR = NIL)

    If non-NIL, a function to add @DECORATION to
    LOG-EVENTs before they are written to a journal. The only allowed
    transformation is to *append* a plist to the event, which is a
    plist itself. The keys can be anything.

- [function] MAKE-LOG-DECORATOR &KEY THREAD TIME REAL-TIME RUN-TIME

    Return a function suitable as JOURNAL-LOG-DECORATOR that may add
    the name of the thread, a timestamp, the internal real-time or
    run-time (both in seconds) to events. THREAD, TIME, REAL-TIME and
    RUN-TIME are @BOOLEAN-VALUED-SYMBOLs.
    
    ```
    (funcall (make-log-decorator :thread t :time t :real-time t :run-time t)
             (make-leaf-event :foo))
    => (:LEAF :FOO :TIME "2020-08-31T13:38:58.129178+02:00"
        :REAL-TIME 66328.82 :RUN-TIME 98.663 :THREAD "worker")
    ```


### Log record

WITH-JOURNALING and WITH-BUNDLE control replaying and recording
within their dynamic extent, which is rather a necessity because
@REPLAY needs to read the events in the same order as the JOURNALED
@BLOCKs are being executed. However, LOG-EVENTs do not affect replay
so we can allow more flexibility in routing them.

The LOG-RECORD argument of JOURNALED and LOGGED controls where
LOG-EVENTs are written both within WITH-JOURNALING and without. The
algorithm to determine the target journal is this:

1. If LOG-RECORD is :RECORD, then `(RECORD-JOURNAL)` is returned.

2. If LOG-RECORD is NIL, then it is returned.

3. If LOG-RECORD is a JOURNAL, then it is returned.

4. If LOG-RECORD is symbol (other than NIL), then the SYMBOL-VALUE
   of that symbol is assigned to LOG-RECORD and we go to step 1.

If the return value is NIL, then the event will not be written
anywhere, else it is written to the journal returned.

This is reminiscent of SYNONYM-STREAMs, also in that it is possible
end up in cycles in the resolution. For this reason, the algorithm
stop with a JOURNAL-ERROR after 100 iterations.

##### Interactions

Events may be written to LOG-RECORD even without an enclosing
WITH-JOURNALING, and it does not affect the JOURNAL-STATE. However,
it is a JOURNAL-ERROR to write to a :COMPLETED journal (see
JOURNAL-STATE).

When multiple threads log to the same journal it is guaranteed that
individual events are written atomically, but frames from different
threads do not necessarily nest. To keep the log informative, the
name of thread may be added to the events as @DECORATION.

Also see notes on thread @SAFETY.

### Logging with LEAF-EVENTs

- [macro] LOGGED (&OPTIONAL (LOG-RECORD :RECORD)) FORMAT-CONTROL &REST FORMAT-ARGS

    LOGGED creates a single LEAF-EVENT whose name is the string
    constructed by FORMAT. For example:
    
    ```
    (with-journaling (:record t)
      (logged () "Hello, ~A." "world")
      (list-events))
    => ((:LEAF "Hello, world."))
    ```
    
    LEAF-EVENTs are LOG-EVENTs with no separate in- and out-events. They
    have an EVENT-NAME and no other properties. Use LOGGED for
    point-in-time textual log messages, and JOURNALED with VERSION
    NIL (i.e. FRAMED) to provide context.
    
    Also see @LOG-RECORD.

## Tracing

JTRACE behaves similarly to CL:TRACE, but deals @NON-LOCAL-EXITs
gracefully.

##### Basic tracing

```
(defun foo (x)
  (sleep 0.12)
  (1+ x))

(defun bar (x)
  (foo (+ x 2))
  (error "xxx"))

(jtrace foo bar)

(ignore-errors (bar 1))
..
.. (BAR 1)
..   (FOO 3)
..   => 4
.. =E "SIMPLE-ERROR" "xxx"
```

##### Log-like output

It can also include the name of the originating thread and
timestamps in the output:

```
(let ((*trace-thread* t)
      (*trace-time* t))
  (ignore-errors (bar 1)))
..
.. 2020-09-02T19:58:19.415204+02:00 worker: (BAR 1)
.. 2020-09-02T19:58:19.415547+02:00 worker:   (FOO 3)
.. 2020-09-02T19:58:19.535766+02:00 worker:   => 4
.. 2020-09-02T19:58:19.535908+02:00 worker: =E "SIMPLE-ERROR" "xxx"
```

##### Profiler-like output

```
(let ((*trace-real-time* t)
      (*trace-run-time* t))
  (ignore-errors (bar 1)))
..
.. #16735.736 !68.368: (BAR 1)
.. #16735.736 !68.369:   (FOO 3)
.. #16735.857 !68.369:   => 4
.. #16735.857 !68.369: =E "SIMPLE-ERROR" "xxx"
```

##### Customizing the content and the format

If these options are insufficient, the content and the format of the
trace can be customized:

```
(let ((*trace-journal*
       (make-pprint-journal :pretty '*trace-pretty*
                     :prettifier (lambda (event depth stream)
                                   (format stream "~%Depth: ~A, event: ~S"
                                           depth event))
                     :stream (make-synonym-stream '*error-output*)
                     :log-decorator (lambda (event)
                                      (append event '(:custom 7))))))
  (ignore-errors (bar 1)))
..
.. Depth: 0, event: (:IN BAR :ARGS (1) :CUSTOM 7)
.. Depth: 1, event: (:IN FOO :ARGS (3) :CUSTOM 7)
.. Depth: 1, event: (:OUT FOO :VALUES (4) :CUSTOM 7)
.. Depth: 0, event: (:OUT BAR :ERROR ("SIMPLE-ERROR" "xxx") :CUSTOM 7)
```

In the above, *TRACE-JOURNAL* was bound locally to keep the example
from wrecking the global default, but the same effect could be
achieved by `SETF`ing PPRINT-JOURNAL-PRETTIFIER,
PPRINT-JOURNAL-STREAM and JOURNAL-LOG-DECORATOR.

- [macro] JTRACE &REST NAMES

    Like CL:TRACE, JTRACE takes a list of symbols. When functions
    denoted by those NAMES are invoked, their names, arguments and
    outcomes are printed in human readable form to *TRACE-OUTPUT*. These
    values may not be @READABLE, JTRACE does not care.
    
    The format of the output is the same as that of PPRINT-EVENTS.
    Behind the scenes, JTRACE encapsulates the global functions with
    NAMES in wrapper that behaves as if `FOO` in the example above was
    defined like this:
    
    ```
    (defun foo (x)
      (framed (foo :args `(,x) :log-record *trace-journal*)
        (1+ x)))
    ```
    
    If JTRACE is invoked with no arguments, it returns the list of
    symbols currently traced.
    
    On Lisps other than SBCL, where a function encapsulation facility is
    not available or it is not used by Journal, JTRACE simply sets
    SYMBOL-FUNCTION. This solution loses the tracing encapsulation when
    the function is recompiled. On these platforms, `(JTRACE)` also
    retraces all functions that should be traced, but aren't.
    
    The main advantage of JTRACE over CL:TRACE is the ability to trace
    errors, not just normal return values. As it is built on JOURNALED,
    it can also detect - somewhat heuristically - THROWs and similar.

- [macro] JUNTRACE &REST NAMES

    Like CL:UNTRACE, JUNTRACE makes it so that the global functions
    denoted by the symbols NAMES are no longer traced by JTRACE. When
    invoked with no arguments, it untraces all traced functions.

- [variable] *TRACE-PRETTY* T

    If *TRACE-PRETTY* is true, then JTRACE produces output like
    PPRINT-EVENTS, else it's like PRINT-EVENTS.

- [variable] *TRACE-THREAD* NIL

    Controls whether to decorate the trace with the name of the
    originating thread. See MAKE-LOG-DECORATOR.

- [variable] *TRACE-TIME* NIL

    Controls whether to decorate the trace with a timestamp. See
    MAKE-LOG-DECORATOR.

- [variable] *TRACE-REAL-TIME* NIL

    Controls whether to decorate the trace with the internal real-time.
    See MAKE-LOG-DECORATOR.

- [variable] *TRACE-RUN-TIME* NIL

    Controls whether to decorate the trace with the internal run-time.
    See MAKE-LOG-DECORATOR.

- [variable] *TRACE-JOURNAL* #\

    The JOURNAL where JTRACE writes LOG-EVENTs. By default it is a
    PPRINT-JOURNAL that sets up a SYNONYM-STREAM to *TRACE-OUTPUT* and
    sends its output there. It pays attention to *TRACE-PRETTY*, and its
    log decorator is affected by *TRACE-TIME* and *TRACE-THREAD*.
    However, by changing JOURNAL-LOG-DECORATOR and
    PPRINT-JOURNAL-PRETTIFIER content and output can be customized.

### Slime integration

[Slime](https://common-lisp.net/project/slime/) by default binds
`C-c C-t` to toggling CL:TRACE. To integrate JTRACE into Slime, add
the following ELisp snippet to your Emacs initialization file or
load `src/journal.el`:

```elisp
(defun slime-toggle-jtrace-fdefinition (spec)
  "Toggle JTRACE."
  (interactive (list (slime-read-from-minibuffer
                      "j(un)trace: " (slime-symbol-at-point))))
  (message "%s" (slime-eval
                 ;; Silently fail if Journal is not loaded.
                 `(cl:when (cl:find-package :journal)
                           (cl:funcall
                            (cl:find-symbol
                             (cl:symbol-name :swank-toggle-jtrace) :journal)
                            ,spec)))))

(define-key slime-mode-map (kbd "C-c C-j")
  'slime-toggle-jtrace-fdefinition)

(define-key slime-repl-mode-map (kbd "C-c C-j")
  'slime-toggle-jtrace-fdefinition)
```

Since JTRACE lacks some features of CL:TRACE, most notably that of
tracing non-global functions, it is assigned a separate binding,
`C-c C-j`.

## Replay

During replay, code is executed normally with special rules for
@BLOCKs. There are two modes for dealing with blocks: replaying the
code or replaying the outcome. When code is replayed, upon entering
and leaving a block, the events generated are matched to events read
from the journal being replayed. If the events don't match, a
REPLAY-FAILURE is signaled which marks the record journal as having
failed the replay. This is intended to make sure that the state of
the program during the replay matches the state at the time of
recording. In the other mode, when the outcome is replayed, a block
may not be executed at all, but its recorded outcome is
reproduced (e.g. the recorded return values are returned).

Replay can be only be initiated with WITH-JOURNALING (or its close
kin WITH-BUNDLE). After the per-event processing described below,
when WITH-JOURNALING finishes, it might signal REPLAY-INCOMPLETE if
there are unprocessed non-log events left in the replay journal.

Replay is deemed successful or failed depending on whether all
events are replayed from the replay journal without a
REPLAY-FAILURE. A journal that records events from a successful
replay can be used in place of the journal that was replayed, and so
on. The logic of replacing journals with their successful replays is
automated by @BUNDLES. WITH-JOURNALING does not allow replay from
journals that were failed replays themselves. The mechanism, in
terms of which tracking success and failure of replays is
implemented, revolves around [JOURNAL-STATE][type] and
[EVENT-VERSION][type]s, which we discuss next.

- [type] JOURNAL-STATE

    JOURNAL's state, with respect to replay, is updated during
    WITH-JOURNALING. This possible states are:
    
    - **:NEW**: This journal was just created, but never recorded to.
    
    - **:REPLAYING**: Replaying events has started, some events may have
      been replayed successfuly, but there are more, non-log events to
      replay.
    
    - **:MISMATCHED**: There was a REPLAY-FAILURE. In this state,
      VERSIONED-EVENTs generated are downgraded to LOG-EVENTs,
      EXTERNAL-EVENTs and INVOKED trigger a DATA-EVENT-LOSSAGE.
    
    - **:RECORDING**: All events from the replay journal were
      successfully replayed and now new events are being recorded
      without being matched to the replay journal.
    
    - **:LOGGING**: There was a RECORD-UNEXPECTED-OUTCOME. In this
      state, VERSIONED-EVENTs generated are downgraded to LOG-EVENTs,
      EXTERNAL-EVENTs and INVOKED trigger a DATA-EVENT-LOSSAGE.
    
    - **:FAILED**: The journal is to be discarded. It encountered a
      JOURNALING-FAILURE or a REPLAY-FAILURE without completing the
      replay and reaching :RECORDING.
    
    - **:COMPLETED**: All events were successfully replayed and
      WITH-JOURNALING finished or a JOURNALING-FAILURE occurred while
      :RECORDING or :LOGGING.
    
    The state transitions are:
    
        :NEW                -> :REPLAYING  (on entering WITH-JOURNALING)
        :REPLAYING          -> :MISMATCHED (on REPLAY-FAILURE)
        :REPLAYING          -> :FAILED     (on REPLAY-INCOMPLETE)
        :REPLAYING          -> :FAILED     (on JOURNALING-FAILURE)
        :REPLAYING          -> :RECORDING  (on successfully replaying all events)
        :MISMATCHED         -> :FAILED     (on leaving WITH-JOURNALING)
        :RECORDING          -> :LOGGING    (on RECORD-UNEXPECTED-OUTCOME)
        :RECORDING/:LOGGING -> :COMPLETED  (on leaving WITH-JOURNALING)
        :RECORDING/:LOGGING -> :COMPLETED  (on JOURNALING-FAILURE)
    
    :NEW is the starting state. It is a JOURNAL-ERROR to attempt to
    write to journals in :COMPLETED. Note that once in :RECORDING, the
    only possible terminal state is :COMPLETED.

### Journaled for replay

The following arguments of JOURNALED control behaviour under replay.

- VERSION: see [EVENT-VERSION][type] below.

- INSERTABLE controls whether VERSIONED-EVENTs and EXTERNAL-EVENTs
  may be replayed with the *insert* replay strategy (see
  @THE-REPLAY-STRATEGY). Does not affect LOG-EVENTs, that are always
  \_insert\_ed. Note that inserting EXTERNAL-EVENTs while :REPLAYING
  is often not meaningful (e.g. asking the user for input may lead
  to a REPLAY-FAILURE). See PEEK-REPLAY-EVENT for an example on how
  to properly insert these kinds of EXTERNAL-EVENTs.

- REPLAY-VALUES, a function or NIL, may be called with EVENT-OUTCOME
  when replaying and :VERSION :INFINITY. NIL is equivalent to
  VALUES-LIST. See `VALUES<-` for an example.

- REPLAY-CONDITION, a function or NIL, may be called with
  EVENT-OUTCOME (the return value of the function provided as
  :CONDITION) when replaying and :VERSION is :INFINITY. NIL is
  equivalent to the ERROR function. Replaying conditions is
  cumbersome and best avoided.


- [variable] *FORCE-INSERTABLE* NIL

    The default value of the INSERTABLE argument of JOURNALED for
    VERSIONED-EVENTs. Binding this to T allows en-masse structural
    upgrades in combination with WITH-REPLAY-FILTER. Does not affect
    EXTERNAL-EVENTs. See @UPGRADES-AND-REPLAY.

- [type] EVENT-VERSION

    An event's version is either NIL, a positive fixnum, or :INFINITY,
    which correspond to LOG-EVENTs, VERSIONED-EVENTs, and
    EXTERNAL-EVENTs, respectively, and have an increasingly strict
    behaviour with regards to @REPLAY. All EVENTs have versions. The
    versions of the in- and out-events belonging to the same @FRAME are
    the same.

- [type] LOG-EVENT

    Events with [EVENT-VERSION][type] NIL called log events. During @REPLAY,
    they are never matched to events from the replay journal, and log
    events in the replay do not affect events being recorded either.
    These properties allow log events to be recorded in arbitrary
    journals with JOURNALED's LOG-RECORD argument. The convenience macro
    FRAMED is creating frames of log-events, while the LOGGED generates
    a log-event that's a LEAF-EVENT.

- [type] VERSIONED-EVENT

    Events with a positive integer [EVENT-VERSION][type] are called
    versioned events. In @REPLAY, they undergo consistency checks unlike
    LOG-EVENTs, but the rules for them are less strict than for
    EXTERNAL-EVENTs. In particular, higher versions are always
    considered compatible with lower versions, they become an *upgrade*
    in terms of the @THE-REPLAY-STRATEGY, and versioned events can be
    inserted into the record without a corresponding REPLAY-EVENT with
    JOURNALED's INSERTABLE.
    
    If a VERSIONED-EVENT has an UNEXPECTED-OUTCOME,
    RECORD-UNEXPECTED-OUTCOME is signalled.

- [type] EXTERNAL-EVENT

    Events with [EVENT-VERSION][type] :INFINITY are called external events.
    They are like VERSIONED-EVENTs whose version was bumped all the way
    to infinity, which rules out easy, non-matching upgrades. Also, they
    are never inserted to the record without a matching replay
    event (see @THE-REPLAY-STRATEGY).
    
    In return for these restrictions, external events can be replayed
    without running the corresponding @BLOCK (see
    @REPLAYING-THE-OUTCOME). This allows their out-event variety, called
    DATA-EVENTs, to be non-deterministic. Data events play a crucial
    role in @PERSISTENCE.
    
    If an EXTERNAL-EVENT has an UNEXPECTED-OUTCOME,
    RECORD-UNEXPECTED-OUTCOME is signalled.

Built on top of JOURNALED, the macros below record a pair of
@IN-EVENTS and @OUT-EVENTS, but differ in how they are replayed and
the requirements on their @BLOCKs. The following table names the
type of EVENT produced (`Event`), how @IN-EVENTS are
replayed (`In-e.`), whether the block is always run (`Run`), how
@OUT-EVENTS are replayed (`Out-e.`), whether the block must be
deterministic (`Det`) or side-effect free (`SEF`).

    |          | Event     | In-e.  | Run | Out-e. | Det | SEF |
    |----------+-----------+--------+-----+--------+-----+-----|
    | FRAMED   | log       | skip   | y   | skip   | n   | n   |
    | CHECKED  | versioned | match  | y   | match  | y   | n   |
    | REPLAYED | external  | match  | n   | replay | n   | y   |
    | INVOKED  | versioned | replay | y   | match  | y   | n   |

Note that the replay-replay combination is not implemented because
there is nowhere to return values from replay-triggered functions.

- [macro] FRAMED (NAME &KEY LOG-RECORD ARGS VALUES CONDITION) &BODY BODY

    A wrapper around JOURNALED to produce @FRAMEs of LOG-EVENTs. That
    is, VERSION is always NIL, and some irrelevant arguments are
    omitted. The related LOGGED creates a single LEAF-EVENT.
    
    With FRAMED, BODY is always run and no REPLAY-FAILUREs are
    triggered. BODY is not required to be deterministic and it may have
    side-effects.

- [macro] CHECKED (NAME &KEY (VERSION 1) ARGS VALUES CONDITION INSERTABLE) &BODY BODY

    A wrapper around JOURNALED to produce @FRAMEs of VERSIONED-EVENTs.
    VERSION defaults to 1. CHECKED is for ensuring that supposedly
    deterministic processing does not veer off the replay.
    
    With CHECKED, BODY - which must be deterministic - is always run and
    REPLAY-FAILUREs are triggered when the events generated do not match
    the events in the replay journal. BODY may have side-effects.
    
    For further discussion of determinism, see REPLAYED.

- [macro] REPLAYED (NAME &KEY ARGS VALUES CONDITION INSERTABLE REPLAY-VALUES REPLAY-CONDITION) &BODY BODY

    A wrapper around JOURNALED to produce @FRAMEs of EXTERNAL-EVENTs.
    VERSION is :INFINITY. REPLAYED is for primarily for marking and
    isolating non-deterministic processing.
    
    With REPLAYED, the IN-EVENT is checked for consistency with the
    replay (as with CHECKED), but BODY is not run (assuming it has a
    recorded EXPECTED-OUTCOME) and the outcome in the OUT-EVENT is
    reproduced (see @REPLAYING-THE-OUTCOME). For this scheme to work,
    REPLAYED requires its BODY to be side-effect free, but it may be
    non-deterministic.

- [glossary-term] Invoked

    Invoked refers to functions and blocks defined by DEFINE-INVOKED or
    FLET-INVOKED. Invoked frames may be recorded in response to
    asynchronous events, and at replay the presence of its in-event
    triggers the execution of the function associated with the name of
    the event.
    
    On one hand, FRAMED, CHECKED, REPLAYED or plain JOURNALED have
    @IN-EVENTS that are always predictable from the code and the
    preceding events. The control flow - on the level of recorded frames
    - is deterministic in this sense. On the other hand, Invoked encodes
    in its IN-EVENT what function to call next, introducing
    non-deterministic control flow.
    
    By letting events choose the code to run, Invoked resembles typical
    [Event Sourcing][event-sourcing] frameworks. When Invoked is used
    exclusively, the journal becomes a sequence of events. In contrast,
    JOURNALED and its wrappers put code first, and the journal will be a
    projection of the call tree.

- [macro] DEFINE-INVOKED FUNCTION-NAME ARGS (NAME &KEY (VERSION 1) INSERTABLE) &BODY BODY

    DEFINE-INVOKED is intended for recording asynchronous function
    invocations like event or signal handlers. It defines a function
    that records VERSIONED-EVENTs with ARGS set to the actual arguments.
    At replay, it is invoked whenever the recorded IN-EVENT becomes the
    REPLAY-EVENT.
    
    DEFUN and CHECKED rolled into one, DEFINE-INVOKED defines a
    top-level function with FUNCTION-NAME and ARGS (only simple
    positional arguments are allowed) and wraps CHECKED with NAME, the
    same ARGS and INSERTABLE around BODY. Whenever an IN-EVENT becomes
    the REPLAY-EVENT and it has a DEFINE-INVOKED defined with the name
    of the event, then FUNCTION-NAME is invoked with EVENT-ARGS.
    
    While BODY's return values are recorded as usual, the defined
    function returns no values to make it less likely to affect control
    flow in a way that's not possible to reproduce when the function is
    called by the replay mechanism.
    
    ```
    (defvar *state*)
    
    (define-invoked foo (x) ("foo")
      (setq *state* (1+ x)))
    
    (define-invoked bar (x) ("bar")
      (setq *state* (+ 2 x)))
    
    (if (zerop (random 2))
        (foo 0)
        (bar 1))
    ```
    
    The above can be alternatively implemented with REPLAYED explicitly
    encapsulating the non-determinism:
    
    ```
    (let ((x (replayed (choose) (random 2))))
      (if (zerop x)
          (checked (foo :args `(,x))
            (setq *state* (1+ x)))
          (checked (bar :args `(,x))
            (setq *state* (+ 2 x)))))
    ```


- [macro] FLET-INVOKED DEFINITIONS &BODY BODY

    Like DEFINE-INVOKED, but with FLET instead of DEFUN. The event
    name and the function are associated in the dynamic extent of BODY.
    WITH-JOURNALING does not change the bindings. The example in
    DEFINE-INVOKED can be rewritten as:
    
    ```
    (let ((state nil))
      (flet-invoked ((foo (x) ("foo")
                       (setq state (1+ x)))
                     (bar (x) ("bar")
                       (setq state (+ 2 x))))
        (if (zerop (random 2))
          (foo 0)
          (bar 1))))
    ```


### Bundles

Consider replaying the same code repeatedly, hoping to make
progress in the processing. Maybe based on the availability of
external input, the code may error out. After each run, one has to
decide whether to keep the journal just recorded or stick with the
replay journal. A typical solution to this would look like this:

```
(let ((record nil))
  (loop
    (setq record (make-in-memory-journal))
    (with-journaling (:record record :replay replay)
      ...)
    (when (and
           ;; RECORD is a valid replay of REPLAY ...
           (eq (journal-state record) :completed)
           ;; ... and is also significantly different from it ...
           (journal-diverged-p record))
      ;; so use it for future replays.
      (setq replay record))))
```

This is pretty much what bundles automate. The above becomes:

```
(let ((bundle (make-in-memory-bundle)))
  (loop
    (with-bundle (bundle)
      ...)))
```

With FILE-JOURNALs, the motivating example above would be even more
complicated, but FILE-BUNDLEs work the same way as
IN-MEMORY-BUNDLEs.

- [macro] WITH-BUNDLE (BUNDLE) &BODY BODY

    This is like WITH-JOURNALING where the REPLAY-JOURNAL is the last
    successfully completed one in BUNDLE, and the RECORD-JOURNAL is a
    new one created in BUNDLE. When WITH-BUNDLE finishes, the record
    journal is in JOURNAL-STATE :FAILED or :COMPLETED.
    
    To avoid accumulating useless data, the new record is immediately
    deleted when WITH-BUNDLE finishes if it has not diverged from the
    replay journal (see JOURNAL-DIVERGENT-P). Because :FAILED journals
    are always divergent in this sense, they are deleted instead based
    on whether there is already a previous failed journal in the bundle
    and the new record is identical to that journal (see
    IDENTICAL-JOURNALS-P).
    
    It is a JOURNAL-ERROR to have concurrent or nested WITH-BUNDLEs on
    the same bundle.

### The replay strategy

The replay process for both @IN-EVENTS and @OUT-EVENTS starts by
determining how the generated event (the *new* event from now on)
shall be replayed. Roughly, the decision is based on the NAME and
VERSION of the new event and the REPLAY-EVENT (the next event to be
read from the replay). There are four possible strategies:

- **match**: A new in-event must match the replay event in its ARGS.
  See @MATCHING-IN-EVENTS for details. A new out-event must match
  the replay event's EXIT and OUTCOME, see @MATCHING-OUT-EVENTS.

- **upgrade**: The new event is not matched to any replay event, but
  an event is consumed from the replay journal. This happens if next
  new event has the same name as the replay event, but its version
  is higher.

- **insert**: The new event is not matched to any replay event, and
  no events are consumed from the replay journal, which may be
  empty. This is always the case for new LOG-EVENTs and when there
  are no more events to read from the replay journal (unless
  REPLAY-EOJ-ERROR-P). For VERSIONED-EVENTs, it is affected by
  setting JOURNALED's INSERTABLE to true (see
  @JOURNALED-FOR-REPLAY).

    The out-event's strategy is always *insert* if the strategy for
    the corresponding in-event was *insert*.

- Also, END-OF-JOURNAL, REPLAY-NAME-MISMATCH and
  REPLAY-VERSION-DOWNGRADE may be signalled. See the algorithm below
  details.

The strategy is determined by the following algorithm, invoked
whenever an event is generated by a journaled @BLOCK:

1. Log events are not matched to the replay. If the new event is a
   log event or a REPLAY-FAILURE has been signalled before (i.e. the
   record journal's JOURNAL-STATE is :MISMATCHED), then **insert**
   is returned.

2. Else, log events to be read in the replay journal are skipped,
   and the next unread, non-log event is peeked at (without
   advancing the replay journal).

    - **end of replay**: If there are no replay events left, then:

        - If REPLAY-EOJ-ERROR-P is NIL in WITH-JOURNALING (the
          default), **insert** is returned.

        - If REPLAY-EOJ-ERROR-P is true, then **`END-OF-JOURNAL`**
          is signalled.

    - **mismatched name**: Else, if the next unread replay event's
      name is not EQUAL to the name of the new event, then:

        - For VERSIONED-EVENTs, **REPLAY-NAME-MISMATCH** is
          signalled if INSERTABLE is NIL, else **insert** is
          returned.

        - For EXTERNAL-EVENTs, **REPLAY-NAME-MISMATCH** is
          signalled.

    - **matching name**: Else, if the name of the next unread event
      in the replay journal is EQUAL to the name of new event, then
      it is chosen as the *replay* event.

        - If the replay event's version is higher than the new
          event's version, then **REPLAY-VERSION-DOWNGRADE** is
          signalled.

        - If the two versions are equal, then **match** is returned.

        - If the new event's version is higher, then **upgrade** is
          returned.

        Where :INFINITY is considered higher than any integer and
        equal to itself.

In summary:

     | new event | end-of-replay     | mismatched name   | matching name |
     |-----------+-------------------+-------------------+---------------|
     | Log       | insert            | insert            | insert        |
     | Versioned | insert/eoj-error  | insert/name-error | match-version |
     | External  | insert/eoj-error  | insert/name-error | match-version |

Version matching (`match-version` above) is based which event has a
higher version:

     | replay event    | =     | new event |
     |-----------------+-------+-----------|
     | downgrade-error | match | upgrade   |


- [glossary-term] replay event

    The replay event is the next event to be read from REPLAY-JOURNAL
    which is not to be skipped. There may be no replay event if there
    are no more unread events in the replay journal.
    
    An event in the replay journal is skipped if it is a LOG-EVENT or
    there is a WITH-REPLAY-FILTER with a matching :SKIP. If :SKIP is in
    effect, the replay event may be indeterminate.
    
    Events from the replay journal are read when they are `:MATCH`ed or
    `:UPGRADE`d (see @THE-REPLAY-STRATEGY), when nested events are
    echoed while @REPLAYING-THE-OUTCOME, or when there is an INVOKED
    defined with the same name as the replay event.
    
    The replay event is available via PEEK-REPLAY-EVENT.

### Matching in-events

If the replay strategy is *match*, then, for in-events, the
matching process continues like this:

- If the [EVENT-ARGS][] are not EQUAL, then **`REPLAY-ARGS-MISMATCH`**
  signalled.

- At this point, two things might happen:

    - For VERSIONED-EVENTs, the @BLOCK will be executed as normal
      and its outcome will be matched to the REPLAY-EVENT (see
      @MATCHING-OUT-EVENTS).

    - For EXTERNAL-EVENTs, the corresponding replay OUT-EVENT is
      looked at. If there is one, meaning that the frame finished
      with an EXPECTED-OUTCOME, then its outcome will be
      replayed (see @REPLAYING-THE-OUTCOME). If the OUT-EVENT is
      missing, then EXTERNAL-EVENTs behave like VERSIONED-EVENTs,
      and the @BLOCK is executed.


#### Replaying the outcome

So, if an in-event is triggered that matches the replay,
EVENT-VERSION is :INFINITY, then normal execution is altered in the
following manner:

- The journaled @BLOCK is not executed.

- To keep execution and the replay journal in sync, events of frames
  nested in the current one are skipped over in the replay journal.

- All events (including LOG-EVENTs) skipped over are echoed to the
  record journal. This serves to keep a trail of what happened
  during the original recording. Note that functions corresponding
  to INVOKED frames are called when their IN-EVENT is skipped over.

- The out-event corresponding to the in-event being processed is
  then read from the replay journal and is recorded again (to allow
  recording to function properly).

To be able to reproduce the outcome in the replay journal, some
assistance may be required from REPLAY-VALUES and REPLAY-CONDITION:

- If the REPLAY-EVENT has normal return (i.e. EVENT-EXIT :VALUES),
  then the recorded return values (in EVENT-OUTCOME) are returned
  immediately as in `(VALUES-LIST (EVENT-OUTCOME REPLAY-EVENT))`. If
  REPLAY-VALUES is specified, it is called instead of VALUES-LIST.
  See @WORKING-WITH-UNREADABLE-VALUES for an example.

- Similarly, if the replay event has unwound with an expected
  condition (has EVENT-EXIT :CONDITION), then the recorded
  condition (in EVENT-OUTCOME) is signalled as
  IN `(ERROR (EVENT-OUTCOME REPLAY-EVENT))`. If REPLAY-CONDITION is
  specified, it is called instead of ERROR. REPLAY-CONDITION must
  not return normally.

WITH-REPLAY-FILTER's NO-REPLAY-OUTCOME can selectively turn off
replaying the outcome. See @TESTING-ON-MULTIPLE-LEVELS, for an
example.

### Matching out-events

If there were no @REPLAY-FAILURES during the matching of the
IN-EVENT, and the conditions for @REPLAYING-THE-OUTCOME were not
met, then the @BLOCK is executed. When the outcome of the block is
determined, an OUT-EVENT is triggered and is matched to the replay
journal. The matching of out-events starts out as in
@THE-REPLAY-STRATEGY with checks for EVENT-NAME and
[EVENT-VERSION][function].

If the replay strategy is *insert* or *upgrade*, then the out-event
is written to RECORD-JOURNAL, consuming an event with a matching
name from the REPLAY-JOURNAL in the latter case. If the strategy is
*match*, then:

- If the new event has an UNEXPECTED-OUTCOME, then
  **REPLAY-UNEXPECTED-OUTCOME** is signalled. Note that the replay
  event always has an EXPECTED-OUTCOME due to the handling of
  RECORD-UNEXPECTED-OUTCOME.

- If the new event has an EXPECTED-OUTCOME, then unless the new and
  REPLAY-EVENT's EVENT-EXITs are `EQ` and their EVENT-OUTCOMEs are
  EQUAL, **REPLAY-OUTCOME-MISMATCH** is signalled.

- Else, the replay event is consumed and the new event is written
  the RECORD-JOURNAL.

Note that @THE-REPLAY-STRATEGY for the in-event and the out-event of
the same @FRAME may differ if the corresponding out-event is not
present in REPLAY-JOURNAL, which may be the case when the recording
process failed hard without unwinding properly, or when an
UNEXPECTED-OUTCOME triggered the transition to JOURNAL-STATE
:LOGGING.

### Replay failures

- [condition] REPLAY-FAILURE SERIOUS-CONDITION

    A common superclass (never signalled itself) for
    all kinds of mismatches between the events produced and the replay
    journal. Signalled only in JOURNAL-STATE :REPLAYING and only once
    per WITH-JOURNALING. If a REPLAY-FAILURE is signalled for an EVENT,
    then the event will be recorded, but RECORD-JOURNAL will transition
    to JOURNAL-STATE :MISMATCHED. Like JOURNALING-FAILURE, this is a
    serious condition because it is to be handled outside the enclosing
    WITH-JOURNALING. If a REPLAY-FAILURE were to be handled inside the
    WITH-JOURNALING, keep in mind that in :MISMATCHED, replay always
    uses the *insert* replay strategy (see @THE-REPLAY-STRATEGY).

- [reader] REPLAY-FAILURE-NEW-EVENT REPLAY-FAILURE (:NEW-EVENT)

- [reader] REPLAY-FAILURE-REPLAY-EVENT REPLAY-FAILURE (:REPLAY-EVENT)

- [reader] REPLAY-FAILURE-REPLAY-JOURNAL REPLAY-FAILURE (= '(REPLAY-JOURNAL))

- [condition] REPLAY-NAME-MISMATCH REPLAY-FAILURE

    Signaled when the new event's and REPLAY-EVENT's
    EVENT-NAME are not EQUAL. The REPLAY-FORCE-INSERT,
    REPLAY-FORCE-UPGRADE restarts are provided.

- [condition] REPLAY-VERSION-DOWNGRADE REPLAY-FAILURE

    Signaled when the new event and the REPLAY-EVENT
    have the same EVENT-NAME, but the new event has a lower version. The
    REPLAY-FORCE-UPGRADE restart is provided.

- [condition] REPLAY-ARGS-MISMATCH REPLAY-FAILURE

    Signaled when the new event's and REPLAY-EVENT's
    EVENT-ARGS are not EQUAL. The REPLAY-FORCE-UPGRADE restart is
    provided.

- [condition] REPLAY-OUTCOME-MISMATCH REPLAY-FAILURE

    Signaled when the new event's and REPLAY-EVENT's
    EVENT-EXIT and/or EVENT-OUTCOME are not EQUAL. The
    REPLAY-FORCE-UPGRADE restart is provided.

- [condition] REPLAY-UNEXPECTED-OUTCOME REPLAY-FAILURE

    Signaled when the new event has an
    UNEXPECTED-OUTCOME. Note that the REPLAY-EVENT always has an
    EXPECTED-OUTCOME due to the logic of RECORD-UNEXPECTED-OUTCOME. No
    restarts are provided.

- [condition] REPLAY-INCOMPLETE REPLAY-FAILURE

    Signaled if there are unprocessed non-log events in
    REPLAY-JOURNAL when WITH-JOURNALING finishes and the body of
    WITH-JOURNALING returned normally, which is to prevent this
    condition to cancel an ongoing unwinding. No restarts are
    provided.

- [restart] REPLAY-FORCE-INSERT

    This restart forces @THE-REPLAY-STRATEGY to be :INSERT, overriding
    REPLAY-NAME-MISMATCH. This is intended for upgrades, and extreme
    care must be taken not to lose data.

- [restart] REPLAY-FORCE-UPGRADE

    This restart forces @THE-REPLAY-STRATEGY to be :UPGRADE, overriding
    REPLAY-NAME-MISMATCH, REPLAY-VERSION-DOWNGRADE,
    REPLAY-ARGS-MISMATCH, REPLAY-OUTCOME-MISMATCH. This is intended for
    upgrades, and extreme care must be taken not to lose data.

### Upgrades and replay

The replay mechanism is built on the assumption that the tree of
@FRAMEs is the same when the code is replayed as it was when the
replay journal was originally recorded. Thus, non-deterministic
control flow poses a challenge, but non-determinism can be isolated
with EXTERNAL-EVENTs. However, when the code changes, we might find
the structure of frames in previous recordings hard to accommodate.
In this case, we might decide to alter the structure, giving up some
of the safety provided by the replay mechanism. There are various
tools at our disposal to control this tradeoff between safety and
flexibility:

- We can insert individual frames with JOURNALED's INSERTABLE,
  upgrade frames by bumping JOURNALED's VERSION, and filter frames
  with WITH-REPLAY-FILTER. This option allows for the most
  consistency checks.

- The REPLAY-FORCE-UPGRADE and REPLAY-FORCE-INSERT restarts allow
  overriding @THE-REPLAY-STRATEGY, but their use requires great care
  to be taken.

- Or we may decide to keep the bare minimum of the replay journal
  around, and discard everything except for EXTERNAL-EVENTs. This
  option is equivalent to

        (let ((*force-insertable* t))
          (with-replay-filter (:skip '((:name nil)))
            42))

- Rerecording the journal without replay might be another option if
  there are no EXTERNAL-EVENTs to worry about.

- Finally, we can rewrite the replay journal using the low-level
  interface (see @STREAMLETS-REFERENCE). In this case, extreme care
  must be taken not to corrupt the journal (and lose data) as there
  are no consistency checks to save us.

With that, let's see how WITH-REPLAY-FILTER works.

- [macro] WITH-REPLAY-STREAMLET (VAR) &BODY BODY

    Open REPLAY-JOURNAL for reading with WITH-OPEN-JOURNAL set the
    READ-POSITION on it to the event next read by the @REPLAY
    mechanism (which is never a LOG-EVENT). The low-level
    @READING-FROM-STREAMLETS api is then available to inspect the
    contents of the replay. It is an error if REPLAY-JOURNAL is NIL.

- [function] PEEK-REPLAY-EVENT

    Return the REPLAY-EVENT to be read from REPLAY-JOURNAL. This is
    roughly equivalent to
    
    ```
    (when (replay-journal)
      (with-replay-streamlet (streamlet)
        (peek-event streamlet))
    ```
    
    except PEEK-REPLAY-EVENT takes into account WITH-REPLAY-FILTER
    :MAP, and it may return `(:INDETERMINATE)` if WITH-REPLAY-FILTER
    :SKIP is in effect and what events are to be skipped cannot be
    decided until the next in-event generated by the code.
    
    Imagine a business process for paying an invoice. In the first
    version of this process, we just pay the invoice:
    
    ```
    (replayed (pay))
    ```
    
    We have left the implementation of PAY blank. In the second version,
    we need to get an approval first:
    
    ```
    (when (replayed (get-approval)
            (= (random 2) 0))
      (replayed (pay)))
    ```
    
    Replaying a journal produced by the first version of the code with
    the second version would run into difficulties because inserting
    EXTERNAL-EVENTs is tricky.
    
    We have to first decide how to handle the lack of approval in the
    first version. Here, we just assume the processes started by the
    first version get approval automatically. The implementation is
    based on a dummy `PROCESS` block whose version is bumped when the
    payment process changes and is inspected at the start of journaling.
    
    When v1 is replayed with v2, we introduce an INSERTABLE, versioned
    `GET-APPROVAL` block that just returns T. When replaying the code
    again, still with v2, the `GET-APPROVAL` block will be upgraded to
    :INFINITY.
    
    ```
    (let ((bundle (make-in-memory-bundle)))
      ;; First version of the payment process. Just pay.
      (with-bundle (bundle)
        (checked (process :version 1))
        (replayed (pay)))
      ;; Second version of the payment process. Only pay if approved.
      (loop repeat 2 do
        (with-bundle (bundle)
          (let ((replay-process-event (peek-replay-event)))
            (checked (process :version 2))
            (when (if (and replay-process-event
                           (< (event-version replay-process-event) 2))
                      ;; This will be upgraded to :INFINITY the second
                      ;; time around the LOOP.
                      (checked (get-approval :insertable t)
                        t)
                      (replayed (get-approval)
                        (= (random 2) 0)))
              (replayed (pay)))))))
    ```


- [macro] WITH-REPLAY-FILTER (&KEY MAP SKIP NO-REPLAY-OUTCOME) &BODY BODY

    WITH-REPLAY-FILTER performs journal upgrade during replay by
    allowing events to be transformed as they are read from the replay
    journal or skipped if they match some patterns. For how to add new
    blocks in a code upgrade, see JOURNALED's :INSERTABLE argument. In
    addition, it also allows some control over @REPLAYING-THE-OUTCOME.
    
    - MAP: A function called with an event read from the replay journal
      which returns a transformed event. See @EVENTS-REFERENCE. MAP
      takes effect before before SKIP.
    
    - SKIP: In addition to filtering out LOG-EVENTs (which always
      happens during replay), filter out all events that belong to
      descendant frames that match any of its SKIP patterns. Filtered
      out events are never seen by JOURNALED as it replays events. SKIP
      patterns are of the format `(&KEY NAME VERSION<)`, where VERSION<
      is a valid [EVENT-VERSION][type], and NAME may be NIL, which acts
      as a wildcard.
    
        SKIP is for when JOURNALED @BLOCKs are removed from the code,
        which would render replaying previously recorded journals
        impossible. Note that, for reasons of safety, it is not possible
        to filter EXTERNAL-EVENTs.
    
    - NO-REPLAY-OUTCOME is a list of EVENT-NAMEs. @REPLAYING-THE-OUTCOME
      is prevented for frames with EQUAL names. See
      @TESTING-ON-MULTIPLE-LEVELS for an example.
    
    WITH-REPLAY-FILTER affects only the immediately enclosing
    WITH-JOURNALING. A WITH-REPLAY-FILTER nested within another in the
    same WITH-JOURNALING inherits the SKIP patterns of its parent, to
    which it adds its own. The MAP function is applied to before the
    parent's MAP.
    
    Examples of SKIP patterns:
    
    ```
    ;; Match events with name FOO and version 1, 2, 3 or 4
    (:name foo :version< 5)
    ;; Match events with name BAR and any version
    (:name bar :version< :infinity)
    ;; Same as the previous
    (:name bar)
    ;; Match all names
    (:name nil)
    ;; Same as the previous
    ()
    ```
    
    Skipping can be thought of as removing nodes of the tree of frames,
    connecting its children to its parent. The following example removes
    frames `J1` and `J2` from around `J3`, the `J1` frame from within
    `J3`, and the third `J1` frame.
    
    ```
    (let ((journal (make-in-memory-journal)))
      ;; Record trees J1 -> J2 -> J3 -> J1, and J1.
      (with-journaling (:record journal)
        (checked (j1)
          (checked (j2)
            (checked (j3)
              (checked (j1)
                42))))
        (checked (j1)
          7))
      ;; Filter out all occurrences of VERSIONED-EVENTs named J1 and
      ;; J2 from the replay, leaving only J3 to match.
      (with-journaling (:replay journal :record t :replay-eoj-error-p t)
        (with-replay-filter (:skip '((:name j1) (:name j2)))
          (checked (j3)
            42))))
    ```


## Testing

Having discussed the @REPLAY mechanism, next are @TESTING and
@PERSISTENCE, which rely heavily on replay. Suppose we want to unit
test user registration. Unfortunately, the code communicates with a
database service and also takes input from the user. A natural
solution is to create [mocks][mock-object] for these external
systems to unshackle the test from the cumbersome database
dependency and to allow it to run without user interaction.

We do this below by wrapping external interaction in JOURNALED with
:VERSION :INFINITY (see @REPLAYING-THE-OUTCOME).

```
(defparameter *db* (make-hash-table))

(defun set-key (key value)
  (replayed ("set-key" :args `(,key ,value))
    (format t "Updating db~%")
    (setf (gethash key *db*) value)
    nil))

(defun get-key (key)
  (replayed ("get-key" :args `(,key))
    (format t "Query db~%")
    (gethash key *db*)))

(defun ask-username ()
  (replayed ("ask-username")
    (format t "Please type your username: ")
    (read-line)))

(defun maybe-win-the-grand-prize ()
  (checked ("maybe-win-the-grand-prize")
    (when (= 1000000 (hash-table-count *db*))
      (format t "You are the lucky one!"))))

(defun register-user (username)
  (unless (get-key username)
    (set-key username `(:user-object :username ,username))
    (maybe-win-the-grand-prize)))
```

Now we write a test that records these interactions in a file when
it's run for the first time.

```
(define-file-bundle-test (test-user-registration
                          :directory (asdf:system-relative-pathname
                                      :journal "test/registration/"))
  (let ((username (ask-username)))
    (register-user username)
    (assert (get-key username))
    (register-user username)
    (assert (get-key username))))

;; Original recording: everything is executed
JRN> (test-user-registration)
Please type your username: joe
Query db
Updating db
Query db
Query db
Query db
=> NIL
```

On reruns, none of the external stuff is executed. The return values
of the external JOURNALED blocks are replayed from the journal:

```
;; Replay: all external interactions are mocked.
JRN> (test-user-registration)
=> NIL
```

Should the code change, we might want to upgrade carefully (see
@UPGRADES-AND-REPLAY) or just rerecord from scratch:

```
JRN> (test-user-registration :rerecord t)
Please type your username: joe
Query db
Updating db
Query db
Query db
Query db
=> NIL
```

Thus satisfied that our test runs, we can commit the journal file in
the bundle into version control. Its contents are:

```

(:IN "ask-username" :VERSION :INFINITY)
(:OUT "ask-username" :VERSION :INFINITY :VALUES ("joe" NIL))
(:IN "get-key" :VERSION :INFINITY :ARGS ("joe"))
(:OUT "get-key" :VERSION :INFINITY :VALUES (NIL NIL))
(:IN "set-key" :VERSION :INFINITY :ARGS ("joe" (:USER-OBJECT :USERNAME "joe")))
(:OUT "set-key" :VERSION :INFINITY :VALUES (NIL))
(:IN "maybe-win-the-grand-prize" :VERSION 1)
(:OUT "maybe-win-the-grand-prize" :VERSION 1 :VALUES (NIL))
(:IN "get-key" :VERSION :INFINITY :ARGS ("joe"))
(:OUT "get-key" :VERSION :INFINITY :VALUES ((:USER-OBJECT :USERNAME "joe") T))
(:IN "get-key" :VERSION :INFINITY :ARGS ("joe"))
(:OUT "get-key" :VERSION :INFINITY :VALUES ((:USER-OBJECT :USERNAME "joe") T))
(:IN "get-key" :VERSION :INFINITY :ARGS ("joe"))
(:OUT "get-key" :VERSION :INFINITY :VALUES ((:USER-OBJECT :USERNAME "joe") T))
```

Note that when this journal is replayed, new VERSIONED-EVENTs are
required to match the replay. So after the original recording, we
can check by eyeballing that the record represents a correct
execution. Then on subsequent replays, even though
`MAYBE-WIN-THE-GRAND-PRIZE` sits behind `REGISTER-USER` and is hard
to test with ASSERTs, the replay mechanism verifies that it is
called only for new users.

This record-and-replay style of testing is not the only possibility:
direct inspection of a journal with the low-level events api (see
@EVENTS-REFERENCE) can facilitate checking non-local invariants.

- [macro] DEFINE-FILE-BUNDLE-TEST (NAME &KEY DIRECTORY (EQUIVALENTP T)) &BODY BODY

    Define a function with NAME for record-and-replay testing. The
    function's BODY is executed in a WITH-BUNDLE to guarantee
    replayability. The bundle in question is a FILE-BUNDLE created in
    DIRECTORY. The function has a single keyword argument, RERECORD. If
    RERECORD is true, the bundle is deleted with DELETE-FILE-BUNDLE to
    start afresh.
    
    Furthermore, if BODY returns normally, and it is a replay of a
    previous run, and EQUIVALENTP, then it is ASSERTed that the record
    and replay journals are EQUIVALENT-REPLAY-JOURNALS-P. If this check
    fails, RECORD-JOURNAL is discarded when the function returns. In
    addition to the replay consistency, this checks that no inserts or
    upgrades were performed (see @THE-REPLAY-STRATEGY).

### Testing on multiple levels

Nesting REPLAYEDs (that is, @FRAMEs of EXTERNAL-EVENTs) is not
obviously useful since the outer REPLAYED will be replayed by
outcome, and the inner one will be just echoed to the record
journal. However, if we turn off @REPLAYING-THE-OUTCOME for the
outer, the inner will be replayed.

This is useful for testing layered communication. For example, we
might have written code that takes input from an external
system (READ-LINE) and does some complicated
processing (READ-FROM-STRING) before returning the input in a form
suitable for further processing. Suppose we wrap REPLAYED around
READ-FROM-STRING for @PERSISTENCE because putting it around
READ-LINE would expose low-level protocol details in the journal,
making protocol changes difficult.

However, upon realizing that READ-FROM-STRING was not the best tool
for the job and switching to PARSE-INTEGER, we want to test by
replaying all previously recorded journals. For this, we prevent the
outer REPLAYED from being replayed by outcome with
WITH-REPLAY-FILTER:

```
(let ((bundle (make-in-memory-bundle)))
  ;; Original with READ-FROM-STRING
  (with-bundle (bundle)
    (replayed ("accept-number")
      (values (read-from-string (replayed ("input-number")
                                  (read-line))))))
  ;; Switch to PARSE-INTEGER and test by replay.
  (with-bundle (bundle)
    (with-replay-filter (:no-replay-outcome '("accept-number"))
      (replayed ("accept-number")
        ;; 1+ is our bug.
        (values (1+ (parse-integer (replayed ("input-number")
                                     (read-line)))))))))
```

The inner `input-number` block is replayed by outcome, and
PARSE-INTEGER is called with the string READ-LINE returned in the
original invocation. The outcome of the outer `accept-number` block
checked as if it was a VERSIONED-EVENT and we get a
REPLAY-OUTCOME-MISMATCH due to the bug.

## Persistence

### Persistence tutorial

Let's write a simple game.

```
(defun play-guess-my-number ()
  (let ((my-number (replayed (think-of-a-number)
                     (random 10))))
    (format t "~%I thought of a number.~%")
    (loop for i upfrom 0 do
      (write-line "Guess my number:")
      (let ((guess (replayed (read-guess)
                     (values (parse-integer (read-line))))))
        (format t "You guessed ~D.~%" guess)
        (when (= guess my-number)
          (checked (game-won :args `(,(1+ i))))
          (format t "You guessed it in ~D tries!" (1+ i))
          (return))))))

(defparameter *the-evergreen-game* (make-in-memory-bundle))
```

##### Original recording

Unfortunately, the implementation is lacking in the input validation
department. In the transcript below, PARSE-INTEGER fails with `junk
in string` when the user enters `not a number`:

```
CL-USER> (handler-case
             (with-bundle (*the-evergreen-game*)
               (play-guess-my-number))
           (error (e)
             (format t "Oops. ~A~%" e)))
I thought of a number.
Guess my number:
7 ; real user input
You guessed 7.
Guess my number:
not a number ; real user input
Oops. junk in string "not a number"
```

##### Replay and extension

Instead of fixing this bug, we just restart the game from the
beginning, @REPLAYING-THE-OUTCOME of external interactions marked
with REPLAYED:

```
CL-USER> (with-bundle (*the-evergreen-game*)
           (play-guess-my-number))
I thought of a number.
Guess my number:
You guessed 7.
Guess my number: ; New recording starts here
5 ; real user input
You guessed 5.
Guess my number:
4 ; real user input
You guessed 4.
Guess my number:
2 ; real user input
You guessed 2.
You guessed it in 4 tries!
```

##### It's evergreen

We can now replay this game many times without any user interaction:

```
CL-USER> (with-bundle (*the-evergreen-game*)
           (play-guess-my-number))
I thought of a number.
Guess my number:
You guessed 7.
Guess my number:
You guessed 5.
Guess my number:
You guessed 4.
Guess my number:
You guessed 2.
You guessed it in 4 tries!
```

##### The generated events

This simple mechanism allows us to isolate external interactions and
write tests in record-and-replay style based on the events produced:

```
CL-USER> (list-events *the-evergreen-game*)
((:IN THINK-OF-A-NUMBER :VERSION :INFINITY)
 (:OUT THINK-OF-A-NUMBER :VERSION :INFINITY :VALUES (2))
 (:IN READ-GUESS :VERSION :INFINITY)
 (:OUT READ-GUESS :VERSION :INFINITY :VALUES (7))
 (:IN READ-GUESS :VERSION :INFINITY :ARGS NIL)
 (:OUT READ-GUESS :VERSION :INFINITY :VALUES (5))
 (:IN READ-GUESS :VERSION :INFINITY :ARGS NIL)
 (:OUT READ-GUESS :VERSION :INFINITY :VALUES (4))
 (:IN READ-GUESS :VERSION :INFINITY :ARGS NIL)
 (:OUT READ-GUESS :VERSION :INFINITY :VALUES (2))
 (:IN GAME-WON :VERSION 1 :ARGS (4))
 (:OUT GAME-WON :VERSION 1 :VALUES (NIL)))
```

In fact, being able to replay this game at all already checks it
through the `GAME-WON` event that the number of tries calculation is
correct.

In addition, thus being able to reconstruct the internal state of
the program gives us persistence by replay. If instead of a
IN-MEMORY-BUNDLE, we used a FILE-BUNDLE, the game would have been
saved on disk without having to write any code for saving and
loading the game state.

##### Discussion

Persistence by replay, also known as [Event
Sourcing][event-sourcing], is appropriate when the external
interactions are well-defined and stable. Storing events shines in
comparison to persisting state when the control flow is too
complicated to be interrupted and resumed easily. Resuming execution
in deeply nested function calls is fraught with such peril that it
is often easier to flatten the program into a state machine, which
is as pleasant as manually managing [continuations][continuation].

[continuation]: https://en.wikipedia.org/wiki/Continuation 

In contrast, the Journal library does not favour certain styles of
control flow, and only requires that non-determinism is packaged up
in REPLAYED, which allows it to reconstruct the state of the program
from the recorded events at any point during its execution and
resume from there.

### Synchronization to storage

In the following, we explore how journals can serve as a
persistence mechanism and the guarantees they offer. The high-level
summary is that journals with SYNC can serve as a durable and
consistent storage medium. The other two
[ACID](https://en.wikipedia.org/wiki/ACID) properties, atomicity and
isolation, do not apply because Journal is single-client and does
not need transactions.

- [glossary-term] aborted execution

    Aborted execution is when the operating system or the application
    crashes, calls `abort()`, is killed by a `SIGKILL` signal or there
    is a power outage. Synchronization guarantees are defined in face of
    aborted execution and do not apply to hardware errors, Lisp or OS
    bugs.

- [glossary-term] data event

    Data events are the only events that may be non-deterministic. They
    record information which could change if the same code were run
    multiple times. Data events typically correspond to interactions
    with the user, servers or even the random number generator. Due to
    their non-determinism, they are the only parts of the journal not
    reproducible by rerunning the code. In this sense, only data events
    are not redundant with the code and whether other events are
    persisted does not affect durability. There are two kinds of data
    events:
    
    - An EXTERNAL-EVENT that is also an OUT-EVENT.
    
    - The IN-EVENT of an INVOKED function, which lies outside the
      normal, deterministic control flow.


#### Synchronization strategies

When a journal or bundle is created (see MAKE-IN-MEMORY-JOURNAL,
MAKE-FILE-JOURNAL, MAKE-IN-MEMORY-BUNDLE, MAKE-FILE-BUNDLE), the
SYNC option determines when - as a RECORD-JOURNAL - the recorded
events and JOURNAL-STATE changes are persisted durably. For
FILE-JOURNALs, persisting means calling something like `fsync()`,
while for IN-MEMORY-JOURNALs, a user defined function is called to
persist the data.

- NIL: Never synchronize. A FILE-JOURNAL's file may be corrupted on
  ABORTED-EXECUTION. In IN-MEMORY-JOURNALs, SYNC-FN is never called.

- T: This is the *no data loss* setting with minimal
  synchronization. It guarantees *consistency* (i.e. no corruption)
  and *durability* up to the most recent DATA-EVENT written in
  JOURNAL-STATE :RECORDING or for the entire record journal in
  states :FAILED and :COMPLETED. :FAILED or :COMPLETED is guaranteed
  when leaving WITH-JOURNALING at the latest.

- Values other than NIL and T are reserved for future extensions.
  Using them triggers a JOURNAL-ERROR.


#### Synchronization with in-memory journals

Unlike FILE-JOURNALs, IN-MEMORY-JOURNALs do not have any built-in
persistent storage backing them, but with SYNC-FN, persistence can
be tacked on. If non-NIL, SYNC-FN must be a function of a single
argument, an IN-MEMORY-JOURNAL. SYNC-FN is called according to
@SYNCHRONIZATION-STRATEGIES, and upon normal return the journal must
be stored durably.

The following example saves the entire journal history when a new
DATA-EVENT is recorded. Note how `SYNC-TO-DB` is careful to
overwrite `*DB*` only if it is called with a journal that has not
failed the replay (as in @REPLAY-FAILURES) and is sufficiently
different from the replay journal as determined by
JOURNAL-DIVERGENT-P.

```
(defparameter *db* ())

(defun sync-to-db (journal)
  (when (and (member (journal-state journal)
                     '(:recording :logging :completed))
             (journal-divergent-p journal))
    (setq *db* (journal-events journal))
    (format t "Saved ~S~%New events from position ~S~%" *db*
            (journal-previous-sync-position journal))))

(defun make-db-backed-record-journal ()
  (make-in-memory-journal :sync-fn 'sync-to-db))

(defun make-db-backed-replay-journal ()
  (make-in-memory-journal :events *db*))

(with-journaling (:record (make-db-backed-record-journal)
                  :replay (make-db-backed-replay-journal))
  (replayed (a)
    2)
  (ignore-errors
    (replayed (b)
      (error "Whoops"))))
.. Saved #((:IN A :VERSION :INFINITY)
..         (:OUT A :VERSION :INFINITY :VALUES (2)))
.. New events from position 0
.. Saved #((:IN A :VERSION :INFINITY)
..         (:OUT A :VERSION :INFINITY :VALUES (2))
..         (:IN B :VERSION :INFINITY)
..         (:OUT B :ERROR ("SIMPLE-ERROR" "Whoops")))
.. New events from position 2
..
```

In a real application, external events often involve unreliable or
high-latency communication. In the above example, block `B` signals
an error, say, to simulate some kind of network condition. Now a new
journal *for replay* is created and initialized with the saved
events and the whole process is restarted.

```
(defun run-with-db ()
  (with-journaling (:record (make-db-backed-record-journal)
                    :replay (make-db-backed-replay-journal))
    (replayed (a)
      (format t "A~%")
      2)
    (replayed (b)
      (format t "B~%")
      3)))

(run-with-db)
.. B
.. Saved #((:IN A :VERSION :INFINITY)
..         (:OUT A :VERSION :INFINITY :VALUES (2))
..         (:IN B :VERSION :INFINITY)
..         (:OUT B :VERSION :INFINITY :VALUES (3)))
.. New events from position 0
..
=> 3
```

Note that on the rerun, block `A` is not executed because external
events are replayed simply by reproducing their outcome, in this
case returning 2. See @REPLAYING-THE-OUTCOME. Block `B`, on the
other hand, was rerun because it had an UNEXPECTED-OUTCOME the first
time around. This time it ran without error, a DATA-EVENT was
triggered and SYNC-FN invoked.

If we were to invoke the now completed `RUN-WITH-DB` again, it would
simply return 3 without ever invoking SYNC-FN:

```
(run-with-db)
=> 3
```

With JOURNAL-REPLAY-MISMATCH, SYNC-FN can be optimized to to reuse
the sequence of events in the replay journal up until the point of
divergence.

#### Synchronization with file journals

For FILE-JOURNALs, SYNC determines when the events written to the
RECORD-JOURNAL and its JOURNAL-STATE will be persisted durably in
the file. Syncing to the file involves two calls to `fsync()`, and
is not cheap.

Syncing events to files is implemented as follows.

- When the journal file is created, its parent directory is
  immediately fsynced to make sure that the file will not be lost on
  ABORTED-EXECUTION.

- When an event is about to be written the first time after file
  creation or after a sync, a transaction start marker is written to
  the file.

- Any number of events may be subsequently written until syncing is
  deemed necessary (see @SYNCHRONIZATION-STRATEGIES).

- At this point, `fsync()` is called to flush all event data and
  state changes to the file, and the transaction start marker is
  *overwritten* with a transaction completed marker and another
  `fsync()` is performed.

- When reading back this file (e.g. for replay), an open transaction
  marker is treated as the end of file.

Note that this implementation assumes that after writing the start
transaction marker a crash cannot leave any kind of garbage bytes
around: it must leave zeros. This is not true for all filesytems.
For example, ext3/ext4 with `data=writeback` [can leave garbage
around][ext4-writeback].

[ext4-writeback]: https://ext4.wiki.kernel.org/index.php/Ext3_Data=Ordered_vs_Data=Writeback_mode 


## Safety

##### Thread safety

Changes to journals come in two varieties: adding an event and
changing the JOURNAL-STATE. Both are performed by JOURNALED only
unless the low-level streamlet interface is used (see
@STREAMLETS-REFERENCE). Using JOURNALED wrapped in a
WITH-JOURNALING, WITH-BUNDLE, or @LOG-RECORD without WITH-JOURNALING
is thread-safe.

- Every journal is guaranteed to have at most a single writer active
  at any time. Writers are WITH-JOURNALING and WITH-BUNDLE, but also
  any journals used as LOG-RECORD (unless that journal is the
  RECORD-JOURNAL) have a log writer stored in the journal object.

- WITH-JOURNALING and WITH-BUNDLE have dynamic extent as writers,
  but log writers of journals have indefinite extent: once a journal
  is used as a LOG-RECORD there remains a writer.

- Attempting to create a second writer triggers a JOURNAL-ERROR.

- Writing to the same journal via LOG-RECORD from multiple threads
  concurrently is possible since this doesn't create multiple
  writers. It is ensured with locking that events are written
  atomically. Frames can be interleaved, but these are LOG-EVENTs,
  so this does not affect replay.

- The juggling of replay and record journals performed by
  WITH-BUNDLE is also thread-safe.

- It is ensured that there is at most one FILE-JOURNAL object in the
  same Lisp image is backed by the same file.

- Similarly, there is at most FILE-BUNDLE object for a directory.

##### Process safety

Currently, there is no protection against multiple OS processes
writing the same FILE-JOURNAL or FILE-BUNDLE.

##### Signal safety

Journal is *designed* to be @ASYNC-UNWIND safe, but *not reentrant*.
Interrupts are disabled only for the most critical cleanup forms. If
a thread is killed without unwinding, that constitutes
ABORTED-EXECUTION, so guarantees about @SYNCHRONIZATION apply, but
JOURNAL objects written by the thread are not safe to access, and
the Lisp should probably be restarted.

## Events reference

Events are normally triggered upon entering and leaving the
dynamic extent of a JOURNALED @BLOCK (see @IN-EVENTS and
@OUT-EVENTS) and also by LOGGED. Apart from being part of the
low-level substrate of the Journal library, working with events
directly is sometimes useful when writing tests that inspect
recorded events. Otherwise, skip this entire section.

All EVENTs have EVENT-NAME and EVENT-VERSION, which feature
prominently in @THE-REPLAY-STRATEGY. After the examples in
@IN-EVENTS and @OUT-EVENTS, the following example is a reminder of
how events look in the simplest case.

```
(with-journaling (:record t)
  (journaled (foo :version 1 :args '(1 2))
    (+ 1 2))
  (logged () "Oops")
  (list-events))
=> ((:IN FOO :VERSION 1 :ARGS (1 2))
    (:OUT FOO :VERSION 1 :VALUES (3))
    (:LEAF "Oops"))
```

So a JOURNALED @BLOCK generates an IN-EVENT and an OUT-EVENT, which
are simple property lists. The following reference lists these
properties, there semantics and the functions to read them.

- [type] EVENT

    An event is either an IN-EVENT, an OUT-EVENT or a LEAF-EVENT.

- [function] EVENT= EVENT-1 EVENT-2

    Return whether EVENT-1 and EVENT-2 represent the same event. In-
    and out-events belonging to the same @FRAME are *not* the same
    event. EVENT-OUTCOME is not compared when EVENT-EXIT is :ERROR to
    avoid undue dependence on implementation specific string
    representations. This function is useful in conjunction with
    MAKE-IN-EVENT and MAKE-OUT-EVENT to write tests.

- [function] EVENT-NAME EVENT

    The name of an event can be of any type. It is often a symbol or a
    string. When replaying, names may be compared with EQUAL. All EVENTs
    have names. The names of the in- and out-events belonging to the
    same @FRAME are the same.

### Event versions

- [function] EVENT-VERSION EVENT

    Return the version of EVENT of type EVENT-VERSION.

- [function] LOG-EVENT-P EVENT

    See if EVENT is a LOG-EVENT.

- [function] VERSIONED-EVENT-P EVENT

    See if EVENT is a VERSIONED-EVENT.

- [function] EXTERNAL-EVENT-P EVENT

    See if EVENT is an EXTERNAL-EVENT.

### In-events

- [type] IN-EVENT

    IN-EVENTs are triggered upon entering the dynamic extent of a
    JOURNALED @BLOCK. IN-EVENTs have EVENT-NAME,
    [EVENT-VERSION][function], and EVENT-ARGS. See @IN-EVENTS for a more
    introductory treatment.

- [function] IN-EVENT-P EVENT

    See if EVENT is a IN-EVENT.

- [function] MAKE-IN-EVENT &KEY NAME VERSION ARGS

    Create an IN-EVENT with NAME, VERSION (of type EVENT-VERSION) and
    ARGS as its EVENT-NAME, [EVENT-VERSION][function] and EVENT-ARGS.

- [function] EVENT-ARGS IN-EVENT

    Return the arguments of IN-EVENT, normally populated with the ARGS
    form in JOURNALED.

### Out-events

- [type] OUT-EVENT

    OUT-EVENTs are triggered upon leaving the dynamic extent of the
    JOURNALED @BLOCK. OUT-EVENTs have EVENT-NAME,
    [EVENT-VERSION][function], [EVENT-EXIT][function] and EVENT-OUTCOME.
    See @OUT-EVENTS for a more introductory treatment.

- [function] OUT-EVENT-P EVENT

    See if EVENT is an OUT-EVENT.

- [function] MAKE-OUT-EVENT &KEY NAME VERSION EXIT OUTCOME

    Create an OUT-EVENT with NAME, VERSION (of type EVENT-VERSION),
    EXIT (of type EVENT-EXIT), and OUTCOME as its EVENT-NAME,
    [EVENT-VERSION][function], [EVENT-EXIT][function] and
    EVENT-OUTCOME.

- [function] EVENT-EXIT OUT-EVENT

    Return how the journaled @BLOCK finished. See [EVENT-EXIT][type]
    for the possible types.

- [function] EXPECTED-OUTCOME-P OUT-EVENT

    See if OUT-EVENT has an EXPECTED-OUTCOME.

- [function] UNEXPECTED-OUTCOME-P OUT-EVENT

    See if OUT-EVENT has an UNEXPECTED-OUTCOME.

- [function] EVENT-OUTCOME OUT-EVENT

    Return the outcome of the @FRAME (or loosely speaking of a @BLOCK)
    to which OUT-EVENT belongs. 

### Leaf-events

- [type] LEAF-EVENT

    Leaf events are triggered by LOGGED. Unlike IN-EVENTs and
    OUT-EVENTs, which represent a @FRAME, leaf events stand alone and
    thus cannot have children. They are also the poorest of their kind:
    they only have an EVENT-NAME. Their VERSION is always NIL, which
    makes them LOG-EVENTs.

- [function] LEAF-EVENT-P EVENT

    See if EVENT is a LEAF-EVENT.

- [function] MAKE-LEAF-EVENT NAME

    Create a LEAF-EVENT with NAME.

## Journals reference

In @JOURNAL-BASICS, we covered the bare minimum needed to work with
journals. Here we go into the details.

- [class] JOURNAL

    A journal is, conceptually, a sequence of events.
    JOURNAL is an abstract base class. In case of FILE-JOURNALs, the
    events are stored in a file, while for IN-MEMORY-JOURNALs, they are
    in a Lisp array. When a journal is opened, it is possible to perform
    I/O on it (see @STREAMLETS-REFERENCE), which is normally taken care
    of by WITH-JOURNALING. For this reason, the user's involvement with
    journals normally only consists of creating and using them in
    WITH-JOURNALING.

- [reader] JOURNAL-STATE JOURNAL (:STATE)

    Return the state of JOURNAL, which is of type
    [JOURNAL-STATE][TYPE].

- [reader] JOURNAL-SYNC JOURNAL (:SYNC = NIL)

    The SYNC argument specified at instantiation. See
    @SYNCHRONIZATION-STRATEGIES.

- [function] SYNC-JOURNAL &OPTIONAL (JOURNAL (RECORD-JOURNAL))

    Durably persist all preceding writes made to JOURNAL during an
    enclosing WITH-JOURNALING or via LOG-RECORD from any thread. Writes
    made in a WITH-JOURNALING in another thread are not persisted. The
    changes in question are WRITE-EVENT calls and state changes. This is
    a noop JOURNAL-SYNC is NIL. This function is safe to call from any
    thread.

- [reader] JOURNAL-REPLAY-MISMATCH JOURNAL (= NIL)

    If JOURNAL-DIVERGENT-P, then this is a list of two
    elements: the READ-POSITIONs in the RECORD-JOURNAL and
    REPLAY-JOURNAL of the first events that were different (ignoring
    LOG-EVENTs). It is NIL, otherwise.

- [function] JOURNAL-DIVERGENT-P JOURNAL

    See if WITH-JOURNALING recorded any event so far in this journal
    which was not EQUAL to its REPLAY-EVENT or it had no corresponding
    replay event. This completely ignores LOG-EVENTs in both journals
    being compared, and is updated continuously during @REPLAY. It plays
    a role in WITH-BUNDLE deciding when a journal is important enough to
    keep, and also in @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS.
    
    The position of the first mismatch that is available via
    JOURNAL-REPLAY-MISMATCH.

### Comparing journals

After replay finished (i.e. WITH-JOURNALING completed), we can ask
the question whether there were any changes produced. This is
answered in the strictest sense by IDENTICAL-JOURNALS-P, and
somewhat more functionally by EQUIVALENT-REPLAY-JOURNALS-P.

Also see JOURNAL-DIVERGENT-P.

- [generic-function] IDENTICAL-JOURNALS-P JOURNAL-1 JOURNAL-2

    Compare two journals in a strict sense: whether
    they have the same JOURNAL-STATE and the lists of their events (as
    in LIST-EVENTS) are EQUAL.

- [generic-function] EQUIVALENT-REPLAY-JOURNALS-P JOURNAL-1 JOURNAL-2

    See if two journals are equivalent when used the
    for REPLAY in WITH-JOURNALING. EQUIVALENT-REPLAY-JOURNALS-P is like
    IDENTICAL-JOURNALS-P, but it ignores LOG-EVENTs and allows events
    with EVENT-EXIT :ERROR to differ in their outcomes, which may very
    well be implementation specific, anyway. Also, it considers two
    groups of states as different :NEW, :REPLAYING, :MISMATCHED, :FAILED
    vs :RECORDING, :LOGGING, COMPLETED.

The rest of section is about concrete subclasses of [JOURNAL][class].

### In-memory journals

- [class] IN-MEMORY-JOURNAL JOURNAL

    IN-MEMORY-JOURNALs are backed by a non-persistent,
    Lisp array of events. Much quicker than FILE-JOURNALs, they are
    ideal for smallish journals persisted manually (see
    @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS for an example).
    
    They are also useful for writing tests based on what events were
    generated. They differ from FILE-JOURNALs in that events written to
    IN-MEMORY-JOURNALs are not serialized (and deserialized on replay)
    with the following consequences for the objects recorded by
    JOURNALED (i.e. its NAME, ARGS arguments, but also the return VALUES
    of the block, or the value returned by CONDITION):
    
    - These objects need not be @READABLE.
    
    - Their identity (`EQ`ness) is not lost.
    
    - They must **must not be mutated** in any way.


- [function] MAKE-IN-MEMORY-JOURNAL &KEY (EVENTS NIL EVENTSP) STATE (SYNC NIL SYNCP) SYNC-FN

    By default, creates an empty IN-MEMORY-JOURNAL in JOURNAL-STATE
    :NEW, which is suitable for recording. To make a replay journal, use
    :STATE :COMPLETED with some sequence of EVENTS:
    
    ```
    (make-in-memory-journal :events '((:in foo :version 1)) :state :completed)
    ```
    
    If the EVENTS argument is provided, then STATE defaults to :NEW,
    else to :COMPLETED.
    
    SYNC determines when SYNC-FN will be invoked on the RECORD-JOURNAL.
    SYNC defaults to T if SYNC-FN, else to NIL. For a description of
    possible values, see @SYNCHRONIZATION-STRATEGIES. For more
    discussion, see @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS.

- [reader] JOURNAL-EVENTS IN-MEMORY-JOURNAL (:EVENTS)

    A sequence of events in the journal. Not to be
    mutated by client code.

- [reader] JOURNAL-PREVIOUS-SYNC-POSITION IN-MEMORY-JOURNAL (= 0)

    The length of JOURNAL-EVENTS at the time of the
    most recent invocation of SYNC-FN.

### File journals

- [class] FILE-JOURNAL JOURNAL

    A FILE-JOURNAL is a journal whose contents and
    JOURNAL-STATE are persisted in a file. This is the [JOURNAL][class]
    subclass with out-of-the-box persistence, but see @FILE-BUNDLES for
    a more full-featured solution for repeated @REPLAYs.
    
    Since serialization in FILE-JOURNALs is built on top of Lisp READ
    and WRITE, everything that JOURNALED records in events (i.e. its
    NAME, ARGS arguments, but also the return VALUES of the block, or
    the value returned by CONDITION) must be @READABLE.
    
    File journals are human-readable, and editable by hand with some
    care. When editing, the following needs to be remembered:
    
    - The first character of the file represents its JOURNAL-STATE. It
      is a `#\Space` (for state :NEW, :REPLAYING, :MISMATCHED and
      :FAILED), or a `#\Newline` (for state :RECORDING, :LOGGING and
      :COMPLETED).
    
    - If the journal has SYNC (see @SYNCHRONIZATION-STRATEGIES), then in
      between events, there may be `#\Del` (also called `#\Rubout`) or
      `#\Ack` characters (CHAR-CODE 127 and 6). `#\Del` marks the end of
      the journal contents which may be read back: it's kind of an
      uncommitted-transaction marker for the events that follow it.
      `#\Ack` characters, of which there may be many in the file, mark
      the sequence of events until the next marker of either kind as
      valid (or committed). `#\Ack` characters are ignored when reading
      the journal.
    
    Thus, when editing a file, don't change the first character and
    leave the `#\Del` character, if any, where it is. Also see
    @SYNCHRONIZATION-WITH-FILE-JOURNALS.

- [function] MAKE-FILE-JOURNAL PATHNAME &KEY SYNC

    Return a FILE-JOURNAL backed by the file with PATHNAME. The file is
    created when the journal is opened for writing. For a description of
    SYNC, see @SYNCHRONIZATION-STRATEGIES.
    
    If there is already an existing FILE-JOURNAL backed by the same
    file, then that object is returned. If the existing object has
    different options (e.g. it has SYNC T while the SYNC argument is NIL
    here), then a JOURNAL-ERROR is signalled.
    
    If there is already an existing FILE-JOURNAL backed by the same
    file, the JOURNAL-STATE is not :NEW, but the file doesn't exist,
    then the existing object is **invalidated**: attempts to write will
    fail with JOURNAL-ERROR. If the existing journal object is being
    written, then invalidation fails with a JOURNAL-ERROR. After
    invalidation, a new FILE-JOURNAL object is created.

- [reader] PATHNAME-OF FILE-JOURNAL (:PATHNAME)

    The pathname of the file backing the journal.

### Pretty-printing journals

- [class] PPRINT-JOURNAL JOURNAL

    When an event is written to a PPRINT-JOURNAL it
    writes that event to a stream in a customizable format. They are
    intended for producing prettier output for @LOGGING and @TRACING,
    but they do not support reads so they cannot be used as a
    REPLAY-JOURNAL, or in LIST-EVENTS, for example. On the other hand,
    events written to PPRINT-JOURNALs need not be @READABLE.

- [function] MAKE-PPRINT-JOURNAL &KEY (STREAM (MAKE-SYNONYM-STREAM '\*STANDARD-OUTPUT\*)) (PRETTY T) (PRETTIFIER 'PRETTIFY-EVENT) LOG-DECORATOR

    Creates a PPRINT-JOURNAL.

- [accessor] PPRINT-JOURNAL-STREAM PPRINT-JOURNAL (:STREAM = \*STANDARD-OUTPUT\*)

    The stream where events are dumped. May be set any
    time to another STREAM.

- [accessor] PPRINT-JOURNAL-PRETTY PPRINT-JOURNAL (:PRETTY = T)

    Whether to use PPRINT-JOURNAL-PRETTIFIER or write
    events in as the property lists they are. A
    @BOOLEAN-VALUED-SYMBOL.

- [accessor] PPRINT-JOURNAL-PRETTIFIER PPRINT-JOURNAL (:PRETTIFIER = 'PRETTIFY-EVENT)

    A function like PRETTIFY-EVENT that writes its an
    event to a stream. Only used when PPRINT-JOURNAL-PRETTY, this is
    the output format customization knob. Also see @DECORATIONs.

## Bundles reference

In @BUNDLES, we covered the repeated replay problem that
WITH-BUNDLE automates. Here we provide a reference for the bundle
classes.

- [class] BUNDLE

    This is an abstract base class. Direct subclasses
    are IN-MEMORY-BUNDLE and FILE-BUNDLE.
    
    A BUNDLE consists of a sequence of journals which are all reruns of
    the same code, hopefully making more and more progress towards
    completion. These journals are @REPLAYs of the previous successful
    one, extending it with new events. Upon replay (see WITH-BUNDLE),
    the latest journal in the bundle in JOURNAL-STATE :COMPLETED plays
    the role of the replay journal, and a new journal is added to the
    bundle for recording. If the replay succeeds, this new journal
    eventually becomes :COMPLETED and takes over the role of the replay
    journal for future replays until another replay succeeds. When the
    bundle is created and it has no journals yet, the replay journal is
    an empty, completed one.

- [accessor] MAX-N-FAILED BUNDLE (:MAX-N-FAILED = 1)

    If MAX-N-FAILED is non-NIL, and the number of
    journals of [JOURNAL-STATE][type] :FAILED in the bundle exceeds
    its value, then some journals (starting with the oldest) are
    deleted.

- [accessor] MAX-N-COMPLETED BUNDLE (:MAX-N-COMPLETED = 1)

    If MAX-N-COMPLETED is non-NIL, and the number of
    journals of [JOURNAL-STATE][type] :COMPLETED in the bundle exceeds
    its value, then some journals (starting with the oldest) are
    deleted.

### In-memory bundles

- [class] IN-MEMORY-BUNDLE BUNDLE

    An IN-MEMORY-BUNDLE is a BUNDLE that is built on
    IN-MEMORY-JOURNALs. IN-MEMORY-BUNDLEs have limited utility as a
    persistence mechanism and are provided mainly for reasons of
    symmetry and for testing. See
    @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS for an example of how to
    achieve persistence without bundles.

- [function] MAKE-IN-MEMORY-BUNDLE &KEY (MAX-N-FAILED 1) (MAX-N-COMPLETED 1) SYNC SYNC-FN

    Create a new IN-MEMORY-BUNDLE with [MAX-N-FAILED][(accessor
    bundle)] and [MAX-N-COMPLETED][(accessor bundle)]. SYNC and SYNC-FN
    are passed on to MAKE-IN-MEMORY-JOURNAL.

### File bundles

- [class] FILE-BUNDLE BUNDLE

    A FILE-BUNDLE is a BUNDLE that is built on
    FILE-JOURNALs. It provides easy replay-based persistence.

- [reader] DIRECTORY-OF FILE-BUNDLE (:DIRECTORY)

    The directory where the files backing the
    FILE-JOURNALs in the FILE-BUNDLE are kept.

- [function] MAKE-FILE-BUNDLE DIRECTORY &KEY (MAX-N-FAILED 1) (MAX-N-COMPLETED 1) SYNC

    Return a FILE-BUNDLE object backed by FILE-JOURNALs in DIRECTORY.
    See [MAX-N-FAILED][(accessor bundle)] and
    [MAX-N-COMPLETED][(accessor bundle)]. For a description of SYNC, see
    @SYNCHRONIZATION-STRATEGIES.
    
    If there is already a FILE-BUNDLE with the same directory (according
    to TRUENAME), return that object is returned if it has the same
    MAX-N-FAILED, MAX-N-COMPLETED and SYNC options, else JOURNAL-ERROR
    is signalled.

- [function] DELETE-FILE-BUNDLE DIRECTORY

    Delete all journal files (`*.jrn`) from DIRECTORY. Delete the
    directory if empty after the journal files were deleted, else signal
    an error. Existing FILE-BUNDLE objects are not updated, so
    MAKE-FILE-JOURNAL with FORCE-RELOAD may be required.

## Streamlets reference

This section is relevant mostly for implementing new kinds of
JOURNALs in addition to FILE-JOURNALs and IN-MEMORY-JOURNALs. In
normal operation, STREAMLETs are not worked with directly.

### Opening and closing

- [class] STREAMLET

    A STREAMLET is a handle to perform I/O on a
    JOURNAL. The high-level stuff (WITH-JOURNALING, JOURNALED, etc) is
    built on top of streamlets.

- [reader] JOURNAL STREAMLET (:JOURNAL)

    The JOURNAL that was passed to OPEN-STREAMLET.
    This is the journal STREAMLET operates on.

- [generic-function] OPEN-STREAMLET JOURNAL &KEY DIRECTION

    Return a STREAMLET suitable for performing I/O on
    JOURNAL. DIRECTION (defaults to :INPUT) is one of :INPUT, :OUTPUT,
    :IO and it has the same purpose as the similarly named argument of
    CL:OPEN.

- [generic-function] CLOSE-STREAMLET STREAMLET

    Close STREAMLET, which was returned by
    OPEN-STREAMLET. After closing, STREAMLET may not longer be used for
    IO.

- [generic-function] MAKE-STREAMLET-FINALIZER STREAMLET

    Return NIL or a function of no arguments suitable
    as a finalizer for STREAMLET. That is, the function closes
    STREAMLET, but holds no reference to it. This is intended for
    streamlets which are not dynamic-extent, so using WITH-OPEN-JOURNAL
    is not appropriate.

- [generic-function] OPEN-STREAMLET-P STREAMLET

    Return true if STREAMLET is open. STREAMLETs are
    open until they have been explicitly closed with CLOSE-STREAMLET.

- [function] INPUT-STREAMLET-P STREAMLET

    See if STREAMLET was opened for input (the DIRECTION argument of
    OPEN-STREAMLET was :INPUT or :IO).

- [function] OUTPUT-STREAMLET-P STREAMLET

    See if STREAMLET was opened for input (the DIRECTION argument of
    OPEN-STREAMLET was :OUTPUT or :IO).

- [macro] WITH-OPEN-JOURNAL (VAR JOURNAL &KEY (DIRECTION :INPUT)) &BODY BODY

    This is like WITH-OPEN-FILE. Open the journal designated by
    JOURNAL (see TO-JOURNAL) with OPEN-STREAMLET, passing DIRECTION
    along, and bind VAR to the resulting STREAMLET. Call CLOSE-STREAMLET
    after BODY finishes. If JOURNAL is NIL, then VAR is bound to NIL and
    no streamlet is created.

- [condition] STREAMLET-ERROR ERROR

    Like CL:STREAM-ERROR: failures regarding trying to
    perform I/O on a closed STREAMLET or of the wrong DIRECTION. Actual
    I/O errors are *not* encapsulated in STREAMLET-ERROR.

### Reading from streamlets

- [generic-function] READ-EVENT STREAMLET &OPTIONAL EOJ-ERROR-P

    Read the event at the current read position from
    STREAMLET and move the read position to the event after. If there
    are no more events, signal END-OF-JOURNAL or return NIL depending on
    EOJ-ERROR-P. Signals STREAMLET-ERROR if STREAMLET is not
    INPUT-STREAMLET-P or not OPEN-STREAMLET-P.

- [generic-function] READ-POSITION STREAMLET

    Return an integer that identifies the position of
    the next event to be read from STREAMLET. `SETF`able, see
    SET-READ-POSITION.

- [generic-function] SET-READ-POSITION STREAMLET POSITION

    Set the read position of STREAMLET to POSITION,
    which must have been acquired from READ-POSITION.

- [macro] SAVE-EXCURSION (STREAMLET) &BODY BODY

    Save READ-POSITION of STREAMLET, execute BODY, and make sure to
    restore the saved read position.

- [generic-function] PEEK-EVENT STREAMLET

    Read the next event from STREAMLET without changing
    the read position, or return NIL if there is no event to be read.

- [method] PEEK-EVENT (STREAMLET STREAMLET)

    This is a slow default implementation, which relies on
    SAVE-EXCURSION and READ-EVENT.

### Writing to streamlets

- [generic-function] WRITE-EVENT EVENT STREAMLET

    Write EVENT to STREAMLET. Writing always happens at
    the end of STREAMLET's journal regardless of the READ-POSITION and
    the read position is not changed. Signals STREAMLET-ERROR if
    STREAMLET is not OUTPUT-STREAMLET-P or not OPEN-STREAMLET-P.

- [method] WRITE-EVENT EVENT (JOURNAL JOURNAL)

    For convenience, it is possible to write directly to a JOURNAL,
    in which case the journal's internal output streamlet is used.
    This internal streamlet is opened for :OUTPUT and may be used by
    LOG-RECORD.

- [generic-function] WRITE-POSITION STREAMLET

    Return an integer that identifies the position of
    the next event to be written to STREAMLET.

- [generic-function] REQUEST-COMPLETED-ON-ABORT STREAMLET

    Make it so that upon ABORTED-EXECUTION STREAMLET's
    JOURNAL will be in JOURNAL-STATE :COMPLETED when loaded fresh (e.g.
    FILE-JOURNAL from a file). Any previously written events must be
    persisted before making this change. Before
    REQUEST-COMPLETED-ON-ABORT is called, a journal must be reloaded in
    state :FAILED.
    
    It is permissible to defer carrying out this request until the next
    SYNC-STREAMLET call. If the request was carried out, return true. If
    it was deferred, return NIL.

- [generic-function] SYNC-STREAMLET STREAMLET

    Durably persist the effects of all preceding
    WRITE-EVENT calls made via STREAMLET to its journal and any deferred
    REQUEST-COMPLETED-ON-ABORT in this order.

## Glossary

- [glossary-term] async-unwind

    If an asynchronous event, say a `SIGINT` triggered by `C-c`, is
    delivered to a thread running Lisp or foreign code called from Lisp,
    a Lisp condition is typically signalled. If the handler for this
    condition unwinds the stack, then we have an asynchronous unwind.
    Another example is BT:INTERRUPT-THREAD which, as it can execute
    arbitrary code, may unwind the stack in the target thread.

- [glossary-term] boolean-valued symbol

    Imagine writing two STREAMs with a spaghetti of functions and
    wanting to have pretty-printed output on one of them. Unfortunately,
    binding *PRINT-PRETTY* to T will affect writes to both streams.
    
    A solution is to have streams look up their own print-pretty flag
    with `(SYMBOL-VALUE (STREAM-PRETTY-PRINT STREAM))` and have the
    caller specify the dynamic variable they want:
    
    ```
    (defvar *print-pretty-1* nil)
    (setf (stream-print-pretty stream-1) '*print-pretty-1*)
    (let ((*print-pretty-1* t))
      (spaghetti stream-1 stream-2))
    ```
    
    Note that if the default `STREAM-PRINT-PRETTY` is `'*PRINT-PRETTY*`,
    then we have the normal Common Lisp behaviour. Setting
    `STREAM-PRINT-PRETTY` to NIL or T also works, because they are
    self-evaluating.
    
    If not by CL:STREAMs, boolean-valued symbols are used by
    MAKE-LOG-DECORATOR and PPRINT-JOURNALs.

- [glossary-term] non-local exit

    This is a term from the Common Lisp ANSI standard. If a form does
    not return normally, but control is transferred via `GO`, RETURN,
    RETURN-FROM or THROW, then it is said to have performed a non-local
    exit. This definition of a non-local exit includes EVENT-EXIT
    :CONDITION, :ERROR and :NLX.

- [glossary-term] readable

    In Common Lisp, readable objects are those that can be printed readably.
    Anything written to stream-based journals needs to be readable.

* * *
###### \[generated by [MGL-PAX](https://github.com/melisgl/mgl-pax)\]


Next: , Previous: , Up: Top   [Contents][Index]

2 Systems

The main system appears first, followed by any subsystem dependency.


Previous: , Up: Systems   [Contents][Index]

2.1 journal

Author

Gábor Melis <mega@retes.hu>

Home Page

http://github.com/melisgl/journal

Source Control

(:git "https://github.com/melisgl/journal.git")

Bug Tracker

http://github.com/melisgl/journal/issues

License

MIT, see COPYING.

Description

A library for logging, tracing, testing and persistence.

Version

0.1.0

Dependencies
Source

journal.asd (file)

Component

src (module)


Next: , Previous: , Up: Top   [Contents][Index]

3 Modules

Modules are listed depth-first from the system components tree.


Previous: , Up: Modules   [Contents][Index]

3.1 journal/src

Parent

journal (system)

Location

src/

Components

Next: , Previous: , Up: Top   [Contents][Index]

4 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Previous: , Up: Files   [Contents][Index]

4.1 Lisp


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.1 journal.asd

Location

journal.asd

Systems

journal (system)


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.2 journal/src/package.lisp

Parent

src (module)

Location

src/package.lisp

Packages

journal


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.3 journal/src/interrupt.lisp

Dependency

package.lisp (file)

Parent

src (module)

Location

src/interrupt.lisp

Internal Definitions

Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.4 journal/src/journal.lisp

Dependency

interrupt.lisp (file)

Parent

src (module)

Location

src/journal.lisp

Exported Definitions
Internal Definitions

Previous: , Up: Lisp files   [Contents][Index]

4.1.5 journal/src/doc.lisp

Dependency

journal.lisp (file)

Parent

src (module)

Location

src/doc.lisp

Internal Definitions

Next: , Previous: , Up: Top   [Contents][Index]

5 Packages

Packages are listed by definition order.


Previous: , Up: Packages   [Contents][Index]

5.1 journal

Source

package.lisp (file)

Nickname

jrn

Use List
Exported Definitions
Internal Definitions

Next: , Previous: , Up: Top   [Contents][Index]

6 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

6.1 Exported definitions


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.1 Special variables

Special Variable: *force-insertable*

The default value of the INSERTABLE argument of JOURNALED for VERSIONED-EVENTs. Binding this to T allows en-masse structural upgrades in combination with WITH-REPLAY-FILTER. Does not affect EXTERNAL-EVENTs. See @UPGRADES-AND-REPLAY.

Package

journal

Source

journal.lisp (file)

Special Variable: *trace-journal*

The JOURNAL where JTRACE writes LOG-EVENTs. By default it is a PPRINT-JOURNAL that sets up a SYNONYM-STREAM to *TRACE-OUTPUT* and sends its output there. It pays attention to *TRACE-PRETTY*, and its log decorator is affected by *TRACE-TIME* and *TRACE-THREAD*. However, by changing JOURNAL-LOG-DECORATOR and PPRINT-JOURNAL-PRETTIFIER content and output can be customized.

Package

journal

Source

journal.lisp (file)

Special Variable: *trace-pretty*

If *TRACE-PRETTY* is true, then JTRACE produces output like PPRINT-EVENTS, else it’s like PRINT-EVENTS.

Package

journal

Source

journal.lisp (file)

Special Variable: *trace-real-time*

Controls whether to decorate the trace with the internal real-time. See MAKE-LOG-DECORATOR.

Package

journal

Source

journal.lisp (file)

Special Variable: *trace-run-time*

Controls whether to decorate the trace with the internal run-time. See MAKE-LOG-DECORATOR.

Package

journal

Source

journal.lisp (file)

Special Variable: *trace-thread*

Controls whether to decorate the trace with the name of the originating thread. See MAKE-LOG-DECORATOR.

Package

journal

Source

journal.lisp (file)

Special Variable: *trace-time*

Controls whether to decorate the trace with a timestamp. See MAKE-LOG-DECORATOR.

Package

journal

Source

journal.lisp (file)

Special Variable: @block
Package

journal

Source

journal.lisp (file)

Special Variable: @bundles
Package

journal

Source

journal.lisp (file)

Special Variable: @bundles-reference
Package

journal

Source

journal.lisp (file)

Special Variable: @comparing-journals
Package

journal

Source

journal.lisp (file)

Special Variable: @customizing-logs
Package

journal

Source

journal.lisp (file)

Special Variable: @decoration
Package

journal

Source

journal.lisp (file)

Special Variable: @event-versions
Package

journal

Source

journal.lisp (file)

Special Variable: @events-reference
Package

journal

Source

journal.lisp (file)

Special Variable: @file-bundles
Package

journal

Source

journal.lisp (file)

Special Variable: @file-journals
Package

journal

Source

journal.lisp (file)

Special Variable: @frame
Package

journal

Source

journal.lisp (file)

Special Variable: @in-events
Package

journal

Source

journal.lisp (file)

Special Variable: @in-events-reference
Package

journal

Source

journal.lisp (file)

Special Variable: @in-memory-bundles
Package

journal

Source

journal.lisp (file)

Special Variable: @in-memory-journals
Package

journal

Source

journal.lisp (file)

Special Variable: @journal-background
Package

journal

Source

journal.lisp (file)

Special Variable: @journal-basics
Package

journal

Source

journal.lisp (file)

Special Variable: @journal-error-handling
Package

journal

Source

journal.lisp (file)

Special Variable: @journal-features
Package

journal

Source

journal.lisp (file)

Package

journal

Source

journal.lisp (file)

Special Variable: @journal-manual
Package

journal

Source

journal.lisp (file)

Special Variable: @journal-portability
Package

journal

Source

journal.lisp (file)

Special Variable: @journal-slime-integration
Package

journal

Source

journal.lisp (file)

Special Variable: @journal-utilities
Package

journal

Source

journal.lisp (file)

Special Variable: @journal/glossary
Package

journal

Source

journal.lisp (file)

Special Variable: @journaled-for-replay
Package

journal

Source

journal.lisp (file)

Special Variable: @journals-reference
Package

journal

Source

journal.lisp (file)

Special Variable: @leaf-events-reference
Package

journal

Source

journal.lisp (file)

Special Variable: @log-record
Package

journal

Source

journal.lisp (file)

Special Variable: @logging
Package

journal

Source

journal.lisp (file)

Special Variable: @logging-with-leaves
Package

journal

Source

journal.lisp (file)

Special Variable: @matching-in-events
Package

journal

Source

journal.lisp (file)

Special Variable: @matching-out-events
Package

journal

Source

journal.lisp (file)

Special Variable: @opening-and-closing
Package

journal

Source

journal.lisp (file)

Special Variable: @out-events
Package

journal

Source

journal.lisp (file)

Special Variable: @out-events-reference
Package

journal

Source

journal.lisp (file)

Special Variable: @persistence
Package

journal

Source

journal.lisp (file)

Special Variable: @persistence-tutorial
Package

journal

Source

journal.lisp (file)

Special Variable: @pprint-journals
Package

journal

Source

journal.lisp (file)

Special Variable: @pretty-printing
Package

journal

Source

journal.lisp (file)

Special Variable: @reading-from-streamlets
Package

journal

Source

journal.lisp (file)

Special Variable: @replay
Package

journal

Source

journal.lisp (file)

Special Variable: @replay-failures
Package

journal

Source

journal.lisp (file)

Special Variable: @replaying-the-outcome
Package

journal

Source

journal.lisp (file)

Special Variable: @safety
Package

journal

Source

journal.lisp (file)

Special Variable: @streamlets-reference
Package

journal

Source

journal.lisp (file)

Special Variable: @synchronization
Package

journal

Source

journal.lisp (file)

Special Variable: @synchronization-strategies
Package

journal

Source

journal.lisp (file)

Special Variable: @synchronization-with-file-journals
Package

journal

Source

journal.lisp (file)

Special Variable: @synchronization-with-in-memory-journals
Package

journal

Source

journal.lisp (file)

Special Variable: @testing
Package

journal

Source

journal.lisp (file)

Special Variable: @testing-on-multiple-levels
Package

journal

Source

journal.lisp (file)

Special Variable: @the-replay-strategy
Package

journal

Source

journal.lisp (file)

Special Variable: @tracing
Package

journal

Source

journal.lisp (file)

Special Variable: @upgrades-and-replay
Package

journal

Source

journal.lisp (file)

Special Variable: @working-with-unreadable-values
Package

journal

Source

journal.lisp (file)

Special Variable: @writing-to-streamlets
Package

journal

Source

journal.lisp (file)

Special Variable: aborted-execution
Package

journal

Source

journal.lisp (file)

Special Variable: condition-outcome
Package

journal

Source

journal.lisp (file)

Special Variable: data-event
Package

journal

Source

journal.lisp (file)

Special Variable: error-outcome
Package

journal

Source

journal.lisp (file)

Special Variable: expected-outcome
Package

journal

Source

journal.lisp (file)

Special Variable: invoked
Package

journal

Source

journal.lisp (file)

Special Variable: nlx-outcome
Package

journal

Source

journal.lisp (file)

Special Variable: replay-event
Package

journal

Source

journal.lisp (file)

Special Variable: unexpected-outcome
Package

journal

Source

journal.lisp (file)

Special Variable: values-outcome
Package

journal

Source

journal.lisp (file)


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.2 Macros

Macro: checked (NAME &key VERSION ARGS VALUES CONDITION INSERTABLE) &body BODY

A wrapper around JOURNALED to produce @FRAMEs of VERSIONED-EVENTs. VERSION defaults to 1. CHECKED is for ensuring that supposedly deterministic processing does not veer off the replay.

With CHECKED, BODY - which must be deterministic - is always run and REPLAY-FAILUREs are triggered when the events generated do not match the events in the replay journal. BODY may have side-effects.

For further discussion of determinism, see REPLAYED.

Package

journal

Source

journal.lisp (file)

Macro: define-file-bundle-test (NAME &key DIRECTORY EQUIVALENTP) &body BODY

Define a function with NAME for record-and-replay testing. The function’s BODY is executed in a WITH-BUNDLE to guarantee replayability. The bundle in question is a FILE-BUNDLE created in DIRECTORY. The function has a single keyword argument, RERECORD. If RERECORD is true, the bundle is deleted with DELETE-FILE-BUNDLE to start afresh.

Furthermore, if BODY returns normally, and it is a replay of a previous run, and EQUIVALENTP, then it is ASSERTed that the record and replay journals are EQUIVALENT-REPLAY-JOURNALS-P. If this check fails, RECORD-JOURNAL is discarded when the function returns. In addition to the replay consistency, this checks that no inserts or upgrades were performed (see @THE-REPLAY-STRATEGY).

Package

journal

Source

journal.lisp (file)

Macro: define-invoked FUNCTION-NAME ARGS (NAME &key VERSION INSERTABLE) &body BODY

DEFINE-INVOKED is intended for recording asynchronous function invocations like event or signal handlers. It defines a function that records VERSIONED-EVENTs with ARGS set to the actual arguments. At replay, it is invoked whenever the recorded IN-EVENT becomes the REPLAY-EVENT.

DEFUN and CHECKED rolled into one, DEFINE-INVOKED defines a top-level function with FUNCTION-NAME and ARGS (only simple positional arguments are allowed) and wraps CHECKED with NAME, the same ARGS and INSERTABLE around BODY. Whenever an IN-EVENT becomes the REPLAY-EVENT and it has a DEFINE-INVOKED defined with the name of the event, then FUNCTION-NAME is invoked with EVENT-ARGS.

While BODY’s return values are recorded as usual, the defined function returns no values to make it less likely to affect control flow in a way that’s not possible to reproduce when the function is called by the replay mechanism.

“‘
(defvar *state*)

(define-invoked foo (x) ("foo")
(setq *state* (1+ x)))

(define-invoked bar (x) ("bar")
(setq *state* (+ 2 x)))

(if (zerop (random 2))
(foo 0)
(bar 1))
“‘

The above can be alternatively implemented with REPLAYED explicitly encapsulating the non-determinism:

“‘
(let ((x (replayed (choose) (random 2))))
(if (zerop x)
(checked (foo :args ‘(,x))
(setq *state* (1+ x)))
(checked (bar :args ‘(,x))
(setq *state* (+ 2 x)))))
“‘

Package

journal

Source

journal.lisp (file)

Macro: flet-invoked DEFINITIONS &body BODY

Like DEFINE-INVOKED, but with FLET instead of DEFUN. The event name and the function are associated in the dynamic extent of BODY. WITH-JOURNALING does not change the bindings. The example in DEFINE-INVOKED can be rewritten as:

“‘
(let ((state nil))
(flet-invoked ((foo (x) ("foo")
(setq state (1+ x)))
(bar (x) ("bar")
(setq state (+ 2 x))))
(if (zerop (random 2))
(foo 0)
(bar 1))))
“‘

Package

journal

Source

journal.lisp (file)

Macro: framed (NAME &key LOG-RECORD ARGS VALUES CONDITION) &body BODY

A wrapper around JOURNALED to produce @FRAMEs of LOG-EVENTs. That is, VERSION is always NIL, and some irrelevant arguments are omitted. The related LOGGED creates a single LEAF-EVENT.

With FRAMED, BODY is always run and no REPLAY-FAILUREs are triggered. BODY is not required to be deterministic and it may have side-effects.

Package

journal

Source

journal.lisp (file)

Macro: journaled (NAME &key LOG-RECORD VERSION ARGS VALUES CONDITION INSERTABLE REPLAY-VALUES REPLAY-CONDITION) &body BODY

JOURNALED generates events upon entering and leaving the dynamic extent of BODY (also known as the journaled @BLOCK), which we call the @IN-EVENTS and @OUT-EVENTS. Between generating the two events, BODY is typically executed normally (except for @REPLAYING-THE-OUTCOME).

Where the generated events are written is determined by the :RECORD argument of the enclosing WITH-JOURNALING. If there is no enclosing WITH-JOURNALING and LOG-RECORD is NIL, then event recording is turned off and JOURNALED imposes minimal overhead.

- NAME can be of any type except [NULL][type], not evaluated. For names, and for anything that gets written to a journal, a non-keyword symbol is a reasonable choice as it can be easily made unique. However, it also exposes the package structure, which might make reading stuff back more difficult. Keywords and strings do not have this problem.

- ARGS can be of any type, but is typically a list.

Also see in @LOG-RECORD in the @LOGGING section. For a description of VERSION, INSERTABLE, REPLAY-VALUES and REPLAY-CONDITION, see @JOURNALED-FOR-REPLAY.

Package

journal

Source

journal.lisp (file)

Macro: jtrace &rest NAMES

Like CL:TRACE, JTRACE takes a list of symbols. When functions denoted by those NAMES are invoked, their names, arguments and outcomes are printed in human readable form to *TRACE-OUTPUT*. These values may not be @READABLE, JTRACE does not care.

The format of the output is the same as that of PPRINT-EVENTS. Behind the scenes, JTRACE encapsulates the global functions with NAMES in wrapper that behaves as if ‘FOO‘ in the example above was defined like this:

“‘
(defun foo (x)
(framed (foo :args ‘(,x) :log-record *trace-journal*)
(1+ x)))
“‘

If JTRACE is invoked with no arguments, it returns the list of symbols currently traced.

On Lisps other than SBCL, where a function encapsulation facility is not available or it is not used by Journal, JTRACE simply sets SYMBOL-FUNCTION. This solution loses the tracing encapsulation when the function is recompiled. On these platforms, ‘(JTRACE)‘ also retraces all functions that should be traced, but aren’t.

The main advantage of JTRACE over CL:TRACE is the ability to trace errors, not just normal return values. As it is built on JOURNALED, it can also detect - somewhat heuristically - THROWs and similar.

Package

journal

Source

journal.lisp (file)

Macro: juntrace &rest NAMES

Like CL:UNTRACE, JUNTRACE makes it so that the global functions denoted by the symbols NAMES are no longer traced by JTRACE. When invoked with no arguments, it untraces all traced functions.

Package

journal

Source

journal.lisp (file)

Macro: logged (&optional LOG-RECORD) FORMAT-CONTROL &rest FORMAT-ARGS

LOGGED creates a single LEAF-EVENT whose name is the string constructed by FORMAT. For example:

“‘
(with-journaling (:record t)
(logged () "Hello, ~A." "world")
(list-events))
=> ((:LEAF "Hello, world."))
“‘

LEAF-EVENTs are LOG-EVENTs with no separate in- and out-events. They have an EVENT-NAME and no other properties. Use LOGGED for point-in-time textual log messages, and JOURNALED with VERSION NIL (i.e. FRAMED) to provide context.

Also see @LOG-RECORD.

Package

journal

Source

journal.lisp (file)

Macro: replayed (NAME &key ARGS VALUES CONDITION INSERTABLE REPLAY-VALUES REPLAY-CONDITION) &body BODY

A wrapper around JOURNALED to produce @FRAMEs of EXTERNAL-EVENTs. VERSION is :INFINITY. REPLAYED is for primarily for marking and isolating non-deterministic processing.

With REPLAYED, the IN-EVENT is checked for consistency with the replay (as with CHECKED), but BODY is not run (assuming it has a recorded EXPECTED-OUTCOME) and the outcome in the OUT-EVENT is reproduced (see @REPLAYING-THE-OUTCOME). For this scheme to work, REPLAYED requires its BODY to be side-effect free, but it may be non-deterministic.

Package

journal

Source

journal.lisp (file)

Macro: save-excursion (STREAMLET) &body BODY

Save READ-POSITION of STREAMLET, execute BODY, and make sure to restore the saved read position.

Package

journal

Source

journal.lisp (file)

Macro: with-bundle (BUNDLE) &body BODY

This is like WITH-JOURNALING where the REPLAY-JOURNAL is the last successfully completed one in BUNDLE, and the RECORD-JOURNAL is a new one created in BUNDLE. When WITH-BUNDLE finishes, the record journal is in JOURNAL-STATE :FAILED or :COMPLETED.

To avoid accumulating useless data, the new record is immediately deleted when WITH-BUNDLE finishes if it has not diverged from the replay journal (see JOURNAL-DIVERGENT-P). Because :FAILED journals are always divergent in this sense, they are deleted instead based on whether there is already a previous failed journal in the bundle and the new record is identical to that journal (see IDENTICAL-JOURNALS-P).

It is a JOURNAL-ERROR to have concurrent or nested WITH-BUNDLEs on the same bundle.

Package

journal

Source

journal.lisp (file)

Macro: with-journaling (&key RECORD REPLAY REPLAY-EOJ-ERROR-P) &body BODY

Turn recording and/or replaying of events on or off for the duration of BODY. Both RECORD and REPLAY should be a JOURNAL designator (in the sense of TO-JOURNAL) or NIL.

If RECORD designates a JOURNAL, then events generated by enclosed JOURNALED @BLOCKs are written to that journal (with exceptions, see the LOG-RECORD argument of JOURNALED). If REPLAY designates a JOURNAL, then the generated events are matched against events from that journal according to the rules of @REPLAY.

A JOURNAL-ERROR is signalled, if RECORD is a JOURNAL that has been previously recorded to by another WITH-JOURNALING (that is, if its JOURNAL-STATE is not :NEW), or if REPLAY is a JOURNAL that is not a complete recording of successful replay (i.e. its JOURNAL-STATE is not :COMPLETED). These checks are intended to catch mistakes that would render the new or existing records unusable for replay. When WITH-JOURNALING finishes, the RECORD journal is marked :COMPLETED or :FAILED in its JOURNAL-STATE.

REPLAY-EOJ-ERROR-P controls whether an END-OF-JOURNAL is signalled when a new event is being matched to the replay journal from which there are no more events to read. If there was a JOURNALING-FAILURE or a REPLAY-FAILURE during execution, then END-OF-JOURNAL is not signalled.

If BODY completes successfully, but REPLAY has unprocessed events, then signal REPLAY-INCOMPLETE.

WITH-JOURNALING for different RECORD journals can be nested and run independently.

Package

journal

Source

journal.lisp (file)

Macro: with-open-journal (VAR JOURNAL &key DIRECTION) &body BODY

This is like WITH-OPEN-FILE. Open the journal designated by JOURNAL (see TO-JOURNAL) with OPEN-STREAMLET, passing DIRECTION along, and bind VAR to the resulting STREAMLET. Call CLOSE-STREAMLET after BODY finishes. If JOURNAL is NIL, then VAR is bound to NIL and no streamlet is created.

Package

journal

Source

journal.lisp (file)

Macro: with-replay-filter (&key MAP SKIP NO-REPLAY-OUTCOME) &body BODY

WITH-REPLAY-FILTER performs journal upgrade during replay by allowing events to be transformed as they are read from the replay journal or skipped if they match some patterns. For how to add new blocks in a code upgrade, see JOURNALED’s :INSERTABLE argument. In addition, it also allows some control over @REPLAYING-THE-OUTCOME.

- MAP: A function called with an event read from the replay journal which returns a transformed event. See @EVENTS-REFERENCE. MAP takes effect before before SKIP.

- SKIP: In addition to filtering out LOG-EVENTs (which always happens during replay), filter out all events that belong to descendant frames that match any of its SKIP patterns. Filtered out events are never seen by JOURNALED as it replays events. SKIP patterns are of the format ‘(&KEY NAME VERSION<)‘, where VERSION< is a valid [EVENT-VERSION][type], and NAME may be NIL, which acts as a wildcard.

SKIP is for when JOURNALED @BLOCKs are removed from the code, which would render replaying previously recorded journals impossible. Note that, for reasons of safety, it is not possible to filter EXTERNAL-EVENTs.

- NO-REPLAY-OUTCOME is a list of EVENT-NAMEs. @REPLAYING-THE-OUTCOME is prevented for frames with EQUAL names. See @TESTING-ON-MULTIPLE-LEVELS for an example.

WITH-REPLAY-FILTER affects only the immediately enclosing WITH-JOURNALING. A WITH-REPLAY-FILTER nested within another in the same WITH-JOURNALING inherits the SKIP patterns of its parent, to which it adds its own. The MAP function is applied to before the parent’s MAP.

Examples of SKIP patterns:

“‘
;; Match events with name FOO and version 1, 2, 3 or 4
(:name foo :version< 5)
;; Match events with name BAR and any version
(:name bar :version< :infinity)
;; Same as the previous
(:name bar)
;; Match all names
(:name nil)
;; Same as the previous
()
“‘

Skipping can be thought of as removing nodes of the tree of frames, connecting its children to its parent. The following example removes frames ‘J1‘ and ‘J2‘ from around ‘J3‘, the ‘J1‘ frame from within ‘J3‘, and the third ‘J1‘ frame.

“‘
(let ((journal (make-in-memory-journal)))
;; Record trees J1 -> J2 -> J3 -> J1, and J1.
(with-journaling (:record journal)
(checked (j1)
(checked (j2)
(checked (j3)
(checked (j1)
42))))
(checked (j1)
7))
;; Filter out all occurrences of VERSIONED-EVENTs named J1 and ;; J2 from the replay, leaving only J3 to match. (with-journaling (:replay journal :record t :replay-eoj-error-p t) (with-replay-filter (:skip ’((:name j1) (:name j2))) (checked (j3)
42))))
“‘

Package

journal

Source

journal.lisp (file)

Macro: with-replay-streamlet (VAR) &body BODY

Open REPLAY-JOURNAL for reading with WITH-OPEN-JOURNAL set the READ-POSITION on it to the event next read by the @REPLAY mechanism (which is never a LOG-EVENT). The low-level @READING-FROM-STREAMLETS api is then available to inspect the contents of the replay. It is an error if REPLAY-JOURNAL is NIL.

Package

journal

Source

journal.lisp (file)


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.3 Functions

Function: delete-file-bundle DIRECTORY

Delete all journal files (‘*.jrn‘) from DIRECTORY. Delete the directory if empty after the journal files were deleted, else signal an error. Existing FILE-BUNDLE objects are not updated, so MAKE-FILE-JOURNAL with FORCE-RELOAD may be required.

Package

journal

Source

journal.lisp (file)

Function: event-args IN-EVENT

Return the arguments of IN-EVENT, normally populated with the ARGS form in JOURNALED.

Package

journal

Source

journal.lisp (file)

Function: event-exit OUT-EVENT

Return how the journaled @BLOCK finished. See [EVENT-EXIT][type] for the possible types.

Package

journal

Source

journal.lisp (file)

Function: event-name EVENT

The name of an event can be of any type. It is often a symbol or a string. When replaying, names may be compared with EQUAL. All EVENTs have names. The names of the in- and out-events belonging to the same @FRAME are the same.

Package

journal

Source

journal.lisp (file)

Function: event-outcome OUT-EVENT

Return the outcome of the @FRAME (or loosely speaking of a @BLOCK) to which OUT-EVENT belongs.

Package

journal

Source

journal.lisp (file)

Function: event-version EVENT

Return the version of EVENT of type EVENT-VERSION.

Package

journal

Source

journal.lisp (file)

Function: event= EVENT-1 EVENT-2

Return whether EVENT-1 and EVENT-2 represent the same event. In- and out-events belonging to the same @FRAME are _not_ the same event. EVENT-OUTCOME is not compared when EVENT-EXIT is :ERROR to avoid undue dependence on implementation specific string representations. This function is useful in conjunction with MAKE-IN-EVENT and MAKE-OUT-EVENT to write tests.

Package

journal

Source

journal.lisp (file)

Function: events-to-frames EVENTS

Convert a flat list of events, such as those returned by LIST-EVENTS, to a nested list representing the @FRAMEs. Each frame is a list of the form ‘(<in-event> <nested-frames>* <out-event>?)‘. Like in PRINT-EVENTS, EVENTS may be a JOURNAL.

“‘
(events-to-frames ’((:in foo :args (1 2))
(:in bar :args (7))
(:leaf "leaf")
(:out bar :values (8))
(:out foo :values (2))
(:in foo :args (3 4))
(:in bar :args (8))))
=> (((:IN FOO :ARGS (1 2))
((:IN BAR :ARGS (7))
(:LEAF "leaf")
(:OUT BAR :VALUES (8)))
(:OUT FOO :VALUES (2)))
((:IN FOO :ARGS (3 4)) ((:IN BAR :ARGS (8)))))
“‘

Note that, as in the above example, incomplete frames (those without an OUT-EVENT) are included in the output.

Package

journal

Source

journal.lisp (file)

Function: expected-outcome-p OUT-EVENT

See if OUT-EVENT has an EXPECTED-OUTCOME.

Package

journal

Source

journal.lisp (file)

Function: expected-type TYPE

Return a function suitable as the CONDITION argument of JOURNALED, which returns the type of its single argument as a string if it is of TYPE, else NIL.

Package

journal

Source

journal.lisp (file)

Function: external-event-p EVENT

See if EVENT is an EXTERNAL-EVENT.

Package

journal

Source

journal.lisp (file)

Function: in-event-p EVENT

See if EVENT is a IN-EVENT.

Package

journal

Source

journal.lisp (file)

Function: input-streamlet-p STREAMLET

See if STREAMLET was opened for input (the DIRECTION argument of OPEN-STREAMLET was :INPUT or :IO).

Package

journal

Source

journal.lisp (file)

Function: journal-divergent-p JOURNAL

See if WITH-JOURNALING recorded any event so far in this journal which was not EQUAL to its REPLAY-EVENT or it had no corresponding replay event. This completely ignores LOG-EVENTs in both journals being compared, and is updated continuously during @REPLAY. It plays a role in WITH-BUNDLE deciding when a journal is important enough to keep, and also in @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS.

The position of the first mismatch that is available via JOURNAL-REPLAY-MISMATCH.

Package

journal

Source

journal.lisp (file)

Function: journaling-failure CONDITION-TYPE &rest ARGS
Package

journal

Source

journal.lisp (file)

Function: leaf-event-p EVENT

See if EVENT is a LEAF-EVENT.

Package

journal

Source

journal.lisp (file)

Function: list-events &optional JOURNAL

Return a list of all the events in the journal designated by JOURNAL. Calls SYNC-JOURNAL first, to make sure that all writes are taken into account.

Package

journal

Source

journal.lisp (file)

Function: log-event-p EVENT

See if EVENT is a LOG-EVENT.

Package

journal

Source

journal.lisp (file)

Function: make-file-bundle DIRECTORY &key MAX-N-FAILED MAX-N-COMPLETED SYNC

Return a FILE-BUNDLE object backed by FILE-JOURNALs in DIRECTORY. See [MAX-N-FAILED][(accessor bundle)] and [MAX-N-COMPLETED][(accessor bundle)]. For a description of SYNC, see @SYNCHRONIZATION-STRATEGIES.

If there is already a FILE-BUNDLE with the same directory (according to TRUENAME), return that object is returned if it has the same MAX-N-FAILED, MAX-N-COMPLETED and SYNC options, else JOURNAL-ERROR is signalled.

Package

journal

Source

journal.lisp (file)

Function: make-file-journal PATHNAME &key SYNC

Return a FILE-JOURNAL backed by the file with PATHNAME. The file is created when the journal is opened for writing. For a description of SYNC, see @SYNCHRONIZATION-STRATEGIES.

If there is already an existing FILE-JOURNAL backed by the same file, then that object is returned. If the existing object has different options (e.g. it has SYNC T while the SYNC argument is NIL here), then a JOURNAL-ERROR is signalled.

If there is already an existing FILE-JOURNAL backed by the same file, the JOURNAL-STATE is not :NEW, but the file doesn’t exist, then the existing object is __invalidated__: attempts to write will fail with JOURNAL-ERROR. If the existing journal object is being written, then invalidation fails with a JOURNAL-ERROR. After invalidation, a new FILE-JOURNAL object is created.

Package

journal

Source

journal.lisp (file)

Function: make-in-event &key NAME VERSION ARGS

Create an IN-EVENT with NAME, VERSION (of type EVENT-VERSION) and ARGS as its EVENT-NAME, [EVENT-VERSION][function] and EVENT-ARGS.

Package

journal

Source

journal.lisp (file)

Function: make-in-memory-bundle &key MAX-N-FAILED MAX-N-COMPLETED SYNC SYNC-FN

Create a new IN-MEMORY-BUNDLE with [MAX-N-FAILED][(accessor bundle)] and [MAX-N-COMPLETED][(accessor bundle)]. SYNC and SYNC-FN are passed on to MAKE-IN-MEMORY-JOURNAL.

Package

journal

Source

journal.lisp (file)

Function: make-in-memory-journal &key EVENTS STATE SYNC SYNC-FN

By default, creates an empty IN-MEMORY-JOURNAL in JOURNAL-STATE
:NEW, which is suitable for recording. To make a replay journal, use :STATE :COMPLETED with some sequence of EVENTS:

“‘
(make-in-memory-journal :events ’((:in foo :version 1)) :state :completed) “‘

If the EVENTS argument is provided, then STATE defaults to :NEW,
else to :COMPLETED.

SYNC determines when SYNC-FN will be invoked on the RECORD-JOURNAL. SYNC defaults to T if SYNC-FN, else to NIL. For a description of possible values, see @SYNCHRONIZATION-STRATEGIES. For more
discussion, see @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS.

Package

journal

Source

journal.lisp (file)

Function: make-leaf-event NAME

Create a LEAF-EVENT with NAME.

Package

journal

Source

journal.lisp (file)

Function: make-log-decorator &key THREAD TIME REAL-TIME RUN-TIME

Return a function suitable as JOURNAL-LOG-DECORATOR that may add
the name of the thread, a timestamp, the internal real-time or run-time (both in seconds) to events. THREAD, TIME, REAL-TIME and RUN-TIME are @BOOLEAN-VALUED-SYMBOLs.

“‘
(funcall (make-log-decorator :thread t :time t :real-time t :run-time t) (make-leaf-event :foo))
=> (:LEAF :FOO :TIME "2020-08-31T13:38:58.129178+02:00"
:REAL-TIME 66328.82 :RUN-TIME 98.663 :THREAD "worker")
“‘

Package

journal

Source

journal.lisp (file)

Function: make-out-event &key NAME VERSION EXIT OUTCOME

Create an OUT-EVENT with NAME, VERSION (of type EVENT-VERSION), EXIT (of type EVENT-EXIT), and OUTCOME as its EVENT-NAME, [EVENT-VERSION][function], [EVENT-EXIT][function] and EVENT-OUTCOME.

Package

journal

Source

journal.lisp (file)

Function: make-pprint-journal &key STREAM PRETTY PRETTIFIER LOG-DECORATOR

Creates a PPRINT-JOURNAL.

Package

journal

Source

journal.lisp (file)

Function: out-event-p EVENT

See if EVENT is an OUT-EVENT.

Package

journal

Source

journal.lisp (file)

Function: output-streamlet-p STREAMLET

See if STREAMLET was opened for input (the DIRECTION argument of OPEN-STREAMLET was :OUTPUT or :IO).

Package

journal

Source

journal.lisp (file)

Function: peek-replay-event ()

Return the REPLAY-EVENT to be read from REPLAY-JOURNAL. This is roughly equivalent to

“‘
(when (replay-journal)
(with-replay-streamlet (streamlet)
(peek-event streamlet))
“‘

except PEEK-REPLAY-EVENT takes into account WITH-REPLAY-FILTER :MAP, and it may return ‘(:INDETERMINATE)‘ if WITH-REPLAY-FILTER :SKIP is in effect and what events are to be skipped cannot be decided until the next in-event generated by the code.

Imagine a business process for paying an invoice. In the first version of this process, we just pay the invoice:

“‘
(replayed (pay))
“‘

We have left the implementation of PAY blank. In the second version, we need to get an approval first:

“‘
(when (replayed (get-approval)
(= (random 2) 0))
(replayed (pay)))
“‘

Replaying a journal produced by the first version of the code with the second version would run into difficulties because inserting EXTERNAL-EVENTs is tricky.

We have to first decide how to handle the lack of approval in the first version. Here, we just assume the processes started by the first version get approval automatically. The implementation is based on a dummy ‘PROCESS‘ block whose version is bumped when the payment process changes and is inspected at the start of journaling.

When v1 is replayed with v2, we introduce an INSERTABLE, versioned ‘GET-APPROVAL‘ block that just returns T. When replaying the code again, still with v2, the ‘GET-APPROVAL‘ block will be upgraded to :INFINITY.

“‘
(let ((bundle (make-in-memory-bundle)))
;; First version of the payment process. Just pay. (with-bundle (bundle)
(checked (process :version 1))
(replayed (pay)))
;; Second version of the payment process. Only pay if approved. (loop repeat 2 do
(with-bundle (bundle)
(let ((replay-process-event (peek-replay-event)))
(checked (process :version 2))
(when (if (and replay-process-event
(< (event-version replay-process-event) 2)) ;; This will be upgraded to :INFINITY the second ;; time around the LOOP.
(checked (get-approval :insertable t) t)
(replayed (get-approval)
(= (random 2) 0)))
(replayed (pay)))))))
“‘

Package

journal

Source

journal.lisp (file)

Function: pprint-events EVENTS &key STREAM PRETTIFIER

Like PRINT-EVENTS, but produces terser, more human readable output.

“‘
(pprint-events ’((:in log :args ("first arg" 2))
(:in versioned :version 1 :args (3))
(:leaf "This is a leaf, not a frame.") (:out versioned :version 1 :values (42 t)) (:out log :condition "a :CONDITION outcome") (:in log-2)
(:out log-2 :nlx nil)
(:in external :version :infinity)
(:out external :version :infinity
:error ("ERROR" "an :ERROR outcome")))) ..
.. (LOG "first arg" 2)
.. (VERSIONED 3) v1
.. This is a leaf, not a frame.
.. => 42, T
.. =C "a :CONDITION outcome"
.. (LOG-2)
.. =X
.. (EXTERNAL) ext
.. =E "ERROR" "an :ERROR outcome"
=> ; No value
“‘

The function given as the PRETTIFIER argument formats individual events. The above output was produced with PRETTIFY-EVENT. For a description of PRETTIFIER’s arguments see PRETTIFY-EVENT.

Package

journal

Source

journal.lisp (file)

Function: prettify-event EVENT DEPTH STREAM

Write EVENT to STREAM in a somewhat human-friendly format. This
is the function PPRINT-JOURNAL, PPRINT-EVENTS, and @TRACING use by default. In addition to the basic example in PPRINT-EVENTS,
@DECORATION on events is printed before normal, indented output like this:

“‘
(pprint-events ’((:leaf "About to sleep" :time "19:57:00" :function "FOO"))) ..
.. 19:57:00 FOO: About to sleep
“‘

DEPTH is the nesting level of the EVENT. Top-level events have depth
0. PRETTIFY-EVENT prints indents the output, after printing the decorations, by 2 spaces per depth.

Package

journal

Source

journal.lisp (file)

Function: print-events EVENTS &key STREAM

Print EVENTS to STREAM as lists, starting a new line for each
event and indenting them according to their nesting structure.
EVENTS may be a JOURNAL, in which case LIST-EVENTS is called on it first.

“‘
(print-events ’((:in log :args ("first arg" 2))
(:in versioned :version 1 :args (3))
(:out versioned :version 1 :values (42 t))
(:out log :condition "a :CONDITION outcome")
(:in log-2)
(:out log-2 :nlx nil)
(:in external :version :infinity)
(:out external :version :infinity
:error ("ERROR" "an :ERROR outcome"))))
..
.. (:IN LOG :ARGS ("first arg" 2))
.. (:IN VERSIONED :VERSION 1 :ARGS (3))
.. (:OUT VERSIONED :VERSION 1 :VALUES (42 T))
.. (:OUT LOG :CONDITION "a :CONDITION outcome")
.. (:IN LOG-2)
.. (:OUT LOG-2 :NLX NIL)
.. (:IN EXTERNAL :VERSION :INFINITY)
.. (:OUT EXTERNAL :VERSION :INFINITY :ERROR ("ERROR" "an :ERROR outcome")) => ; No value
“‘

Package

journal

Source

journal.lisp (file)

Function: record-journal ()

Return the journal in which events are currently being recorded (see WITH-JOURNALING and WITH-BUNDLE) or NIL.

Package

journal

Source

journal.lisp (file)

Function: replay-failure CONDITION-TYPE &key NEW-EVENT REPLAY-EVENT INSERT-RESTART UPGRADE-RESTART CONTINUE-RESTART
Package

journal

Source

journal.lisp (file)

Function: replay-journal ()

Return the journal from which events are currently being replayed (see WITH-JOURNALING and WITH-BUNDLE) or NIL.

Package

journal

Source

journal.lisp (file)

Function: sync-journal &optional JOURNAL

Durably persist all preceding writes made to JOURNAL during an enclosing WITH-JOURNALING or via LOG-RECORD from any thread. Writes made in a WITH-JOURNALING in another thread are not persisted. The changes in question are WRITE-EVENT calls and state changes. This is a noop JOURNAL-SYNC is NIL. This function is safe to call from any thread.

Package

journal

Source

journal.lisp (file)

Function: unexpected-outcome-p OUT-EVENT

See if OUT-EVENT has an UNEXPECTED-OUTCOME.

Package

journal

Source

journal.lisp (file)

Function: values-> &rest FNS

A utility to create a function suitable as the [VALUES][argument] argument of JOURNALED. The VALUES function is called with the list of values returned by the @BLOCK and returns a transformed set of values that may be recorded in a journal. While arbitrary transformations are allowed, ‘VALUES->‘ handles the common case of transforming individual elements of the list independently by calling the functions in FN with the values of the list of the same position.

“‘
(funcall (values-> #’1+) ’(7 :something))
=> (8 :SOMETHING)
“‘

Note how ‘#’1+‘ is applied only to the first element of the values list. The list of functions is shorter than the values list, so ‘:SOMETHING‘ is not transformed. A value can be left explicitly untransformed by specifying #’IDENTITY or NIL as the function:

“‘
(funcall (values-> #’1+ nil #’symbol-name)
’(7 :something :another))
=> (8 :SOMETHING "ANOTHER")
“‘

Package

journal

Source

journal.lisp (file)

Function: values<- &rest FNS

The inverse of ‘VALUES->‘, this returns a function suitable as the REPLAY-VALUES argument of JOURNALED. It does pretty much what ‘VALUES->‘ does, but the function returned returns the transformed list as multiple values instead of as a list.

“‘
(funcall (values<- #’1-) ’(8 :something))
=> 7
=> :SOMETHING
“‘

Package

journal

Source

journal.lisp (file)

Function: versioned-event-p EVENT

See if EVENT is a VERSIONED-EVENT.

Package

journal

Source

journal.lisp (file)


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.4 Generic functions

Generic Function: close-streamlet STREAMLET

Close STREAMLET, which was returned by
OPEN-STREAMLET. After closing, STREAMLET may not longer be used for IO.

Package

journal

Source

journal.lisp (file)

Methods
Method: close-streamlet (STREAMLET file-streamlet)
Method: close-streamlet (STREAMLET in-memory-streamlet)
Method: close-streamlet (STREAMLET pprint-streamlet)
Method: close-streamlet (STREAMLET streamlet) around
Generic Function: directory-of OBJECT
Package

journal

Methods
Method: directory-of (FILE-BUNDLE file-bundle)

The directory where the files backing the FILE-JOURNALs in the FILE-BUNDLE are kept.

Source

journal.lisp (file)

Generic Function: equivalent-replay-journals-p JOURNAL-1 JOURNAL-2

See if two journals are equivalent when used the
for REPLAY in WITH-JOURNALING. EQUIVALENT-REPLAY-JOURNALS-P is like IDENTICAL-JOURNALS-P, but it ignores LOG-EVENTs and allows events with EVENT-EXIT :ERROR to differ in their outcomes, which may very well be implementation specific, anyway. Also, it considers two groups of states as different :NEW, :REPLAYING, :MISMATCHED, :FAILED vs :RECORDING, :LOGGING, COMPLETED.

Package

journal

Source

journal.lisp (file)

Methods
Method: equivalent-replay-journals-p JOURNAL-1 JOURNAL-2 around
Method: equivalent-replay-journals-p JOURNAL-1 JOURNAL-2
Generic Function: identical-journals-p JOURNAL-1 JOURNAL-2

Compare two journals in a strict sense: whether
they have the same JOURNAL-STATE and the lists of their events (as in LIST-EVENTS) are EQUAL.

Package

journal

Source

journal.lisp (file)

Methods
Method: identical-journals-p (JOURNAL-1 in-memory-journal) (JOURNAL-2 in-memory-journal)
Method: identical-journals-p JOURNAL-1 JOURNAL-2 around
Method: identical-journals-p JOURNAL-1 JOURNAL-2
Generic Function: journal OBJECT
Package

journal

Methods
Method: journal (CONDITION end-of-journal)
Source

journal.lisp (file)

Method: journal (CONDITION journal-error)
Source

journal.lisp (file)

Method: journal (STREAMLET streamlet)

The JOURNAL that was passed to OPEN-STREAMLET.
This is the journal [STREAMLET][dislocated] operates on.

Source

journal.lisp (file)

Generic Function: journal-events OBJECT
Package

journal

Methods
Method: journal-events (IN-MEMORY-JOURNAL in-memory-journal)

A sequence of events in the journal. Not to be mutated by client code.

Source

journal.lisp (file)

Generic Function: journal-log-decorator OBJECT
Generic Function: (setf journal-log-decorator) NEW-VALUE OBJECT
Package

journal

Methods
Method: journal-log-decorator (JOURNAL journal)
Method: (setf journal-log-decorator) NEW-VALUE (JOURNAL journal)

If non-NIL, a function to add @DECORATION to
LOG-EVENTs before they are written to a journal. The only allowed transformation is to _append_ a plist to the event, which is a plist itself. The keys can be anything.

Source

journal.lisp (file)

Generic Function: journal-previous-sync-position OBJECT
Package

journal

Methods
Method: journal-previous-sync-position (IN-MEMORY-JOURNAL in-memory-journal)

The length of JOURNAL-EVENTS at the time of the most recent invocation of SYNC-FN.

Source

journal.lisp (file)

Generic Function: journal-replay-mismatch OBJECT
Package

journal

Methods
Method: journal-replay-mismatch (JOURNAL journal)

If JOURNAL-DIVERGENT-P, then this is a list of two
elements: the READ-POSITIONs in the RECORD-JOURNAL and REPLAY-JOURNAL of the first events that were different (ignoring LOG-EVENTs). It is NIL, otherwise.

Source

journal.lisp (file)

Generic Function: journal-state OBJECT
Package

journal

Methods
Method: journal-state (JOURNAL journal)

Return the state of JOURNAL, which is of type [JOURNAL-STATE][TYPE].

Source

journal.lisp (file)

Generic Function: journal-sync OBJECT
Package

journal

Methods
Method: journal-sync (JOURNAL journal)

The SYNC argument specified at instantiation. See @SYNCHRONIZATION-STRATEGIES.

Source

journal.lisp (file)

Generic Function: journaling-failure-embedded-condition CONDITION
Package

journal

Methods
Method: journaling-failure-embedded-condition (CONDITION journaling-failure)
Source

journal.lisp (file)

Generic Function: make-streamlet-finalizer STREAMLET

Return NIL or a function of no arguments suitable
as a finalizer for STREAMLET. That is, the function closes STREAMLET, but holds no reference to it. This is intended for streamlets which are not dynamic-extent, so using WITH-OPEN-JOURNAL is not appropriate.

Package

journal

Source

journal.lisp (file)

Methods
Method: make-streamlet-finalizer (STREAMLET file-streamlet)
Method: make-streamlet-finalizer (STREAMLET in-memory-streamlet)
Method: make-streamlet-finalizer (STREAMLET pprint-streamlet)
Generic Function: max-n-completed OBJECT
Generic Function: (setf max-n-completed) NEW-VALUE OBJECT
Package

journal

Methods
Method: max-n-completed (BUNDLE bundle)
Method: (setf max-n-completed) NEW-VALUE (BUNDLE bundle)

If MAX-N-COMPLETED is non-NIL, and the number of
journals of [JOURNAL-STATE][type] :COMPLETED in the bundle exceeds its value, then some journals (starting with the oldest) are deleted.

Source

journal.lisp (file)

Generic Function: max-n-failed OBJECT
Generic Function: (setf max-n-failed) NEW-VALUE OBJECT
Package

journal

Methods
Method: max-n-failed (BUNDLE bundle)
Method: (setf max-n-failed) NEW-VALUE (BUNDLE bundle)

If MAX-N-FAILED is non-NIL, and the number of
journals of [JOURNAL-STATE][type] :FAILED in the bundle exceeds its value, then some journals (starting with the oldest) are deleted.

Source

journal.lisp (file)

Generic Function: open-streamlet JOURNAL &key DIRECTION

Return a STREAMLET suitable for performing I/O on
JOURNAL. DIRECTION (defaults to :INPUT) is one of :INPUT, :OUTPUT, :IO and it has the same purpose as the similarly named argument of CL:OPEN.

Package

journal

Source

journal.lisp (file)

Methods
Method: open-streamlet (BUNDLE bundle) &key DIRECTION
Method: open-streamlet (JOURNAL file-journal) &key DIRECTION
Method: open-streamlet (JOURNAL in-memory-journal) &key DIRECTION
Method: open-streamlet (JOURNAL pprint-journal) &key DIRECTION
Method: open-streamlet JOURNAL &key DIRECTION around
Generic Function: open-streamlet-p STREAMLET

Return true if STREAMLET is open. STREAMLETs are
open until they have been explicitly closed with CLOSE-STREAMLET.

Package

journal

Source

journal.lisp (file)

Methods
Method: open-streamlet-p (STREAMLET streamlet)
Generic Function: pathname-of OBJECT
Package

journal

Methods
Method: pathname-of (FILE-JOURNAL file-journal)

The pathname of the file backing the journal.

Source

journal.lisp (file)

Generic Function: peek-event STREAMLET

Read the next event from STREAMLET without changing
the read position, or return NIL if there is no event to be read.

Package

journal

Source

journal.lisp (file)

Methods
Method: peek-event (STREAMLET file-streamlet)
Method: peek-event (STREAMLET in-memory-streamlet)
Method: peek-event (STREAMLET streamlet)

This is a slow default implementation, which relies on SAVE-EXCURSION and READ-EVENT.

Generic Function: pprint-journal-prettifier OBJECT
Generic Function: (setf pprint-journal-prettifier) NEW-VALUE OBJECT
Package

journal

Methods
Method: pprint-journal-prettifier (PPRINT-JOURNAL pprint-journal)
Method: (setf pprint-journal-prettifier) NEW-VALUE (PPRINT-JOURNAL pprint-journal)

A function like PRETTIFY-EVENT that writes its an
event to a stream. Only used when PPRINT-JOURNAL-PRETTY, this is the output format customization knob. Also see @DECORATIONs.

Source

journal.lisp (file)

Generic Function: pprint-journal-pretty OBJECT
Generic Function: (setf pprint-journal-pretty) NEW-VALUE OBJECT
Package

journal

Methods
Method: pprint-journal-pretty (PPRINT-JOURNAL pprint-journal)
Method: (setf pprint-journal-pretty) NEW-VALUE (PPRINT-JOURNAL pprint-journal)

Whether to use PPRINT-JOURNAL-PRETTIFIER or write events in as the property lists they are. A @BOOLEAN-VALUED-SYMBOL.

Source

journal.lisp (file)

Generic Function: pprint-journal-stream OBJECT
Generic Function: (setf pprint-journal-stream) NEW-VALUE OBJECT
Package

journal

Methods
Method: pprint-journal-stream (PPRINT-JOURNAL pprint-journal)
Method: (setf pprint-journal-stream) NEW-VALUE (PPRINT-JOURNAL pprint-journal)

The stream where events are dumped. May be set any time to another STREAM.

Source

journal.lisp (file)

Generic Function: read-event STREAMLET &optional EOJ-ERROR-P

Read the event at the current read position from
STREAMLET and move the read position to the event after. If there are no more events, signal END-OF-JOURNAL or return NIL depending on EOJ-ERROR-P. Signals STREAMLET-ERROR if STREAMLET is not INPUT-STREAMLET-P or not OPEN-STREAMLET-P.

Package

journal

Source

journal.lisp (file)

Methods
Method: read-event (STREAMLET file-streamlet) &optional EOJ-ERROR-P
Method: read-event (STREAMLET in-memory-streamlet) &optional EOJ-ERROR-P
Method: read-event (STREAMLET streamlet) &optional EOJ-ERROR-P around
Generic Function: read-position STREAMLET

Return an integer that identifies the position of
the next event to be read from STREAMLET. ‘SETF‘able, see SET-READ-POSITION.

Package

journal

Source

journal.lisp (file)

Setf Expander

(setf read-position) (setf expander)

Methods
Method: read-position (STREAMLET file-streamlet)
Method: read-position (IN-MEMORY-STREAMLET in-memory-streamlet)

automatically generated reader method

Setf Expander: (setf read-position) STREAMLET POSITION
Package

journal

Source

journal.lisp (file)

Reader

read-position (generic function)

Writer

set-read-position (generic function)

Generic Function: replay-failure-new-event CONDITION
Package

journal

Methods
Method: replay-failure-new-event (CONDITION replay-failure)
Source

journal.lisp (file)

Generic Function: replay-failure-replay-event CONDITION
Package

journal

Methods
Method: replay-failure-replay-event (CONDITION replay-failure)
Source

journal.lisp (file)

Generic Function: replay-failure-replay-journal CONDITION
Package

journal

Methods
Method: replay-failure-replay-journal (CONDITION replay-failure)
Source

journal.lisp (file)

Generic Function: request-completed-on-abort STREAMLET

Make it so that upon ABORTED-EXECUTION STREAMLET’s
JOURNAL will be in JOURNAL-STATE :COMPLETED when loaded fresh (e.g. FILE-JOURNAL from a file). Any previously written events must be persisted before making this change. Before REQUEST-COMPLETED-ON-ABORT is called, a journal must be reloaded in state :FAILED.

It is permissible to defer carrying out this request until the next SYNC-STREAMLET call. If the request was carried out, return true. If it was deferred, return NIL.

Package

journal

Source

journal.lisp (file)

Methods
Method: request-completed-on-abort (STREAMLET file-streamlet)
Method: request-completed-on-abort (STREAMLET in-memory-streamlet)
Method: request-completed-on-abort (STREAMLET pprint-streamlet)
Method: request-completed-on-abort (STREAMLET streamlet) around
Generic Function: set-read-position STREAMLET POSITION

Set the read position of STREAMLET to POSITION, which must have been acquired from READ-POSITION.

Package

journal

Source

journal.lisp (file)

Setf Expander

(setf read-position) (setf expander)

Methods
Method: set-read-position (STREAMLET file-streamlet) READ-POSITION
Method: set-read-position (STREAMLET in-memory-streamlet) READ-POSITION
Generic Function: streamlet CONDITION
Package

journal

Methods
Method: streamlet (CONDITION streamlet-error)
Source

journal.lisp (file)

Generic Function: sync-streamlet STREAMLET

Durably persist the effects of all preceding
WRITE-EVENT calls made via STREAMLET to its journal and any deferred REQUEST-COMPLETED-ON-ABORT in this order.

Package

journal

Source

journal.lisp (file)

Methods
Method: sync-streamlet (STREAMLET file-streamlet)
Method: sync-streamlet (STREAMLET in-memory-streamlet)
Method: sync-streamlet (STREAMLET pprint-streamlet)
Method: sync-streamlet (STREAMLET streamlet) around
Generic Function: to-journal DESIGNATOR

Return the journal designated by DESIGNATOR or
signal an error. The default implementation:

- returns DESIGNATOR itself if it is of type JOURNAL, - returns a new IN-MEMORY-JOURNAL if DESIGNATOR is T, - returns a new FILE-JOURNAL if DESIGNATOR is a PATHNAME.

Package

journal

Source

journal.lisp (file)

Methods
Method: to-journal (BUNDLE bundle)
Method: to-journal (DESIGNATOR journal)
Method: to-journal (DESIGNATOR (eql t))
Method: to-journal (DESIGNATOR pathname)
Method: to-journal DESIGNATOR
Generic Function: write-event EVENT STREAMLET

Write EVENT to STREAMLET. Writing always happens at
the end of STREAMLET’s journal regardless of the READ-POSITION and the read position is not changed. Signals STREAMLET-ERROR if STREAMLET is not OUTPUT-STREAMLET-P or not OPEN-STREAMLET-P.

Package

journal

Source

journal.lisp (file)

Methods
Method: write-event EVENT (STREAMLET file-streamlet)
Method: write-event EVENT (STREAMLET in-memory-streamlet)
Method: write-event EVENT (STREAMLET pprint-streamlet)
Method: write-event EVENT (STREAMLET streamlet) around
Method: write-event EVENT (JOURNAL journal)

For convenience, it is possible to write directly to a JOURNAL, in which case the journal’s internal output streamlet is used. This internal streamlet is opened for :OUTPUT and may be used by LOG-RECORD.

Generic Function: write-position STREAMLET

Return an integer that identifies the position of the next event to be written to STREAMLET.

Package

journal

Source

journal.lisp (file)

Methods
Method: write-position (STREAMLET file-streamlet)
Method: write-position (STREAMLET in-memory-streamlet)
Method: write-position (STREAMLET streamlet) around

Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.5 Conditions

Condition: data-event-lossage ()

Signalled when a DATA-EVENT is about to be recorded
in JOURNAL-STATE :MISMATCHED or :LOGGING. Since the data event will not be replayed that constitutes data loss.

Package

journal

Source

journal.lisp (file)

Direct superclasses

journaling-failure (condition)

Condition: end-of-journal ()

This might be signalled by the replay mechanism if WITH-JOURNALING’s REPLAY-EOJ-ERROR-P is true. Unlike REPLAY-FAILUREs, this does not affect JOURNAL-STATE of RECORD-JOURNAL. At a lower level, it is signalled by READ-EVENT upon reading past the end of the JOURNAL if EOJ-ERROR-P.

Package

journal

Source

journal.lisp (file)

Direct superclasses

journal-error (condition)

Direct methods

journal (method)

Direct slots
Slot: journal
Initargs

:journal

Readers

journal (generic function)

Condition: journal-error ()

Signalled by WITH-JOURNALING, WITH-BUNDLE and by @LOG-RECORD. It is also signalled by the low-level streamlet interface (see @STREAMLETS-REFERENCE).

Package

journal

Source

journal.lisp (file)

Direct superclasses

error (condition)

Direct subclasses

end-of-journal (condition)

Direct methods
Direct slots
Slot: journal

The JOURNAL in question.

Initargs

:journal

Readers

journal (generic function)

Slot: format-control
Initargs

:format-control

Readers

format-control (generic function)

Slot: format-args
Initargs

:format-args

Initform

(quote nil)

Readers

format-args (generic function)

Condition: journaling-failure ()

Signalled during the dynamic extent of
WITH-JOURNALING when an error threatens to leave the journaling mechanism in an inconsistent state. These include I/O errors encountered reading or writing journals by WITH-JOURNALING, JOURNALED, LOGGED, WITH-REPLAY-FILTER, SYNC-JOURNAL, but also STORAGE-CONDITIONs, assertion failures, and errors calling JOURNALED’s [VALUES][argument] and [CONDITION][argument] function arguments. Crucially, this does not apply to non-local exits from other code, such as JOURNALED @BLOCKs, whose error handling is largely unaltered (see @OUT-EVENTS and @REPLAY-FAILURES).

In general, any @NON-LOCAL-EXIT from critical parts of the code is turned into a JOURNALING-FAILURE to protect the integrity of the RECORD-JOURNAL. The condition that caused the unwinding is in JOURNALING-FAILURE-EMBEDDED-CONDITION, or NIL if it was a pure @NON-LOCAL-EXIT like THROW. This is a SERIOUS-CONDITION, not to be handled within WITH-JOURNALING.

After a JOURNALING-FAILURE, the journaling mechanism cannot be trusted anymore. The REPLAY-JOURNAL might have failed a read and be out-of-sync. The RECORD-JOURNAL may have missing events (or even half-written events with FILE-JOURNALs without SYNC, see @SYNCHRONIZATION-STRATEGIES), and further writes to it would risk replayability, which is equivalent to database corruption. Thus, upon signalling JOURNALING-FAILURE, JOURNAL-STATE is set to

- :COMPLETED if the journal is in state :RECORDING or :LOGGING and the transition to :RECORDING was reflected in storage,

- else it is set to :FAILED.

After a JOURNALING-FAILURE, any further attempt within the affected WITH-JOURNALING to use the critical machinery mentioned
above (JOURNALED, LOGGED, etc) resignals the same journal failure condition. As a consequence, the record journal cannot be changed and the only way to recover is to leave WITH-JOURNALING. This does not affect processing in other threads, which by design cannot write to the record journal.

Note that in contrast with JOURNALING-FAILURE and REPLAY-FAILURE, which necessitate leaving WITH-JOURNALING to recover from, the other conditions - JOURNAL-ERROR, and STREAMLET-ERROR - are subclasses of [ERROR][condition] as the their handling need not be so heavy-handed.

Package

journal

Source

journal.lisp (file)

Direct superclasses

serious-condition (condition)

Direct subclasses

data-event-lossage (condition)

Direct methods
Direct slots
Slot: embedded-condition
Initargs

:embedded-condition

Readers

journaling-failure-embedded-condition (generic function)

Slot: n-resignallings
Initform

(quote 0)

Readers

journaling-failure-n-resignallings (generic function)

Writers

(setf journaling-failure-n-resignallings) (generic function)

Condition: record-unexpected-outcome ()

Signalled (with SIGNAL: this is not an
[ERROR][condition]) by JOURNALED when a VERSIONED-EVENT or an EXTERNAL-EVENT had an UNEXPECTED-OUTCOME while in JOURNAL-STATE :RECORDING. Upon signalling this condition, JOURNAL-STATE is set to :LOGGING, thus no more events can be recorded that will affect replay of the journal being recorded. The event that triggered this condition is recorded in state :LOGGING, with its version downgraded. Since @REPLAY (except INVOKED) is built on the assumption that control flow is deterministic, an unexpected outcome is significant because it makes this assumption to hold unlikely.

Also see REPLAY-UNEXPECTED-OUTCOME.

Package

journal

Source

journal.lisp (file)

Direct superclasses

condition (condition)

Direct methods

new-event (method)

Direct slots
Slot: new-event

The event that triggered this condition.

Initargs

:new-event

Readers

new-event (generic function)

Condition: replay-args-mismatch ()

Signaled when the new event’s and REPLAY-EVENT’s
EVENT-ARGS are not EQUAL. The REPLAY-FORCE-UPGRADE restart is provided.

Package

journal

Source

journal.lisp (file)

Direct superclasses

replay-failure (condition)

Condition: replay-failure ()

A common superclass (never signalled itself) for
all kinds of mismatches between the events produced and the replay journal. Signalled only in JOURNAL-STATE :REPLAYING and only once per WITH-JOURNALING. If a REPLAY-FAILURE is signalled for an EVENT, then the event will be recorded, but RECORD-JOURNAL will transition to JOURNAL-STATE :MISMATCHED. Like JOURNALING-FAILURE, this is a serious condition because it is to be handled outside the enclosing WITH-JOURNALING. If a REPLAY-FAILURE were to be handled inside the WITH-JOURNALING, keep in mind that in :MISMATCHED, replay always uses the _insert_ replay strategy (see @THE-REPLAY-STRATEGY).

Package

journal

Source

journal.lisp (file)

Direct superclasses

serious-condition (condition)

Direct subclasses
Direct methods
Direct slots
Slot: new-event

The event being generated.

Initargs

:new-event

Readers

replay-failure-new-event (generic function)

Slot: replay-event

The event read from the replay journal.

Initargs

:replay-event

Readers

replay-failure-replay-event (generic function)

Slot: record-journal

The RECORD-JOURNAL in effect at the time of signalling the error.

Initform

(quote (journal:record-journal))

Readers

replay-failure-record-journal (generic function)

Slot: replay-journal

The REPLAY-JOURNAL in effect at the time of signalling the error.

Initform

(quote (journal:replay-journal))

Readers

replay-failure-replay-journal (generic function)

Slot: replay-position
Initform

(quote (journal:read-position journal::*replay-streamlet*))

Readers

replay-failure-replay-position (generic function)

Condition: replay-incomplete ()

Signaled if there are unprocessed non-log events in REPLAY-JOURNAL when WITH-JOURNALING finishes and the body of WITH-JOURNALING returned normally, which is to prevent this condition to cancel an ongoing unwinding. No restarts are provided.

Package

journal

Source

journal.lisp (file)

Direct superclasses

replay-failure (condition)

Condition: replay-name-mismatch ()

Signaled when the new event’s and REPLAY-EVENT’s EVENT-NAME are not EQUAL. The REPLAY-FORCE-INSERT, REPLAY-FORCE-UPGRADE restarts are provided.

Package

journal

Source

journal.lisp (file)

Direct superclasses

replay-failure (condition)

Condition: replay-outcome-mismatch ()

Signaled when the new event’s and REPLAY-EVENT’s EVENT-EXIT and/or EVENT-OUTCOME are not EQUAL. The REPLAY-FORCE-UPGRADE restart is provided.

Package

journal

Source

journal.lisp (file)

Direct superclasses

replay-failure (condition)

Condition: replay-unexpected-outcome ()

Signaled when the new event has an
UNEXPECTED-OUTCOME. Note that the REPLAY-EVENT always has an EXPECTED-OUTCOME due to the logic of RECORD-UNEXPECTED-OUTCOME. No restarts are provided.

Package

journal

Source

journal.lisp (file)

Direct superclasses

replay-failure (condition)

Condition: replay-version-downgrade ()

Signaled when the new event and the REPLAY-EVENT
have the same EVENT-NAME, but the new event has a lower version. The REPLAY-FORCE-UPGRADE restart is provided.

Package

journal

Source

journal.lisp (file)

Direct superclasses

replay-failure (condition)

Condition: streamlet-error ()

Like CL:STREAM-ERROR: failures regarding trying to
perform I/O on a closed STREAMLET or of the wrong DIRECTION. Actual I/O errors are _not_ encapsulated in STREAMLET-ERROR.

Package

journal

Source

journal.lisp (file)

Direct superclasses

error (condition)

Direct methods
Direct slots
Slot: streamlet
Initargs

:streamlet

Readers

streamlet (generic function)

Slot: format-control
Initargs

:format-control

Readers

format-control (generic function)

Slot: format-args
Initargs

:format-args

Initform

(quote nil)

Readers

format-args (generic function)


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.6 Classes

Class: bundle ()

This is an abstract base class. Direct subclasses
are IN-MEMORY-BUNDLE and FILE-BUNDLE.

A BUNDLE consists of a sequence of journals which are all reruns of the same code, hopefully making more and more progress towards completion. These journals are @REPLAYs of the previous successful one, extending it with new events. Upon replay (see WITH-BUNDLE), the latest journal in the bundle in JOURNAL-STATE :COMPLETED plays the role of the replay journal, and a new journal is added to the bundle for recording. If the replay succeeds, this new journal eventually becomes :COMPLETED and takes over the role of the replay journal for future replays until another replay succeeds. When the bundle is created and it has no journals yet, the replay journal is an empty, completed one.

Package

journal

Source

journal.lisp (file)

Direct superclasses

standard-object (class)

Direct subclasses
Direct methods
Direct slots
Slot: journals
Initargs

:journals

Readers
Writers

(setf %journals) (generic function)

Slot: max-n-failed

If MAX-N-FAILED is non-NIL, and the number of
journals of [JOURNAL-STATE][type] :FAILED in the bundle exceeds its value, then some journals (starting with the oldest) are deleted.

Initargs

:max-n-failed

Initform

1

Readers

max-n-failed (generic function)

Writers

(setf max-n-failed) (generic function)

Slot: max-n-completed

If MAX-N-COMPLETED is non-NIL, and the number of
journals of [JOURNAL-STATE][type] :COMPLETED in the bundle exceeds its value, then some journals (starting with the oldest) are deleted.

Initargs

:max-n-completed

Initform

1

Readers

max-n-completed (generic function)

Writers

(setf max-n-completed) (generic function)

Slot: lock
Initform

(bordeaux-threads:make-recursive-lock "a bundle-lock")

Slot: n-writers
Initform

0

Class: file-bundle ()

A FILE-BUNDLE is a BUNDLE that is built on FILE-JOURNALs. It provides easy replay-based persistence.

Package

journal

Source

journal.lisp (file)

Direct superclasses

bundle (class)

Direct methods
Direct slots
Slot: directory

The directory where the files backing the FILE-JOURNALs in the FILE-BUNDLE are kept.

Initargs

:directory

Readers

directory-of (generic function)

Slot: sync
Initargs

:sync

Class: file-journal ()

A FILE-JOURNAL is a journal whose contents and
JOURNAL-STATE are persisted in a file. This is the [JOURNAL][class] subclass with out-of-the-box persistence, but see @FILE-BUNDLES for a more full-featured solution for repeated @REPLAYs.

Since serialization in FILE-JOURNALs is built on top of Lisp READ and WRITE, everything that JOURNALED records in events (i.e. its NAME, ARGS arguments, but also the return VALUES of the block, or the value returned by CONDITION) must be @READABLE.

File journals are human-readable, and editable by hand with some care. When editing, the following needs to be remembered:

- The first character of the file represents its JOURNAL-STATE. It is a ‘#\Space‘ (for state :NEW, :REPLAYING, :MISMATCHED and :FAILED), or a ‘#\Newline‘ (for state :RECORDING, :LOGGING and :COMPLETED).

- If the journal has SYNC (see @SYNCHRONIZATION-STRATEGIES), then in between events, there may be ‘#\Del‘ (also called ‘#\Rubout‘) or ‘#\Ack‘ characters (CHAR-CODE 127 and 6). ‘#\Del‘ marks the end of the journal contents which may be read back: it’s kind of an uncommitted-transaction marker for the events that follow it. ‘#\Ack‘ characters, of which there may be many in the file, mark the sequence of events until the next marker of either kind as valid (or committed). ‘#\Ack‘ characters are ignored when reading the journal.

Thus, when editing a file, don’t change the first character and leave the ‘#\Del‘ character, if any, where it is. Also see @SYNCHRONIZATION-WITH-FILE-JOURNALS.

Package

journal

Source

journal.lisp (file)

Direct superclasses

journal (class)

Direct methods
Direct slots
Slot: pathname

The pathname of the file backing the journal.

Initargs

:pathname

Readers

pathname-of (generic function)

Class: in-memory-bundle ()

An IN-MEMORY-BUNDLE is a BUNDLE that is built on IN-MEMORY-JOURNALs. IN-MEMORY-BUNDLEs have limited utility as a persistence mechanism and are provided mainly for reasons of symmetry and for testing. See @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS for an example of how to achieve persistence without bundles.

Package

journal

Source

journal.lisp (file)

Direct superclasses

bundle (class)

Direct methods
Direct slots
Slot: sync
Initargs

:sync

Slot: sync-fn
Initargs

:sync-fn

Class: in-memory-journal ()

IN-MEMORY-JOURNALs are backed by a non-persistent,
Lisp array of events. Much quicker than FILE-JOURNALs, they are ideal for smallish journals persisted manually (see @SYNCHRONIZATION-WITH-IN-MEMORY-JOURNALS for an example).

They are also useful for writing tests based on what events were generated. They differ from FILE-JOURNALs in that events written to IN-MEMORY-JOURNALs are not serialized (and deserialized on replay) with the following consequences for the objects recorded by JOURNALED (i.e. its NAME, ARGS arguments, but also the return VALUES of the block, or the value returned by CONDITION):

- These objects need not be @READABLE.

- Their identity (‘EQ‘ness) is not lost.

- They must __must not be mutated__ in any way.

Package

journal

Source

journal.lisp (file)

Direct superclasses

journal (class)

Direct methods
Direct slots
Slot: events

A sequence of events in the journal. Not to be mutated by client code.

Initargs

:events

Readers
Slot: sync-fn
Initargs

:sync-fn

Slot: previous-sync-position

The length of JOURNAL-EVENTS at the time of the most recent invocation of SYNC-FN.

Initform

0

Readers

journal-previous-sync-position (generic function)

Class: journal ()

A journal is, conceptually, a sequence of events.
JOURNAL is an abstract base class. In case of FILE-JOURNALs, the events are stored in a file, while for IN-MEMORY-JOURNALs, they are in a Lisp array. When a journal is opened, it is possible to perform I/O on it (see @STREAMLETS-REFERENCE), which is normally taken care of by WITH-JOURNALING. For this reason, the user’s involvement with journals normally only consists of creating and using them in WITH-JOURNALING.

Package

journal

Source

journal.lisp (file)

Direct superclasses

standard-object (class)

Direct subclasses
Direct methods
Direct slots
Slot: state

Return the state of JOURNAL, which is of type [JOURNAL-STATE][TYPE].

Type

journal:journal-state

Initargs

:state

Readers
Writers

(setf %state) (generic function)

Slot: sync

The SYNC argument specified at instantiation. See @SYNCHRONIZATION-STRATEGIES.

Initargs

:sync

Readers

journal-sync (generic function)

Slot: output-streamlet
Readers

%output-streamlet-of (generic function)

Writers

(setf %output-streamlet-of) (generic function)

Slot: log-decorator

If non-NIL, a function to add @DECORATION to
LOG-EVENTs before they are written to a journal. The only allowed transformation is to _append_ a plist to the event, which is a plist itself. The keys can be anything.

Initargs

:log-decorator

Readers

journal-log-decorator (generic function)

Writers

(setf journal-log-decorator) (generic function)

Slot: lock
Initform

(bordeaux-threads:make-recursive-lock "a journal-lock")

Slot: n-readers
Initform

0

Slot: n-writers
Initform

0

Slot: replay-mismatch

If JOURNAL-DIVERGENT-P, then this is a list of two
elements: the READ-POSITIONs in the RECORD-JOURNAL and REPLAY-JOURNAL of the first events that were different (ignoring LOG-EVENTs). It is NIL, otherwise.

Readers

journal-replay-mismatch (generic function)

Class: pprint-journal ()

When an event is written to a PPRINT-JOURNAL it
writes that event to a stream in a customizable format. They are intended for producing prettier output for @LOGGING and @TRACING, but they do not support reads so they cannot be used as a REPLAY-JOURNAL, or in LIST-EVENTS, for example. On the other hand, events written to PPRINT-JOURNALs need not be @READABLE.

Package

journal

Source

journal.lisp (file)

Direct superclasses

journal (class)

Direct methods
Direct slots
Slot: stream

The stream where events are dumped. May be set any time to another STREAM.

Type

stream

Initargs

:stream

Initform

*standard-output*

Readers

pprint-journal-stream (generic function)

Writers

(setf pprint-journal-stream) (generic function)

Slot: pretty

Whether to use PPRINT-JOURNAL-PRETTIFIER or write events in as the property lists they are. A @BOOLEAN-VALUED-SYMBOL.

Initargs

:pretty

Initform

t

Readers

pprint-journal-pretty (generic function)

Writers

(setf pprint-journal-pretty) (generic function)

Slot: prettifier

A function like PRETTIFY-EVENT that writes its an
event to a stream. Only used when PPRINT-JOURNAL-PRETTY, this is the output format customization knob. Also see @DECORATIONs.

Initargs

:prettifier

Initform

(quote journal:prettify-event)

Readers

pprint-journal-prettifier (generic function)

Writers

(setf pprint-journal-prettifier) (generic function)

Class: streamlet ()

A STREAMLET is a handle to perform I/O on a
JOURNAL. The high-level stuff (WITH-JOURNALING, JOURNALED, etc) is built on top of streamlets.

Package

journal

Source

journal.lisp (file)

Direct superclasses

standard-object (class)

Direct subclasses
Direct methods
Direct slots
Slot: journal

The JOURNAL that was passed to OPEN-STREAMLET.
This is the journal [STREAMLET][dislocated] operates on.

Initargs

:journal

Readers

journal (generic function)

Slot: direction
Type

(or journal::direction null)

Initargs

:direction

Readers

%direction (generic function)

Writers

(setf %direction) (generic function)

Slot: in-depth
Initform

0

Readers

%in-depth (generic function)

Writers

(setf %in-depth) (generic function)

Slot: sync
Initargs

:sync

Initform

t

Slot: %trusted
Slot: completed-on-abort-deferred-p

Previous: , Up: Exported definitions   [Contents][Index]

6.1.7 Types

Type: event ()

An event is either an IN-EVENT, an OUT-EVENT or a LEAF-EVENT.

Package

journal

Source

journal.lisp (file)

Type: event-exit ()

One of :VALUES, :CONDITION, :ERROR and :NLX. Indicates whether a journaled @BLOCK:

- returned normally (:VALUES, see VALUES-OUTCOME),

- unwound on an expected condition (:CONDITION, see CONDITION-OUTCOME),

- unwound on an unexpected condition (:ERROR, see ERROR-OUTCOME),

- unwound by performing a @NON-LOCAL-EXIT of some other kind such as a throw (:NLX, see NLX-OUTCOME).

The first two are EXPECTED-OUTCOMEs, while the latter two are UNEXPECTED-OUTCOMEs.

Package

journal

Source

journal.lisp (file)

Type: event-version ()

An event’s version is either NIL, a positive fixnum, or :INFINITY, which correspond to LOG-EVENTs, VERSIONED-EVENTs, and EXTERNAL-EVENTs, respectively, and have an increasingly strict behaviour with regards to @REPLAY. All EVENTs have versions. The versions of the in- and out-events belonging to the same @FRAME are the same.

Package

journal

Source

journal.lisp (file)

Type: external-event ()

Events with [EVENT-VERSION][type] :INFINITY are called external events. They are like VERSIONED-EVENTs whose version was bumped all the way to infinity, which rules out easy, non-matching upgrades. Also, they are never inserted to the record without a matching replay
event (see @THE-REPLAY-STRATEGY).

In return for these restrictions, external events can be replayed without running the corresponding @BLOCK (see @REPLAYING-THE-OUTCOME). This allows their out-event variety, called DATA-EVENTs, to be non-deterministic. Data events play a crucial role in @PERSISTENCE.

If an EXTERNAL-EVENT has an UNEXPECTED-OUTCOME, RECORD-UNEXPECTED-OUTCOME is signalled.

Package

journal

Source

journal.lisp (file)

Type: in-event ()

IN-EVENTs are triggered upon entering the dynamic extent of a JOURNALED @BLOCK. IN-EVENTs have EVENT-NAME, [EVENT-VERSION][function], and EVENT-ARGS. See @IN-EVENTS for a more introductory treatment.

Package

journal

Source

journal.lisp (file)

Type: journal-state ()

JOURNAL’s state, with respect to replay, is updated during
WITH-JOURNALING. This possible states are:

- __:NEW__: This journal was just created, but never recorded to.

- __:REPLAYING__: Replaying events has started, some events may have
been replayed successfuly, but there are more, non-log events to replay.

- __:MISMATCHED__: There was a REPLAY-FAILURE. In this state, VERSIONED-EVENTs generated are downgraded to LOG-EVENTs, EXTERNAL-EVENTs and INVOKED trigger a DATA-EVENT-LOSSAGE.

- __:RECORDING__: All events from the replay journal were
successfully replayed and now new events are being recorded
without being matched to the replay journal.

- __:LOGGING__: There was a RECORD-UNEXPECTED-OUTCOME. In this
state, VERSIONED-EVENTs generated are downgraded to LOG-EVENTs, EXTERNAL-EVENTs and INVOKED trigger a DATA-EVENT-LOSSAGE.

- __:FAILED__: The journal is to be discarded. It encountered a JOURNALING-FAILURE or a REPLAY-FAILURE without completing the
replay and reaching :RECORDING.

- __:COMPLETED__: All events were successfully replayed and WITH-JOURNALING finished or a JOURNALING-FAILURE occurred while :RECORDING or :LOGGING.

The state transitions are:

:NEW -> :REPLAYING (on entering WITH-JOURNALING) :REPLAYING -> :MISMATCHED (on REPLAY-FAILURE)
:REPLAYING -> :FAILED (on REPLAY-INCOMPLETE)
:REPLAYING -> :FAILED (on JOURNALING-FAILURE)
:REPLAYING -> :RECORDING (on successfully replaying all events) :MISMATCHED -> :FAILED (on leaving WITH-JOURNALING) :RECORDING -> :LOGGING (on RECORD-UNEXPECTED-OUTCOME) :RECORDING/:LOGGING -> :COMPLETED (on leaving WITH-JOURNALING) :RECORDING/:LOGGING -> :COMPLETED (on JOURNALING-FAILURE)

:NEW is the starting state. It is a JOURNAL-ERROR to attempt to
write to journals in :COMPLETED. Note that once in :RECORDING, the
only possible terminal state is :COMPLETED.

Package

journal

Source

journal.lisp (file)

Type: leaf-event ()

Leaf events are triggered by LOGGED. Unlike IN-EVENTs and OUT-EVENTs, which represent a @FRAME, leaf events stand alone and thus cannot have children. They are also the poorest of their kind: they only have an EVENT-NAME. Their VERSION is always NIL, which makes them LOG-EVENTs.

Package

journal

Source

journal.lisp (file)

Type: log-event ()

Events with [EVENT-VERSION][type] NIL called log events. During @REPLAY, they are never matched to events from the replay journal, and log events in the replay do not affect events being recorded either. These properties allow log events to be recorded in arbitrary journals with JOURNALED’s LOG-RECORD argument. The convenience macro FRAMED is creating frames of log-events, while the LOGGED generates a log-event that’s a LEAF-EVENT.

Package

journal

Source

journal.lisp (file)

Type: out-event ()

OUT-EVENTs are triggered upon leaving the dynamic extent of the JOURNALED @BLOCK. OUT-EVENTs have EVENT-NAME, [EVENT-VERSION][function], [EVENT-EXIT][function] and EVENT-OUTCOME. See @OUT-EVENTS for a more introductory treatment.

Package

journal

Source

journal.lisp (file)

Type: versioned-event ()

Events with a positive integer [EVENT-VERSION][type] are called versioned events. In @REPLAY, they undergo consistency checks unlike LOG-EVENTs, but the rules for them are less strict than for EXTERNAL-EVENTs. In particular, higher versions are always considered compatible with lower versions, they become an _upgrade_ in terms of the @THE-REPLAY-STRATEGY, and versioned events can be inserted into the record without a corresponding REPLAY-EVENT with JOURNALED’s INSERTABLE.

If a VERSIONED-EVENT has an UNEXPECTED-OUTCOME, RECORD-UNEXPECTED-OUTCOME is signalled.

Package

journal

Source

journal.lisp (file)


Previous: , Up: Definitions   [Contents][Index]

6.2 Internal definitions


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.1 Special variables

Special Variable: *file-bundle-lock*
Package

journal

Source

journal.lisp (file)

Special Variable: *file-journal-lock*
Package

journal

Source

journal.lisp (file)

Special Variable: *invoked-event-name-to-function-name*
Package

journal

Source

journal.lisp (file)

Special Variable: *journaling-failure*
Package

journal

Source

journal.lisp (file)

Special Variable: *local-invoked-event-name-to-function*
Package

journal

Source

journal.lisp (file)

Special Variable: *next-write-event-fn*
Package

journal

Source

journal.lisp (file)

Special Variable: *no-replay-outcome-names*
Package

journal

Source

journal.lisp (file)

Special Variable: *record-journal-state*
Package

journal

Source

journal.lisp (file)

Special Variable: *record-streamlet*
Package

journal

Source

journal.lisp (file)

Special Variable: *replay-eoj-error-p*
Package

journal

Source

journal.lisp (file)

Special Variable: *replay-event-mapper*
Package

journal

Source

journal.lisp (file)

Special Variable: *replay-failure*
Package

journal

Source

journal.lisp (file)

Special Variable: *replay-filter-base-depth*
Package

journal

Source

journal.lisp (file)

Special Variable: *replay-streamlet*
Package

journal

Source

journal.lisp (file)

Special Variable: *skip-events*
Package

journal

Source

journal.lisp (file)

Special Variable: *skip-patterns*
Package

journal

Source

journal.lisp (file)

Special Variable: *skipped-events-until*
Package

journal

Source

journal.lisp (file)

Special Variable: *suppress-trace*
Package

journal

Source

journal.lisp (file)

Special Variable: *testing*
Package

journal

Source

journal.lisp (file)

Special Variable: *traced-functions*
Package

journal

Source

journal.lisp (file)

Special Variable: *truename-to-file-bundle*
Package

journal

Source

journal.lisp (file)

Special Variable: *truename-to-file-journal*
Package

journal

Source

journal.lisp (file)

Special Variable: *with-interrupts-available*
Package

journal

Source

interrupt.lisp (file)

Special Variable: *with-journaling-failure-on-nlx-body-completed*
Package

journal

Source

journal.lisp (file)

Special Variable: *without-interrupts-available*
Package

journal

Source

interrupt.lisp (file)

Special Variable: @async-unwind
Package

journal

Source

journal.lisp (file)

Special Variable: @boolean-valued-symbol
Package

journal

Source

journal.lisp (file)

Special Variable: @non-local-exit
Package

journal

Source

journal.lisp (file)

Special Variable: @readable
Package

journal

Source

journal.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.2 Macros

Macro: async-signal-safe &body BODY
Package

journal

Source

interrupt.lisp (file)

Macro: jtrace-1 NAME
Package

journal

Source

journal.lisp (file)

Macro: nlx-protect (&key ON-RETURN ON-NLX) &body BODY
Package

journal

Source

journal.lisp (file)

Macro: unwind-protect* PROTECTED &body CLEANUP
Package

journal

Source

interrupt.lisp (file)

Macro: with-bundle-locked (BUNDLE) &body BODY
Package

journal

Source

journal.lisp (file)

Macro: with-interrupts &body BODY
Package

journal

Source

interrupt.lisp (file)

Macro: with-journal-locked (JOURNAL) &body BODY
Package

journal

Source

journal.lisp (file)

Macro: with-journaling-failure-on-nlx &body BODY
Package

journal

Source

journal.lisp (file)

Macro: with-nlx-cancelled (DATUM &rest ARGUMENTS) &body BODY
Package

journal

Source

journal.lisp (file)

Macro: with-standard-io-syntax* &body BODY
Package

journal

Source

journal.lisp (file)

Macro: without-interrupts &body BODY
Package

journal

Source

interrupt.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.3 Functions

Function: %commit-file-journal-events STREAMLET
Package

journal

Source

journal.lisp (file)

Function: %fsync FD
Package

journal

Source

journal.lisp (file)

Function: %print-events EVENTS STREAM PRETTIFIER
Package

journal

Source

journal.lisp (file)

Function: %print-journal-object-slots JOURNAL STREAM
Package

journal

Source

journal.lisp (file)

Function: %read-event-from-stream STREAM EOF
Package

journal

Source

journal.lisp (file)

Function: %read-event-from-streamlet STREAMLET EOJ-ERROR-P
Package

journal

Source

journal.lisp (file)

Function: %set-file-journal-completed-on-abort STREAMLET
Package

journal

Source

journal.lisp (file)

Function: %set-in-memory-streamlet-read-position STREAMLET READ-POSITION
Package

journal

Source

journal.lisp (file)

Function: %truename PATHNAME
Package

journal

Source

journal.lisp (file)

Function: ->recording-p RECORD-STREAMLET REPLAY-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: apply-key KEY-FN OBJ
Package

journal

Source

journal.lisp (file)

Function: bundle-file-version PATHNAME
Package

journal

Source

journal.lisp (file)

Function: bundle-record-journal BUNDLE
Package

journal

Source

journal.lisp (file)

Function: bundle-replay-journal BUNDLE
Package

journal

Source

journal.lisp (file)

Function: call-journaled FUNCTION RECORD-STREAMLET LOG-RECORD NAME VERSION ARGS VALUES-KEY CONDITION-KEY REPLAY-STREAMLET INSERTABLE REPLAY-VALUES REPLAY-CONDITION REPLAY-EOJ-ERROR-P
Package

journal

Source

journal.lisp (file)

Function: call-with-journaling FN RECORD REPLAY REPLAY-EOJ-ERROR-P
Package

journal

Source

journal.lisp (file)

Function: call-with-journaling-failure-on-nlx FN
Package

journal

Source

journal.lisp (file)

Function: call-with-open-journal JOURNAL DIRECTION FN
Package

journal

Source

journal.lisp (file)

Function: check-args IN-EVENT REPLAYED-IN-EVENT
Package

journal

Source

journal.lisp (file)

Function: check-concurrent-write-access JOURNAL
Package

journal

Source

journal.lisp (file)

Function: check-file-bundle-options BUNDLE MAX-N-FAILED MAX-N-COMPLETED SYNC
Package

journal

Source

journal.lisp (file)

Function: check-file-journal-options JOURNAL SYNC
Package

journal

Source

journal.lisp (file)

Function: check-input-streamlet-p STREAMLET
Package

journal

Source

journal.lisp (file)

Function: check-journal-state NAME JOURNAL EXPECTED-STATE
Package

journal

Source

journal.lisp (file)

Function: check-okay-for-input STREAMLET
Package

journal

Source

journal.lisp (file)

Function: check-okay-for-output STREAMLET
Package

journal

Source

journal.lisp (file)

Function: check-open-streamlet-p STREAMLET
Package

journal

Source

journal.lisp (file)

Function: check-outcome OUT-EVENT REPLAYED-OUT-EVENT
Package

journal

Source

journal.lisp (file)

Function: check-output-streamlet-p STREAMLET
Package

journal

Source

journal.lisp (file)

Function: check-sync-value SYNC
Package

journal

Source

journal.lisp (file)

Function: check-within-with-journaling-failure-on-nlx ()
Package

journal

Source

journal.lisp (file)

Function: cleanup OBJ
Package

journal

Source

journal.lisp (file)

Function: condition-event-p OUT-EVENT
Package

journal

Source

journal.lisp (file)

Function: condition-to-string C
Package

journal

Source

journal.lisp (file)

Function: delete-file-journal JOURNAL
Package

journal

Source

journal.lisp (file)

Function: eat-event EVENT STREAMLET
Package

journal

Source

journal.lisp (file)

Function: eat-events PRED STREAMLET BASE-DEPTH IN-OR-LEAF-EVENT-P
Package

journal

Source

journal.lisp (file)

Function: eat-full-frames-of-events PRED STREAMLET BASE-DEPTH
Package

journal

Source

journal.lisp (file)

Function: echo-current-frame INPUT-STREAMLET OUTPUT-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: end-of-frame-position STREAMLET &key DEPTH
Package

journal

Source

journal.lisp (file)

Function: ensure-txn STREAMLET STREAM
Package

journal

Source

journal.lisp (file)

Function: equivalent-states-p STATE-1 STATE-2
Package

journal

Source

journal.lisp (file)

Function: error-event-p OUT-EVENT
Package

journal

Source

journal.lisp (file)

Function: every-event-in-frame PRED STREAMLET
Package

journal

Source

journal.lisp (file)

Function: fail-with-journaling-failure RECORD-STREAMLET CONDITION
Package

journal

Source

journal.lisp (file)

Function: finalize-journal-state RECORD-STREAMLET ABORT
Package

journal

Source

journal.lisp (file)

Function: flet-invoked/1 DEFINITION
Package

journal

Source

journal.lisp (file)

Function: fsync STREAM
Package

journal

Source

journal.lisp (file)

Function: fsync-directory PATHNAME
Package

journal

Source

journal.lisp (file)

Function: getf* ()
Package

journal

Source

journal.lisp (file)

Function: handle-in-event RECORD-STREAMLET LOG-RECORD NAME VERSION ARGS REPLAY-STREAMLET INSERTABLE REPLAY-VALUES REPLAY-CONDITION REPLAY-EOJ-ERROR-P
Package

journal

Source

journal.lisp (file)

Function: handle-leaf-event RECORD-STREAMLET LOG-RECORD NAME
Package

journal

Source

journal.lisp (file)

Function: handle-out-event RECORD-STREAMLET LOG-RECORD OUT-EVENT IN-EVENT-STRATEGY INSERTABLE REPLAY-STREAMLET REPLAY-EOJ-ERROR-P
Package

journal

Source

journal.lisp (file)

Function: in-with-journaling-p ()
Package

journal

Source

journal.lisp (file)

Function: initialize-journal-state RECORD-STREAMLET REPLAY-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: input-direction-p DIRECTION
Package

journal

Source

journal.lisp (file)

Function: invalidate-journal JOURNAL
Package

journal

Source

journal.lisp (file)

Function: invoked-function EVENT-NAME
Package

journal

Source

journal.lisp (file)

Function: invoked/1 FUNCTION-NAME ARGS NAME VERSION INSERTABLE BODY
Package

journal

Source

journal.lisp (file)

Function: journal-output-streamlet JOURNAL
Package

journal

Source

journal.lisp (file)

Function: jtracedp NAME
Package

journal

Source

journal.lisp (file)

Function: juntrace-1 NAME
Package

journal

Source

journal.lisp (file)

Function: list-journal-files-in-directory DIRECTORY
Package

journal

Source

journal.lisp (file)

Function: list-traced-functions ()
Package

journal

Source

journal.lisp (file)

Function: make-file-journals-for-bundle DIRECTORY SYNC
Package

journal

Source

journal.lisp (file)

Function: make-in-event* REPLAY-EVENT NAME VERSION ARGS
Package

journal

Source

journal.lisp (file)

Function: make-out-event* REPLAY-EVENT NAME VERSION EXIT OUTCOME
Package

journal

Source

journal.lisp (file)

Function: match-version EVENT REPLAY-EVENT
Package

journal

Source

journal.lisp (file)

Function: maybe-downgrade-version VERSION NAME RECORD-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: maybe-handle-invoked IN-EVENT
Package

journal

Source

journal.lisp (file)

Function: maybe-mark-record-as-divergent VERSION &optional REPLAY-READ-POSITION
Package

journal

Source

journal.lisp (file)

Function: maybe-print-resignalling-message CONDITION STREAM
Package

journal

Source

journal.lisp (file)

Function: maybe-replay-outcome RECORD-STREAMLET REPLAY-STREAMLET REPLAYED-OUT-EVENT REPLAY-VALUES REPLAY-CONDITION
Package

journal

Source

journal.lisp (file)

Function: maybe-resignal-journaling-failure ()
Package

journal

Source

journal.lisp (file)

Function: maybe-sync-after-in-event IN-EVENT RECORD-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: maybe-sync-after-out-event OUT-EVENT RECORD-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: nlx-event-p OUT-EVENT
Package

journal

Source

journal.lisp (file)

Function: nlx-outcome-and-maybe->logging VERSION RECORD-STREAMLET CONDITION CONDITION-KEY
Package

journal

Source

journal.lisp (file)

Function: output-direction-p DIRECTION
Package

journal

Source

journal.lisp (file)

Function: pattern-to-pred PATTERN
Package

journal

Source

journal.lisp (file)

Function: patterns-to-disjunction PATTERNS
Package

journal

Source

journal.lisp (file)

Function: pax-pages ()
Package

journal

Source

doc.lisp (file)

Function: pax-sections ()
Package

journal

Source

doc.lisp (file)

Function: peek-at-out-event STREAMLET
Package

journal

Source

journal.lisp (file)

Function: peek-mapped-replay-event REPLAY-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: position-to-read STREAMLET
Package

journal

Source

journal.lisp (file)

Function: position-to-write STREAMLET
Package

journal

Source

journal.lisp (file)

Function: print-record-closed STREAM
Package

journal

Source

journal.lisp (file)

Function: read-file-journal-state PATHNAME
Package

journal

Source

journal.lisp (file)

Function: read-mapped-replay-event REPLAY-STREAMLET
Package

journal

Source

journal.lisp (file)

Function: reap-identical-or-non-divergent-journals BUNDLE
Package

journal

Source

journal.lisp (file)

Function: reap-journals-in-bundle BUNDLE
Package

journal

Source

journal.lisp (file)

Function: replay-filter-at-base-depth-p ()
Package

journal

Source

journal.lisp (file)

Function: replay-strategy EVENT INSERTABLE RECORD-STREAMLET REPLAY-STREAMLET REPLAY-EOJ-ERROR-P
Package

journal

Source

journal.lisp (file)

Function: replaying-outcome-allowed-p IN-EVENT
Package

journal

Source

journal.lisp (file)

Function: resolve-log-record LOG-RECORD
Package

journal

Source

journal.lisp (file)

Function: route-event EVENT RECORD-STREAMLET LOG-RECORD
Package

journal

Source

journal.lisp (file)

Function: set-file-journal-completed-on-abort STREAMLET
Package

journal

Source

journal.lisp (file)

Function: set-journal-state STREAMLET STATE
Package

journal

Source

journal.lisp (file)

Function: skip-events REPLAY-STREAMLET IN-OR-LEAF-EVENT-P
Package

journal

Source

journal.lisp (file)

Function: skip-events-and-maybe->recording RECORD-STREAMLET REPLAY-STREAMLET &optional IN-OR-LEAF-EVENT-P
Package

journal

Source

journal.lisp (file)

Function: skip-log-events STREAMLET
Package

journal

Source

journal.lisp (file)

Function: stream-fd STREAM
Package

journal

Source

journal.lisp (file)

Function: swank-toggle-jtrace SPEC-STRING
Package

journal

Source

journal.lisp (file)

Function: turn-off-with-journaling-failure-on-nlx ()
Package

journal

Source

journal.lisp (file)

Function: untrace-all ()
Package

journal

Source

journal.lisp (file)

Function: values-event-p OUT-EVENT
Package

journal

Source

journal.lisp (file)

Function: version< VERSION-1 VERSION-2
Package

journal

Source

journal.lisp (file)

Function: version= VERSION-1 VERSION-2
Package

journal

Source

journal.lisp (file)

Function: write-file-journal-state STREAM STATE
Package

journal

Source

journal.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.4 Generic functions

Generic Function: %direction OBJECT
Generic Function: (setf %direction) NEW-VALUE OBJECT
Package

journal

Methods
Method: %direction (STREAMLET streamlet)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf %direction) NEW-VALUE (STREAMLET streamlet)

automatically generated writer method

Source

journal.lisp (file)

Generic Function: %in-depth OBJECT
Generic Function: (setf %in-depth) NEW-VALUE OBJECT
Package

journal

Methods
Method: %in-depth (STREAMLET streamlet)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf %in-depth) NEW-VALUE (STREAMLET streamlet)

automatically generated writer method

Source

journal.lisp (file)

Generic Function: %journals OBJECT
Generic Function: (setf %journals) NEW-VALUE OBJECT
Package

journal

Methods
Method: %journals (BUNDLE bundle)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf %journals) NEW-VALUE (BUNDLE bundle)

automatically generated writer method

Source

journal.lisp (file)

Generic Function: %out-depth OBJECT
Generic Function: (setf %out-depth) NEW-VALUE OBJECT
Package

journal

Methods
Method: %out-depth (FILE-STREAMLET file-streamlet)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf %out-depth) NEW-VALUE (FILE-STREAMLET file-streamlet)

automatically generated writer method

Source

journal.lisp (file)

Method: %out-depth (PPRINT-STREAMLET pprint-streamlet)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf %out-depth) NEW-VALUE (PPRINT-STREAMLET pprint-streamlet)

automatically generated writer method

Source

journal.lisp (file)

Generic Function: %output-streamlet-of OBJECT
Generic Function: (setf %output-streamlet-of) NEW-VALUE OBJECT
Package

journal

Methods
Method: %output-streamlet-of (JOURNAL journal)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf %output-streamlet-of) NEW-VALUE (JOURNAL journal)

automatically generated writer method

Source

journal.lisp (file)

Generic Function: %state OBJECT
Generic Function: (setf %state) NEW-VALUE OBJECT
Package

journal

Methods
Method: %state (JOURNAL journal)
Method: (setf %state) NEW-VALUE (JOURNAL journal)

Return the state of JOURNAL, which is of type [JOURNAL-STATE][TYPE].

Source

journal.lisp (file)

Generic Function: %stream OBJECT
Generic Function: (setf %stream) NEW-VALUE OBJECT
Package

journal

Methods
Method: %stream (FILE-STREAMLET file-streamlet)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf %stream) NEW-VALUE (FILE-STREAMLET file-streamlet)

automatically generated writer method

Source

journal.lisp (file)

Generic Function: delete-journal-from-bundle BUNDLE JOURNAL
Package

journal

Source

journal.lisp (file)

Methods
Method: delete-journal-from-bundle (BUNDLE file-bundle) JOURNAL
Method: delete-journal-from-bundle (BUNDLE in-memory-bundle) JOURNAL
Method: delete-journal-from-bundle BUNDLE JOURNAL around
Generic Function: events OBJECT
Package

journal

Methods
Method: events (IN-MEMORY-JOURNAL in-memory-journal)

A sequence of events in the journal. Not to be mutated by client code.

Source

journal.lisp (file)

Generic Function: format-args CONDITION
Package

journal

Methods
Method: format-args (CONDITION journal-error)
Source

journal.lisp (file)

Method: format-args (CONDITION streamlet-error)
Source

journal.lisp (file)

Generic Function: format-control CONDITION
Package

journal

Methods
Method: format-control (CONDITION journal-error)
Source

journal.lisp (file)

Method: format-control (CONDITION streamlet-error)
Source

journal.lisp (file)

Generic Function: journaling-failure-n-resignallings CONDITION
Generic Function: (setf journaling-failure-n-resignallings) NEW-VALUE CONDITION
Package

journal

Methods
Method: journaling-failure-n-resignallings (CONDITION journaling-failure)
Method: (setf journaling-failure-n-resignallings) NEW-VALUE (CONDITION journaling-failure)
Source

journal.lisp (file)

Generic Function: journals OBJECT
Package

journal

Methods
Method: journals (BUNDLE bundle)

automatically generated reader method

Source

journal.lisp (file)

Generic Function: make-record-journal-in-bundle BUNDLE
Package

journal

Source

journal.lisp (file)

Methods
Method: make-record-journal-in-bundle (BUNDLE file-bundle)
Method: make-record-journal-in-bundle (BUNDLE in-memory-bundle)
Generic Function: new-event CONDITION
Package

journal

Methods
Method: new-event (CONDITION record-unexpected-outcome)
Source

journal.lisp (file)

Generic Function: read-file-position OBJECT
Generic Function: (setf read-file-position) NEW-VALUE OBJECT
Package

journal

Methods
Method: read-file-position (FILE-STREAMLET file-streamlet)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf read-file-position) NEW-VALUE (FILE-STREAMLET file-streamlet)

automatically generated writer method

Source

journal.lisp (file)

Generic Function: replay-failure-record-journal CONDITION
Package

journal

Methods
Method: replay-failure-record-journal (CONDITION replay-failure)
Source

journal.lisp (file)

Generic Function: replay-failure-replay-position CONDITION
Package

journal

Methods
Method: replay-failure-replay-position (CONDITION replay-failure)
Source

journal.lisp (file)

Generic Function: wrote-last-p OBJECT
Generic Function: (setf wrote-last-p) NEW-VALUE OBJECT
Package

journal

Methods
Method: wrote-last-p (FILE-STREAMLET file-streamlet)

automatically generated reader method

Source

journal.lisp (file)

Method: (setf wrote-last-p) NEW-VALUE (FILE-STREAMLET file-streamlet)

automatically generated writer method

Source

journal.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.5 Classes

Class: file-streamlet ()
Package

journal

Source

journal.lisp (file)

Direct superclasses

streamlet (class)

Direct methods
Direct slots
Slot: stream
Type

(or stream null)

Initargs

:stream

Readers

%stream (generic function)

Writers

(setf %stream) (generic function)

Slot: wrote-last-p
Readers

wrote-last-p (generic function)

Writers

(setf wrote-last-p) (generic function)

Slot: read-file-position
Readers

read-file-position (generic function)

Writers

(setf read-file-position) (generic function)

Slot: peeked
Slot: out-depth
Initform

0

Readers

%out-depth (generic function)

Writers

(setf %out-depth) (generic function)

Slot: txn-start-file-position
Slot: set-complete-on-abort-on-commit-p
Class: in-memory-streamlet ()

A streamlet for performing IO on IN-MEMORY-JOURNALs.

Package

journal

Source

journal.lisp (file)

Direct superclasses

streamlet (class)

Direct methods
Direct slots
Slot: %read-position
Initform

0

Readers

read-position (generic function)

Slot: peeked
Class: pprint-streamlet ()
Package

journal

Source

journal.lisp (file)

Direct superclasses

streamlet (class)

Direct methods
Direct slots
Slot: out-depth
Initform

0

Readers

%out-depth (generic function)

Writers

(setf %out-depth) (generic function)


Previous: , Up: Internal definitions   [Contents][Index]

6.2.6 Types

Type: direction ()
Package

journal

Source

journal.lisp (file)

Type: safe-condition ()
Package

journal

Source

journal.lisp (file)

Type: unsafe-condition ()
Package

journal

Source

journal.lisp (file)


Previous: , Up: Top   [Contents][Index]

Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts

Jump to:   F   J   L   M  
Index Entry  Section

F
File, Lisp, journal.asd: The journal․asd file
File, Lisp, journal/src/doc.lisp: The journal/src/doc․lisp file
File, Lisp, journal/src/interrupt.lisp: The journal/src/interrupt․lisp file
File, Lisp, journal/src/journal.lisp: The journal/src/journal․lisp file
File, Lisp, journal/src/package.lisp: The journal/src/package․lisp file

J
journal.asd: The journal․asd file
journal/src: The journal/src module
journal/src/doc.lisp: The journal/src/doc․lisp file
journal/src/interrupt.lisp: The journal/src/interrupt․lisp file
journal/src/journal.lisp: The journal/src/journal․lisp file
journal/src/package.lisp: The journal/src/package․lisp file

L
Lisp File, journal.asd: The journal․asd file
Lisp File, journal/src/doc.lisp: The journal/src/doc․lisp file
Lisp File, journal/src/interrupt.lisp: The journal/src/interrupt․lisp file
Lisp File, journal/src/journal.lisp: The journal/src/journal․lisp file
Lisp File, journal/src/package.lisp: The journal/src/package․lisp file

M
Module, journal/src: The journal/src module

Jump to:   F   J   L   M  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   %   (   -  
A   B   C   D   E   F   G   H   I   J   L   M   N   O   P   R   S   T   U   V   W  
Index Entry  Section

%
%commit-file-journal-events: Internal functions
%direction: Internal generic functions
%direction: Internal generic functions
%fsync: Internal functions
%in-depth: Internal generic functions
%in-depth: Internal generic functions
%journals: Internal generic functions
%journals: Internal generic functions
%out-depth: Internal generic functions
%out-depth: Internal generic functions
%out-depth: Internal generic functions
%output-streamlet-of: Internal generic functions
%output-streamlet-of: Internal generic functions
%print-events: Internal functions
%print-journal-object-slots: Internal functions
%read-event-from-stream: Internal functions
%read-event-from-streamlet: Internal functions
%set-file-journal-completed-on-abort: Internal functions
%set-in-memory-streamlet-read-position: Internal functions
%state: Internal generic functions
%state: Internal generic functions
%stream: Internal generic functions
%stream: Internal generic functions
%truename: Internal functions

(
(setf %direction): Internal generic functions
(setf %direction): Internal generic functions
(setf %in-depth): Internal generic functions
(setf %in-depth): Internal generic functions
(setf %journals): Internal generic functions
(setf %journals): Internal generic functions
(setf %out-depth): Internal generic functions
(setf %out-depth): Internal generic functions
(setf %out-depth): Internal generic functions
(setf %output-streamlet-of): Internal generic functions
(setf %output-streamlet-of): Internal generic functions
(setf %state): Internal generic functions
(setf %state): Internal generic functions
(setf %stream): Internal generic functions
(setf %stream): Internal generic functions
(setf journal-log-decorator): Exported generic functions
(setf journal-log-decorator): Exported generic functions
(setf journaling-failure-n-resignallings): Internal generic functions
(setf journaling-failure-n-resignallings): Internal generic functions
(setf max-n-completed): Exported generic functions
(setf max-n-completed): Exported generic functions
(setf max-n-failed): Exported generic functions
(setf max-n-failed): Exported generic functions
(setf pprint-journal-prettifier): Exported generic functions
(setf pprint-journal-prettifier): Exported generic functions
(setf pprint-journal-pretty): Exported generic functions
(setf pprint-journal-pretty): Exported generic functions
(setf pprint-journal-stream): Exported generic functions
(setf pprint-journal-stream): Exported generic functions
(setf read-file-position): Internal generic functions
(setf read-file-position): Internal generic functions
(setf read-position): Exported generic functions
(setf wrote-last-p): Internal generic functions
(setf wrote-last-p): Internal generic functions

-
->recording-p: Internal functions

A
apply-key: Internal functions
async-signal-safe: Internal macros

B
bundle-file-version: Internal functions
bundle-record-journal: Internal functions
bundle-replay-journal: Internal functions

C
call-journaled: Internal functions
call-with-journaling: Internal functions
call-with-journaling-failure-on-nlx: Internal functions
call-with-open-journal: Internal functions
check-args: Internal functions
check-concurrent-write-access: Internal functions
check-file-bundle-options: Internal functions
check-file-journal-options: Internal functions
check-input-streamlet-p: Internal functions
check-journal-state: Internal functions
check-okay-for-input: Internal functions
check-okay-for-output: Internal functions
check-open-streamlet-p: Internal functions
check-outcome: Internal functions
check-output-streamlet-p: Internal functions
check-sync-value: Internal functions
check-within-with-journaling-failure-on-nlx: Internal functions
checked: Exported macros
cleanup: Internal functions
close-streamlet: Exported generic functions
close-streamlet: Exported generic functions
close-streamlet: Exported generic functions
close-streamlet: Exported generic functions
close-streamlet: Exported generic functions
condition-event-p: Internal functions
condition-to-string: Internal functions

D
define-file-bundle-test: Exported macros
define-invoked: Exported macros
delete-file-bundle: Exported functions
delete-file-journal: Internal functions
delete-journal-from-bundle: Internal generic functions
delete-journal-from-bundle: Internal generic functions
delete-journal-from-bundle: Internal generic functions
delete-journal-from-bundle: Internal generic functions
directory-of: Exported generic functions
directory-of: Exported generic functions

E
eat-event: Internal functions
eat-events: Internal functions
eat-full-frames-of-events: Internal functions
echo-current-frame: Internal functions
end-of-frame-position: Internal functions
ensure-txn: Internal functions
equivalent-replay-journals-p: Exported generic functions
equivalent-replay-journals-p: Exported generic functions
equivalent-replay-journals-p: Exported generic functions
equivalent-states-p: Internal functions
error-event-p: Internal functions
event-args: Exported functions
event-exit: Exported functions
event-name: Exported functions
event-outcome: Exported functions
event-version: Exported functions
event=: Exported functions
events: Internal generic functions
events: Internal generic functions
events-to-frames: Exported functions
every-event-in-frame: Internal functions
expected-outcome-p: Exported functions
expected-type: Exported functions
external-event-p: Exported functions

F
fail-with-journaling-failure: Internal functions
finalize-journal-state: Internal functions
flet-invoked: Exported macros
flet-invoked/1: Internal functions
format-args: Internal generic functions
format-args: Internal generic functions
format-args: Internal generic functions
format-control: Internal generic functions
format-control: Internal generic functions
format-control: Internal generic functions
framed: Exported macros
fsync: Internal functions
fsync-directory: Internal functions
Function, %commit-file-journal-events: Internal functions
Function, %fsync: Internal functions
Function, %print-events: Internal functions
Function, %print-journal-object-slots: Internal functions
Function, %read-event-from-stream: Internal functions
Function, %read-event-from-streamlet: Internal functions
Function, %set-file-journal-completed-on-abort: Internal functions
Function, %set-in-memory-streamlet-read-position: Internal functions
Function, %truename: Internal functions
Function, ->recording-p: Internal functions
Function, apply-key: Internal functions
Function, bundle-file-version: Internal functions
Function, bundle-record-journal: Internal functions
Function, bundle-replay-journal: Internal functions
Function, call-journaled: Internal functions
Function, call-with-journaling: Internal functions
Function, call-with-journaling-failure-on-nlx: Internal functions
Function, call-with-open-journal: Internal functions
Function, check-args: Internal functions
Function, check-concurrent-write-access: Internal functions
Function, check-file-bundle-options: Internal functions
Function, check-file-journal-options: Internal functions
Function, check-input-streamlet-p: Internal functions
Function, check-journal-state: Internal functions
Function, check-okay-for-input: Internal functions
Function, check-okay-for-output: Internal functions
Function, check-open-streamlet-p: Internal functions
Function, check-outcome: Internal functions
Function, check-output-streamlet-p: Internal functions
Function, check-sync-value: Internal functions
Function, check-within-with-journaling-failure-on-nlx: Internal functions
Function, cleanup: Internal functions
Function, condition-event-p: Internal functions
Function, condition-to-string: Internal functions
Function, delete-file-bundle: Exported functions
Function, delete-file-journal: Internal functions
Function, eat-event: Internal functions
Function, eat-events: Internal functions
Function, eat-full-frames-of-events: Internal functions
Function, echo-current-frame: Internal functions
Function, end-of-frame-position: Internal functions
Function, ensure-txn: Internal functions
Function, equivalent-states-p: Internal functions
Function, error-event-p: Internal functions
Function, event-args: Exported functions
Function, event-exit: Exported functions
Function, event-name: Exported functions
Function, event-outcome: Exported functions
Function, event-version: Exported functions
Function, event=: Exported functions
Function, events-to-frames: Exported functions
Function, every-event-in-frame: Internal functions
Function, expected-outcome-p: Exported functions
Function, expected-type: Exported functions
Function, external-event-p: Exported functions
Function, fail-with-journaling-failure: Internal functions
Function, finalize-journal-state: Internal functions
Function, flet-invoked/1: Internal functions
Function, fsync: Internal functions
Function, fsync-directory: Internal functions
Function, getf*: Internal functions
Function, handle-in-event: Internal functions
Function, handle-leaf-event: Internal functions
Function, handle-out-event: Internal functions
Function, in-event-p: Exported functions
Function, in-with-journaling-p: Internal functions
Function, initialize-journal-state: Internal functions
Function, input-direction-p: Internal functions
Function, input-streamlet-p: Exported functions
Function, invalidate-journal: Internal functions
Function, invoked-function: Internal functions
Function, invoked/1: Internal functions
Function, journal-divergent-p: Exported functions
Function, journal-output-streamlet: Internal functions
Function, journaling-failure: Exported functions
Function, jtracedp: Internal functions
Function, juntrace-1: Internal functions
Function, leaf-event-p: Exported functions
Function, list-events: Exported functions
Function, list-journal-files-in-directory: Internal functions
Function, list-traced-functions: Internal functions
Function, log-event-p: Exported functions
Function, make-file-bundle: Exported functions
Function, make-file-journal: Exported functions
Function, make-file-journals-for-bundle: Internal functions
Function, make-in-event: Exported functions
Function, make-in-event*: Internal functions
Function, make-in-memory-bundle: Exported functions
Function, make-in-memory-journal: Exported functions
Function, make-leaf-event: Exported functions
Function, make-log-decorator: Exported functions
Function, make-out-event: Exported functions
Function, make-out-event*: Internal functions
Function, make-pprint-journal: Exported functions
Function, match-version: Internal functions
Function, maybe-downgrade-version: Internal functions
Function, maybe-handle-invoked: Internal functions
Function, maybe-mark-record-as-divergent: Internal functions
Function, maybe-print-resignalling-message: Internal functions
Function, maybe-replay-outcome: Internal functions
Function, maybe-resignal-journaling-failure: Internal functions
Function, maybe-sync-after-in-event: Internal functions
Function, maybe-sync-after-out-event: Internal functions
Function, nlx-event-p: Internal functions
Function, nlx-outcome-and-maybe->logging: Internal functions
Function, out-event-p: Exported functions
Function, output-direction-p: Internal functions
Function, output-streamlet-p: Exported functions
Function, pattern-to-pred: Internal functions
Function, patterns-to-disjunction: Internal functions
Function, pax-pages: Internal functions
Function, pax-sections: Internal functions
Function, peek-at-out-event: Internal functions
Function, peek-mapped-replay-event: Internal functions
Function, peek-replay-event: Exported functions
Function, position-to-read: Internal functions
Function, position-to-write: Internal functions
Function, pprint-events: Exported functions
Function, prettify-event: Exported functions
Function, print-events: Exported functions
Function, print-record-closed: Internal functions
Function, read-file-journal-state: Internal functions
Function, read-mapped-replay-event: Internal functions
Function, reap-identical-or-non-divergent-journals: Internal functions
Function, reap-journals-in-bundle: Internal functions
Function, record-journal: Exported functions
Function, replay-failure: Exported functions
Function, replay-filter-at-base-depth-p: Internal functions
Function, replay-journal: Exported functions
Function, replay-strategy: Internal functions
Function, replaying-outcome-allowed-p: Internal functions
Function, resolve-log-record: Internal functions
Function, route-event: Internal functions
Function, set-file-journal-completed-on-abort: Internal functions
Function, set-journal-state: Internal functions
Function, skip-events: Internal functions
Function, skip-events-and-maybe->recording: Internal functions
Function, skip-log-events: Internal functions
Function, stream-fd: Internal functions
Function, swank-toggle-jtrace: Internal functions
Function, sync-journal: Exported functions
Function, turn-off-with-journaling-failure-on-nlx: Internal functions
Function, unexpected-outcome-p: Exported functions
Function, untrace-all: Internal functions
Function, values->: Exported functions
Function, values-event-p: Internal functions
Function, values<-: Exported functions
Function, version<: Internal functions
Function, version=: Internal functions
Function, versioned-event-p: Exported functions
Function, write-file-journal-state: Internal functions

G
Generic Function, %direction: Internal generic functions
Generic Function, %in-depth: Internal generic functions
Generic Function, %journals: Internal generic functions
Generic Function, %out-depth: Internal generic functions
Generic Function, %output-streamlet-of: Internal generic functions
Generic Function, %state: Internal generic functions
Generic Function, %stream: Internal generic functions
Generic Function, (setf %direction): Internal generic functions
Generic Function, (setf %in-depth): Internal generic functions
Generic Function, (setf %journals): Internal generic functions
Generic Function, (setf %out-depth): Internal generic functions
Generic Function, (setf %output-streamlet-of): Internal generic functions
Generic Function, (setf %state): Internal generic functions
Generic Function, (setf %stream): Internal generic functions
Generic Function, (setf journal-log-decorator): Exported generic functions
Generic Function, (setf journaling-failure-n-resignallings): Internal generic functions
Generic Function, (setf max-n-completed): Exported generic functions
Generic Function, (setf max-n-failed): Exported generic functions
Generic Function, (setf pprint-journal-prettifier): Exported generic functions
Generic Function, (setf pprint-journal-pretty): Exported generic functions
Generic Function, (setf pprint-journal-stream): Exported generic functions
Generic Function, (setf read-file-position): Internal generic functions
Generic Function, (setf wrote-last-p): Internal generic functions
Generic Function, close-streamlet: Exported generic functions
Generic Function, delete-journal-from-bundle: Internal generic functions
Generic Function, directory-of: Exported generic functions
Generic Function, equivalent-replay-journals-p: Exported generic functions
Generic Function, events: Internal generic functions
Generic Function, format-args: Internal generic functions
Generic Function, format-control: Internal generic functions
Generic Function, identical-journals-p: Exported generic functions
Generic Function, journal: Exported generic functions
Generic Function, journal-events: Exported generic functions
Generic Function, journal-log-decorator: Exported generic functions
Generic Function, journal-previous-sync-position: Exported generic functions
Generic Function, journal-replay-mismatch: Exported generic functions
Generic Function, journal-state: Exported generic functions
Generic Function, journal-sync: Exported generic functions
Generic Function, journaling-failure-embedded-condition: Exported generic functions
Generic Function, journaling-failure-n-resignallings: Internal generic functions
Generic Function, journals: Internal generic functions
Generic Function, make-record-journal-in-bundle: Internal generic functions
Generic Function, make-streamlet-finalizer: Exported generic functions
Generic Function, max-n-completed: Exported generic functions
Generic Function, max-n-failed: Exported generic functions
Generic Function, new-event: Internal generic functions
Generic Function, open-streamlet: Exported generic functions
Generic Function, open-streamlet-p: Exported generic functions
Generic Function, pathname-of: Exported generic functions
Generic Function, peek-event: Exported generic functions
Generic Function, pprint-journal-prettifier: Exported generic functions
Generic Function, pprint-journal-pretty: Exported generic functions
Generic Function, pprint-journal-stream: Exported generic functions
Generic Function, read-event: Exported generic functions
Generic Function, read-file-position: Internal generic functions
Generic Function, read-position: Exported generic functions
Generic Function, replay-failure-new-event: Exported generic functions
Generic Function, replay-failure-record-journal: Internal generic functions
Generic Function, replay-failure-replay-event: Exported generic functions
Generic Function, replay-failure-replay-journal: Exported generic functions
Generic Function, replay-failure-replay-position: Internal generic functions
Generic Function, request-completed-on-abort: Exported generic functions
Generic Function, set-read-position: Exported generic functions
Generic Function, streamlet: Exported generic functions
Generic Function, sync-streamlet: Exported generic functions
Generic Function, to-journal: Exported generic functions
Generic Function, write-event: Exported generic functions
Generic Function, write-position: Exported generic functions
Generic Function, wrote-last-p: Internal generic functions
getf*: Internal functions

H
handle-in-event: Internal functions
handle-leaf-event: Internal functions
handle-out-event: Internal functions

I
identical-journals-p: Exported generic functions
identical-journals-p: Exported generic functions
identical-journals-p: Exported generic functions
identical-journals-p: Exported generic functions
in-event-p: Exported functions
in-with-journaling-p: Internal functions
initialize-journal-state: Internal functions
input-direction-p: Internal functions
input-streamlet-p: Exported functions
invalidate-journal: Internal functions
invoked-function: Internal functions
invoked/1: Internal functions

J
journal: Exported generic functions
journal: Exported generic functions
journal: Exported generic functions
journal: Exported generic functions
journal-divergent-p: Exported functions
journal-events: Exported generic functions
journal-events: Exported generic functions
journal-log-decorator: Exported generic functions
journal-log-decorator: Exported generic functions
journal-output-streamlet: Internal functions
journal-previous-sync-position: Exported generic functions
journal-previous-sync-position: Exported generic functions
journal-replay-mismatch: Exported generic functions
journal-replay-mismatch: Exported generic functions
journal-state: Exported generic functions
journal-state: Exported generic functions
journal-sync: Exported generic functions
journal-sync: Exported generic functions
journaled: Exported macros
journaling-failure: Exported functions
journaling-failure-embedded-condition: Exported generic functions
journaling-failure-embedded-condition: Exported generic functions
journaling-failure-n-resignallings: Internal generic functions
journaling-failure-n-resignallings: Internal generic functions
journals: Internal generic functions
journals: Internal generic functions
jtrace: Exported macros
jtrace-1: Internal macros
jtracedp: Internal functions
juntrace: Exported macros
juntrace-1: Internal functions

L
leaf-event-p: Exported functions
list-events: Exported functions
list-journal-files-in-directory: Internal functions
list-traced-functions: Internal functions
log-event-p: Exported functions
logged: Exported macros

M
Macro, async-signal-safe: Internal macros
Macro, checked: Exported macros
Macro, define-file-bundle-test: Exported macros
Macro, define-invoked: Exported macros
Macro, flet-invoked: Exported macros
Macro, framed: Exported macros
Macro, journaled: Exported macros
Macro, jtrace: Exported macros
Macro, jtrace-1: Internal macros
Macro, juntrace: Exported macros
Macro, logged: Exported macros
Macro, nlx-protect: Internal macros
Macro, replayed: Exported macros
Macro, save-excursion: Exported macros
Macro, unwind-protect*: Internal macros
Macro, with-bundle: Exported macros
Macro, with-bundle-locked: Internal macros
Macro, with-interrupts: Internal macros
Macro, with-journal-locked: Internal macros
Macro, with-journaling: Exported macros
Macro, with-journaling-failure-on-nlx: Internal macros
Macro, with-nlx-cancelled: Internal macros
Macro, with-open-journal: Exported macros
Macro, with-replay-filter: Exported macros
Macro, with-replay-streamlet: Exported macros
Macro, with-standard-io-syntax*: Internal macros
Macro, without-interrupts: Internal macros
make-file-bundle: Exported functions
make-file-journal: Exported functions
make-file-journals-for-bundle: Internal functions
make-in-event: Exported functions
make-in-event*: Internal functions
make-in-memory-bundle: Exported functions
make-in-memory-journal: Exported functions
make-leaf-event: Exported functions
make-log-decorator: Exported functions
make-out-event: Exported functions
make-out-event*: Internal functions
make-pprint-journal: Exported functions
make-record-journal-in-bundle: Internal generic functions
make-record-journal-in-bundle: Internal generic functions
make-record-journal-in-bundle: Internal generic functions
make-streamlet-finalizer: Exported generic functions
make-streamlet-finalizer: Exported generic functions
make-streamlet-finalizer: Exported generic functions
make-streamlet-finalizer: Exported generic functions
match-version: Internal functions
max-n-completed: Exported generic functions
max-n-completed: Exported generic functions
max-n-failed: Exported generic functions
max-n-failed: Exported generic functions
maybe-downgrade-version: Internal functions
maybe-handle-invoked: Internal functions
maybe-mark-record-as-divergent: Internal functions
maybe-print-resignalling-message: Internal functions
maybe-replay-outcome: Internal functions
maybe-resignal-journaling-failure: Internal functions
maybe-sync-after-in-event: Internal functions
maybe-sync-after-out-event: Internal functions
Method, %direction: Internal generic functions
Method, %in-depth: Internal generic functions
Method, %journals: Internal generic functions
Method, %out-depth: Internal generic functions
Method, %out-depth: Internal generic functions
Method, %output-streamlet-of: Internal generic functions
Method, %state: Internal generic functions
Method, %stream: Internal generic functions
Method, (setf %direction): Internal generic functions
Method, (setf %in-depth): Internal generic functions
Method, (setf %journals): Internal generic functions
Method, (setf %out-depth): Internal generic functions
Method, (setf %out-depth): Internal generic functions
Method, (setf %output-streamlet-of): Internal generic functions
Method, (setf %state): Internal generic functions
Method, (setf %stream): Internal generic functions
Method, (setf journal-log-decorator): Exported generic functions
Method, (setf journaling-failure-n-resignallings): Internal generic functions
Method, (setf max-n-completed): Exported generic functions
Method, (setf max-n-failed): Exported generic functions
Method, (setf pprint-journal-prettifier): Exported generic functions
Method, (setf pprint-journal-pretty): Exported generic functions
Method, (setf pprint-journal-stream): Exported generic functions
Method, (setf read-file-position): Internal generic functions
Method, (setf wrote-last-p): Internal generic functions
Method, close-streamlet: Exported generic functions
Method, close-streamlet: Exported generic functions
Method, close-streamlet: Exported generic functions
Method, close-streamlet: Exported generic functions
Method, delete-journal-from-bundle: Internal generic functions
Method, delete-journal-from-bundle: Internal generic functions
Method, delete-journal-from-bundle: Internal generic functions
Method, directory-of: Exported generic functions
Method, equivalent-replay-journals-p: Exported generic functions
Method, equivalent-replay-journals-p: Exported generic functions
Method, events: Internal generic functions
Method, format-args: Internal generic functions
Method, format-args: Internal generic functions
Method, format-control: Internal generic functions
Method, format-control: Internal generic functions
Method, identical-journals-p: Exported generic functions
Method, identical-journals-p: Exported generic functions
Method, identical-journals-p: Exported generic functions
Method, journal: Exported generic functions
Method, journal: Exported generic functions
Method, journal: Exported generic functions
Method, journal-events: Exported generic functions
Method, journal-log-decorator: Exported generic functions
Method, journal-previous-sync-position: Exported generic functions
Method, journal-replay-mismatch: Exported generic functions
Method, journal-state: Exported generic functions
Method, journal-sync: Exported generic functions
Method, journaling-failure-embedded-condition: Exported generic functions
Method, journaling-failure-n-resignallings: Internal generic functions
Method, journals: Internal generic functions
Method, make-record-journal-in-bundle: Internal generic functions
Method, make-record-journal-in-bundle: Internal generic functions
Method, make-streamlet-finalizer: Exported generic functions
Method, make-streamlet-finalizer: Exported generic functions
Method, make-streamlet-finalizer: Exported generic functions
Method, max-n-completed: Exported generic functions
Method, max-n-failed: Exported generic functions
Method, new-event: Internal generic functions
Method, open-streamlet: Exported generic functions
Method, open-streamlet: Exported generic functions
Method, open-streamlet: Exported generic functions
Method, open-streamlet: Exported generic functions
Method, open-streamlet: Exported generic functions
Method, open-streamlet-p: Exported generic functions
Method, pathname-of: Exported generic functions
Method, peek-event: Exported generic functions
Method, peek-event: Exported generic functions
Method, peek-event: Exported generic functions
Method, pprint-journal-prettifier: Exported generic functions
Method, pprint-journal-pretty: Exported generic functions
Method, pprint-journal-stream: Exported generic functions
Method, read-event: Exported generic functions
Method, read-event: Exported generic functions
Method, read-event: Exported generic functions
Method, read-file-position: Internal generic functions
Method, read-position: Exported generic functions
Method, read-position: Exported generic functions
Method, replay-failure-new-event: Exported generic functions
Method, replay-failure-record-journal: Internal generic functions
Method, replay-failure-replay-event: Exported generic functions
Method, replay-failure-replay-journal: Exported generic functions
Method, replay-failure-replay-position: Internal generic functions
Method, request-completed-on-abort: Exported generic functions
Method, request-completed-on-abort: Exported generic functions
Method, request-completed-on-abort: Exported generic functions
Method, request-completed-on-abort: Exported generic functions
Method, set-read-position: Exported generic functions
Method, set-read-position: Exported generic functions
Method, streamlet: Exported generic functions
Method, sync-streamlet: Exported generic functions
Method, sync-streamlet: Exported generic functions
Method, sync-streamlet: Exported generic functions
Method, sync-streamlet: Exported generic functions
Method, to-journal: Exported generic functions
Method, to-journal: Exported generic functions
Method, to-journal: Exported generic functions
Method, to-journal: Exported generic functions
Method, to-journal: Exported generic functions
Method, write-event: Exported generic functions
Method, write-event: Exported generic functions
Method, write-event: Exported generic functions
Method, write-event: Exported generic functions
Method, write-event: Exported generic functions
Method, write-position: Exported generic functions
Method, write-position: Exported generic functions
Method, write-position: Exported generic functions
Method, wrote-last-p: Internal generic functions

N
new-event: Internal generic functions
new-event: Internal generic functions
nlx-event-p: Internal functions
nlx-outcome-and-maybe->logging: Internal functions
nlx-protect: Internal macros

O
open-streamlet: Exported generic functions
open-streamlet: Exported generic functions
open-streamlet: Exported generic functions
open-streamlet: Exported generic functions
open-streamlet: Exported generic functions
open-streamlet: Exported generic functions
open-streamlet-p: Exported generic functions
open-streamlet-p: Exported generic functions
out-event-p: Exported functions
output-direction-p: Internal functions
output-streamlet-p: Exported functions

P
pathname-of: Exported generic functions
pathname-of: Exported generic functions
pattern-to-pred: Internal functions
patterns-to-disjunction: Internal functions
pax-pages: Internal functions
pax-sections: Internal functions
peek-at-out-event: Internal functions
peek-event: Exported generic functions
peek-event: Exported generic functions
peek-event: Exported generic functions
peek-event: Exported generic functions
peek-mapped-replay-event: Internal functions
peek-replay-event: Exported functions
position-to-read: Internal functions
position-to-write: Internal functions
pprint-events: Exported functions
pprint-journal-prettifier: Exported generic functions
pprint-journal-prettifier: Exported generic functions
pprint-journal-pretty: Exported generic functions
pprint-journal-pretty: Exported generic functions
pprint-journal-stream: Exported generic functions
pprint-journal-stream: Exported generic functions
prettify-event: Exported functions
print-events: Exported functions
print-record-closed: Internal functions

R
read-event: Exported generic functions
read-event: Exported generic functions
read-event: Exported generic functions
read-event: Exported generic functions
read-file-journal-state: Internal functions
read-file-position: Internal generic functions
read-file-position: Internal generic functions
read-mapped-replay-event: Internal functions
read-position: Exported generic functions
read-position: Exported generic functions
read-position: Exported generic functions
reap-identical-or-non-divergent-journals: Internal functions
reap-journals-in-bundle: Internal functions
record-journal: Exported functions
replay-failure: Exported functions
replay-failure-new-event: Exported generic functions
replay-failure-new-event: Exported generic functions
replay-failure-record-journal: Internal generic functions
replay-failure-record-journal: Internal generic functions
replay-failure-replay-event: Exported generic functions
replay-failure-replay-event: Exported generic functions
replay-failure-replay-journal: Exported generic functions
replay-failure-replay-journal: Exported generic functions
replay-failure-replay-position: Internal generic functions
replay-failure-replay-position: Internal generic functions
replay-filter-at-base-depth-p: Internal functions
replay-journal: Exported functions
replay-strategy: Internal functions
replayed: Exported macros
replaying-outcome-allowed-p: Internal functions
request-completed-on-abort: Exported generic functions
request-completed-on-abort: Exported generic functions
request-completed-on-abort: Exported generic functions
request-completed-on-abort: Exported generic functions
request-completed-on-abort: Exported generic functions
resolve-log-record: Internal functions
route-event: Internal functions

S
save-excursion: Exported macros
set-file-journal-completed-on-abort: Internal functions
set-journal-state: Internal functions
set-read-position: Exported generic functions
set-read-position: Exported generic functions
set-read-position: Exported generic functions
Setf Expander, (setf read-position): Exported generic functions
skip-events: Internal functions
skip-events-and-maybe->recording: Internal functions
skip-log-events: Internal functions
stream-fd: Internal functions
streamlet: Exported generic functions
streamlet: Exported generic functions
swank-toggle-jtrace: Internal functions
sync-journal: Exported functions
sync-streamlet: Exported generic functions
sync-streamlet: Exported generic functions
sync-streamlet: Exported generic functions
sync-streamlet: Exported generic functions
sync-streamlet: Exported generic functions

T
to-journal: Exported generic functions
to-journal: Exported generic functions
to-journal: Exported generic functions
to-journal: Exported generic functions
to-journal: Exported generic functions
to-journal: Exported generic functions
turn-off-with-journaling-failure-on-nlx: Internal functions

U
unexpected-outcome-p: Exported functions
untrace-all: Internal functions
unwind-protect*: Internal macros

V
values->: Exported functions
values-event-p: Internal functions
values<-: Exported functions
version<: Internal functions
version=: Internal functions
versioned-event-p: Exported functions

W
with-bundle: Exported macros
with-bundle-locked: Internal macros
with-interrupts: Internal macros
with-journal-locked: Internal macros
with-journaling: Exported macros
with-journaling-failure-on-nlx: Internal macros
with-nlx-cancelled: Internal macros
with-open-journal: Exported macros
with-replay-filter: Exported macros
with-replay-streamlet: Exported macros
with-standard-io-syntax*: Internal macros
without-interrupts: Internal macros
write-event: Exported generic functions
write-event: Exported generic functions
write-event: Exported generic functions
write-event: Exported generic functions
write-event: Exported generic functions
write-event: Exported generic functions
write-file-journal-state: Internal functions
write-position: Exported generic functions
write-position: Exported generic functions
write-position: Exported generic functions
write-position: Exported generic functions
wrote-last-p: Internal generic functions
wrote-last-p: Internal generic functions

Jump to:   %   (   -  
A   B   C   D   E   F   G   H   I   J   L   M   N   O   P   R   S   T   U   V   W  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.3 Variables

Jump to:   %   *   @  
A   C   D   E   F   I   J   L   M   N   O   P   R   S   T   U   V   W  
Index Entry  Section

%
%read-position: Internal classes
%trusted: Exported classes

*
*file-bundle-lock*: Internal special variables
*file-journal-lock*: Internal special variables
*force-insertable*: Exported special variables
*invoked-event-name-to-function-name*: Internal special variables
*journaling-failure*: Internal special variables
*local-invoked-event-name-to-function*: Internal special variables
*next-write-event-fn*: Internal special variables
*no-replay-outcome-names*: Internal special variables
*record-journal-state*: Internal special variables
*record-streamlet*: Internal special variables
*replay-eoj-error-p*: Internal special variables
*replay-event-mapper*: Internal special variables
*replay-failure*: Internal special variables
*replay-filter-base-depth*: Internal special variables
*replay-streamlet*: Internal special variables
*skip-events*: Internal special variables
*skip-patterns*: Internal special variables
*skipped-events-until*: Internal special variables
*suppress-trace*: Internal special variables
*testing*: Internal special variables
*trace-journal*: Exported special variables
*trace-pretty*: Exported special variables
*trace-real-time*: Exported special variables
*trace-run-time*: Exported special variables
*trace-thread*: Exported special variables
*trace-time*: Exported special variables
*traced-functions*: Internal special variables
*truename-to-file-bundle*: Internal special variables
*truename-to-file-journal*: Internal special variables
*with-interrupts-available*: Internal special variables
*with-journaling-failure-on-nlx-body-completed*: Internal special variables
*without-interrupts-available*: Internal special variables

@
@async-unwind: Internal special variables
@block: Exported special variables
@boolean-valued-symbol: Internal special variables
@bundles: Exported special variables
@bundles-reference: Exported special variables
@comparing-journals: Exported special variables
@customizing-logs: Exported special variables
@decoration: Exported special variables
@event-versions: Exported special variables
@events-reference: Exported special variables
@file-bundles: Exported special variables
@file-journals: Exported special variables
@frame: Exported special variables
@in-events: Exported special variables
@in-events-reference: Exported special variables
@in-memory-bundles: Exported special variables
@in-memory-journals: Exported special variables
@journal-background: Exported special variables
@journal-basics: Exported special variables
@journal-error-handling: Exported special variables
@journal-features: Exported special variables
@journal-links: Exported special variables
@journal-manual: Exported special variables
@journal-portability: Exported special variables
@journal-slime-integration: Exported special variables
@journal-utilities: Exported special variables
@journal/glossary: Exported special variables
@journaled-for-replay: Exported special variables
@journals-reference: Exported special variables
@leaf-events-reference: Exported special variables
@log-record: Exported special variables
@logging: Exported special variables
@logging-with-leaves: Exported special variables
@matching-in-events: Exported special variables
@matching-out-events: Exported special variables
@non-local-exit: Internal special variables
@opening-and-closing: Exported special variables
@out-events: Exported special variables
@out-events-reference: Exported special variables
@persistence: Exported special variables
@persistence-tutorial: Exported special variables
@pprint-journals: Exported special variables
@pretty-printing: Exported special variables
@readable: Internal special variables
@reading-from-streamlets: Exported special variables
@replay: Exported special variables
@replay-failures: Exported special variables
@replaying-the-outcome: Exported special variables
@safety: Exported special variables
@streamlets-reference: Exported special variables
@synchronization: Exported special variables
@synchronization-strategies: Exported special variables
@synchronization-with-file-journals: Exported special variables
@synchronization-with-in-memory-journals: Exported special variables
@testing: Exported special variables
@testing-on-multiple-levels: Exported special variables
@the-replay-strategy: Exported special variables
@tracing: Exported special variables
@upgrades-and-replay: Exported special variables
@working-with-unreadable-values: Exported special variables
@writing-to-streamlets: Exported special variables

A
aborted-execution: Exported special variables

C
completed-on-abort-deferred-p: Exported classes
condition-outcome: Exported special variables

D
data-event: Exported special variables
direction: Exported classes
directory: Exported classes

E
embedded-condition: Exported conditions
error-outcome: Exported special variables
events: Exported classes
expected-outcome: Exported special variables

F
format-args: Exported conditions
format-args: Exported conditions
format-control: Exported conditions
format-control: Exported conditions

I
in-depth: Exported classes
invoked: Exported special variables

J
journal: Exported conditions
journal: Exported conditions
journal: Exported classes
journals: Exported classes

L
lock: Exported classes
lock: Exported classes
log-decorator: Exported classes

M
max-n-completed: Exported classes
max-n-failed: Exported classes

N
n-readers: Exported classes
n-resignallings: Exported conditions
n-writers: Exported classes
n-writers: Exported classes
new-event: Exported conditions
new-event: Exported conditions
nlx-outcome: Exported special variables

O
out-depth: Internal classes
out-depth: Internal classes
output-streamlet: Exported classes

P
pathname: Exported classes
peeked: Internal classes
peeked: Internal classes
prettifier: Exported classes
pretty: Exported classes
previous-sync-position: Exported classes

R
read-file-position: Internal classes
record-journal: Exported conditions
replay-event: Exported special variables
replay-event: Exported conditions
replay-journal: Exported conditions
replay-mismatch: Exported classes
replay-position: Exported conditions

S
set-complete-on-abort-on-commit-p: Internal classes
Slot, %read-position: Internal classes
Slot, %trusted: Exported classes
Slot, completed-on-abort-deferred-p: Exported classes
Slot, direction: Exported classes
Slot, directory: Exported classes
Slot, embedded-condition: Exported conditions
Slot, events: Exported classes
Slot, format-args: Exported conditions
Slot, format-args: Exported conditions
Slot, format-control: Exported conditions
Slot, format-control: Exported conditions
Slot, in-depth: Exported classes
Slot, journal: Exported conditions
Slot, journal: Exported conditions
Slot, journal: Exported classes
Slot, journals: Exported classes
Slot, lock: Exported classes
Slot, lock: Exported classes
Slot, log-decorator: Exported classes
Slot, max-n-completed: Exported classes
Slot, max-n-failed: Exported classes
Slot, n-readers: Exported classes
Slot, n-resignallings: Exported conditions
Slot, n-writers: Exported classes
Slot, n-writers: Exported classes
Slot, new-event: Exported conditions
Slot, new-event: Exported conditions
Slot, out-depth: Internal classes
Slot, out-depth: Internal classes
Slot, output-streamlet: Exported classes
Slot, pathname: Exported classes
Slot, peeked: Internal classes
Slot, peeked: Internal classes
Slot, prettifier: Exported classes
Slot, pretty: Exported classes
Slot, previous-sync-position: Exported classes
Slot, read-file-position: Internal classes
Slot, record-journal: Exported conditions
Slot, replay-event: Exported conditions
Slot, replay-journal: Exported conditions
Slot, replay-mismatch: Exported classes
Slot, replay-position: Exported conditions
Slot, set-complete-on-abort-on-commit-p: Internal classes
Slot, state: Exported classes
Slot, stream: Exported classes
Slot, stream: Internal classes
Slot, streamlet: Exported conditions
Slot, sync: Exported classes
Slot, sync: Exported classes
Slot, sync: Exported classes
Slot, sync: Exported classes
Slot, sync-fn: Exported classes
Slot, sync-fn: Exported classes
Slot, txn-start-file-position: Internal classes
Slot, wrote-last-p: Internal classes
Special Variable, *file-bundle-lock*: Internal special variables
Special Variable, *file-journal-lock*: Internal special variables
Special Variable, *force-insertable*: Exported special variables
Special Variable, *invoked-event-name-to-function-name*: Internal special variables
Special Variable, *journaling-failure*: Internal special variables
Special Variable, *local-invoked-event-name-to-function*: Internal special variables
Special Variable, *next-write-event-fn*: Internal special variables
Special Variable, *no-replay-outcome-names*: Internal special variables
Special Variable, *record-journal-state*: Internal special variables
Special Variable, *record-streamlet*: Internal special variables
Special Variable, *replay-eoj-error-p*: Internal special variables
Special Variable, *replay-event-mapper*: Internal special variables
Special Variable, *replay-failure*: Internal special variables
Special Variable, *replay-filter-base-depth*: Internal special variables
Special Variable, *replay-streamlet*: Internal special variables
Special Variable, *skip-events*: Internal special variables
Special Variable, *skip-patterns*: Internal special variables
Special Variable, *skipped-events-until*: Internal special variables
Special Variable, *suppress-trace*: Internal special variables
Special Variable, *testing*: Internal special variables
Special Variable, *trace-journal*: Exported special variables
Special Variable, *trace-pretty*: Exported special variables
Special Variable, *trace-real-time*: Exported special variables
Special Variable, *trace-run-time*: Exported special variables
Special Variable, *trace-thread*: Exported special variables
Special Variable, *trace-time*: Exported special variables
Special Variable, *traced-functions*: Internal special variables
Special Variable, *truename-to-file-bundle*: Internal special variables
Special Variable, *truename-to-file-journal*: Internal special variables
Special Variable, *with-interrupts-available*: Internal special variables
Special Variable, *with-journaling-failure-on-nlx-body-completed*: Internal special variables
Special Variable, *without-interrupts-available*: Internal special variables
Special Variable, @async-unwind: Internal special variables
Special Variable, @block: Exported special variables
Special Variable, @boolean-valued-symbol: Internal special variables
Special Variable, @bundles: Exported special variables
Special Variable, @bundles-reference: Exported special variables
Special Variable, @comparing-journals: Exported special variables
Special Variable, @customizing-logs: Exported special variables
Special Variable, @decoration: Exported special variables
Special Variable, @event-versions: Exported special variables
Special Variable, @events-reference: Exported special variables
Special Variable, @file-bundles: Exported special variables
Special Variable, @file-journals: Exported special variables
Special Variable, @frame: Exported special variables
Special Variable, @in-events: Exported special variables
Special Variable, @in-events-reference: Exported special variables
Special Variable, @in-memory-bundles: Exported special variables
Special Variable, @in-memory-journals: Exported special variables
Special Variable, @journal-background: Exported special variables
Special Variable, @journal-basics: Exported special variables
Special Variable, @journal-error-handling: Exported special variables
Special Variable, @journal-features: Exported special variables
Special Variable, @journal-links: Exported special variables
Special Variable, @journal-manual: Exported special variables
Special Variable, @journal-portability: Exported special variables
Special Variable, @journal-slime-integration: Exported special variables
Special Variable, @journal-utilities: Exported special variables
Special Variable, @journal/glossary: Exported special variables
Special Variable, @journaled-for-replay: Exported special variables
Special Variable, @journals-reference: Exported special variables
Special Variable, @leaf-events-reference: Exported special variables
Special Variable, @log-record: Exported special variables
Special Variable, @logging: Exported special variables
Special Variable, @logging-with-leaves: Exported special variables
Special Variable, @matching-in-events: Exported special variables
Special Variable, @matching-out-events: Exported special variables
Special Variable, @non-local-exit: Internal special variables
Special Variable, @opening-and-closing: Exported special variables
Special Variable, @out-events: Exported special variables
Special Variable, @out-events-reference: Exported special variables
Special Variable, @persistence: Exported special variables
Special Variable, @persistence-tutorial: Exported special variables
Special Variable, @pprint-journals: Exported special variables
Special Variable, @pretty-printing: Exported special variables
Special Variable, @readable: Internal special variables
Special Variable, @reading-from-streamlets: Exported special variables
Special Variable, @replay: Exported special variables
Special Variable, @replay-failures: Exported special variables
Special Variable, @replaying-the-outcome: Exported special variables
Special Variable, @safety: Exported special variables
Special Variable, @streamlets-reference: Exported special variables
Special Variable, @synchronization: Exported special variables
Special Variable, @synchronization-strategies: Exported special variables
Special Variable, @synchronization-with-file-journals: Exported special variables
Special Variable, @synchronization-with-in-memory-journals: Exported special variables
Special Variable, @testing: Exported special variables
Special Variable, @testing-on-multiple-levels: Exported special variables
Special Variable, @the-replay-strategy: Exported special variables
Special Variable, @tracing: Exported special variables
Special Variable, @upgrades-and-replay: Exported special variables
Special Variable, @working-with-unreadable-values: Exported special variables
Special Variable, @writing-to-streamlets: Exported special variables
Special Variable, aborted-execution: Exported special variables
Special Variable, condition-outcome: Exported special variables
Special Variable, data-event: Exported special variables
Special Variable, error-outcome: Exported special variables
Special Variable, expected-outcome: Exported special variables
Special Variable, invoked: Exported special variables
Special Variable, nlx-outcome: Exported special variables
Special Variable, replay-event: Exported special variables
Special Variable, unexpected-outcome: Exported special variables
Special Variable, values-outcome: Exported special variables
state: Exported classes
stream: Exported classes
stream: Internal classes
streamlet: Exported conditions
sync: Exported classes
sync: Exported classes
sync: Exported classes
sync: Exported classes
sync-fn: Exported classes
sync-fn: Exported classes

T
txn-start-file-position: Internal classes

U
unexpected-outcome: Exported special variables

V
values-outcome: Exported special variables

W
wrote-last-p: Internal classes

Jump to:   %   *   @  
A   C   D   E   F   I   J   L   M   N   O   P   R   S   T   U   V   W  

Previous: , Up: Indexes   [Contents][Index]

A.4 Data types

Jump to:   B   C   D   E   F   I   J   L   O   P   R   S   T   U   V  
Index Entry  Section

B
bundle: Exported classes

C
Class, bundle: Exported classes
Class, file-bundle: Exported classes
Class, file-journal: Exported classes
Class, file-streamlet: Internal classes
Class, in-memory-bundle: Exported classes
Class, in-memory-journal: Exported classes
Class, in-memory-streamlet: Internal classes
Class, journal: Exported classes
Class, pprint-journal: Exported classes
Class, pprint-streamlet: Internal classes
Class, streamlet: Exported classes
Condition, data-event-lossage: Exported conditions
Condition, end-of-journal: Exported conditions
Condition, journal-error: Exported conditions
Condition, journaling-failure: Exported conditions
Condition, record-unexpected-outcome: Exported conditions
Condition, replay-args-mismatch: Exported conditions
Condition, replay-failure: Exported conditions
Condition, replay-incomplete: Exported conditions
Condition, replay-name-mismatch: Exported conditions
Condition, replay-outcome-mismatch: Exported conditions
Condition, replay-unexpected-outcome: Exported conditions
Condition, replay-version-downgrade: Exported conditions
Condition, streamlet-error: Exported conditions

D
data-event-lossage: Exported conditions
direction: Internal types

E
end-of-journal: Exported conditions
event: Exported types
event-exit: Exported types
event-version: Exported types
external-event: Exported types

F
file-bundle: Exported classes
file-journal: Exported classes
file-streamlet: Internal classes

I
in-event: Exported types
in-memory-bundle: Exported classes
in-memory-journal: Exported classes
in-memory-streamlet: Internal classes

J
journal: The journal system
journal: The journal package
journal: Exported classes
journal-error: Exported conditions
journal-state: Exported types
journaling-failure: Exported conditions

L
leaf-event: Exported types
log-event: Exported types

O
out-event: Exported types

P
Package, journal: The journal package
pprint-journal: Exported classes
pprint-streamlet: Internal classes

R
record-unexpected-outcome: Exported conditions
replay-args-mismatch: Exported conditions
replay-failure: Exported conditions
replay-incomplete: Exported conditions
replay-name-mismatch: Exported conditions
replay-outcome-mismatch: Exported conditions
replay-unexpected-outcome: Exported conditions
replay-version-downgrade: Exported conditions

S
safe-condition: Internal types
streamlet: Exported classes
streamlet-error: Exported conditions
System, journal: The journal system

T
Type, direction: Internal types
Type, event: Exported types
Type, event-exit: Exported types
Type, event-version: Exported types
Type, external-event: Exported types
Type, in-event: Exported types
Type, journal-state: Exported types
Type, leaf-event: Exported types
Type, log-event: Exported types
Type, out-event: Exported types
Type, safe-condition: Internal types
Type, unsafe-condition: Internal types
Type, versioned-event: Exported types

U
unsafe-condition: Internal types

V
versioned-event: Exported types

Jump to:   B   C   D   E   F   I   J   L   O   P   R   S   T   U   V