BUG-5280: fix problems identified by integration tests
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / AbstractFrontendHistory.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.datastore;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Ticker;
12 import java.util.HashMap;
13 import java.util.Map;
14 import java.util.Optional;
15 import javax.annotation.Nullable;
16 import org.opendaylight.controller.cluster.access.commands.CommitLocalTransactionRequest;
17 import org.opendaylight.controller.cluster.access.commands.OutOfOrderRequestException;
18 import org.opendaylight.controller.cluster.access.commands.TransactionRequest;
19 import org.opendaylight.controller.cluster.access.commands.TransactionSuccess;
20 import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
21 import org.opendaylight.controller.cluster.access.concepts.RequestEnvelope;
22 import org.opendaylight.controller.cluster.access.concepts.RequestException;
23 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
24 import org.opendaylight.yangtools.concepts.Identifiable;
25 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Abstract class for providing logical tracking of frontend local histories. This class is specialized for
31  * standalone transactions and chained transactions.
32  *
33  * @author Robert Varga
34  */
35 abstract class AbstractFrontendHistory implements Identifiable<LocalHistoryIdentifier> {
36     private static final Logger LOG = LoggerFactory.getLogger(AbstractFrontendHistory.class);
37     private static final OutOfOrderRequestException UNSEQUENCED_START = new OutOfOrderRequestException(0);
38
39     private final Map<TransactionIdentifier, FrontendTransaction> transactions = new HashMap<>();
40     private final String persistenceId;
41     private final Ticker ticker;
42
43     AbstractFrontendHistory(final String persistenceId, final Ticker ticker) {
44         this.persistenceId = Preconditions.checkNotNull(persistenceId);
45         this.ticker = Preconditions.checkNotNull(ticker);
46     }
47
48     final String persistenceId() {
49         return persistenceId;
50     }
51
52     final long readTime() {
53         return ticker.read();
54     }
55
56     final @Nullable TransactionSuccess<?> handleTransactionRequest(final TransactionRequest<?> request,
57             final RequestEnvelope envelope, final long now) throws RequestException {
58
59         // FIXME: handle purging of transactions
60
61         final TransactionIdentifier id = request.getTarget();
62         FrontendTransaction tx = transactions.get(id);
63         if (tx == null) {
64             // The transaction does not exist and we are about to create it, check sequence number
65             if (request.getSequence() != 0) {
66                 LOG.debug("{}: no transaction state present, unexpected request {}", persistenceId(), request);
67                 throw UNSEQUENCED_START;
68             }
69
70             if (request instanceof CommitLocalTransactionRequest) {
71                 tx = createReadyTransaction(id, ((CommitLocalTransactionRequest) request).getModification());
72                 LOG.debug("{}: allocated new ready transaction {}", persistenceId(), id);
73             } else {
74                 tx = createOpenTransaction(id);
75                 LOG.debug("{}: allocated new open transaction {}", persistenceId(), id);
76             }
77
78             transactions.put(id, tx);
79         } else {
80             final Optional<TransactionSuccess<?>> maybeReplay = tx.replaySequence(request.getSequence());
81             if (maybeReplay.isPresent()) {
82                 final TransactionSuccess<?> replay = maybeReplay.get();
83                 LOG.debug("{}: envelope {} replaying response {}", persistenceId(), envelope, replay);
84                 return replay;
85             }
86         }
87
88         return tx.handleRequest(request, envelope, now);
89     }
90
91     abstract FrontendTransaction createOpenTransaction(TransactionIdentifier id) throws RequestException;
92
93     abstract FrontendTransaction createReadyTransaction(TransactionIdentifier id, DataTreeModification mod)
94         throws RequestException;
95
96     abstract ShardDataTreeCohort createReadyCohort(final TransactionIdentifier id, final DataTreeModification mod);
97 }