in accord-core/src/main/java/accord/local/cfk/Updating.java [310:414]
static Object computeInfoAndAdditions(TxnInfo[] byId, int insertPos, int updatePos, TxnId plainTxnId, InternalStatus newStatus, boolean mayExecute, Ballot ballot, Timestamp executeAt, TxnInfo prunedBefore, Timestamp depsKnownBefore, MergeCursor<TxnId, DepList> deps)
{
TxnId[] additions = NO_TXNIDS, missing = NO_TXNIDS;
int additionCount = 0, missingCount = 0;
// the position until which we should have witnessed transactions, i.e. for computing the missing collection
// *NOT* to be used for terminating *inserts* from deps parameter, as this may see the future
// (due to pruning sometimes including a later transaction where it cannot include all earlier ones)
int depsKnownBeforePos = insertPos;
if (depsKnownBefore != plainTxnId)
{
depsKnownBeforePos = Arrays.binarySearch(byId, insertPos, byId.length, depsKnownBefore);
// depsKnownBeforePos can be positive if we have a uniqueHlc but agreed the TxnId as the executeAt
if (depsKnownBeforePos < 0)
depsKnownBeforePos = -1 - depsKnownBeforePos;
}
int txnIdsIndex = 0;
while (txnIdsIndex < byId.length && deps.hasCur())
{
TxnInfo t = byId[txnIdsIndex];
TxnId d = deps.cur();
int c = t.compareTo(d);
if (c == 0)
{
// TODO (expected): if plainTxnId implies TRANSITIVE_VISIBLE dependencies,
// we should ensure any existing TRANSITIVE entries are upgraded.
// OR we should remove TRANSITIVE for simplicity,
// OR document/enforce that TRANSITIVE_VISIBLE can only be applied to dependencies of unmanaged transactions
if (d.is(UNSTABLE) && txnIdsIndex < depsKnownBeforePos && t.compareTo(COMMITTED) < 0 && plainTxnId.witnesses(d))
missing = append(missing, missingCount++, d, cachedTxnIds());
++txnIdsIndex;
deps.advance();
}
else if (c < 0)
{
// we expect to be missing ourselves
// we also permit any transaction we have recorded as COMMITTED or later to be missing, as recovery will not need to consult our information
if (txnIdsIndex != updatePos && txnIdsIndex < depsKnownBeforePos && t.compareTo(COMMITTED) < 0 && plainTxnId.witnesses(t))
missing = append(missing, missingCount++, t.plainTxnId(), cachedTxnIds());
txnIdsIndex++;
}
else
{
if (plainTxnId.witnesses(d))
{
if (d.is(UNSTABLE))
{
if (d.compareTo(depsKnownBefore) < 0 && (manages(d) || d.compareTo(prunedBefore) > 0))
missing = append(missing, missingCount++, d, cachedTxnIds());
d = d.withoutNonIdentityFlags();
}
additions = append(additions, additionCount++, d, cachedTxnIds());
}
else
{
// we can take dependencies on ExclusiveSyncPoints to represent a GC point in the log
// if we don't ordinarily witness a transaction it is meaningless to include it as a dependency
// as we will not logically be able to work with it (the missing collection will not correctly represent it anyway)
Invariants.require(d.is(ExclusiveSyncPoint));
}
deps.advance();
}
}
if (deps.hasCur())
{
do
{
TxnId d = deps.cur();
if (plainTxnId.witnesses(d))
{
if (d.is(UNSTABLE))
{
if (d.compareTo(depsKnownBefore) < 0 && (manages(d) || d.compareTo(prunedBefore) > 0))
missing = append(missing, missingCount++, d, cachedTxnIds());
d = d.withoutNonIdentityFlags();
}
additions = append(additions, additionCount++, d, cachedTxnIds());
}
deps.advance();
}
while (deps.hasCur());
}
else if (txnIdsIndex < byId.length)
{
while (txnIdsIndex < depsKnownBeforePos)
{
if (txnIdsIndex != updatePos && byId[txnIdsIndex].compareTo(COMMITTED) < 0)
{
TxnInfo txn = byId[txnIdsIndex];
if (plainTxnId.witnesses(txn))
missing = append(missing, missingCount++, txn.plainTxnId(), cachedTxnIds());
}
txnIdsIndex++;
}
}
TxnInfo info = TxnInfo.create(plainTxnId, newStatus, mayExecute, executeAt, cachedTxnIds().completeAndDiscard(missing, missingCount), ballot);
if (additionCount == 0)
return info;
return new InfoWithAdditions(info, additions, additionCount);
}