This patch adds the wrapper class and updates users to use it directly.
The implementation itself is not changed, that will be done in a follow-up
patch.
Change-Id: Ie240ca5c3c9fc1448629bb5db6ecfa1029f66b8f
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
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 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;
private static final Logger LOG = LoggerFactory.getLogger(FrontendClientMetadataBuilder.class);
private final Map<LocalHistoryIdentifier, FrontendHistoryMetadataBuilder> currentHistories = new HashMap<>();
- private final RangeSet<UnsignedLong> purgedHistories;
+ private final UnsignedLongRangeSet purgedHistories;
private final ClientIdentifier identifier;
private final String shardName;
FrontendClientMetadataBuilder(final String shardName, final ClientIdentifier identifier) {
this.shardName = Preconditions.checkNotNull(shardName);
this.identifier = Preconditions.checkNotNull(identifier);
- purgedHistories = TreeRangeSet.create();
+ purgedHistories = UnsignedLongRangeSet.create();
// History for stand-alone transactions is always present
final LocalHistoryIdentifier standaloneId = standaloneHistoryId();
FrontendClientMetadataBuilder(final String shardName, final FrontendClientMetadata meta) {
this.shardName = Preconditions.checkNotNull(shardName);
this.identifier = Preconditions.checkNotNull(meta.getIdentifier());
- purgedHistories = TreeRangeSet.create(meta.getPurgedHistories());
+ purgedHistories = UnsignedLongRangeSet.create(meta.getPurgedHistories());
for (FrontendHistoryMetadata h : meta.getCurrentHistories()) {
final FrontendHistoryMetadataBuilder b = new FrontendHistoryMetadataBuilder(identifier, h);
@Override
public FrontendClientMetadata build() {
- return new FrontendClientMetadata(identifier, purgedHistories,
+ return new FrontendClientMetadata(identifier, purgedHistories.toImmutable(),
Collections2.transform(currentHistories.values(), FrontendHistoryMetadataBuilder::build));
}
}
// XXX: do we need to account for cookies?
- final UnsignedLong ul = UnsignedLong.fromLongBits(historyId.getHistoryId());
- purgedHistories.add(Range.closedOpen(ul, UnsignedLong.ONE.plus(ul)));
+ purgedHistories.add(historyId.getHistoryId());
LOG.debug("{}: Purged history {}", historyId);
}
}
return new LeaderFrontendState(shard.persistenceId(), getIdentifier(), shard.getDataStore(),
- TreeRangeSet.create(purgedHistories), singleHistory, histories);
+ purgedHistories.copy(), singleHistory, histories);
}
private FrontendHistoryMetadataBuilder getHistory(final TransactionIdentifier txId) {
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
-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.Nullable;
import org.opendaylight.controller.cluster.access.concepts.RequestEnvelope;
import org.opendaylight.controller.cluster.access.concepts.RequestException;
import org.opendaylight.controller.cluster.access.concepts.UnsupportedRequestException;
+import org.opendaylight.controller.cluster.datastore.utils.UnsignedLongRangeSet;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Map<LocalHistoryIdentifier, LocalFrontendHistory> localHistories;
// RangeSet performs automatic merging, hence we keep minimal state tracking information
- private final RangeSet<UnsignedLong> purgedHistories;
+ private final UnsignedLongRangeSet purgedHistories;
// Used for all standalone transactions
private final AbstractFrontendHistory standaloneHistory;
// - per-RequestException throw counters
LeaderFrontendState(final String persistenceId, final ClientIdentifier clientId, final ShardDataTree tree) {
- this(persistenceId, clientId, tree, TreeRangeSet.create(), StandaloneFrontendHistory.create(persistenceId,
- clientId, tree), new HashMap<>());
+ this(persistenceId, clientId, tree, UnsignedLongRangeSet.create(),
+ StandaloneFrontendHistory.create(persistenceId, clientId, tree), new HashMap<>());
}
LeaderFrontendState(final String persistenceId, final ClientIdentifier clientId, final ShardDataTree tree,
- final RangeSet<UnsignedLong> purgedHistories, final AbstractFrontendHistory standaloneHistory,
+ final UnsignedLongRangeSet purgedHistories, final AbstractFrontendHistory standaloneHistory,
final Map<LocalHistoryIdentifier, LocalFrontendHistory> localHistories) {
this.persistenceId = Preconditions.checkNotNull(persistenceId);
this.clientId = Preconditions.checkNotNull(clientId);
// We have not found the history. Before we create it we need to check history ID sequencing so that we do not
// end up resurrecting a purged history.
- if (purgedHistories.contains(UnsignedLong.fromLongBits(historyId.getHistoryId()))) {
+ if (purgedHistories.contains(historyId.getHistoryId())) {
LOG.debug("{}: rejecting purged request {}", persistenceId, request);
- throw new DeadHistoryException(purgedHistories);
+ throw new DeadHistoryException(purgedHistories.toImmutable());
}
// Update last history we have seen
}
LOG.debug("{}: purging history {}", persistenceId, id);
- final UnsignedLong ul = UnsignedLong.fromLongBits(id.getHistoryId());
- purgedHistories.add(Range.closedOpen(ul, UnsignedLong.ONE.plus(ul)));
+ purgedHistories.add(id.getHistoryId());
existing.purge(request.getSequence(), envelope, now);
return null;
}
if (lhId.getHistoryId() != 0) {
history = localHistories.get(lhId);
if (history == null) {
- if (purgedHistories.contains(UnsignedLong.fromLongBits(lhId.getHistoryId()))) {
+ if (purgedHistories.contains(lhId.getHistoryId())) {
LOG.warn("{}: rejecting request {} to purged history", persistenceId, request);
- throw new DeadHistoryException(purgedHistories);
+ throw new DeadHistoryException(purgedHistories.toImmutable());
}
LOG.warn("{}: rejecting unknown history request {}", persistenceId, request);
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.datastore.utils;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableRangeSet;
+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 org.opendaylight.yangtools.concepts.Mutable;
+
+/**
+ * Utility {@link RangeSet}-like class, specialized for holding {@link UnsignedLong}. It does not directly implement
+ * the {@link RangeSet} interface, but allows converting to and from it. Internal implementation takes advantage of
+ * knowing that {@link UnsignedLong} is a discrete type and that it can be stored in a long.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public final class UnsignedLongRangeSet implements Mutable {
+ // FIXME: this is just to get us started
+ private final RangeSet<UnsignedLong> rangeset;
+
+ private UnsignedLongRangeSet(final RangeSet<UnsignedLong> rangeset) {
+ this.rangeset = Preconditions.checkNotNull(rangeset);
+ }
+
+ public static UnsignedLongRangeSet create() {
+ return new UnsignedLongRangeSet(TreeRangeSet.create());
+ }
+
+ public static UnsignedLongRangeSet create(final RangeSet<UnsignedLong> input) {
+ return new UnsignedLongRangeSet(TreeRangeSet.create(input));
+ }
+
+ public RangeSet<UnsignedLong> toImmutable() {
+ return ImmutableRangeSet.copyOf(rangeset);
+ }
+
+ public void add(final long longBits) {
+ add(UnsignedLong.fromLongBits(longBits));
+ }
+
+ public void add(final UnsignedLong value) {
+ rangeset.add(Range.closedOpen(value, UnsignedLong.ONE.plus(value)));
+ }
+
+ public boolean contains(final UnsignedLong value) {
+ return rangeset.contains(value);
+ }
+
+ public boolean contains(final long longBits) {
+ return contains(UnsignedLong.fromLongBits(longBits));
+ }
+
+ public UnsignedLongRangeSet copy() {
+ return new UnsignedLongRangeSet(TreeRangeSet.create(rangeset));
+ }
+}