Committed by
Gerrit Code Review
Adding atomic countetr compare and set method
Change-Id: I5cf459e9e09ab1a84ced8160ef61d6a52ea4bea4
Showing
10 changed files
with
106 additions
and
45 deletions
| ... | @@ -66,4 +66,13 @@ public interface AsyncAtomicCounter { | ... | @@ -66,4 +66,13 @@ public interface AsyncAtomicCounter { |
| 66 | * @return future void | 66 | * @return future void |
| 67 | */ | 67 | */ |
| 68 | CompletableFuture<Void> set(long value); | 68 | CompletableFuture<Void> set(long value); |
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise | ||
| 72 | + * no change occurs. | ||
| 73 | + * @param expectedValue the expected current value of the counter | ||
| 74 | + * @param updateValue the new value to be set | ||
| 75 | + * @return true if the update occurred and the expected value was equal to the current value, false otherwise | ||
| 76 | + */ | ||
| 77 | + CompletableFuture<Boolean> compareAndSet(long expectedValue, long updateValue); | ||
| 69 | } | 78 | } | ... | ... |
| ... | @@ -57,6 +57,14 @@ public interface AtomicCounter { | ... | @@ -57,6 +57,14 @@ public interface AtomicCounter { |
| 57 | */ | 57 | */ |
| 58 | void set(long value); | 58 | void set(long value); |
| 59 | 59 | ||
| 60 | + /** | ||
| 61 | + * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise | ||
| 62 | + * no change occurs. | ||
| 63 | + * @param expectedValue the expected current value of the counter | ||
| 64 | + * @param updateValue the new value to be set | ||
| 65 | + * @return true if the update occurred and the expected value was equal to the current value, false otherwise | ||
| 66 | + */ | ||
| 67 | + boolean compareAndSet(long expectedValue, long updateValue); | ||
| 60 | 68 | ||
| 61 | /** | 69 | /** |
| 62 | * Returns the current value of the counter without modifying it. | 70 | * Returns the current value of the counter without modifying it. | ... | ... |
| ... | @@ -53,6 +53,11 @@ public final class TestAtomicCounter implements AtomicCounter { | ... | @@ -53,6 +53,11 @@ public final class TestAtomicCounter implements AtomicCounter { |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | @Override | 55 | @Override |
| 56 | + public boolean compareAndSet(long expectedValue, long updateValue) { | ||
| 57 | + return value.compareAndSet(expectedValue, updateValue); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @Override | ||
| 56 | public long get() { | 61 | public long get() { |
| 57 | return value.get(); | 62 | return value.get(); |
| 58 | } | 63 | } | ... | ... |
| ... | @@ -16,14 +16,14 @@ | ... | @@ -16,14 +16,14 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.store.consistent.impl; | 17 | package org.onosproject.store.consistent.impl; |
| 18 | 18 | ||
| 19 | +import org.onosproject.store.service.Transaction; | ||
| 20 | +import org.onosproject.store.service.Versioned; | ||
| 21 | + | ||
| 19 | import java.util.Collection; | 22 | import java.util.Collection; |
| 20 | import java.util.Map; | 23 | import java.util.Map; |
| 21 | import java.util.Set; | 24 | import java.util.Set; |
| 22 | import java.util.concurrent.CompletableFuture; | 25 | import java.util.concurrent.CompletableFuture; |
| 23 | 26 | ||
| 24 | -import org.onosproject.store.service.Transaction; | ||
| 25 | -import org.onosproject.store.service.Versioned; | ||
| 26 | - | ||
| 27 | /** | 27 | /** |
| 28 | * Database proxy. | 28 | * Database proxy. |
| 29 | */ | 29 | */ |
| ... | @@ -160,6 +160,16 @@ public interface DatabaseProxy<K, V> { | ... | @@ -160,6 +160,16 @@ public interface DatabaseProxy<K, V> { |
| 160 | CompletableFuture<Void> counterSet(String counterName, long value); | 160 | CompletableFuture<Void> counterSet(String counterName, long value); |
| 161 | 161 | ||
| 162 | /** | 162 | /** |
| 163 | + * Atomically sets the given counter to the specified update value if and only if the current value is equal to the | ||
| 164 | + * expected value. | ||
| 165 | + * @param counterName counter name | ||
| 166 | + * @param expectedValue value to use for equivalence check | ||
| 167 | + * @param update value to set if expected value is current value | ||
| 168 | + * @return true if an update occurred, false otherwise | ||
| 169 | + */ | ||
| 170 | + CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update); | ||
| 171 | + | ||
| 172 | + /** | ||
| 163 | * Returns the current value of the specified atomic counter. | 173 | * Returns the current value of the specified atomic counter. |
| 164 | * | 174 | * |
| 165 | * @param counterName counter name | 175 | * @param counterName counter name | ... | ... |
| ... | @@ -16,18 +16,17 @@ | ... | @@ -16,18 +16,17 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.store.consistent.impl; | 17 | package org.onosproject.store.consistent.impl; |
| 18 | 18 | ||
| 19 | -import java.util.Collection; | ||
| 20 | -import java.util.Map; | ||
| 21 | -import java.util.Map.Entry; | ||
| 22 | -import java.util.Set; | ||
| 23 | - | ||
| 24 | -import org.onosproject.store.service.Transaction; | ||
| 25 | -import org.onosproject.store.service.Versioned; | ||
| 26 | - | ||
| 27 | import net.kuujo.copycat.state.Command; | 19 | import net.kuujo.copycat.state.Command; |
| 28 | import net.kuujo.copycat.state.Initializer; | 20 | import net.kuujo.copycat.state.Initializer; |
| 29 | import net.kuujo.copycat.state.Query; | 21 | import net.kuujo.copycat.state.Query; |
| 30 | import net.kuujo.copycat.state.StateContext; | 22 | import net.kuujo.copycat.state.StateContext; |
| 23 | +import org.onosproject.store.service.Transaction; | ||
| 24 | +import org.onosproject.store.service.Versioned; | ||
| 25 | + | ||
| 26 | +import java.util.Collection; | ||
| 27 | +import java.util.Map; | ||
| 28 | +import java.util.Map.Entry; | ||
| 29 | +import java.util.Set; | ||
| 31 | 30 | ||
| 32 | /** | 31 | /** |
| 33 | * Database state. | 32 | * Database state. |
| ... | @@ -83,6 +82,9 @@ public interface DatabaseState<K, V> { | ... | @@ -83,6 +82,9 @@ public interface DatabaseState<K, V> { |
| 83 | Long counterAddAndGet(String counterName, long delta); | 82 | Long counterAddAndGet(String counterName, long delta); |
| 84 | 83 | ||
| 85 | @Command | 84 | @Command |
| 85 | + Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue); | ||
| 86 | + | ||
| 87 | + @Command | ||
| 86 | Long counterGetAndAdd(String counterName, long delta); | 88 | Long counterGetAndAdd(String counterName, long delta); |
| 87 | 89 | ||
| 88 | @Query | 90 | @Query | ... | ... |
| ... | @@ -40,6 +40,7 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { | ... | @@ -40,6 +40,7 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { |
| 40 | private static final String ADD_AND_GET = "addAndGet"; | 40 | private static final String ADD_AND_GET = "addAndGet"; |
| 41 | private static final String GET = "get"; | 41 | private static final String GET = "get"; |
| 42 | private static final String SET = "set"; | 42 | private static final String SET = "set"; |
| 43 | + private static final String COMPARE_AND_SET = "compareAndSet"; | ||
| 43 | 44 | ||
| 44 | public DefaultAsyncAtomicCounter(String name, | 45 | public DefaultAsyncAtomicCounter(String name, |
| 45 | Database database, | 46 | Database database, |
| ... | @@ -90,4 +91,11 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { | ... | @@ -90,4 +91,11 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { |
| 90 | return database.counterSet(name, value) | 91 | return database.counterSet(name, value) |
| 91 | .whenComplete((r, e) -> timer.stop(e)); | 92 | .whenComplete((r, e) -> timer.stop(e)); |
| 92 | } | 93 | } |
| 94 | + | ||
| 95 | + @Override | ||
| 96 | + public CompletableFuture<Boolean> compareAndSet(long expectedValue, long updateValue) { | ||
| 97 | + final MeteringAgent.Context timer = monitor.startTimer(COMPARE_AND_SET); | ||
| 98 | + return database.counterCompareAndSet(name, expectedValue, updateValue) | ||
| 99 | + .whenComplete((r, e) -> timer.stop(e)); | ||
| 100 | + } | ||
| 93 | } | 101 | } | ... | ... |
| ... | @@ -68,6 +68,11 @@ public class DefaultAtomicCounter implements AtomicCounter { | ... | @@ -68,6 +68,11 @@ public class DefaultAtomicCounter implements AtomicCounter { |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | @Override | 70 | @Override |
| 71 | + public boolean compareAndSet(long expectedValue, long updateValue) { | ||
| 72 | + return complete(asyncCounter.compareAndSet(expectedValue, updateValue)); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Override | ||
| 71 | public long get() { | 76 | public long get() { |
| 72 | return complete(asyncCounter.get()); | 77 | return complete(asyncCounter.get()); |
| 73 | } | 78 | } | ... | ... |
| ... | @@ -16,12 +16,15 @@ | ... | @@ -16,12 +16,15 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.store.consistent.impl; | 17 | package org.onosproject.store.consistent.impl; |
| 18 | 18 | ||
| 19 | -import net.kuujo.copycat.state.StateMachine; | 19 | +import com.google.common.collect.Sets; |
| 20 | import net.kuujo.copycat.resource.internal.AbstractResource; | 20 | import net.kuujo.copycat.resource.internal.AbstractResource; |
| 21 | import net.kuujo.copycat.resource.internal.ResourceManager; | 21 | import net.kuujo.copycat.resource.internal.ResourceManager; |
| 22 | +import net.kuujo.copycat.state.StateMachine; | ||
| 22 | import net.kuujo.copycat.state.internal.DefaultStateMachine; | 23 | import net.kuujo.copycat.state.internal.DefaultStateMachine; |
| 23 | import net.kuujo.copycat.util.concurrent.Futures; | 24 | import net.kuujo.copycat.util.concurrent.Futures; |
| 24 | import net.kuujo.copycat.util.function.TriConsumer; | 25 | import net.kuujo.copycat.util.function.TriConsumer; |
| 26 | +import org.onosproject.store.service.Transaction; | ||
| 27 | +import org.onosproject.store.service.Versioned; | ||
| 25 | 28 | ||
| 26 | import java.util.Collection; | 29 | import java.util.Collection; |
| 27 | import java.util.Map; | 30 | import java.util.Map; |
| ... | @@ -30,11 +33,6 @@ import java.util.concurrent.CompletableFuture; | ... | @@ -30,11 +33,6 @@ import java.util.concurrent.CompletableFuture; |
| 30 | import java.util.function.Consumer; | 33 | import java.util.function.Consumer; |
| 31 | import java.util.function.Supplier; | 34 | import java.util.function.Supplier; |
| 32 | 35 | ||
| 33 | -import org.onosproject.store.service.Transaction; | ||
| 34 | -import org.onosproject.store.service.Versioned; | ||
| 35 | - | ||
| 36 | -import com.google.common.collect.Sets; | ||
| 37 | - | ||
| 38 | /** | 36 | /** |
| 39 | * Default database. | 37 | * Default database. |
| 40 | */ | 38 | */ |
| ... | @@ -48,9 +46,9 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab | ... | @@ -48,9 +46,9 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab |
| 48 | public DefaultDatabase(ResourceManager context) { | 46 | public DefaultDatabase(ResourceManager context) { |
| 49 | super(context); | 47 | super(context); |
| 50 | this.stateMachine = new DefaultStateMachine(context, | 48 | this.stateMachine = new DefaultStateMachine(context, |
| 51 | - DatabaseState.class, | 49 | + DatabaseState.class, |
| 52 | - DefaultDatabaseState.class, | 50 | + DefaultDatabaseState.class, |
| 53 | - DefaultDatabase.class.getClassLoader()); | 51 | + DefaultDatabase.class.getClassLoader()); |
| 54 | this.stateMachine.addStartupTask(() -> { | 52 | this.stateMachine.addStartupTask(() -> { |
| 55 | stateMachine.registerWatcher(watcher); | 53 | stateMachine.registerWatcher(watcher); |
| 56 | return CompletableFuture.completedFuture(null); | 54 | return CompletableFuture.completedFuture(null); |
| ... | @@ -158,6 +156,11 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab | ... | @@ -158,6 +156,11 @@ public class DefaultDatabase extends AbstractResource<Database> implements Datab |
| 158 | } | 156 | } |
| 159 | 157 | ||
| 160 | @Override | 158 | @Override |
| 159 | + public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long update) { | ||
| 160 | + return checkOpen(() -> proxy.counterCompareAndSet(counterName, expectedValue, update)); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + @Override | ||
| 161 | public CompletableFuture<Long> queueSize(String queueName) { | 164 | public CompletableFuture<Long> queueSize(String queueName) { |
| 162 | return checkOpen(() -> proxy.queueSize(queueName)); | 165 | return checkOpen(() -> proxy.queueSize(queueName)); |
| 163 | } | 166 | } | ... | ... |
| ... | @@ -16,27 +16,26 @@ | ... | @@ -16,27 +16,26 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.store.consistent.impl; | 17 | package org.onosproject.store.consistent.impl; |
| 18 | 18 | ||
| 19 | +import com.google.common.base.Objects; | ||
| 20 | +import com.google.common.collect.ImmutableList; | ||
| 21 | +import com.google.common.collect.ImmutableSet; | ||
| 22 | +import com.google.common.collect.Lists; | ||
| 23 | +import com.google.common.collect.Maps; | ||
| 24 | +import net.kuujo.copycat.state.Initializer; | ||
| 25 | +import net.kuujo.copycat.state.StateContext; | ||
| 26 | +import org.onosproject.store.service.DatabaseUpdate; | ||
| 27 | +import org.onosproject.store.service.Transaction; | ||
| 28 | +import org.onosproject.store.service.Versioned; | ||
| 29 | + | ||
| 19 | import java.util.Arrays; | 30 | import java.util.Arrays; |
| 20 | import java.util.Collection; | 31 | import java.util.Collection; |
| 21 | import java.util.LinkedList; | 32 | import java.util.LinkedList; |
| 22 | import java.util.Map; | 33 | import java.util.Map; |
| 23 | import java.util.Map.Entry; | 34 | import java.util.Map.Entry; |
| 24 | import java.util.Queue; | 35 | import java.util.Queue; |
| 36 | +import java.util.Set; | ||
| 25 | import java.util.concurrent.atomic.AtomicLong; | 37 | import java.util.concurrent.atomic.AtomicLong; |
| 26 | import java.util.stream.Collectors; | 38 | import java.util.stream.Collectors; |
| 27 | -import java.util.Set; | ||
| 28 | - | ||
| 29 | -import org.onosproject.store.service.DatabaseUpdate; | ||
| 30 | -import org.onosproject.store.service.Transaction; | ||
| 31 | -import org.onosproject.store.service.Versioned; | ||
| 32 | -import com.google.common.base.Objects; | ||
| 33 | -import com.google.common.collect.ImmutableList; | ||
| 34 | -import com.google.common.collect.ImmutableSet; | ||
| 35 | -import com.google.common.collect.Lists; | ||
| 36 | -import com.google.common.collect.Maps; | ||
| 37 | - | ||
| 38 | -import net.kuujo.copycat.state.Initializer; | ||
| 39 | -import net.kuujo.copycat.state.StateContext; | ||
| 40 | 39 | ||
| 41 | /** | 40 | /** |
| 42 | * Default database state. | 41 | * Default database state. |
| ... | @@ -195,6 +194,11 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -195,6 +194,11 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
| 195 | } | 194 | } |
| 196 | 195 | ||
| 197 | @Override | 196 | @Override |
| 197 | + public Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue) { | ||
| 198 | + return getCounter(counterName).compareAndSet(expectedValue, updateValue); | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + @Override | ||
| 198 | public Long counterGet(String counterName) { | 202 | public Long counterGet(String counterName) { |
| 199 | return getCounter(counterName).get(); | 203 | return getCounter(counterName).get(); |
| 200 | } | 204 | } | ... | ... |
| ... | @@ -16,6 +16,17 @@ | ... | @@ -16,6 +16,17 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.store.consistent.impl; | 17 | package org.onosproject.store.consistent.impl; |
| 18 | 18 | ||
| 19 | +import com.google.common.collect.ImmutableList; | ||
| 20 | +import com.google.common.collect.Lists; | ||
| 21 | +import com.google.common.collect.Maps; | ||
| 22 | +import com.google.common.collect.Sets; | ||
| 23 | +import net.kuujo.copycat.Task; | ||
| 24 | +import net.kuujo.copycat.cluster.Cluster; | ||
| 25 | +import net.kuujo.copycat.resource.ResourceState; | ||
| 26 | +import org.onosproject.store.service.DatabaseUpdate; | ||
| 27 | +import org.onosproject.store.service.Transaction; | ||
| 28 | +import org.onosproject.store.service.Versioned; | ||
| 29 | + | ||
| 19 | import java.util.Collection; | 30 | import java.util.Collection; |
| 20 | import java.util.List; | 31 | import java.util.List; |
| 21 | import java.util.Map; | 32 | import java.util.Map; |
| ... | @@ -28,18 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger; | ... | @@ -28,18 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger; |
| 28 | import java.util.function.Consumer; | 39 | import java.util.function.Consumer; |
| 29 | import java.util.stream.Collectors; | 40 | import java.util.stream.Collectors; |
| 30 | 41 | ||
| 31 | -import org.onosproject.store.service.DatabaseUpdate; | ||
| 32 | -import org.onosproject.store.service.Transaction; | ||
| 33 | -import org.onosproject.store.service.Versioned; | ||
| 34 | - | ||
| 35 | -import com.google.common.collect.ImmutableList; | ||
| 36 | -import com.google.common.collect.Lists; | ||
| 37 | -import com.google.common.collect.Maps; | ||
| 38 | -import com.google.common.collect.Sets; | ||
| 39 | - | ||
| 40 | -import net.kuujo.copycat.Task; | ||
| 41 | -import net.kuujo.copycat.cluster.Cluster; | ||
| 42 | -import net.kuujo.copycat.resource.ResourceState; | ||
| 43 | import static com.google.common.base.Preconditions.checkState; | 42 | import static com.google.common.base.Preconditions.checkState; |
| 44 | 43 | ||
| 45 | /** | 44 | /** |
| ... | @@ -227,6 +226,14 @@ public class PartitionedDatabase implements Database { | ... | @@ -227,6 +226,14 @@ public class PartitionedDatabase implements Database { |
| 227 | } | 226 | } |
| 228 | 227 | ||
| 229 | @Override | 228 | @Override |
| 229 | + public CompletableFuture<Boolean> counterCompareAndSet(String counterName, long expectedValue, long updateValue) { | ||
| 230 | + checkState(isOpen.get(), DB_NOT_OPEN); | ||
| 231 | + return partitioner.getPartition(counterName, counterName). | ||
| 232 | + counterCompareAndSet(counterName, expectedValue, updateValue); | ||
| 233 | + | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + @Override | ||
| 230 | public CompletableFuture<Long> queueSize(String queueName) { | 237 | public CompletableFuture<Long> queueSize(String queueName) { |
| 231 | checkState(isOpen.get(), DB_NOT_OPEN); | 238 | checkState(isOpen.get(), DB_NOT_OPEN); |
| 232 | return partitioner.getPartition(queueName, queueName).queueSize(queueName); | 239 | return partitioner.getPartition(queueName, queueName).queueSize(queueName); | ... | ... |
-
Please register or login to post a comment