Madan Jampani
Committed by Ray Milkey

Added a AtomicValue distributed primitive.

Change-Id: I00ff165cbd9c6e4f2610af9877ff262527b7b048
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.service;
17 +
18 +/**
19 + * Distributed version of java.util.concurrent.atomic.AtomicReference.
20 + *
21 + * @param <V> value type
22 + */
23 +public interface AtomicValue<V> {
24 +
25 + /**
26 + * Atomically sets the value to the given updated value if the current value is equal to the expected value.
27 + * <p>
28 + * IMPORTANT: Equality is based on the equality of the serialized byte[] representations.
29 + * <p>
30 + * @param expect the expected value
31 + * @param update the new value
32 + * @return true if successful. false return indicates that the actual value was not equal to the expected value.
33 + */
34 + boolean compareAndSet(V expect, V update);
35 +
36 + /**
37 + * Gets the current value.
38 + * @return current value
39 + */
40 + V get();
41 +
42 + /**
43 + * Atomically sets to the given value and returns the old value.
44 + * @param value the new value
45 + * @return previous value
46 + */
47 + V getAndSet(V value);
48 +
49 + /**
50 + * Sets to the given value.
51 + * @param value new value
52 + */
53 + void set(V value);
54 +
55 + /**
56 + * Registers the specified listener to be notified whenever the atomic value is updated.
57 + *
58 + * @param listener listener to notify about events
59 + */
60 + void addListener(AtomicValueEventListener<V> listener);
61 +
62 + /**
63 + * Unregisters the specified listener such that it will no longer
64 + * receive atomic value update notifications.
65 + *
66 + * @param listener listener to unregister
67 + */
68 + void removeListener(AtomicValueEventListener<V> listener);
69 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.service;
17 +
18 +/**
19 + * Builder for constructing new AtomicValue instances.
20 + *
21 + * @param <V> atomic value type
22 + */
23 +public interface AtomicValueBuilder<V> {
24 + /**
25 + * Sets the name for the atomic value.
26 + * <p>
27 + * Each atomic value is identified by a unique name.
28 + * </p>
29 + * <p>
30 + * Note: This is a mandatory parameter.
31 + * </p>
32 + *
33 + * @param name name of the atomic value
34 + * @return this AtomicValueBuilder for method chaining
35 + */
36 + AtomicValueBuilder<V> withName(String name);
37 +
38 + /**
39 + * Sets a serializer that can be used to serialize the value.
40 + * <p>
41 + * Note: This is a mandatory parameter.
42 + * </p>
43 + *
44 + * @param serializer serializer
45 + * @return this AtomicValueBuilder for method chaining
46 + */
47 + AtomicValueBuilder<V> withSerializer(Serializer serializer);
48 +
49 + /**
50 + * Creates this atomic value on the partition that spans the entire cluster.
51 + * <p>
52 + * When partitioning is disabled, the value state will be
53 + * ephemeral and does not survive a full cluster restart.
54 + * </p>
55 + * <p>
56 + * Note: By default partitions are enabled.
57 + * </p>
58 + * @return this AtomicValueBuilder for method chaining
59 + */
60 + AtomicValueBuilder<V> withPartitionsDisabled();
61 +
62 + /**
63 + * Builds a AtomicValue based on the configuration options
64 + * supplied to this builder.
65 + *
66 + * @return new AtomicValue
67 + * @throws java.lang.RuntimeException if a mandatory parameter is missing
68 + */
69 + AtomicValue<V> build();
70 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.service;
17 +
18 +import java.util.Objects;
19 +
20 +import com.google.common.base.MoreObjects;
21 +
22 +/**
23 + * Representation of a AtomicValue update notification.
24 + *
25 + * @param <V> atomic value type
26 + */
27 +public class AtomicValueEvent<V> {
28 +
29 + /**
30 + * AtomicValueEvent type.
31 + */
32 + public enum Type {
33 +
34 + /**
35 + * Value was updated.
36 + */
37 + UPDATE,
38 + }
39 +
40 + private final String name;
41 + private final Type type;
42 + private final V value;
43 +
44 + /**
45 + * Creates a new event object.
46 + *
47 + * @param name AtomicValue name
48 + * @param type the type of the event
49 + * @param value the new value
50 + */
51 + public AtomicValueEvent(String name, Type type, V value) {
52 + this.name = name;
53 + this.type = type;
54 + this.value = value;
55 + }
56 +
57 + /**
58 + * Returns the AtomicValue name.
59 + *
60 + * @return name of atomic value
61 + */
62 + public String name() {
63 + return name;
64 + }
65 +
66 + /**
67 + * Returns the type of the event.
68 + *
69 + * @return the type of the event
70 + */
71 + public Type type() {
72 + return type;
73 + }
74 +
75 + /**
76 + * Returns the new updated value.
77 + *
78 + * @return the value
79 + */
80 + public V value() {
81 + return value;
82 + }
83 +
84 + @Override
85 + public boolean equals(Object o) {
86 + if (!(o instanceof AtomicValueEvent)) {
87 + return false;
88 + }
89 +
90 + AtomicValueEvent<V> that = (AtomicValueEvent) o;
91 + return Objects.equals(this.name, that.name) &&
92 + Objects.equals(this.type, that.type) &&
93 + Objects.equals(this.value, that.value);
94 + }
95 +
96 + @Override
97 + public int hashCode() {
98 + return Objects.hash(name, type, value);
99 + }
100 +
101 + @Override
102 + public String toString() {
103 + return MoreObjects.toStringHelper(getClass())
104 + .add("name", name)
105 + .add("type", type)
106 + .add("value", value)
107 + .toString();
108 + }
109 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.service;
17 +
18 +/**
19 + * Listener to be notified about updates to a AtomicValue.
20 + */
21 +public interface AtomicValueEventListener<V> {
22 + /**
23 + * Reacts to the specified event.
24 + *
25 + * @param event the event
26 + */
27 + void event(AtomicValueEvent<V> event);
28 +}
...@@ -71,6 +71,14 @@ public interface StorageService { ...@@ -71,6 +71,14 @@ public interface StorageService {
71 AtomicCounterBuilder atomicCounterBuilder(); 71 AtomicCounterBuilder atomicCounterBuilder();
72 72
73 /** 73 /**
74 + * Creates a new AtomicValueBuilder.
75 + *
76 + * @param <V> atomic value type
77 + * @return atomic value builder
78 + */
79 + <V> AtomicValueBuilder<V> atomicValueBuilder();
80 +
81 + /**
74 * Creates a new transaction context builder. 82 * Creates a new transaction context builder.
75 * 83 *
76 * @return a builder for a transaction context. 84 * @return a builder for a transaction context.
......
...@@ -63,6 +63,7 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService; ...@@ -63,6 +63,7 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
63 import org.onosproject.store.cluster.messaging.MessageSubject; 63 import org.onosproject.store.cluster.messaging.MessageSubject;
64 import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl; 64 import org.onosproject.store.ecmap.EventuallyConsistentMapBuilderImpl;
65 import org.onosproject.store.service.AtomicCounterBuilder; 65 import org.onosproject.store.service.AtomicCounterBuilder;
66 +import org.onosproject.store.service.AtomicValueBuilder;
66 import org.onosproject.store.service.ConsistentMapBuilder; 67 import org.onosproject.store.service.ConsistentMapBuilder;
67 import org.onosproject.store.service.ConsistentMapException; 68 import org.onosproject.store.service.ConsistentMapException;
68 import org.onosproject.store.service.DistributedQueueBuilder; 69 import org.onosproject.store.service.DistributedQueueBuilder;
...@@ -383,6 +384,11 @@ public class DatabaseManager implements StorageService, StorageAdminService { ...@@ -383,6 +384,11 @@ public class DatabaseManager implements StorageService, StorageAdminService {
383 } 384 }
384 385
385 @Override 386 @Override
387 + public <V> AtomicValueBuilder<V> atomicValueBuilder() {
388 + return new DefaultAtomicValueBuilder<>(this);
389 + }
390 +
391 + @Override
386 public List<MapInfo> getMapInfo() { 392 public List<MapInfo> getMapInfo() {
387 List<MapInfo> maps = Lists.newArrayList(); 393 List<MapInfo> maps = Lists.newArrayList();
388 maps.addAll(getMapInfo(inMemoryDatabase)); 394 maps.addAll(getMapInfo(inMemoryDatabase));
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.consistent.impl;
17 +
18 +import java.util.Set;
19 +import java.util.concurrent.CopyOnWriteArraySet;
20 +
21 +import org.onosproject.store.service.AtomicValue;
22 +import org.onosproject.store.service.AtomicValueEvent;
23 +import org.onosproject.store.service.AtomicValueEventListener;
24 +import org.onosproject.store.service.ConsistentMap;
25 +import org.onosproject.store.service.MapEvent;
26 +import org.onosproject.store.service.MapEventListener;
27 +import org.onosproject.store.service.Serializer;
28 +import org.onosproject.store.service.Versioned;
29 +
30 +/**
31 + * Default implementation of AtomicValue.
32 + *
33 + * @param <V> value type
34 + */
35 +public class DefaultAtomicValue<V> implements AtomicValue<V> {
36 +
37 + private final Set<AtomicValueEventListener<V>> listeners = new CopyOnWriteArraySet<>();
38 + private final ConsistentMap<String, byte[]> valueMap;
39 + private final String name;
40 + private final Serializer serializer;
41 + private final MapEventListener<String, byte[]> mapEventListener = new InternalMapEventListener();
42 +
43 + public DefaultAtomicValue(ConsistentMap<String, byte[]> valueMap,
44 + String name,
45 + Serializer serializer) {
46 + this.valueMap = valueMap;
47 + this.name = name;
48 + this.serializer = serializer;
49 + }
50 +
51 + @Override
52 + public boolean compareAndSet(V expect, V update) {
53 + if (expect == null) {
54 + if (update == null) {
55 + return true;
56 + }
57 + return valueMap.putIfAbsent(name, serializer.encode(update)) == null;
58 + } else {
59 + if (update == null) {
60 + return valueMap.remove(name, serializer.encode(expect));
61 + }
62 + return valueMap.replace(name, serializer.encode(expect), serializer.encode(update));
63 + }
64 + }
65 +
66 + @Override
67 + public V get() {
68 + Versioned<byte[]> rawValue = valueMap.get(name);
69 + return rawValue == null ? null : serializer.decode(rawValue.value());
70 + }
71 +
72 + @Override
73 + public V getAndSet(V value) {
74 + Versioned<byte[]> previousValue = value == null ?
75 + valueMap.remove(name) : valueMap.put(name, serializer.encode(value));
76 + return previousValue == null ? null : serializer.decode(previousValue.value());
77 + }
78 +
79 + @Override
80 + public void set(V value) {
81 + getAndSet(value);
82 + }
83 +
84 + @Override
85 + public void addListener(AtomicValueEventListener<V> listener) {
86 + synchronized (listeners) {
87 + if (listeners.add(listener)) {
88 + if (listeners.size() == 1) {
89 + valueMap.addListener(mapEventListener);
90 + }
91 + }
92 + }
93 + }
94 +
95 + @Override
96 + public void removeListener(AtomicValueEventListener<V> listener) {
97 + synchronized (listeners) {
98 + if (listeners.remove(listener)) {
99 + if (listeners.size() == 0) {
100 + valueMap.removeListener(mapEventListener);
101 + }
102 + }
103 + }
104 + }
105 +
106 + private class InternalMapEventListener implements MapEventListener<String, byte[]> {
107 +
108 + @Override
109 + public void event(MapEvent<String, byte[]> mapEvent) {
110 + V newValue = mapEvent.type() == MapEvent.Type.REMOVE ? null : serializer.decode(mapEvent.value().value());
111 + AtomicValueEvent<V> atomicValueEvent = new AtomicValueEvent<>(name, AtomicValueEvent.Type.UPDATE, newValue);
112 + listeners.forEach(l -> l.event(atomicValueEvent));
113 + }
114 + }
115 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.store.consistent.impl;
17 +
18 +import org.onosproject.store.serializers.KryoNamespaces;
19 +import org.onosproject.store.service.AtomicValue;
20 +import org.onosproject.store.service.AtomicValueBuilder;
21 +import org.onosproject.store.service.ConsistentMapBuilder;
22 +import org.onosproject.store.service.Serializer;
23 +
24 +/**
25 + * Default implementation of AtomicValueBuilder.
26 + *
27 + * @param <V> value type
28 + */
29 +public class DefaultAtomicValueBuilder<V> implements AtomicValueBuilder<V> {
30 +
31 + private Serializer serializer;
32 + private String name;
33 + private ConsistentMapBuilder<String, byte[]> mapBuilder;
34 +
35 + public DefaultAtomicValueBuilder(DatabaseManager manager) {
36 + mapBuilder = manager.<String, byte[]>consistentMapBuilder()
37 + .withName("onos-atomic-values")
38 + .withSerializer(Serializer.using(KryoNamespaces.BASIC));
39 + }
40 +
41 + @Override
42 + public AtomicValueBuilder<V> withName(String name) {
43 + this.name = name;
44 + return this;
45 + }
46 +
47 + @Override
48 + public AtomicValueBuilder<V> withSerializer(Serializer serializer) {
49 + this.serializer = serializer;
50 + return this;
51 + }
52 +
53 + @Override
54 + public AtomicValueBuilder<V> withPartitionsDisabled() {
55 + mapBuilder.withPartitionsDisabled();
56 + return this;
57 + }
58 +
59 + @Override
60 + public AtomicValue<V> build() {
61 + return new DefaultAtomicValue<>(mapBuilder.build(), name, serializer);
62 + }
63 +}
...\ No newline at end of file ...\ No newline at end of file