public boolean visit()

in accord-core/src/main/java/accord/messages/BeginRecovery.java [253:362]


        public boolean visit(Unseekable keyOrRange, TxnId testTxnId, Timestamp testExecuteAt, SummaryStatus status, IsDep dep, Durability minDurability)
        {
            if (status == NOT_DIRECTLY_WITNESSED || !txnId.witnessedBy(testTxnId))
                return true;

            int c = testTxnId.compareTo(txnId);
            if (c == 0)
                return true;

            if (c < 0)
            {
                if (testTxnId.is(ExclusiveSyncPoint) && testTxnId.hlc() > txnId.hlc() && txnId.is(Write))
                {
                    // TODO (required): define our invariants and make sure they're enforce elsewhere.
                    //   Specifically, consider whether truncation/GC can lead to erroneous answers here.
                    //   We're relying on a TxnId that sorts earlier but has a higher HLC to reject a higher
                    //   TxnId with lower HLC.
                    //  Note that right now we are requiring that any sync point is >= any prior syncpoint on
                    //  both HLC and epoch, which likely makes this safe. Let's confirm this works and
                    //  make sure this is properly enforced.
                    switch (status)
                    {
                        default: throw new UnhandledEnum(status);
                        case APPLIED:
                        case STABLE:
                        case COMMITTED:
                        case ACCEPTED:
                            if (testExecuteAt.is(HLC_BOUND))
                                return markSupersedingRejects();
                            if (status != ACCEPTED)
                                break;
                        case PREACCEPTED:
                            ensureEarlierWait().add(keyOrRange, testTxnId);
                        case NOTACCEPTED:
                        case INVALIDATED:
                    }
                    return true;
                }
                switch (dep)
                {
                    default: throw new UnhandledEnum(dep);
                    case IS_STABLE_DEP:
                        ensureEarlierNoWait().add(keyOrRange, testTxnId);
                        break;

                    case IS_NOT_STABLE_DEP:
                        /*
                         * The idea here is to discover those transactions that have been decided to execute after us
                         * and did not witness us as part of their pre-accept or accept round, as this means that we CANNOT have
                         * taken the fast path. This is central to safe recovery, as if every transaction that executes later has
                         * witnessed us we are safe to propose the pre-accept timestamp regardless, whereas if any transaction
                         * has not witnessed us we can safely invalidate.
                         */
                        return markSupersedingRejects();

                    case NOT_ELIGIBLE:
                        switch (status)
                        {
                            case INVALIDATED:
                                // TODO (desired): optionally exclude these and other normally-unnecessary entries on e.g. first recovery attempt
                                ensureEarlierNoWait().add(keyOrRange, testTxnId);
                                break;

                            case ACCEPTED:
                                if (testExecuteAt.compareTo(txnId) > 0)
                                    ensureEarlierWait().add(keyOrRange, testTxnId);
                                break;

                            case PREACCEPTED:
                            case NOTACCEPTED:
                                // no need to wait for potential medium path transactions started before us, only after
                                // however, both privileged coordinator optimisations require waiting for the earlier potential fast path to decide itself
                                // (that is, if either transaction use the optimisation, we must wait for the earlier transaction)
                                // TODO (desired): compute against shard whether this is a necessary wait condition - for many quorum configurations it isn't
                                if (testTxnId.hasPrivilegedCoordinator() || txnId.hasPrivilegedCoordinator())
                                    ensureEarlierWait().add(keyOrRange, testTxnId);
                        }
                }
            }
            else
            {
                switch (dep)
                {
                    case IS_NOT_STABLE_DEP:
                        /*
                         * The idea here is to discover those transactions that were started after us and have been Accepted
                         * and did not witness us as part of their pre-accept round, as this means that we CANNOT have taken
                         * the fast path. This is central to safe recovery, as if every transaction that executes later has
                         * witnessed us we are safe to propose the pre-accept timestamp regardless, whereas if any transaction
                         * has not witnessed us we can safely invalidate (us).
                         */
                        return markSupersedingRejects();

                    case NOT_ELIGIBLE:
                        // the command doesn't have any coordinator deps; or we are its coordinator and cannot commit on the privileged fast path
                    case IS_STABLE_DEP:
                        // the command has been committed with stable deps that witness us, so we're a durable dependency
                    case IS_COORD_DEP:
                        // the original coordinator witnessed us, so if it takes the fast or medium path we will be a durable dependency
                        // if it doesn't, it will take the slow path (and witness us), or be invalidated (in which case it doesn't matter)
                        break;

                    case IS_NOT_COORD_DEP:
                        Invariants.requireArgument(testTxnId.is(PrivilegedCoordinatorWithDeps));
                        ensureLaterCoordRejects().add(keyOrRange, testTxnId);
                }
            }

            return true;
        }