in accord-core/src/main/java/accord/local/Commands.java [1058:1182]
public void accept(SafeCommandStore safeStore)
{
SafeCommand waitingSafe = safeStore.get(waitingId);
SafeCommand depSafe = null;
{
Command waiting = waitingSafe.current();
if (waiting.saveStatus().compareTo(Applying) >= 0)
return; // nothing to do
if (loadDepId != null)
{
depSafe = safeStore.ifInitialised(loadDepId);
if (depSafe == null) // TODO (required): slice to waiting.participants().waitsOn? can simplify method
depSafe = initialiseOrRemoveDependency(safeStore, waitingSafe, loadDepId, waiting.partialDeps().participants(loadDepId));
}
}
while (true)
{
Command waiting = waitingSafe.current();
if (waiting.saveStatus().compareTo(Applying) >= 0)
return; // nothing to do
if (depSafe == null)
{
WaitingOn waitingOn = waiting.asCommitted().waitingOn();
TxnId directlyBlockedOn = waitingOn.nextWaitingOn();
if (directlyBlockedOn == null)
{
if (waitingOn.isWaiting())
return; // nothing more we can do; all direct dependencies are notified
switch (waiting.saveStatus())
{
default: throw illegalState("Invalid saveStatus with empty waitingOn: " + waiting.saveStatus());
case ReadyToExecute:
case Applied:
case Applying:
return;
case Stable:
case PreApplied:
boolean executed = maybeExecute(safeStore, waitingSafe, true, false);
Invariants.require(executed);
return;
}
}
depSafe = safeStore.ifLoadedAndInitialised(directlyBlockedOn);
if (depSafe == null)
{
loadDepId = directlyBlockedOn;
safeStore.commandStore().execute(this, this, safeStore.agent());
return;
}
}
else
{
Command dep = depSafe.current();
SaveStatus depStatus = dep.saveStatus();
SaveStatus.LocalExecution depExecution = depStatus.execution;
if (!waitingId.awaitsOnlyDeps() && depStatus.known.isExecuteAtKnown() && dep.executeAt().compareTo(waiting.executeAt()) > 0)
depExecution = SaveStatus.LocalExecution.Applied;
Participants<?> participants = null;
if (depExecution.compareTo(WaitingToExecute) < 0 && dep.participants().owns().isEmpty())
{
// TODO (desired): slightly costly to invert a large partialDeps collection
participants = waiting.partialDeps().participants(dep.txnId());
Participants<?> stillExecutes = participants.intersecting(waiting.participants().stillExecutes(), Minimal);
depSafe = maybeCleanupRedundantDependency(safeStore, waitingSafe, depSafe, stillExecutes);
if (depSafe == null)
continue;
}
switch (depExecution)
{
default: throw new UnhandledEnum(depStatus.execution);
case NotReady:
if (logger.isTraceEnabled()) logger.trace("{} blocked on {} until ReadyToExclude", waitingId, dep.txnId());
safeStore.registerListener(depSafe, HasDecidedExecuteAt.unblockedFrom, waitingId);
safeStore.progressLog().waiting(HasDecidedExecuteAt, safeStore, depSafe, null, participants, null);
return;
case ReadyToExclude:
case WaitingToExecute:
case ReadyToExecute:
safeStore.progressLog().waiting(CanApply, safeStore, depSafe, null, participants, null);
case Applying:
safeStore.registerListener(depSafe, SaveStatus.Applied, waitingId);
return;
case WaitingToApply:
if (dep.asCommitted().isWaitingOnDependency())
{
safeStore.registerListener(depSafe, SaveStatus.Applied, waitingId);
return;
}
else
{
maybeExecute(safeStore, depSafe, false, false);
switch (depSafe.current().saveStatus())
{
default: throw illegalState("Invalid child status after attempt to execute: " + depSafe.current().saveStatus());
case Applying:
safeStore.registerListener(depSafe, SaveStatus.Applied, waitingId);
return;
case Applied:
// fall-through to outer Applied branch
}
}
case Applied:
case CleaningUp:
updateDependencyAndMaybeExecute(safeStore, waitingSafe, depSafe, false);
waiting = waitingSafe.current();
Invariants.require(waiting.saveStatus().compareTo(Applying) >= 0 || !waiting.asCommitted().waitingOn().isWaitingOn(dep.txnId()));
depSafe = null;
}
}
}
}