use of org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier in project controller by opendaylight.
the class ShardDataTree method applyReplicatedPayload.
/**
* Apply a payload coming from the leader, which could actually be us. This method assumes the leader and follower
* SchemaContexts match and does not perform any pruning.
*
* @param identifier Payload identifier as returned from RaftActor
* @param payload Payload
* @throws IOException when the snapshot fails to deserialize
* @throws DataValidationFailedException when the snapshot fails to apply
*/
void applyReplicatedPayload(final Identifier identifier, final Payload payload) throws IOException, DataValidationFailedException {
/*
* This is a bit more involved than it needs to be due to to the fact we do not want to be touching the payload
* if we are the leader and it has originated with us.
*
* The identifier will only ever be non-null when we were the leader which achieved consensus. Unfortunately,
* though, this may not be the case anymore, as we are being called some time afterwards and we may not be
* acting in that capacity anymore.
*
* In any case, we know that this is an entry coming from replication, hence we can be sure we will not observe
* pre-Boron state -- which limits the number of options here.
*/
if (payload instanceof CommitTransactionPayload) {
final TransactionIdentifier txId;
if (identifier == null) {
final Entry<TransactionIdentifier, DataTreeCandidate> e = ((CommitTransactionPayload) payload).getCandidate();
txId = e.getKey();
applyReplicatedCandidate(txId, e.getValue());
} else {
Verify.verify(identifier instanceof TransactionIdentifier);
txId = (TransactionIdentifier) identifier;
payloadReplicationComplete(txId);
}
allMetadataCommittedTransaction(txId);
} else if (payload instanceof AbortTransactionPayload) {
if (identifier != null) {
payloadReplicationComplete((AbortTransactionPayload) payload);
}
allMetadataAbortedTransaction(((AbortTransactionPayload) payload).getIdentifier());
} else if (payload instanceof PurgeTransactionPayload) {
if (identifier != null) {
payloadReplicationComplete((PurgeTransactionPayload) payload);
}
allMetadataPurgedTransaction(((PurgeTransactionPayload) payload).getIdentifier());
} else if (payload instanceof CloseLocalHistoryPayload) {
if (identifier != null) {
payloadReplicationComplete((CloseLocalHistoryPayload) payload);
}
allMetadataClosedLocalHistory(((CloseLocalHistoryPayload) payload).getIdentifier());
} else if (payload instanceof CreateLocalHistoryPayload) {
if (identifier != null) {
payloadReplicationComplete((CreateLocalHistoryPayload) payload);
}
allMetadataCreatedLocalHistory(((CreateLocalHistoryPayload) payload).getIdentifier());
} else if (payload instanceof PurgeLocalHistoryPayload) {
if (identifier != null) {
payloadReplicationComplete((PurgeLocalHistoryPayload) payload);
}
allMetadataPurgedLocalHistory(((PurgeLocalHistoryPayload) payload).getIdentifier());
} else {
LOG.warn("{}: ignoring unhandled identifier {} payload {}", logContext, identifier, payload);
}
}
use of org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier in project controller by opendaylight.
the class ShardDataTree method startCommit.
void startCommit(final SimpleShardDataTreeCohort cohort, final DataTreeCandidate candidate) {
final CommitEntry entry = pendingCommits.peek();
Preconditions.checkState(entry != null, "Attempted to start commit of %s when no transactions pending", cohort);
final SimpleShardDataTreeCohort current = entry.cohort;
if (!cohort.equals(current)) {
LOG.debug("{}: Transaction {} scheduled for commit step", logContext, cohort.getIdentifier());
return;
}
LOG.debug("{}: Starting commit for transaction {}", logContext, current.getIdentifier());
final TransactionIdentifier txId = cohort.getIdentifier();
final Payload payload;
try {
payload = CommitTransactionPayload.create(txId, candidate);
} catch (IOException e) {
LOG.error("{}: Failed to encode transaction {} candidate {}", logContext, txId, candidate, e);
pendingCommits.poll().cohort.failedCommit(e);
processNextPending();
return;
}
// We process next transactions pending canCommit before we call persistPayload to possibly progress subsequent
// transactions to the COMMIT_PENDING state so the payloads can be batched for replication. This is done for
// single-shard transactions that immediately transition from canCommit to preCommit to commit. Note that
// if the next pending transaction is progressed to COMMIT_PENDING and this method (startCommit) is called,
// the next transaction will not attempt to replicate b/c the current transaction is still at the head of the
// pendingCommits queue.
processNextPendingTransaction();
// After processing next pending transactions, we can now remove the current transaction from pendingCommits.
// Note this must be done before the call to peekNextPendingCommit below so we check the next transaction
// in order to properly determine the batchHint flag for the call to persistPayload.
pendingCommits.remove();
pendingFinishCommits.add(entry);
// See if the next transaction is pending commit (ie in the COMMIT_PENDING state) so it can be batched with
// this transaction for replication.
boolean replicationBatchHint = peekNextPendingCommit();
// Once completed, we will continue via payloadReplicationComplete
shard.persistPayload(txId, payload, replicationBatchHint);
entry.lastAccess = shard.ticker().read();
LOG.debug("{}: Transaction {} submitted to persistence", logContext, txId);
// Process the next transaction pending commit, if any. If there is one it will be batched with this
// transaction for replication.
processNextPendingCommit();
}
use of org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier in project controller by opendaylight.
the class AbstractFrontendHistory method handleTransactionPurgeRequest.
private TransactionSuccess<?> handleTransactionPurgeRequest(final TransactionRequest<?> request, final RequestEnvelope envelope, final long now) {
final TransactionIdentifier id = request.getTarget();
final UnsignedLong ul = UnsignedLong.fromLongBits(id.getTransactionId());
if (purgedTransactions.contains(ul)) {
// Retransmitted purge request: nothing to do
LOG.debug("{}: transaction {} already purged", persistenceId, id);
return new TransactionPurgeResponse(id, request.getSequence());
}
// to an ImmutableMap, which does not allow remove().
if (closedTransactions.containsKey(ul)) {
tree.purgeTransaction(id, () -> {
closedTransactions.remove(ul);
if (closedTransactions.isEmpty()) {
closedTransactions = ImmutableMap.of();
}
purgedTransactions.add(Range.closedOpen(ul, UnsignedLong.ONE.plus(ul)));
LOG.debug("{}: finished purging inherited transaction {}", persistenceId(), id);
envelope.sendSuccess(new TransactionPurgeResponse(id, request.getSequence()), readTime() - now);
});
return null;
}
final FrontendTransaction tx = transactions.get(id);
if (tx == null) {
// This should never happen because the purge callback removes the transaction and puts it into
// purged transactions in one go. If it does, we warn about the situation and
LOG.warn("{}: transaction {} not tracked in {}, but not present in active transactions", persistenceId, id, purgedTransactions);
purgedTransactions.add(Range.closedOpen(ul, UnsignedLong.ONE.plus(ul)));
return new TransactionPurgeResponse(id, request.getSequence());
}
tree.purgeTransaction(id, () -> {
purgedTransactions.add(Range.closedOpen(ul, UnsignedLong.ONE.plus(ul)));
transactions.remove(id);
LOG.debug("{}: finished purging transaction {}", persistenceId(), id);
envelope.sendSuccess(new TransactionPurgeResponse(id, request.getSequence()), readTime() - now);
});
return null;
}
use of org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier in project controller by opendaylight.
the class ProxyHistory method createTransactionProxy.
AbstractProxyTransaction createTransactionProxy(final TransactionIdentifier txId, final boolean snapshotOnly, final boolean isDone) {
lock.lock();
try {
if (successor != null) {
return successor.createTransactionProxy(txId, snapshotOnly, isDone);
}
final TransactionIdentifier proxyId = new TransactionIdentifier(identifier, txId.getTransactionId());
final AbstractProxyTransaction ret = doCreateTransactionProxy(connection, proxyId, snapshotOnly, isDone);
proxies.put(proxyId, ret);
LOG.debug("Allocated proxy {} for transaction {}", proxyId, txId);
return ret;
} finally {
lock.unlock();
}
}
use of org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier in project controller by opendaylight.
the class SingleClientHistory method doCreateSnapshot.
@Override
ClientSnapshot doCreateSnapshot() {
final TransactionIdentifier txId = new TransactionIdentifier(getIdentifier(), nextTx());
LOG.debug("{}: creating a new snapshot {}", this, txId);
return new ClientSnapshot(this, txId);
}
Aggregations