X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatastore%2FFrontendClientMetadataBuilder.java;h=6270b380cb701bbcf7f513a8bfa9bacb2923ddf4;hb=885474c4a5086d8011360a0df1ad856a4fae4969;hp=0dab830584b70fd6e1f388ae2d819619a6c401a7;hpb=edd61d79da614388134b0e0a618010c91e9c91bd;p=controller.git diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/FrontendClientMetadataBuilder.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/FrontendClientMetadataBuilder.java index 0dab830584..6270b380cb 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/FrontendClientMetadataBuilder.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/FrontendClientMetadataBuilder.java @@ -7,45 +7,72 @@ */ package org.opendaylight.controller.cluster.datastore; -import com.google.common.base.Preconditions; +import static com.google.common.base.Verify.verify; +import static java.util.Objects.requireNonNull; + +import com.google.common.base.MoreObjects; import com.google.common.collect.Collections2; -import com.google.common.collect.Range; -import com.google.common.collect.RangeSet; -import com.google.common.collect.TreeRangeSet; -import com.google.common.primitives.UnsignedLong; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier; import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier; import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier; import org.opendaylight.controller.cluster.datastore.persisted.FrontendClientMetadata; import org.opendaylight.controller.cluster.datastore.persisted.FrontendHistoryMetadata; +import org.opendaylight.controller.cluster.datastore.utils.UnsignedLongRangeSet; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.concepts.Identifiable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +@NotThreadSafe final class FrontendClientMetadataBuilder implements Builder, Identifiable { + private static final Logger LOG = LoggerFactory.getLogger(FrontendClientMetadataBuilder.class); + private final Map currentHistories = new HashMap<>(); - private final RangeSet purgedHistories; + private final UnsignedLongRangeSet purgedHistories; + private final LocalHistoryIdentifier standaloneId; private final ClientIdentifier identifier; + private final String shardName; - FrontendClientMetadataBuilder(final ClientIdentifier identifier) { - this.identifier = Preconditions.checkNotNull(identifier); - purgedHistories = TreeRangeSet.create(); + FrontendClientMetadataBuilder(final String shardName, final ClientIdentifier identifier) { + this.shardName = requireNonNull(shardName); + this.identifier = requireNonNull(identifier); + purgedHistories = UnsignedLongRangeSet.create(); + + // History for stand-alone transactions is always present + standaloneId = standaloneHistoryId(); + currentHistories.put(standaloneId, new FrontendHistoryMetadataBuilder(standaloneId)); } - FrontendClientMetadataBuilder(final FrontendClientMetadata meta) { - this.identifier = Preconditions.checkNotNull(meta.getIdentifier()); - purgedHistories = TreeRangeSet.create(meta.getPurgedHistories()); + FrontendClientMetadataBuilder(final String shardName, final FrontendClientMetadata meta) { + this.shardName = requireNonNull(shardName); + this.identifier = meta.getIdentifier(); + purgedHistories = UnsignedLongRangeSet.create(meta.getPurgedHistories()); for (FrontendHistoryMetadata h : meta.getCurrentHistories()) { final FrontendHistoryMetadataBuilder b = new FrontendHistoryMetadataBuilder(identifier, h); currentHistories.put(b.getIdentifier(), b); } + + // Sanity check and recovery + standaloneId = standaloneHistoryId(); + if (!currentHistories.containsKey(standaloneId)) { + LOG.warn("{}: Client {} recovered histories {} do not contain stand-alone history, attempting recovery", + shardName, identifier, currentHistories); + currentHistories.put(standaloneId, new FrontendHistoryMetadataBuilder(standaloneId)); + } + } + + private LocalHistoryIdentifier standaloneHistoryId() { + return new LocalHistoryIdentifier(identifier, 0); } @Override public FrontendClientMetadata build() { - return new FrontendClientMetadata(identifier, purgedHistories, + return new FrontendClientMetadata(identifier, purgedHistories.toImmutable(), Collections2.transform(currentHistories.values(), FrontendHistoryMetadataBuilder::build)); } @@ -54,28 +81,120 @@ final class FrontendClientMetadataBuilder implements Builder histories = new HashMap<>(); + for (FrontendHistoryMetadataBuilder e : currentHistories.values()) { + if (e.getIdentifier().getHistoryId() != 0) { + final AbstractFrontendHistory state = e.toLeaderState(shard); + verify(state instanceof LocalFrontendHistory, "Unexpected state %s", state); + histories.put(e.getIdentifier(), (LocalFrontendHistory) state); + } + } + + final AbstractFrontendHistory singleHistory; + final FrontendHistoryMetadataBuilder singleHistoryMeta = currentHistories.get( + new LocalHistoryIdentifier(identifier, 0)); + if (singleHistoryMeta == null) { + final ShardDataTree tree = shard.getDataStore(); + singleHistory = StandaloneFrontendHistory.create(shard.persistenceId(), getIdentifier(), tree); + } else { + singleHistory = singleHistoryMeta.toLeaderState(shard); + } + + return new LeaderFrontendState(shard.persistenceId(), getIdentifier(), shard.getDataStore(), + purgedHistories.copy(), singleHistory, histories); } - private FrontendHistoryMetadataBuilder ensureHistory(final LocalHistoryIdentifier historyId) { - final FrontendHistoryMetadataBuilder existing = currentHistories.get(historyId); - if (existing != null) { - return existing; + private FrontendHistoryMetadataBuilder getHistory(final TransactionIdentifier txId) { + LocalHistoryIdentifier historyId = txId.getHistoryId(); + if (historyId.getHistoryId() == 0 && historyId.getCookie() != 0) { + // We are pre-creating the history for free-standing transactions with a zero cookie, hence our lookup + // needs to account for that. + LOG.debug("{}: looking up {} instead of {}", shardName, standaloneId, historyId); + historyId = standaloneId; } - final FrontendHistoryMetadataBuilder ret = new FrontendHistoryMetadataBuilder(historyId); - currentHistories.put(historyId, ret); - return ret; + return currentHistories.get(historyId); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("identifier", identifier).add("current", currentHistories) + .add("purged", purgedHistories).toString(); } }