BUG-8676: add UnsignedLongRangeSet 03/59703/6
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 29 Jun 2017 16:47:14 +0000 (18:47 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 10 Jul 2017 11:17:11 +0000 (13:17 +0200)
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>
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/FrontendClientMetadataBuilder.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/LeaderFrontendState.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/UnsignedLongRangeSet.java [new file with mode: 0644]

index 519a360b06fd57245cfba8191d791939435ddfa1..4ffa27c60dcdb771767d836490d2af333b2c5f9f 100644 (file)
@@ -11,10 +11,6 @@ import com.google.common.base.MoreObjects;
 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;
@@ -24,6 +20,7 @@ import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifie
 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;
@@ -34,14 +31,14 @@ final class FrontendClientMetadataBuilder implements Builder<FrontendClientMetad
     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();
@@ -51,7 +48,7 @@ final class FrontendClientMetadataBuilder implements Builder<FrontendClientMetad
     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);
@@ -73,7 +70,7 @@ final class FrontendClientMetadataBuilder implements Builder<FrontendClientMetad
 
     @Override
     public FrontendClientMetadata build() {
-        return new FrontendClientMetadata(identifier, purgedHistories,
+        return new FrontendClientMetadata(identifier, purgedHistories.toImmutable(),
             Collections2.transform(currentHistories.values(), FrontendHistoryMetadataBuilder::build));
     }
 
@@ -110,8 +107,7 @@ final class FrontendClientMetadataBuilder implements Builder<FrontendClientMetad
         }
 
         // 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);
     }
 
@@ -174,7 +170,7 @@ final class FrontendClientMetadataBuilder implements Builder<FrontendClientMetad
         }
 
         return new LeaderFrontendState(shard.persistenceId(), getIdentifier(), shard.getDataStore(),
-            TreeRangeSet.create(purgedHistories), singleHistory, histories);
+            purgedHistories.copy(), singleHistory, histories);
     }
 
     private FrontendHistoryMetadataBuilder getHistory(final TransactionIdentifier txId) {
index d860bfa289e39f7b9a144aa652a5a030ec4c4546..ba2bdb3c7bfc87ba0dcc479ec754d7ff8dd7a751 100644 (file)
@@ -9,10 +9,6 @@ package org.opendaylight.controller.cluster.datastore;
 
 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;
@@ -32,6 +28,7 @@ import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifie
 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;
@@ -50,7 +47,7 @@ final class LeaderFrontendState implements Identifiable<ClientIdentifier> {
     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;
@@ -71,12 +68,12 @@ final class LeaderFrontendState implements Identifiable<ClientIdentifier> {
     // - 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);
@@ -133,9 +130,9 @@ final class LeaderFrontendState implements Identifiable<ClientIdentifier> {
 
         // 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
@@ -179,8 +176,7 @@ final class LeaderFrontendState implements Identifiable<ClientIdentifier> {
         }
 
         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;
     }
@@ -196,9 +192,9 @@ final class LeaderFrontendState implements Identifiable<ClientIdentifier> {
             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);
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/UnsignedLongRangeSet.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/UnsignedLongRangeSet.java
new file mode 100644 (file)
index 0000000..eeb39ea
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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));
+    }
+}