<chapter xml:id="chapter-controlflow-errors">

    <title>org.multiverse.api.exceptions.ControlFlowError</title>
    <sect1>
        <title>Introduction</title>
        <para>
            STM in most cases is very optimistic, this means that a txn can fail at the end and needs to be
            retried because the next time it is more likely to succeed. The problem with normal Java code is that
            control flow only is limited to normal returns in methods or through exceptions (throwables). Multiverse
            lifts on the latter to regulate control flow. E.g. if a read conflict is detected, a special multiverse
            error: org.multiverse.api.exceptions.ControlFlowError is thrown. This Error is caught by the AtomicBlock
            and then it decides what to do next. There currently are 3 different subclasses of the ControlFlowError in
            Multiverse:
            <itemizedlist>
                <listitem>
                    <para>org.multiverse.api.exceptions.ReadWriteConflict</para>
                </listitem>
                <listitem>
                    <para>org.multiverse.api.exceptions.RetryError</para>
                </listitem>
                <listitem>
                    <para>org.multiverse.api.exceptions.SpeculativeConfigurationError</para>
                </listitem>
            </itemizedlist>
            These exceptions normally should not be caught. Therefor it is best to make sure that all resources used
            inside a txn are used in a try/finally clause to make sure that they are cleaned up.
        </para>
    </sect1>

    <sect1>
        <title>org.multiverse.api.exceptions.ReadWriteConflict</title>
        <para>
            If the Transaction detects a read or write conflict, a org.multiverse.api.exceptions.ReadWriteConflict is
            thrown. This Error is caught by the AtomicBlock and it automatically retries the txn. To prevent
            contention, there also is a org.multiverse.api.BackoffPolicy available, that control if the txn
            should wait a little (so should back off), or should retry immediately. The maximum number of retries can
            be configured through the maxRetries property on the org.multiverse.api.TxnFactoryBuilder.
        </para>
    </sect1>

    <sect1>
        <title>org.multiverse.api.exceptions.RetryError</title>
        <para>
            If a blocking operation should be executed, a RetryError is thrown. This ControlFlowError is caught by the
            AtomicBlock and it registers a latch to all refs read and the calling thread blocks on the latch. If a read
            on one of those refs happens, the latch is opened and the blocked thread continues.
        </para>
    </sect1>

    <sect1>
        <title>org.multiverse.api.exceptions.SpeculativeConfigurationError</title>
        <para>
            Multiverse uses a speculative mechanism to figure out the best config for a txn. E.g.
            there a different txn implementations optimized for a different number of refs. The speculative
            config mechanism starts with a settings, but as soon as it figures out that the settings are too
            cheap,
            it throws a org.multiverse.api.exceptions.SpeculativeConfigurationError. This error is caught by the
            org.multiverse.api.TxnExecutor and upgrades the txn/settings. Once the AtomicBlock has learned, it
            will not make the same mistakes again. So in the beginning there can be some unexpected failure, but
            after a few tries, they won't appear again. This mechanism can be disabled by setting the 'setSpeculative'
            to true on the org.multiverse.api.TxnFactoryBuilder.
        </para>
    </sect1>

    <sect1>
        <title>Caching of org.multiverse.api.exceptions.ControlFlowError</title>
        <para>
            Normally caching an Exception would be considered an very big no-no. The problem with using new exceptions
            for control flow, is that is can seriously limit scalability since exceptions are very expensive to create
            (especially the stacktrace). That is why the default is that instances of the
            org.multiverse.api.exceptions.ControlFlowError
            are created in the beginning and reused. If you need to have a closer look in the exception to see what is
            happening
            (or where it is happening), the 'setControlFlowErrorsReused' on the
            org.multiverse.api.TxnFactoryBuilder
            can be called (else you will see an empty stacktrace). You need to make sure that you don't gobble up this
            Error, but
            propagate it since the AtomicBlock is the one that is going to deal with it.
        </para>
    </sect1>

</chapter>

