2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.datastore;
10 import com.google.common.base.MoreObjects;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Ticker;
13 import java.util.HashMap;
15 import java.util.Optional;
16 import javax.annotation.Nullable;
17 import org.opendaylight.controller.cluster.access.commands.AbstractReadTransactionRequest;
18 import org.opendaylight.controller.cluster.access.commands.CommitLocalTransactionRequest;
19 import org.opendaylight.controller.cluster.access.commands.OutOfOrderRequestException;
20 import org.opendaylight.controller.cluster.access.commands.TransactionPurgeRequest;
21 import org.opendaylight.controller.cluster.access.commands.TransactionPurgeResponse;
22 import org.opendaylight.controller.cluster.access.commands.TransactionRequest;
23 import org.opendaylight.controller.cluster.access.commands.TransactionSuccess;
24 import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
25 import org.opendaylight.controller.cluster.access.concepts.RequestEnvelope;
26 import org.opendaylight.controller.cluster.access.concepts.RequestException;
27 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
28 import org.opendaylight.yangtools.concepts.Identifiable;
29 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * Abstract class for providing logical tracking of frontend local histories. This class is specialized for
35 * standalone transactions and chained transactions.
37 * @author Robert Varga
39 abstract class AbstractFrontendHistory implements Identifiable<LocalHistoryIdentifier> {
40 private static final Logger LOG = LoggerFactory.getLogger(AbstractFrontendHistory.class);
41 private static final OutOfOrderRequestException UNSEQUENCED_START = new OutOfOrderRequestException(0);
43 private final Map<TransactionIdentifier, FrontendTransaction> transactions = new HashMap<>();
44 private final String persistenceId;
45 private final Ticker ticker;
47 AbstractFrontendHistory(final String persistenceId, final Ticker ticker) {
48 this.persistenceId = Preconditions.checkNotNull(persistenceId);
49 this.ticker = Preconditions.checkNotNull(ticker);
52 final String persistenceId() {
56 final long readTime() {
60 final @Nullable TransactionSuccess<?> handleTransactionRequest(final TransactionRequest<?> request,
61 final RequestEnvelope envelope, final long now) throws RequestException {
62 final TransactionIdentifier id = request.getTarget();
64 FrontendTransaction tx;
65 if (request instanceof TransactionPurgeRequest) {
66 tx = transactions.remove(id);
68 // We have no record of the transaction, nothing to do
69 LOG.debug("{}: no state for transaction {}, purge is complete", persistenceId(), id);
70 return new TransactionPurgeResponse(id, request.getSequence());
73 tx = transactions.get(id);
75 // The transaction does not exist and we are about to create it, check sequence number
76 if (request.getSequence() != 0) {
77 LOG.debug("{}: no transaction state present, unexpected request {}", persistenceId(), request);
78 throw UNSEQUENCED_START;
81 tx = createTransaction(request, id);
82 transactions.put(id, tx);
84 final Optional<TransactionSuccess<?>> maybeReplay = tx.replaySequence(request.getSequence());
85 if (maybeReplay.isPresent()) {
86 final TransactionSuccess<?> replay = maybeReplay.get();
87 LOG.debug("{}: envelope {} replaying response {}", persistenceId(), envelope, replay);
93 return tx.handleRequest(request, envelope, now);
96 private FrontendTransaction createTransaction(final TransactionRequest<?> request, final TransactionIdentifier id)
97 throws RequestException {
98 if (request instanceof CommitLocalTransactionRequest) {
99 LOG.debug("{}: allocating new ready transaction {}", persistenceId(), id);
100 return createReadyTransaction(id, ((CommitLocalTransactionRequest) request).getModification());
102 if (request instanceof AbstractReadTransactionRequest) {
103 if (((AbstractReadTransactionRequest<?>) request).isSnapshotOnly()) {
104 LOG.debug("{}: allocatint new open snapshot {}", persistenceId(), id);
105 return createOpenSnapshot(id);
109 LOG.debug("{}: allocating new open transaction {}", persistenceId(), id);
110 return createOpenTransaction(id);
113 abstract FrontendTransaction createOpenSnapshot(TransactionIdentifier id) throws RequestException;
115 abstract FrontendTransaction createOpenTransaction(TransactionIdentifier id) throws RequestException;
117 abstract FrontendTransaction createReadyTransaction(TransactionIdentifier id, DataTreeModification mod)
118 throws RequestException;
120 abstract ShardDataTreeCohort createReadyCohort(TransactionIdentifier id, DataTreeModification mod);
123 public String toString() {
124 return MoreObjects.toStringHelper(this).omitNullValues().add("identifier", getIdentifier())
125 .add("persistenceId", persistenceId).add("transactions", transactions).toString();