public RecoverReply apply()

in accord-core/src/main/java/accord/messages/BeginRecovery.java [82:142]


    public RecoverReply apply(SafeCommandStore safeStore)
    {
        SafeCommand safeCommand = safeStore.command(txnId);
        switch (Commands.recover(safeStore, txnId, partialTxn, route != null ? route : scope, progressKey, ballot))
        {
            default:
                throw new IllegalStateException("Unhandled Outcome");

            case Redundant:
                throw new IllegalStateException("Invalid Outcome");

            case RejectedBallot:
                return new RecoverNack(safeCommand.current().promised());

            case Success:
        }

        Command command = safeCommand.current();
        PartialDeps deps = command.partialDeps();
        if (!command.known().deps.hasProposedOrDecidedDeps())
        {
            deps = calculatePartialDeps(safeStore, txnId, partialTxn.keys(), txnId, safeStore.ranges().coordinates(txnId));
        }

        boolean rejectsFastPath;
        Deps earlierCommittedWitness, earlierAcceptedNoWitness;

        if (command.hasBeen(PreCommitted))
        {
            rejectsFastPath = false;
            earlierCommittedWitness = earlierAcceptedNoWitness = Deps.NONE;
        }
        else
        {
            // TODO (expected): if we can combine these with the earlierAcceptedNoWitness we can avoid persisting deps on Accept
            //    the problem is we need some way to ensure liveness. If we were to store witnessedAt as a separate register
            //    we could return these and filter them by whatever the max witnessedAt is that we discover, OR we could
            //    filter on replicas to exclude any that are started after anything that is committed, since they will have to adopt
            //    them as a dependency (but we have to make sure we consider dependency rules, so if there's no write and only reads)
            //    we might still have new transactions block our execution.
            Ranges ranges = safeStore.ranges().allAt(txnId);
            rejectsFastPath = hasAcceptedStartedAfterWithoutWitnessing(safeStore, txnId, ranges, partialTxn.keys());
            if (!rejectsFastPath)
                rejectsFastPath = hasCommittedExecutesAfterWithoutWitnessing(safeStore, txnId, ranges, partialTxn.keys());

            // TODO (expected, testing): introduce some good unit tests for verifying these two functions in a real repair scenario
            // committed txns with an earlier txnid and have our txnid as a dependency
            earlierCommittedWitness = committedStartedBeforeAndWitnessed(safeStore, txnId, ranges, partialTxn.keys());

            // accepted txns with an earlier txnid that don't have our txnid as a dependency
            earlierAcceptedNoWitness = acceptedStartedBeforeWithoutWitnessing(safeStore, txnId, ranges, partialTxn.keys());
        }

        Status status = command.status();
        Ballot accepted = command.accepted();
        Timestamp executeAt = command.executeAt();
        PartialDeps acceptedDeps = status.phase.compareTo(Phase.Accept) >= 0 ? deps : PartialDeps.NONE;
        Writes writes = command.isExecuted() ? command.asExecuted().writes() : null;
        Result result = command.isExecuted() ? command.asExecuted().result() : null;
        return new RecoverOk(txnId, status, accepted, executeAt, deps, acceptedDeps, earlierCommittedWitness, earlierAcceptedNoWitness, rejectsFastPath, writes, result);
    }