Committed by
Gerrit Code Review
Added a LogicalClockService for ordering arbitrary events in the cluster. Update…
…d couple of areas that are currently vulnerable to clock skew Change-Id: I14548ecb3c783104de8d72cbb5eb21de6ece08ed
Showing
9 changed files
with
161 additions
and
30 deletions
... | @@ -33,7 +33,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; | ... | @@ -33,7 +33,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; |
33 | description = "Lists information about atomic counters in the system") | 33 | description = "Lists information about atomic counters in the system") |
34 | public class CountersListCommand extends AbstractShellCommand { | 34 | public class CountersListCommand extends AbstractShellCommand { |
35 | 35 | ||
36 | - private static final String FMT = "name=%s next_value=%d"; | 36 | + private static final String FMT = "name=%s value=%d"; |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * Displays counters as text. | 39 | * Displays counters as text. |
... | @@ -41,7 +41,7 @@ public class CountersListCommand extends AbstractShellCommand { | ... | @@ -41,7 +41,7 @@ public class CountersListCommand extends AbstractShellCommand { |
41 | * @param mapInfo map descriptions | 41 | * @param mapInfo map descriptions |
42 | */ | 42 | */ |
43 | private void displayCounters(Map<String, Long> counters) { | 43 | private void displayCounters(Map<String, Long> counters) { |
44 | - counters.forEach((name, nextValue) -> print(FMT, name, nextValue)); | 44 | + counters.forEach((name, value) -> print(FMT, name, value)); |
45 | } | 45 | } |
46 | 46 | ||
47 | /** | 47 | /** | ... | ... |
... | @@ -37,7 +37,7 @@ public class MapsListCommand extends AbstractShellCommand { | ... | @@ -37,7 +37,7 @@ public class MapsListCommand extends AbstractShellCommand { |
37 | // TODO: Add support to display different eventually | 37 | // TODO: Add support to display different eventually |
38 | // consistent maps as well. | 38 | // consistent maps as well. |
39 | 39 | ||
40 | - private static final String FMT = "%-20s %8s"; | 40 | + private static final String FMT = "name=%s size=%d"; |
41 | 41 | ||
42 | /** | 42 | /** |
43 | * Displays map info as text. | 43 | * Displays map info as text. |
... | @@ -45,17 +45,9 @@ public class MapsListCommand extends AbstractShellCommand { | ... | @@ -45,17 +45,9 @@ public class MapsListCommand extends AbstractShellCommand { |
45 | * @param mapInfo map descriptions | 45 | * @param mapInfo map descriptions |
46 | */ | 46 | */ |
47 | private void displayMaps(List<MapInfo> mapInfo) { | 47 | private void displayMaps(List<MapInfo> mapInfo) { |
48 | - print("------------------------------"); | ||
49 | - print(FMT, "Name", "Size"); | ||
50 | - print("------------------------------"); | ||
51 | - | ||
52 | - | ||
53 | for (MapInfo info : mapInfo) { | 48 | for (MapInfo info : mapInfo) { |
54 | print(FMT, info.name(), info.size()); | 49 | print(FMT, info.name(), info.size()); |
55 | } | 50 | } |
56 | - if (mapInfo.size() > 0) { | ||
57 | - print("------------------------------"); | ||
58 | - } | ||
59 | } | 51 | } |
60 | 52 | ||
61 | /** | 53 | /** | ... | ... |
1 | +package org.onosproject.store.service; | ||
2 | + | ||
3 | +import org.onosproject.store.Timestamp; | ||
4 | + | ||
5 | +/** | ||
6 | + * Service that issues logical timestamps. | ||
7 | + * <p> | ||
8 | + * The logical timestamps are useful for establishing a total ordering of | ||
9 | + * arbitrary cluster wide events without relying on a fully synchronized | ||
10 | + * system clock (wall clock) | ||
11 | + */ | ||
12 | +public interface LogicalClockService { | ||
13 | + | ||
14 | + /** | ||
15 | + * Generates a new logical timestamp. | ||
16 | + * | ||
17 | + * @return timestamp | ||
18 | + */ | ||
19 | + Timestamp getTimestamp(); | ||
20 | +} |
... | @@ -18,6 +18,7 @@ package org.onosproject.store.app; | ... | @@ -18,6 +18,7 @@ package org.onosproject.store.app; |
18 | import com.google.common.base.Charsets; | 18 | import com.google.common.base.Charsets; |
19 | import com.google.common.collect.ImmutableSet; | 19 | import com.google.common.collect.ImmutableSet; |
20 | import com.google.common.util.concurrent.ListenableFuture; | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | + | ||
21 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
22 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
23 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -44,12 +45,11 @@ import org.onosproject.store.cluster.messaging.ClusterMessage; | ... | @@ -44,12 +45,11 @@ import org.onosproject.store.cluster.messaging.ClusterMessage; |
44 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | 45 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; |
45 | import org.onosproject.store.cluster.messaging.MessageSubject; | 46 | import org.onosproject.store.cluster.messaging.MessageSubject; |
46 | import org.onosproject.store.impl.MultiValuedTimestamp; | 47 | import org.onosproject.store.impl.MultiValuedTimestamp; |
47 | -import org.onosproject.store.impl.WallclockClockManager; | ||
48 | import org.onosproject.store.serializers.KryoNamespaces; | 48 | import org.onosproject.store.serializers.KryoNamespaces; |
49 | -import org.onosproject.store.service.ClockService; | ||
50 | import org.onosproject.store.service.EventuallyConsistentMap; | 49 | import org.onosproject.store.service.EventuallyConsistentMap; |
51 | import org.onosproject.store.service.EventuallyConsistentMapEvent; | 50 | import org.onosproject.store.service.EventuallyConsistentMapEvent; |
52 | import org.onosproject.store.service.EventuallyConsistentMapListener; | 51 | import org.onosproject.store.service.EventuallyConsistentMapListener; |
52 | +import org.onosproject.store.service.LogicalClockService; | ||
53 | import org.onosproject.store.service.StorageService; | 53 | import org.onosproject.store.service.StorageService; |
54 | import org.slf4j.Logger; | 54 | import org.slf4j.Logger; |
55 | 55 | ||
... | @@ -61,8 +61,6 @@ import java.util.concurrent.CountDownLatch; | ... | @@ -61,8 +61,6 @@ import java.util.concurrent.CountDownLatch; |
61 | import java.util.concurrent.ExecutorService; | 61 | import java.util.concurrent.ExecutorService; |
62 | import java.util.concurrent.Executors; | 62 | import java.util.concurrent.Executors; |
63 | import java.util.concurrent.ScheduledExecutorService; | 63 | import java.util.concurrent.ScheduledExecutorService; |
64 | -import java.util.concurrent.atomic.AtomicLong; | ||
65 | - | ||
66 | import static com.google.common.io.ByteStreams.toByteArray; | 64 | import static com.google.common.io.ByteStreams.toByteArray; |
67 | import static java.util.concurrent.TimeUnit.MILLISECONDS; | 65 | import static java.util.concurrent.TimeUnit.MILLISECONDS; |
68 | import static org.onlab.util.Tools.groupedThreads; | 66 | import static org.onlab.util.Tools.groupedThreads; |
... | @@ -115,9 +113,10 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -115,9 +113,10 @@ public class GossipApplicationStore extends ApplicationArchive |
115 | protected StorageService storageService; | 113 | protected StorageService storageService; |
116 | 114 | ||
117 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 115 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
118 | - protected ApplicationIdStore idStore; | 116 | + protected LogicalClockService clockService; |
119 | 117 | ||
120 | - private final AtomicLong sequence = new AtomicLong(); | 118 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
119 | + protected ApplicationIdStore idStore; | ||
121 | 120 | ||
122 | @Activate | 121 | @Activate |
123 | public void activate() { | 122 | public void activate() { |
... | @@ -135,24 +134,16 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -135,24 +134,16 @@ public class GossipApplicationStore extends ApplicationArchive |
135 | 134 | ||
136 | // FIXME: Consider consolidating into a single map. | 135 | // FIXME: Consider consolidating into a single map. |
137 | 136 | ||
138 | - ClockService<ApplicationId, Application> appsClockService = (appId, app) -> | ||
139 | - new MultiValuedTimestamp<>(getUpdateTime(appId.name()), | ||
140 | - sequence.incrementAndGet()); | ||
141 | - | ||
142 | apps = storageService.<ApplicationId, Application>eventuallyConsistentMapBuilder() | 137 | apps = storageService.<ApplicationId, Application>eventuallyConsistentMapBuilder() |
143 | .withName("apps") | 138 | .withName("apps") |
144 | .withSerializer(serializer) | 139 | .withSerializer(serializer) |
145 | - .withClockService(appsClockService) | 140 | + .withClockService((k, v) -> clockService.getTimestamp()) |
146 | .build(); | 141 | .build(); |
147 | 142 | ||
148 | - ClockService<Application, InternalState> statesClockService = (app, state) -> | ||
149 | - new MultiValuedTimestamp<>(getUpdateTime(app.id().name()), | ||
150 | - sequence.incrementAndGet()); | ||
151 | - | ||
152 | states = storageService.<Application, InternalState>eventuallyConsistentMapBuilder() | 143 | states = storageService.<Application, InternalState>eventuallyConsistentMapBuilder() |
153 | .withName("app-states") | 144 | .withName("app-states") |
154 | .withSerializer(serializer) | 145 | .withSerializer(serializer) |
155 | - .withClockService(statesClockService) | 146 | + .withClockService((k, v) -> clockService.getTimestamp()) |
156 | .build(); | 147 | .build(); |
157 | 148 | ||
158 | states.addListener(new InternalAppStatesListener()); | 149 | states.addListener(new InternalAppStatesListener()); |
... | @@ -160,7 +151,7 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -160,7 +151,7 @@ public class GossipApplicationStore extends ApplicationArchive |
160 | permissions = storageService.<Application, Set<Permission>>eventuallyConsistentMapBuilder() | 151 | permissions = storageService.<Application, Set<Permission>>eventuallyConsistentMapBuilder() |
161 | .withName("app-permissions") | 152 | .withName("app-permissions") |
162 | .withSerializer(serializer) | 153 | .withSerializer(serializer) |
163 | - .withClockService(new WallclockClockManager<>()) | 154 | + .withClockService((k, v) -> clockService.getTimestamp()) |
164 | .build(); | 155 | .build(); |
165 | 156 | ||
166 | log.info("Started"); | 157 | log.info("Started"); | ... | ... |
... | @@ -26,11 +26,11 @@ import org.onosproject.cfg.ComponentConfigEvent; | ... | @@ -26,11 +26,11 @@ import org.onosproject.cfg.ComponentConfigEvent; |
26 | import org.onosproject.cfg.ComponentConfigStore; | 26 | import org.onosproject.cfg.ComponentConfigStore; |
27 | import org.onosproject.cfg.ComponentConfigStoreDelegate; | 27 | import org.onosproject.cfg.ComponentConfigStoreDelegate; |
28 | import org.onosproject.store.AbstractStore; | 28 | import org.onosproject.store.AbstractStore; |
29 | -import org.onosproject.store.impl.WallclockClockManager; | ||
30 | import org.onosproject.store.serializers.KryoNamespaces; | 29 | import org.onosproject.store.serializers.KryoNamespaces; |
31 | import org.onosproject.store.service.EventuallyConsistentMap; | 30 | import org.onosproject.store.service.EventuallyConsistentMap; |
32 | import org.onosproject.store.service.EventuallyConsistentMapEvent; | 31 | import org.onosproject.store.service.EventuallyConsistentMapEvent; |
33 | import org.onosproject.store.service.EventuallyConsistentMapListener; | 32 | import org.onosproject.store.service.EventuallyConsistentMapListener; |
33 | +import org.onosproject.store.service.LogicalClockService; | ||
34 | import org.onosproject.store.service.StorageService; | 34 | import org.onosproject.store.service.StorageService; |
35 | import org.slf4j.Logger; | 35 | import org.slf4j.Logger; |
36 | 36 | ||
... | @@ -59,6 +59,9 @@ public class GossipComponentConfigStore | ... | @@ -59,6 +59,9 @@ public class GossipComponentConfigStore |
59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
60 | protected StorageService storageService; | 60 | protected StorageService storageService; |
61 | 61 | ||
62 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
63 | + protected LogicalClockService clockService; | ||
64 | + | ||
62 | @Activate | 65 | @Activate |
63 | public void activate() { | 66 | public void activate() { |
64 | KryoNamespace.Builder serializer = KryoNamespace.newBuilder() | 67 | KryoNamespace.Builder serializer = KryoNamespace.newBuilder() |
... | @@ -67,7 +70,7 @@ public class GossipComponentConfigStore | ... | @@ -67,7 +70,7 @@ public class GossipComponentConfigStore |
67 | properties = storageService.<String, String>eventuallyConsistentMapBuilder() | 70 | properties = storageService.<String, String>eventuallyConsistentMapBuilder() |
68 | .withName("cfg") | 71 | .withName("cfg") |
69 | .withSerializer(serializer) | 72 | .withSerializer(serializer) |
70 | - .withClockService(new WallclockClockManager<>()) | 73 | + .withClockService((k, v) -> clockService.getTimestamp()) |
71 | .build(); | 74 | .build(); |
72 | 75 | ||
73 | properties.addListener(new InternalPropertiesListener()); | 76 | properties.addListener(new InternalPropertiesListener()); | ... | ... |
1 | +package org.onosproject.store.core.impl; | ||
2 | + | ||
3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
4 | + | ||
5 | +import org.apache.felix.scr.annotations.Activate; | ||
6 | +import org.apache.felix.scr.annotations.Component; | ||
7 | +import org.apache.felix.scr.annotations.Deactivate; | ||
8 | +import org.apache.felix.scr.annotations.Reference; | ||
9 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
10 | +import org.apache.felix.scr.annotations.Service; | ||
11 | +import org.onosproject.store.Timestamp; | ||
12 | +import org.onosproject.store.impl.LogicalTimestamp; | ||
13 | +import org.onosproject.store.service.AtomicCounter; | ||
14 | +import org.onosproject.store.service.LogicalClockService; | ||
15 | +import org.onosproject.store.service.StorageService; | ||
16 | +import org.slf4j.Logger; | ||
17 | + | ||
18 | +/** | ||
19 | + * LogicalClockService implementation based on a AtomicCounter. | ||
20 | + */ | ||
21 | +@Component(immediate = true, enabled = true) | ||
22 | +@Service | ||
23 | +public class LogicalClockManager implements LogicalClockService { | ||
24 | + | ||
25 | + private final Logger log = getLogger(getClass()); | ||
26 | + | ||
27 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
28 | + protected StorageService storageService; | ||
29 | + | ||
30 | + private static final String SYSTEM_LOGICAL_CLOCK_COUNTER_NAME = "sys-clock-counter"; | ||
31 | + private AtomicCounter atomicCounter; | ||
32 | + | ||
33 | + @Activate | ||
34 | + public void activate() { | ||
35 | + atomicCounter = storageService.atomicCounterBuilder() | ||
36 | + .withName(SYSTEM_LOGICAL_CLOCK_COUNTER_NAME) | ||
37 | + .withPartitionsDisabled() | ||
38 | + .build(); | ||
39 | + log.info("Started."); | ||
40 | + } | ||
41 | + | ||
42 | + @Deactivate | ||
43 | + public void deactivate() { | ||
44 | + log.info("Stopped."); | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public Timestamp getTimestamp() { | ||
49 | + return new LogicalTimestamp(atomicCounter.incrementAndGet()); | ||
50 | + } | ||
51 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -18,6 +18,7 @@ package org.onosproject.store.ecmap; | ... | @@ -18,6 +18,7 @@ package org.onosproject.store.ecmap; |
18 | import com.google.common.collect.ImmutableList; | 18 | import com.google.common.collect.ImmutableList; |
19 | import com.google.common.collect.Lists; | 19 | import com.google.common.collect.Lists; |
20 | import com.google.common.collect.Maps; | 20 | import com.google.common.collect.Maps; |
21 | + | ||
21 | import org.apache.commons.lang3.RandomUtils; | 22 | import org.apache.commons.lang3.RandomUtils; |
22 | import org.apache.commons.lang3.mutable.MutableBoolean; | 23 | import org.apache.commons.lang3.mutable.MutableBoolean; |
23 | import org.apache.commons.lang3.tuple.Pair; | 24 | import org.apache.commons.lang3.tuple.Pair; |
... | @@ -32,6 +33,7 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | ... | @@ -32,6 +33,7 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
32 | import org.onosproject.store.cluster.messaging.ClusterMessage; | 33 | import org.onosproject.store.cluster.messaging.ClusterMessage; |
33 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | 34 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; |
34 | import org.onosproject.store.cluster.messaging.MessageSubject; | 35 | import org.onosproject.store.cluster.messaging.MessageSubject; |
36 | +import org.onosproject.store.impl.LogicalTimestamp; | ||
35 | import org.onosproject.store.impl.Timestamped; | 37 | import org.onosproject.store.impl.Timestamped; |
36 | import org.onosproject.store.impl.WallClockTimestamp; | 38 | import org.onosproject.store.impl.WallClockTimestamp; |
37 | import org.onosproject.store.serializers.KryoSerializer; | 39 | import org.onosproject.store.serializers.KryoSerializer; |
... | @@ -223,6 +225,7 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -223,6 +225,7 @@ public class EventuallyConsistentMapImpl<K, V> |
223 | protected void setupKryoPool() { | 225 | protected void setupKryoPool() { |
224 | // Add the map's internal helper classes to the user-supplied serializer | 226 | // Add the map's internal helper classes to the user-supplied serializer |
225 | serializerPool = builder | 227 | serializerPool = builder |
228 | + .register(LogicalTimestamp.class) | ||
226 | .register(WallClockTimestamp.class) | 229 | .register(WallClockTimestamp.class) |
227 | .register(PutEntry.class) | 230 | .register(PutEntry.class) |
228 | .register(RemoveEntry.class) | 231 | .register(RemoveEntry.class) | ... | ... |
1 | +package org.onosproject.store.impl; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkArgument; | ||
4 | + | ||
5 | +import java.util.Objects; | ||
6 | + | ||
7 | +import org.onosproject.store.Timestamp; | ||
8 | + | ||
9 | +import com.google.common.base.MoreObjects; | ||
10 | +import com.google.common.collect.ComparisonChain; | ||
11 | + | ||
12 | +/** | ||
13 | + * Timestamp based on logical sequence value. | ||
14 | + * <p> | ||
15 | + * LogicalTimestamps are ordered by their sequence values. | ||
16 | + */ | ||
17 | +public class LogicalTimestamp implements Timestamp { | ||
18 | + | ||
19 | + private final long value; | ||
20 | + | ||
21 | + public LogicalTimestamp(long value) { | ||
22 | + this.value = value; | ||
23 | + } | ||
24 | + | ||
25 | + @Override | ||
26 | + public int compareTo(Timestamp o) { | ||
27 | + checkArgument(o instanceof LogicalTimestamp, | ||
28 | + "Must be LogicalTimestamp", o); | ||
29 | + LogicalTimestamp that = (LogicalTimestamp) o; | ||
30 | + | ||
31 | + return ComparisonChain.start() | ||
32 | + .compare(this.value, that.value) | ||
33 | + .result(); | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public int hashCode() { | ||
38 | + return Objects.hash(value); | ||
39 | + } | ||
40 | + | ||
41 | + @Override | ||
42 | + public boolean equals(Object obj) { | ||
43 | + if (this == obj) { | ||
44 | + return true; | ||
45 | + } | ||
46 | + if (!(obj instanceof LogicalTimestamp)) { | ||
47 | + return false; | ||
48 | + } | ||
49 | + LogicalTimestamp that = (LogicalTimestamp) obj; | ||
50 | + return Objects.equals(this.value, that.value); | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + public String toString() { | ||
55 | + return MoreObjects.toStringHelper(getClass()) | ||
56 | + .add("value", value) | ||
57 | + .toString(); | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * Returns the sequence value. | ||
62 | + * | ||
63 | + * @return sequence value | ||
64 | + */ | ||
65 | + public long value() { | ||
66 | + return this.value; | ||
67 | + } | ||
68 | +} |
... | @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet; | ... | @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet; |
20 | import com.google.common.collect.Lists; | 20 | import com.google.common.collect.Lists; |
21 | import com.google.common.util.concurrent.ListenableFuture; | 21 | import com.google.common.util.concurrent.ListenableFuture; |
22 | import com.google.common.util.concurrent.MoreExecutors; | 22 | import com.google.common.util.concurrent.MoreExecutors; |
23 | + | ||
23 | import org.junit.After; | 24 | import org.junit.After; |
24 | import org.junit.Before; | 25 | import org.junit.Before; |
25 | import org.junit.Test; | 26 | import org.junit.Test; |
... | @@ -35,6 +36,7 @@ import org.onosproject.store.cluster.messaging.ClusterMessage; | ... | @@ -35,6 +36,7 @@ import org.onosproject.store.cluster.messaging.ClusterMessage; |
35 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | 36 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; |
36 | import org.onosproject.store.cluster.messaging.MessageSubject; | 37 | import org.onosproject.store.cluster.messaging.MessageSubject; |
37 | import org.onosproject.store.service.ClockService; | 38 | import org.onosproject.store.service.ClockService; |
39 | +import org.onosproject.store.impl.LogicalTimestamp; | ||
38 | import org.onosproject.store.impl.WallClockTimestamp; | 40 | import org.onosproject.store.impl.WallClockTimestamp; |
39 | import org.onosproject.store.serializers.KryoNamespaces; | 41 | import org.onosproject.store.serializers.KryoNamespaces; |
40 | import org.onosproject.store.serializers.KryoSerializer; | 42 | import org.onosproject.store.serializers.KryoSerializer; |
... | @@ -102,6 +104,7 @@ public class EventuallyConsistentMapImplTest { | ... | @@ -102,6 +104,7 @@ public class EventuallyConsistentMapImplTest { |
102 | .register(KryoNamespaces.API) | 104 | .register(KryoNamespaces.API) |
103 | .register(TestTimestamp.class) | 105 | .register(TestTimestamp.class) |
104 | // Below is the classes that the map internally registers | 106 | // Below is the classes that the map internally registers |
107 | + .register(LogicalTimestamp.class) | ||
105 | .register(WallClockTimestamp.class) | 108 | .register(WallClockTimestamp.class) |
106 | .register(PutEntry.class) | 109 | .register(PutEntry.class) |
107 | .register(RemoveEntry.class) | 110 | .register(RemoveEntry.class) | ... | ... |
-
Please register or login to post a comment