Simplified ECMap implmentation by merging items and tombstones maps
Change-Id: If4253722d91c35a7e57dec3c2fceb216d14a7314
Showing
9 changed files
with
182 additions
and
331 deletions
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.ecmap; | ||
17 | - | ||
18 | -import java.util.Objects; | ||
19 | - | ||
20 | -import org.onosproject.store.Timestamp; | ||
21 | - | ||
22 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
23 | - | ||
24 | -/** | ||
25 | - * Base class for events in an EventuallyConsistentMap. | ||
26 | - */ | ||
27 | -public abstract class AbstractEntry<K, V> implements Comparable<AbstractEntry<K, V>> { | ||
28 | - private final K key; | ||
29 | - private final Timestamp timestamp; | ||
30 | - | ||
31 | - /** | ||
32 | - * Creates a new put entry. | ||
33 | - * | ||
34 | - * @param key key of the entry | ||
35 | - * @param timestamp timestamp of the put event | ||
36 | - */ | ||
37 | - public AbstractEntry(K key, Timestamp timestamp) { | ||
38 | - this.key = checkNotNull(key); | ||
39 | - this.timestamp = checkNotNull(timestamp); | ||
40 | - } | ||
41 | - | ||
42 | - // Needed for serialization. | ||
43 | - @SuppressWarnings("unused") | ||
44 | - protected AbstractEntry() { | ||
45 | - this.key = null; | ||
46 | - this.timestamp = null; | ||
47 | - } | ||
48 | - | ||
49 | - /** | ||
50 | - * Returns the key of the entry. | ||
51 | - * | ||
52 | - * @return the key | ||
53 | - */ | ||
54 | - public K key() { | ||
55 | - return key; | ||
56 | - } | ||
57 | - | ||
58 | - /** | ||
59 | - * Returns the timestamp of the event. | ||
60 | - * | ||
61 | - * @return the timestamp | ||
62 | - */ | ||
63 | - public Timestamp timestamp() { | ||
64 | - return timestamp; | ||
65 | - } | ||
66 | - | ||
67 | - @Override | ||
68 | - public int compareTo(AbstractEntry<K, V> o) { | ||
69 | - return this.timestamp.compareTo(o.timestamp); | ||
70 | - } | ||
71 | - | ||
72 | - @Override | ||
73 | - public int hashCode() { | ||
74 | - return Objects.hash(timestamp); | ||
75 | - } | ||
76 | - | ||
77 | - @Override | ||
78 | - public boolean equals(Object o) { | ||
79 | - if (this == o) { | ||
80 | - return true; | ||
81 | - } | ||
82 | - if (o instanceof AbstractEntry) { | ||
83 | - final AbstractEntry that = (AbstractEntry) o; | ||
84 | - return this.timestamp.equals(that.timestamp); | ||
85 | - } | ||
86 | - return false; | ||
87 | - } | ||
88 | -} |
... | @@ -16,11 +16,11 @@ | ... | @@ -16,11 +16,11 @@ |
16 | package org.onosproject.store.ecmap; | 16 | package org.onosproject.store.ecmap; |
17 | 17 | ||
18 | import com.google.common.base.MoreObjects; | 18 | import com.google.common.base.MoreObjects; |
19 | +import com.google.common.collect.ImmutableMap; | ||
20 | + | ||
19 | import org.onosproject.cluster.NodeId; | 21 | import org.onosproject.cluster.NodeId; |
20 | -import org.onosproject.store.Timestamp; | ||
21 | 22 | ||
22 | import java.util.Map; | 23 | import java.util.Map; |
23 | - | ||
24 | import static com.google.common.base.Preconditions.checkNotNull; | 24 | import static com.google.common.base.Preconditions.checkNotNull; |
25 | 25 | ||
26 | /** | 26 | /** |
... | @@ -29,22 +29,18 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -29,22 +29,18 @@ import static com.google.common.base.Preconditions.checkNotNull; |
29 | public class AntiEntropyAdvertisement<K> { | 29 | public class AntiEntropyAdvertisement<K> { |
30 | 30 | ||
31 | private final NodeId sender; | 31 | private final NodeId sender; |
32 | - private final Map<K, Timestamp> timestamps; | 32 | + private final Map<K, MapValue.Digest> digest; |
33 | - private final Map<K, Timestamp> tombstones; | ||
34 | 33 | ||
35 | /** | 34 | /** |
36 | * Creates a new anti entropy advertisement message. | 35 | * Creates a new anti entropy advertisement message. |
37 | * | 36 | * |
38 | * @param sender the sender's node ID | 37 | * @param sender the sender's node ID |
39 | - * @param timestamps map of item key to timestamp for current items | 38 | + * @param digest for map entries |
40 | - * @param tombstones map of item key to timestamp for removed items | ||
41 | */ | 39 | */ |
42 | public AntiEntropyAdvertisement(NodeId sender, | 40 | public AntiEntropyAdvertisement(NodeId sender, |
43 | - Map<K, Timestamp> timestamps, | 41 | + Map<K, MapValue.Digest> digest) { |
44 | - Map<K, Timestamp> tombstones) { | ||
45 | this.sender = checkNotNull(sender); | 42 | this.sender = checkNotNull(sender); |
46 | - this.timestamps = checkNotNull(timestamps); | 43 | + this.digest = ImmutableMap.copyOf(checkNotNull(digest)); |
47 | - this.tombstones = checkNotNull(tombstones); | ||
48 | } | 44 | } |
49 | 45 | ||
50 | /** | 46 | /** |
... | @@ -57,36 +53,19 @@ public class AntiEntropyAdvertisement<K> { | ... | @@ -57,36 +53,19 @@ public class AntiEntropyAdvertisement<K> { |
57 | } | 53 | } |
58 | 54 | ||
59 | /** | 55 | /** |
60 | - * Returns the map of current item timestamps. | 56 | + * Returns the digest for map entries. |
61 | * | 57 | * |
62 | - * @return current item timestamps | 58 | + * @return mapping from key to associated digest |
63 | */ | 59 | */ |
64 | - public Map<K, Timestamp> timestamps() { | 60 | + public Map<K, MapValue.Digest> digest() { |
65 | - return timestamps; | 61 | + return digest; |
66 | - } | ||
67 | - | ||
68 | - /** | ||
69 | - * Returns the map of removed item timestamps. | ||
70 | - * | ||
71 | - * @return removed item timestamps | ||
72 | - */ | ||
73 | - public Map<K, Timestamp> tombstones() { | ||
74 | - return tombstones; | ||
75 | - } | ||
76 | - | ||
77 | - // For serializer | ||
78 | - @SuppressWarnings("unused") | ||
79 | - private AntiEntropyAdvertisement() { | ||
80 | - this.sender = null; | ||
81 | - this.timestamps = null; | ||
82 | - this.tombstones = null; | ||
83 | } | 62 | } |
84 | 63 | ||
85 | @Override | 64 | @Override |
86 | public String toString() { | 65 | public String toString() { |
87 | return MoreObjects.toStringHelper(getClass()) | 66 | return MoreObjects.toStringHelper(getClass()) |
88 | - .add("timestampsSize", timestamps.size()) | 67 | + .add("sender", sender) |
89 | - .add("tombstonesSize", tombstones.size()) | 68 | + .add("totalEntries", digest.size()) |
90 | .toString(); | 69 | .toString(); |
91 | } | 70 | } |
92 | } | 71 | } | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -16,13 +16,10 @@ | ... | @@ -16,13 +16,10 @@ |
16 | 16 | ||
17 | package org.onosproject.store.ecmap; | 17 | package org.onosproject.store.ecmap; |
18 | 18 | ||
19 | -import org.apache.commons.lang3.mutable.MutableBoolean; | ||
20 | import org.mapdb.DB; | 19 | import org.mapdb.DB; |
21 | import org.mapdb.DBMaker; | 20 | import org.mapdb.DBMaker; |
22 | import org.mapdb.Hasher; | 21 | import org.mapdb.Hasher; |
23 | import org.mapdb.Serializer; | 22 | import org.mapdb.Serializer; |
24 | -import org.onosproject.store.Timestamp; | ||
25 | -import org.onosproject.store.impl.Timestamped; | ||
26 | import org.onosproject.store.serializers.KryoSerializer; | 23 | import org.onosproject.store.serializers.KryoSerializer; |
27 | 24 | ||
28 | import java.io.File; | 25 | import java.io.File; |
... | @@ -42,7 +39,6 @@ class MapDbPersistentStore<K, V> implements PersistentStore<K, V> { | ... | @@ -42,7 +39,6 @@ class MapDbPersistentStore<K, V> implements PersistentStore<K, V> { |
42 | private final DB database; | 39 | private final DB database; |
43 | 40 | ||
44 | private final Map<byte[], byte[]> items; | 41 | private final Map<byte[], byte[]> items; |
45 | - private final Map<byte[], byte[]> tombstones; | ||
46 | 42 | ||
47 | /** | 43 | /** |
48 | * Creates a new MapDB based persistent store. | 44 | * Creates a new MapDB based persistent store. |
... | @@ -65,102 +61,32 @@ class MapDbPersistentStore<K, V> implements PersistentStore<K, V> { | ... | @@ -65,102 +61,32 @@ class MapDbPersistentStore<K, V> implements PersistentStore<K, V> { |
65 | .valueSerializer(Serializer.BYTE_ARRAY) | 61 | .valueSerializer(Serializer.BYTE_ARRAY) |
66 | .hasher(Hasher.BYTE_ARRAY) | 62 | .hasher(Hasher.BYTE_ARRAY) |
67 | .makeOrGet(); | 63 | .makeOrGet(); |
68 | - | ||
69 | - tombstones = database.createHashMap("tombstones") | ||
70 | - .keySerializer(Serializer.BYTE_ARRAY) | ||
71 | - .valueSerializer(Serializer.BYTE_ARRAY) | ||
72 | - .hasher(Hasher.BYTE_ARRAY) | ||
73 | - .makeOrGet(); | ||
74 | } | 64 | } |
75 | 65 | ||
76 | @Override | 66 | @Override |
77 | - public void readInto(Map<K, Timestamped<V>> items, Map<K, Timestamp> tombstones) { | 67 | + public void readInto(Map<K, MapValue<V>> items) { |
78 | this.items.forEach((keyBytes, valueBytes) -> | 68 | this.items.forEach((keyBytes, valueBytes) -> |
79 | items.put(serializer.decode(keyBytes), | 69 | items.put(serializer.decode(keyBytes), |
80 | serializer.decode(valueBytes))); | 70 | serializer.decode(valueBytes))); |
81 | - | ||
82 | - this.tombstones.forEach((keyBytes, valueBytes) -> | ||
83 | - tombstones.put(serializer.decode(keyBytes), | ||
84 | - serializer.decode(valueBytes))); | ||
85 | } | 71 | } |
86 | 72 | ||
87 | @Override | 73 | @Override |
88 | - public void put(K key, V value, Timestamp timestamp) { | 74 | + public void update(K key, MapValue<V> value) { |
89 | - executor.submit(() -> putInternal(key, value, timestamp)); | 75 | + executor.submit(() -> updateInternal(key, value)); |
90 | } | 76 | } |
91 | 77 | ||
92 | - private void putInternal(K key, V value, Timestamp timestamp) { | 78 | + private void updateInternal(K key, MapValue<V> newValue) { |
93 | byte[] keyBytes = serializer.encode(key); | 79 | byte[] keyBytes = serializer.encode(key); |
94 | - byte[] removedBytes = tombstones.get(keyBytes); | ||
95 | - | ||
96 | - Timestamp removed = removedBytes == null ? null : | ||
97 | - serializer.decode(removedBytes); | ||
98 | - if (removed != null && removed.isNewerThan(timestamp)) { | ||
99 | - return; | ||
100 | - } | ||
101 | - | ||
102 | - final MutableBoolean updated = new MutableBoolean(false); | ||
103 | 80 | ||
104 | items.compute(keyBytes, (k, existingBytes) -> { | 81 | items.compute(keyBytes, (k, existingBytes) -> { |
105 | - Timestamped<V> existing = existingBytes == null ? null : | 82 | + MapValue<V> existing = existingBytes == null ? null : |
106 | serializer.decode(existingBytes); | 83 | serializer.decode(existingBytes); |
107 | - if (existing != null && existing.isNewerThan(timestamp)) { | 84 | + if (existing == null || newValue.isNewerThan(existing)) { |
108 | - updated.setFalse(); | 85 | + return serializer.encode(newValue); |
109 | - return existingBytes; | ||
110 | } else { | 86 | } else { |
111 | - updated.setTrue(); | ||
112 | - return serializer.encode(new Timestamped<>(value, timestamp)); | ||
113 | - } | ||
114 | - }); | ||
115 | - | ||
116 | - boolean success = updated.booleanValue(); | ||
117 | - | ||
118 | - if (success && removed != null) { | ||
119 | - tombstones.remove(keyBytes, removedBytes); | ||
120 | - } | ||
121 | - | ||
122 | - database.commit(); | ||
123 | - } | ||
124 | - | ||
125 | - @Override | ||
126 | - public void remove(K key, Timestamp timestamp) { | ||
127 | - executor.submit(() -> removeInternal(key, timestamp)); | ||
128 | - } | ||
129 | - | ||
130 | - private void removeInternal(K key, Timestamp timestamp) { | ||
131 | - byte[] keyBytes = serializer.encode(key); | ||
132 | - | ||
133 | - final MutableBoolean updated = new MutableBoolean(false); | ||
134 | - | ||
135 | - items.compute(keyBytes, (k, existingBytes) -> { | ||
136 | - Timestamp existing = existingBytes == null ? null : | ||
137 | - serializer.decode(existingBytes); | ||
138 | - if (existing != null && existing.isNewerThan(timestamp)) { | ||
139 | - updated.setFalse(); | ||
140 | return existingBytes; | 87 | return existingBytes; |
141 | - } else { | ||
142 | - updated.setTrue(); | ||
143 | - // remove from items map | ||
144 | - return null; | ||
145 | } | 88 | } |
146 | }); | 89 | }); |
147 | - | ||
148 | - if (!updated.booleanValue()) { | ||
149 | - return; | ||
150 | - } | ||
151 | - | ||
152 | - byte[] timestampBytes = serializer.encode(timestamp); | ||
153 | - byte[] removedBytes = tombstones.get(keyBytes); | ||
154 | - | ||
155 | - Timestamp removedTimestamp = removedBytes == null ? null : | ||
156 | - serializer.decode(removedBytes); | ||
157 | - if (removedTimestamp == null) { | ||
158 | - tombstones.putIfAbsent(keyBytes, timestampBytes); | ||
159 | - } else if (timestamp.isNewerThan(removedTimestamp)) { | ||
160 | - tombstones.replace(keyBytes, removedBytes, timestampBytes); | ||
161 | - } | ||
162 | - | ||
163 | database.commit(); | 90 | database.commit(); |
164 | } | 91 | } |
165 | - | ||
166 | } | 92 | } | ... | ... |
1 | +package org.onosproject.store.ecmap; | ||
2 | + | ||
3 | +import org.onosproject.store.Timestamp; | ||
4 | +import com.google.common.base.MoreObjects; | ||
5 | + | ||
6 | +/** | ||
7 | + * Representation of a value in EventuallyConsistentMap. | ||
8 | + * | ||
9 | + * @param <V> value type | ||
10 | + */ | ||
11 | +public class MapValue<V> implements Comparable<MapValue<V>> { | ||
12 | + private final Timestamp timestamp; | ||
13 | + private final V value; | ||
14 | + | ||
15 | + public MapValue(V value, Timestamp timestamp) { | ||
16 | + this.value = value; | ||
17 | + this.timestamp = timestamp; | ||
18 | + } | ||
19 | + | ||
20 | + public boolean isTombstone() { | ||
21 | + return value == null; | ||
22 | + } | ||
23 | + | ||
24 | + public boolean isAlive() { | ||
25 | + return value != null; | ||
26 | + } | ||
27 | + | ||
28 | + public Timestamp timestamp() { | ||
29 | + return timestamp; | ||
30 | + } | ||
31 | + | ||
32 | + public V get() { | ||
33 | + return value; | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public int compareTo(MapValue<V> o) { | ||
38 | + return this.timestamp.compareTo(o.timestamp); | ||
39 | + } | ||
40 | + | ||
41 | + public boolean isNewerThan(MapValue<V> other) { | ||
42 | + return timestamp.isNewerThan(other.timestamp); | ||
43 | + } | ||
44 | + | ||
45 | + public boolean isNewerThan(Timestamp timestamp) { | ||
46 | + return timestamp.isNewerThan(timestamp); | ||
47 | + } | ||
48 | + | ||
49 | + public Digest digest() { | ||
50 | + return new Digest(timestamp, isTombstone()); | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + public String toString() { | ||
55 | + return MoreObjects.toStringHelper(getClass()) | ||
56 | + .add("timestamp", timestamp) | ||
57 | + .add("value", value) | ||
58 | + .toString(); | ||
59 | + } | ||
60 | + | ||
61 | + @SuppressWarnings("unused") | ||
62 | + private MapValue() { | ||
63 | + this.timestamp = null; | ||
64 | + this.value = null; | ||
65 | + } | ||
66 | + | ||
67 | + /** | ||
68 | + * Digest or summary of a MapValue for use during Anti-Entropy exchanges. | ||
69 | + */ | ||
70 | + public static class Digest { | ||
71 | + private final Timestamp timestamp; | ||
72 | + private final boolean isTombstone; | ||
73 | + | ||
74 | + public Digest(Timestamp timestamp, boolean isTombstone) { | ||
75 | + this.timestamp = timestamp; | ||
76 | + this.isTombstone = isTombstone; | ||
77 | + } | ||
78 | + | ||
79 | + public Timestamp timestamp() { | ||
80 | + return timestamp; | ||
81 | + } | ||
82 | + | ||
83 | + public boolean isTombstone() { | ||
84 | + return isTombstone; | ||
85 | + } | ||
86 | + | ||
87 | + public boolean isNewerThan(Digest other) { | ||
88 | + return timestamp.isNewerThan(other.timestamp); | ||
89 | + } | ||
90 | + | ||
91 | + @Override | ||
92 | + public String toString() { | ||
93 | + return MoreObjects.toStringHelper(getClass()) | ||
94 | + .add("timestamp", timestamp) | ||
95 | + .add("isTombstone", isTombstone) | ||
96 | + .toString(); | ||
97 | + } | ||
98 | + } | ||
99 | +} |
... | @@ -16,9 +16,6 @@ | ... | @@ -16,9 +16,6 @@ |
16 | 16 | ||
17 | package org.onosproject.store.ecmap; | 17 | package org.onosproject.store.ecmap; |
18 | 18 | ||
19 | -import org.onosproject.store.Timestamp; | ||
20 | -import org.onosproject.store.impl.Timestamped; | ||
21 | - | ||
22 | import java.util.Map; | 19 | import java.util.Map; |
23 | 20 | ||
24 | /** | 21 | /** |
... | @@ -30,24 +27,14 @@ interface PersistentStore<K, V> { | ... | @@ -30,24 +27,14 @@ interface PersistentStore<K, V> { |
30 | * Read the contents of the disk into the given maps. | 27 | * Read the contents of the disk into the given maps. |
31 | * | 28 | * |
32 | * @param items items map | 29 | * @param items items map |
33 | - * @param tombstones tombstones map | ||
34 | */ | 30 | */ |
35 | - void readInto(Map<K, Timestamped<V>> items, Map<K, Timestamp> tombstones); | 31 | + void readInto(Map<K, MapValue<V>> items); |
36 | 32 | ||
37 | /** | 33 | /** |
38 | - * Puts a new key,value pair into the map on disk. | 34 | + * Updates a key,value pair in the persistent store. |
39 | * | 35 | * |
40 | * @param key the key | 36 | * @param key the key |
41 | * @param value the value | 37 | * @param value the value |
42 | - * @param timestamp the timestamp of the update | ||
43 | - */ | ||
44 | - void put(K key, V value, Timestamp timestamp); | ||
45 | - | ||
46 | - /** | ||
47 | - * Removes a key from the map on disk. | ||
48 | - * | ||
49 | - * @param key the key | ||
50 | - * @param timestamp the timestamp of the update | ||
51 | */ | 38 | */ |
52 | - void remove(K key, Timestamp timestamp); | 39 | + void update(K key, MapValue<V> value); |
53 | } | 40 | } | ... | ... |
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.ecmap; | ||
17 | - | ||
18 | -import com.google.common.base.MoreObjects; | ||
19 | -import org.onosproject.store.Timestamp; | ||
20 | - | ||
21 | -/** | ||
22 | - * Describes a single remove event in an EventuallyConsistentMap. | ||
23 | - */ | ||
24 | -final class RemoveEntry<K, V> extends AbstractEntry<K, V> { | ||
25 | - /** | ||
26 | - * Creates a new remove entry. | ||
27 | - * | ||
28 | - * @param key key of the entry | ||
29 | - * @param timestamp timestamp of the remove event | ||
30 | - */ | ||
31 | - public RemoveEntry(K key, Timestamp timestamp) { | ||
32 | - super(key, timestamp); | ||
33 | - } | ||
34 | - | ||
35 | - // Needed for serialization. | ||
36 | - @SuppressWarnings("unused") | ||
37 | - private RemoveEntry() { | ||
38 | - super(); | ||
39 | - } | ||
40 | - | ||
41 | - @Override | ||
42 | - public String toString() { | ||
43 | - return MoreObjects.toStringHelper(getClass()) | ||
44 | - .add("key", key()) | ||
45 | - .add("timestamp", timestamp()) | ||
46 | - .toString(); | ||
47 | - } | ||
48 | -} |
... | @@ -15,34 +15,35 @@ | ... | @@ -15,34 +15,35 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.store.ecmap; | 16 | package org.onosproject.store.ecmap; |
17 | 17 | ||
18 | -import com.google.common.base.MoreObjects; | ||
19 | -import org.onosproject.store.Timestamp; | ||
20 | - | ||
21 | import static com.google.common.base.Preconditions.checkNotNull; | 18 | import static com.google.common.base.Preconditions.checkNotNull; |
22 | 19 | ||
20 | +import com.google.common.base.MoreObjects; | ||
21 | + | ||
23 | /** | 22 | /** |
24 | - * Describes a single put event in an EventuallyConsistentMap. | 23 | + * Describes a single update event in an EventuallyConsistentMap. |
25 | */ | 24 | */ |
26 | -final class PutEntry<K, V> extends AbstractEntry<K, V> { | 25 | +final class UpdateEntry<K, V> implements Comparable<UpdateEntry<K, V>> { |
27 | - private final V value; | 26 | + private final K key; |
27 | + private final MapValue<V> value; | ||
28 | 28 | ||
29 | /** | 29 | /** |
30 | - * Creates a new put entry. | 30 | + * Creates a new update entry. |
31 | * | 31 | * |
32 | * @param key key of the entry | 32 | * @param key key of the entry |
33 | * @param value value of the entry | 33 | * @param value value of the entry |
34 | - * @param timestamp timestamp of the put event | ||
35 | */ | 34 | */ |
36 | - public PutEntry(K key, V value, Timestamp timestamp) { | 35 | + public UpdateEntry(K key, MapValue<V> value) { |
37 | - super(key, timestamp); | 36 | + this.key = checkNotNull(key); |
38 | this.value = checkNotNull(value); | 37 | this.value = checkNotNull(value); |
39 | } | 38 | } |
40 | 39 | ||
41 | - // Needed for serialization. | 40 | + /** |
42 | - @SuppressWarnings("unused") | 41 | + * Returns the key. |
43 | - private PutEntry() { | 42 | + * |
44 | - super(); | 43 | + * @return the key |
45 | - this.value = null; | 44 | + */ |
45 | + public K key() { | ||
46 | + return key; | ||
46 | } | 47 | } |
47 | 48 | ||
48 | /** | 49 | /** |
... | @@ -50,16 +51,26 @@ final class PutEntry<K, V> extends AbstractEntry<K, V> { | ... | @@ -50,16 +51,26 @@ final class PutEntry<K, V> extends AbstractEntry<K, V> { |
50 | * | 51 | * |
51 | * @return the value | 52 | * @return the value |
52 | */ | 53 | */ |
53 | - public V value() { | 54 | + public MapValue<V> value() { |
54 | return value; | 55 | return value; |
55 | } | 56 | } |
56 | 57 | ||
57 | @Override | 58 | @Override |
59 | + public int compareTo(UpdateEntry<K, V> o) { | ||
60 | + return this.value.timestamp().compareTo(o.value.timestamp()); | ||
61 | + } | ||
62 | + | ||
63 | + @Override | ||
58 | public String toString() { | 64 | public String toString() { |
59 | return MoreObjects.toStringHelper(getClass()) | 65 | return MoreObjects.toStringHelper(getClass()) |
60 | .add("key", key()) | 66 | .add("key", key()) |
61 | .add("value", value) | 67 | .add("value", value) |
62 | - .add("timestamp", timestamp()) | ||
63 | .toString(); | 68 | .toString(); |
64 | } | 69 | } |
70 | + | ||
71 | + @SuppressWarnings("unused") | ||
72 | + private UpdateEntry() { | ||
73 | + this.key = null; | ||
74 | + this.value = null; | ||
75 | + } | ||
65 | } | 76 | } | ... | ... |
... | @@ -16,8 +16,8 @@ | ... | @@ -16,8 +16,8 @@ |
16 | package org.onosproject.store.ecmap; | 16 | package org.onosproject.store.ecmap; |
17 | 17 | ||
18 | import com.google.common.collect.ComparisonChain; | 18 | import com.google.common.collect.ComparisonChain; |
19 | +import com.google.common.collect.ImmutableList; | ||
19 | import com.google.common.collect.ImmutableSet; | 20 | import com.google.common.collect.ImmutableSet; |
20 | -import com.google.common.collect.Lists; | ||
21 | import com.google.common.util.concurrent.MoreExecutors; | 21 | import com.google.common.util.concurrent.MoreExecutors; |
22 | 22 | ||
23 | import org.junit.After; | 23 | import org.junit.After; |
... | @@ -32,7 +32,6 @@ import org.onosproject.cluster.NodeId; | ... | @@ -32,7 +32,6 @@ import org.onosproject.cluster.NodeId; |
32 | import org.onosproject.event.AbstractEvent; | 32 | import org.onosproject.event.AbstractEvent; |
33 | import org.onosproject.store.Timestamp; | 33 | import org.onosproject.store.Timestamp; |
34 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | 34 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
35 | -import org.onosproject.store.cluster.messaging.ClusterMessage; | ||
36 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | 35 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; |
37 | import org.onosproject.store.cluster.messaging.MessageSubject; | 36 | import org.onosproject.store.cluster.messaging.MessageSubject; |
38 | import org.onosproject.store.impl.LogicalTimestamp; | 37 | import org.onosproject.store.impl.LogicalTimestamp; |
... | @@ -44,11 +43,13 @@ import org.onosproject.store.service.EventuallyConsistentMapEvent; | ... | @@ -44,11 +43,13 @@ import org.onosproject.store.service.EventuallyConsistentMapEvent; |
44 | import org.onosproject.store.service.EventuallyConsistentMapListener; | 43 | import org.onosproject.store.service.EventuallyConsistentMapListener; |
45 | 44 | ||
46 | import java.util.ArrayList; | 45 | import java.util.ArrayList; |
46 | +import java.util.Collection; | ||
47 | import java.util.HashMap; | 47 | import java.util.HashMap; |
48 | import java.util.HashSet; | 48 | import java.util.HashSet; |
49 | import java.util.List; | 49 | import java.util.List; |
50 | import java.util.Map; | 50 | import java.util.Map; |
51 | import java.util.Objects; | 51 | import java.util.Objects; |
52 | +import java.util.Optional; | ||
52 | import java.util.Set; | 53 | import java.util.Set; |
53 | import java.util.concurrent.CompletableFuture; | 54 | import java.util.concurrent.CompletableFuture; |
54 | import java.util.concurrent.CountDownLatch; | 55 | import java.util.concurrent.CountDownLatch; |
... | @@ -89,8 +90,8 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -89,8 +90,8 @@ public class EventuallyConsistentMapImplTest { |
89 | private final ControllerNode self = | 90 | private final ControllerNode self = |
90 | new DefaultControllerNode(new NodeId("local"), IpAddress.valueOf(1)); | 91 | new DefaultControllerNode(new NodeId("local"), IpAddress.valueOf(1)); |
91 | 92 | ||
92 | - private ClusterMessageHandler updateHandler; | 93 | + private Consumer<Collection<UpdateEntry<String, String>>> updateHandler; |
93 | - private ClusterMessageHandler antiEntropyHandler; | 94 | + private Consumer<AntiEntropyAdvertisement<String>> antiEntropyHandler; |
94 | 95 | ||
95 | /* | 96 | /* |
96 | * Serialization is a bit tricky here. We need to serialize in the tests | 97 | * Serialization is a bit tricky here. We need to serialize in the tests |
... | @@ -109,11 +110,10 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -109,11 +110,10 @@ public class EventuallyConsistentMapImplTest { |
109 | // Below is the classes that the map internally registers | 110 | // Below is the classes that the map internally registers |
110 | .register(LogicalTimestamp.class) | 111 | .register(LogicalTimestamp.class) |
111 | .register(WallClockTimestamp.class) | 112 | .register(WallClockTimestamp.class) |
112 | - .register(PutEntry.class) | ||
113 | - .register(RemoveEntry.class) | ||
114 | .register(ArrayList.class) | 113 | .register(ArrayList.class) |
115 | .register(AntiEntropyAdvertisement.class) | 114 | .register(AntiEntropyAdvertisement.class) |
116 | .register(HashMap.class) | 115 | .register(HashMap.class) |
116 | + .register(Optional.class) | ||
117 | .build(); | 117 | .build(); |
118 | } | 118 | } |
119 | }; | 119 | }; |
... | @@ -131,9 +131,9 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -131,9 +131,9 @@ public class EventuallyConsistentMapImplTest { |
131 | // delegate to our ClusterCommunicationService implementation. This | 131 | // delegate to our ClusterCommunicationService implementation. This |
132 | // allows us to get a reference to the map's internal cluster message | 132 | // allows us to get a reference to the map's internal cluster message |
133 | // handlers so we can induce events coming in from a peer. | 133 | // handlers so we can induce events coming in from a peer. |
134 | - clusterCommunicator.addSubscriber(anyObject(MessageSubject.class), | 134 | + clusterCommunicator.<String>addSubscriber(anyObject(MessageSubject.class), |
135 | - anyObject(ClusterMessageHandler.class), anyObject(ExecutorService.class)); | 135 | + anyObject(Function.class), anyObject(Consumer.class), anyObject(Executor.class)); |
136 | - expectLastCall().andDelegateTo(new TestClusterCommunicationService()).times(3); | 136 | + expectLastCall().andDelegateTo(new TestClusterCommunicationService()).times(2); |
137 | 137 | ||
138 | replay(clusterCommunicator); | 138 | replay(clusterCommunicator); |
139 | 139 | ||
... | @@ -237,15 +237,15 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -237,15 +237,15 @@ public class EventuallyConsistentMapImplTest { |
237 | assertEquals(VALUE1, ecMap.get(KEY1)); | 237 | assertEquals(VALUE1, ecMap.get(KEY1)); |
238 | 238 | ||
239 | // Remote put | 239 | // Remote put |
240 | - ClusterMessage message | 240 | + List<UpdateEntry<String, String>> message |
241 | - = generatePutMessage(KEY2, VALUE2, clockService.getTimestamp(KEY2, VALUE2)); | 241 | + = ImmutableList.of(generatePutMessage(KEY2, VALUE2, clockService.getTimestamp(KEY2, VALUE2))); |
242 | 242 | ||
243 | // Create a latch so we know when the put operation has finished | 243 | // Create a latch so we know when the put operation has finished |
244 | latch = new CountDownLatch(1); | 244 | latch = new CountDownLatch(1); |
245 | ecMap.addListener(new TestListener(latch)); | 245 | ecMap.addListener(new TestListener(latch)); |
246 | 246 | ||
247 | assertNull(ecMap.get(KEY2)); | 247 | assertNull(ecMap.get(KEY2)); |
248 | - updateHandler.handle(message); | 248 | + updateHandler.accept(message); |
249 | assertTrue("External listener never got notified of internal event", | 249 | assertTrue("External listener never got notified of internal event", |
250 | latch.await(100, TimeUnit.MILLISECONDS)); | 250 | latch.await(100, TimeUnit.MILLISECONDS)); |
251 | assertEquals(VALUE2, ecMap.get(KEY2)); | 251 | assertEquals(VALUE2, ecMap.get(KEY2)); |
... | @@ -255,14 +255,13 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -255,14 +255,13 @@ public class EventuallyConsistentMapImplTest { |
255 | assertNull(ecMap.get(KEY2)); | 255 | assertNull(ecMap.get(KEY2)); |
256 | 256 | ||
257 | // Remote remove | 257 | // Remote remove |
258 | - ClusterMessage removeMessage | 258 | + message = ImmutableList.of(generateRemoveMessage(KEY1, clockService.getTimestamp(KEY1, VALUE1))); |
259 | - = generateRemoveMessage(KEY1, clockService.getTimestamp(KEY1, VALUE1)); | ||
260 | 259 | ||
261 | // Create a latch so we know when the remove operation has finished | 260 | // Create a latch so we know when the remove operation has finished |
262 | latch = new CountDownLatch(1); | 261 | latch = new CountDownLatch(1); |
263 | ecMap.addListener(new TestListener(latch)); | 262 | ecMap.addListener(new TestListener(latch)); |
264 | 263 | ||
265 | - updateHandler.handle(removeMessage); | 264 | + updateHandler.accept(message); |
266 | assertTrue("External listener never got notified of internal event", | 265 | assertTrue("External listener never got notified of internal event", |
267 | latch.await(100, TimeUnit.MILLISECONDS)); | 266 | latch.await(100, TimeUnit.MILLISECONDS)); |
268 | assertNull(ecMap.get(KEY1)); | 267 | assertNull(ecMap.get(KEY1)); |
... | @@ -601,49 +600,35 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -601,49 +600,35 @@ public class EventuallyConsistentMapImplTest { |
601 | } | 600 | } |
602 | } | 601 | } |
603 | 602 | ||
604 | - private ClusterMessage generatePutMessage(String key, String value, Timestamp timestamp) { | 603 | + private UpdateEntry<String, String> generatePutMessage(String key, String value, Timestamp timestamp) { |
605 | - PutEntry<String, String> event = new PutEntry<>(key, value, timestamp); | 604 | + return new UpdateEntry<>(key, new MapValue<>(value, timestamp)); |
606 | - | ||
607 | - return new ClusterMessage( | ||
608 | - clusterService.getLocalNode().id(), UPDATE_MESSAGE_SUBJECT, | ||
609 | - SERIALIZER.encode(Lists.newArrayList(event))); | ||
610 | } | 605 | } |
611 | 606 | ||
612 | - private List<PutEntry<String, String>> generatePutMessage( | 607 | + private List<UpdateEntry<String, String>> generatePutMessage( |
613 | String key1, String value1, String key2, String value2) { | 608 | String key1, String value1, String key2, String value2) { |
614 | - ArrayList<PutEntry<String, String>> list = new ArrayList<>(); | 609 | + List<UpdateEntry<String, String>> list = new ArrayList<>(); |
615 | 610 | ||
616 | Timestamp timestamp1 = clockService.peek(1); | 611 | Timestamp timestamp1 = clockService.peek(1); |
617 | Timestamp timestamp2 = clockService.peek(2); | 612 | Timestamp timestamp2 = clockService.peek(2); |
618 | 613 | ||
619 | - PutEntry<String, String> pe1 = new PutEntry<>(key1, value1, timestamp1); | 614 | + list.add(generatePutMessage(key1, value1, timestamp1)); |
620 | - PutEntry<String, String> pe2 = new PutEntry<>(key2, value2, timestamp2); | 615 | + list.add(generatePutMessage(key2, value2, timestamp2)); |
621 | - | ||
622 | - list.add(pe1); | ||
623 | - list.add(pe2); | ||
624 | 616 | ||
625 | return list; | 617 | return list; |
626 | } | 618 | } |
627 | 619 | ||
628 | - private ClusterMessage generateRemoveMessage(String key, Timestamp timestamp) { | 620 | + private UpdateEntry<String, String> generateRemoveMessage(String key, Timestamp timestamp) { |
629 | - RemoveEntry<String, String> event = new RemoveEntry<>(key, timestamp); | 621 | + return new UpdateEntry<>(key, new MapValue<>(null, timestamp)); |
630 | - | ||
631 | - return new ClusterMessage( | ||
632 | - clusterService.getLocalNode().id(), UPDATE_MESSAGE_SUBJECT, | ||
633 | - SERIALIZER.encode(Lists.newArrayList(event))); | ||
634 | } | 622 | } |
635 | 623 | ||
636 | - private List<RemoveEntry<String, String>> generateRemoveMessage(String key1, String key2) { | 624 | + private List<UpdateEntry<String, String>> generateRemoveMessage(String key1, String key2) { |
637 | - ArrayList<RemoveEntry<String, String>> list = new ArrayList<>(); | 625 | + List<UpdateEntry<String, String>> list = new ArrayList<>(); |
638 | 626 | ||
639 | Timestamp timestamp1 = clockService.peek(1); | 627 | Timestamp timestamp1 = clockService.peek(1); |
640 | Timestamp timestamp2 = clockService.peek(2); | 628 | Timestamp timestamp2 = clockService.peek(2); |
641 | 629 | ||
642 | - RemoveEntry<String, String> re1 = new RemoveEntry<>(key1, timestamp1); | 630 | + list.add(generateRemoveMessage(key1, timestamp1)); |
643 | - RemoveEntry<String, String> re2 = new RemoveEntry<>(key2, timestamp2); | 631 | + list.add(generateRemoveMessage(key2, timestamp2)); |
644 | - | ||
645 | - list.add(re1); | ||
646 | - list.add(re2); | ||
647 | 632 | ||
648 | return list; | 633 | return list; |
649 | } | 634 | } |
... | @@ -737,13 +722,6 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -737,13 +722,6 @@ public class EventuallyConsistentMapImplTest { |
737 | public void addSubscriber(MessageSubject subject, | 722 | public void addSubscriber(MessageSubject subject, |
738 | ClusterMessageHandler subscriber, | 723 | ClusterMessageHandler subscriber, |
739 | ExecutorService executor) { | 724 | ExecutorService executor) { |
740 | - if (subject.equals(UPDATE_MESSAGE_SUBJECT)) { | ||
741 | - updateHandler = subscriber; | ||
742 | - } else if (subject.equals(ANTI_ENTROPY_MESSAGE_SUBJECT)) { | ||
743 | - antiEntropyHandler = subscriber; | ||
744 | - } else { | ||
745 | - throw new RuntimeException("Unexpected message subject " + subject.toString()); | ||
746 | - } | ||
747 | } | 725 | } |
748 | 726 | ||
749 | @Override | 727 | @Override |
... | @@ -793,6 +771,13 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -793,6 +771,13 @@ public class EventuallyConsistentMapImplTest { |
793 | public <M> void addSubscriber(MessageSubject subject, | 771 | public <M> void addSubscriber(MessageSubject subject, |
794 | Function<byte[], M> decoder, Consumer<M> handler, | 772 | Function<byte[], M> decoder, Consumer<M> handler, |
795 | Executor executor) { | 773 | Executor executor) { |
774 | + if (subject.equals(UPDATE_MESSAGE_SUBJECT)) { | ||
775 | + updateHandler = (Consumer<Collection<UpdateEntry<String, String>>>) handler; | ||
776 | + } else if (subject.equals(ANTI_ENTROPY_MESSAGE_SUBJECT)) { | ||
777 | + antiEntropyHandler = (Consumer<AntiEntropyAdvertisement<String>>) handler; | ||
778 | + } else { | ||
779 | + throw new RuntimeException("Unexpected message subject " + subject.toString()); | ||
780 | + } | ||
796 | } | 781 | } |
797 | } | 782 | } |
798 | 783 | ... | ... |
-
Please register or login to post a comment