Preliminary checkin for implementing version aware topology state.
Showing
7 changed files
with
469 additions
and
27 deletions
... | @@ -16,6 +16,7 @@ import org.onlab.onos.cluster.ClusterService; | ... | @@ -16,6 +16,7 @@ import org.onlab.onos.cluster.ClusterService; |
16 | import org.onlab.onos.cluster.MastershipEvent; | 16 | import org.onlab.onos.cluster.MastershipEvent; |
17 | import org.onlab.onos.cluster.MastershipListener; | 17 | import org.onlab.onos.cluster.MastershipListener; |
18 | import org.onlab.onos.cluster.MastershipService; | 18 | import org.onlab.onos.cluster.MastershipService; |
19 | +import org.onlab.onos.cluster.MastershipTerm; | ||
19 | import org.onlab.onos.event.AbstractListenerRegistry; | 20 | import org.onlab.onos.event.AbstractListenerRegistry; |
20 | import org.onlab.onos.event.EventDeliveryService; | 21 | import org.onlab.onos.event.EventDeliveryService; |
21 | import org.onlab.onos.net.Device; | 22 | import org.onlab.onos.net.Device; |
... | @@ -36,6 +37,7 @@ import org.onlab.onos.net.device.DeviceStoreDelegate; | ... | @@ -36,6 +37,7 @@ import org.onlab.onos.net.device.DeviceStoreDelegate; |
36 | import org.onlab.onos.net.device.PortDescription; | 37 | import org.onlab.onos.net.device.PortDescription; |
37 | import org.onlab.onos.net.provider.AbstractProviderRegistry; | 38 | import org.onlab.onos.net.provider.AbstractProviderRegistry; |
38 | import org.onlab.onos.net.provider.AbstractProviderService; | 39 | import org.onlab.onos.net.provider.AbstractProviderService; |
40 | +import org.onlab.onos.store.common.ClockService; | ||
39 | import org.slf4j.Logger; | 41 | import org.slf4j.Logger; |
40 | 42 | ||
41 | /** | 43 | /** |
... | @@ -74,6 +76,9 @@ implements DeviceService, DeviceAdminService, DeviceProviderRegistry { | ... | @@ -74,6 +76,9 @@ implements DeviceService, DeviceAdminService, DeviceProviderRegistry { |
74 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 76 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
75 | protected MastershipService mastershipService; | 77 | protected MastershipService mastershipService; |
76 | 78 | ||
79 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
80 | + protected ClockService clockService; | ||
81 | + | ||
77 | @Activate | 82 | @Activate |
78 | public void activate() { | 83 | public void activate() { |
79 | store.setDelegate(delegate); | 84 | store.setDelegate(delegate); |
... | @@ -250,6 +255,8 @@ implements DeviceService, DeviceAdminService, DeviceProviderRegistry { | ... | @@ -250,6 +255,8 @@ implements DeviceService, DeviceAdminService, DeviceProviderRegistry { |
250 | @Override | 255 | @Override |
251 | public void event(MastershipEvent event) { | 256 | public void event(MastershipEvent event) { |
252 | if (event.master().equals(clusterService.getLocalNode().id())) { | 257 | if (event.master().equals(clusterService.getLocalNode().id())) { |
258 | + MastershipTerm term = mastershipService.requestTermService().getMastershipTerm(event.subject()); | ||
259 | + clockService.setMastershipTerm(event.subject(), term); | ||
253 | applyRole(event.subject(), MastershipRole.MASTER); | 260 | applyRole(event.subject(), MastershipRole.MASTER); |
254 | } else { | 261 | } else { |
255 | applyRole(event.subject(), MastershipRole.STANDBY); | 262 | applyRole(event.subject(), MastershipRole.STANDBY); | ... | ... |
1 | +package org.onlab.onos.store.common; | ||
2 | + | ||
3 | +import org.onlab.onos.cluster.MastershipTerm; | ||
4 | +import org.onlab.onos.net.DeviceId; | ||
5 | +import org.onlab.onos.store.Timestamp; | ||
6 | + | ||
7 | +/** | ||
8 | + * Interface for a logical clock service that vends per device timestamps. | ||
9 | + */ | ||
10 | +public interface ClockService { | ||
11 | + | ||
12 | + /** | ||
13 | + * Returns a new timestamp for the specified deviceId. | ||
14 | + * @param deviceId device identifier. | ||
15 | + * @return timestamp. | ||
16 | + */ | ||
17 | + public Timestamp getTimestamp(DeviceId deviceId); | ||
18 | + | ||
19 | + /** | ||
20 | + * Updates the mastership term for the specified deviceId. | ||
21 | + * @param deviceId device identifier. | ||
22 | + * @param term mastership term. | ||
23 | + */ | ||
24 | + public void setMastershipTerm(DeviceId deviceId, MastershipTerm term); | ||
25 | +} |
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
4 | + | ||
5 | +import java.util.concurrent.ConcurrentHashMap; | ||
6 | +import java.util.concurrent.ConcurrentMap; | ||
7 | +import java.util.concurrent.atomic.AtomicInteger; | ||
8 | + | ||
9 | +import org.apache.felix.scr.annotations.Activate; | ||
10 | +import org.apache.felix.scr.annotations.Component; | ||
11 | +import org.apache.felix.scr.annotations.Deactivate; | ||
12 | +import org.apache.felix.scr.annotations.Service; | ||
13 | +import org.onlab.onos.cluster.MastershipTerm; | ||
14 | +import org.onlab.onos.net.DeviceId; | ||
15 | +import org.onlab.onos.store.Timestamp; | ||
16 | +import org.onlab.onos.store.common.ClockService; | ||
17 | +import org.onlab.onos.store.impl.OnosTimestamp; | ||
18 | +import org.slf4j.Logger; | ||
19 | + | ||
20 | +@Component(immediate = true) | ||
21 | +@Service | ||
22 | +public class OnosClockService implements ClockService { | ||
23 | + | ||
24 | + private final Logger log = getLogger(getClass()); | ||
25 | + | ||
26 | + // TODO: Implement per device ticker that is reset to 0 at the beginning of a new term. | ||
27 | + private final AtomicInteger ticker = new AtomicInteger(0); | ||
28 | + private ConcurrentMap<DeviceId, MastershipTerm> deviceMastershipTerms = new ConcurrentHashMap<>(); | ||
29 | + | ||
30 | + @Activate | ||
31 | + public void activate() { | ||
32 | + log.info("Started"); | ||
33 | + } | ||
34 | + | ||
35 | + @Deactivate | ||
36 | + public void deactivate() { | ||
37 | + log.info("Stopped"); | ||
38 | + } | ||
39 | + | ||
40 | + @Override | ||
41 | + public Timestamp getTimestamp(DeviceId deviceId) { | ||
42 | + MastershipTerm term = deviceMastershipTerms.get(deviceId); | ||
43 | + if (term == null) { | ||
44 | + throw new IllegalStateException("Requesting timestamp for a deviceId without mastership"); | ||
45 | + } | ||
46 | + return new OnosTimestamp(term.termNumber(), ticker.incrementAndGet()); | ||
47 | + } | ||
48 | + | ||
49 | + @Override | ||
50 | + public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) { | ||
51 | + deviceMastershipTerms.put(deviceId, term); | ||
52 | + } | ||
53 | +} |
core/store/src/main/java/org/onlab/onos/store/device/impl/OnosDistributedDeviceStore.java
0 → 100644
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import static com.google.common.base.Predicates.notNull; | ||
4 | + | ||
5 | +import com.google.common.base.Preconditions; | ||
6 | +import com.google.common.collect.FluentIterable; | ||
7 | +import com.google.common.collect.ImmutableSet; | ||
8 | +import com.google.common.collect.ImmutableSet.Builder; | ||
9 | + | ||
10 | +import org.apache.felix.scr.annotations.Activate; | ||
11 | +import org.apache.felix.scr.annotations.Component; | ||
12 | +import org.apache.felix.scr.annotations.Deactivate; | ||
13 | +import org.apache.felix.scr.annotations.Reference; | ||
14 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
15 | +import org.apache.felix.scr.annotations.Service; | ||
16 | +import org.onlab.onos.net.DefaultDevice; | ||
17 | +import org.onlab.onos.net.DefaultPort; | ||
18 | +import org.onlab.onos.net.Device; | ||
19 | +import org.onlab.onos.net.DeviceId; | ||
20 | +import org.onlab.onos.net.Port; | ||
21 | +import org.onlab.onos.net.PortNumber; | ||
22 | +import org.onlab.onos.net.device.DeviceDescription; | ||
23 | +import org.onlab.onos.net.device.DeviceEvent; | ||
24 | +import org.onlab.onos.net.device.DeviceStore; | ||
25 | +import org.onlab.onos.net.device.DeviceStoreDelegate; | ||
26 | +import org.onlab.onos.net.device.PortDescription; | ||
27 | +import org.onlab.onos.net.provider.ProviderId; | ||
28 | +import org.onlab.onos.store.Timestamp; | ||
29 | +import org.onlab.onos.store.common.ClockService; | ||
30 | +import org.onlab.onos.store.impl.AbstractDistributedStore; | ||
31 | +import org.slf4j.Logger; | ||
32 | + | ||
33 | +import java.util.ArrayList; | ||
34 | +import java.util.Collections; | ||
35 | +import java.util.HashMap; | ||
36 | +import java.util.HashSet; | ||
37 | +import java.util.Iterator; | ||
38 | +import java.util.List; | ||
39 | +import java.util.Map; | ||
40 | +import java.util.Objects; | ||
41 | +import java.util.Set; | ||
42 | +import java.util.concurrent.ConcurrentHashMap; | ||
43 | + | ||
44 | +import static com.google.common.base.Preconditions.checkArgument; | ||
45 | +import static org.onlab.onos.net.device.DeviceEvent.Type.*; | ||
46 | +import static org.slf4j.LoggerFactory.getLogger; | ||
47 | + | ||
48 | +/** | ||
49 | + * Manages inventory of infrastructure devices using a protocol that takes into consideration | ||
50 | + * the order in which device events occur. | ||
51 | + */ | ||
52 | +@Component(immediate = true) | ||
53 | +@Service | ||
54 | +public class OnosDistributedDeviceStore | ||
55 | + extends AbstractDistributedStore<DeviceEvent, DeviceStoreDelegate> | ||
56 | + implements DeviceStore { | ||
57 | + | ||
58 | + private final Logger log = getLogger(getClass()); | ||
59 | + | ||
60 | + public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | ||
61 | + | ||
62 | + private ConcurrentHashMap<DeviceId, VersionedValue<Device>> devices; | ||
63 | + private ConcurrentHashMap<DeviceId, Map<PortNumber, VersionedValue<Port>>> devicePorts; | ||
64 | + | ||
65 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
66 | + protected ClockService clockService; | ||
67 | + | ||
68 | + @Override | ||
69 | + @Activate | ||
70 | + public void activate() { | ||
71 | + super.activate(); | ||
72 | + | ||
73 | + devices = new ConcurrentHashMap<>(); | ||
74 | + devicePorts = new ConcurrentHashMap<>(); | ||
75 | + | ||
76 | + log.info("Started"); | ||
77 | + } | ||
78 | + | ||
79 | + @Deactivate | ||
80 | + public void deactivate() { | ||
81 | + log.info("Stopped"); | ||
82 | + } | ||
83 | + | ||
84 | + @Override | ||
85 | + public int getDeviceCount() { | ||
86 | + return devices.size(); | ||
87 | + } | ||
88 | + | ||
89 | + @Override | ||
90 | + public Iterable<Device> getDevices() { | ||
91 | + // TODO builder v.s. copyOf. Guava semms to be using copyOf? | ||
92 | + // FIXME: synchronize. | ||
93 | + Builder<Device> builder = ImmutableSet.builder(); | ||
94 | + for (VersionedValue<? extends Device> device : devices.values()) { | ||
95 | + builder.add(device.entity()); | ||
96 | + } | ||
97 | + return builder.build(); | ||
98 | + } | ||
99 | + | ||
100 | + @Override | ||
101 | + public Device getDevice(DeviceId deviceId) { | ||
102 | + return devices.get(deviceId).entity(); | ||
103 | + } | ||
104 | + | ||
105 | + @Override | ||
106 | + public DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | ||
107 | + DeviceDescription deviceDescription) { | ||
108 | + Timestamp now = clockService.getTimestamp(deviceId); | ||
109 | + VersionedValue<Device> device = devices.get(deviceId); | ||
110 | + | ||
111 | + if (device == null) { | ||
112 | + return createDevice(providerId, deviceId, deviceDescription, now); | ||
113 | + } | ||
114 | + | ||
115 | + Preconditions.checkState(now.compareTo(device.timestamp()) > 0, "Existing device has a timestamp in the future!"); | ||
116 | + | ||
117 | + return updateDevice(providerId, device.entity(), deviceDescription, now); | ||
118 | + } | ||
119 | + | ||
120 | + // Creates the device and returns the appropriate event if necessary. | ||
121 | + private DeviceEvent createDevice(ProviderId providerId, DeviceId deviceId, | ||
122 | + DeviceDescription desc, Timestamp timestamp) { | ||
123 | + DefaultDevice device = new DefaultDevice(providerId, deviceId, desc.type(), | ||
124 | + desc.manufacturer(), | ||
125 | + desc.hwVersion(), desc.swVersion(), | ||
126 | + desc.serialNumber()); | ||
127 | + | ||
128 | + devices.put(deviceId, new VersionedValue<Device>(device, true, timestamp)); | ||
129 | + // FIXME: broadcast a message telling peers of a device event. | ||
130 | + return new DeviceEvent(DEVICE_ADDED, device, null); | ||
131 | + } | ||
132 | + | ||
133 | + // Updates the device and returns the appropriate event if necessary. | ||
134 | + private DeviceEvent updateDevice(ProviderId providerId, Device device, | ||
135 | + DeviceDescription desc, Timestamp timestamp) { | ||
136 | + // We allow only certain attributes to trigger update | ||
137 | + if (!Objects.equals(device.hwVersion(), desc.hwVersion()) || | ||
138 | + !Objects.equals(device.swVersion(), desc.swVersion())) { | ||
139 | + | ||
140 | + Device updated = new DefaultDevice(providerId, device.id(), | ||
141 | + desc.type(), | ||
142 | + desc.manufacturer(), | ||
143 | + desc.hwVersion(), | ||
144 | + desc.swVersion(), | ||
145 | + desc.serialNumber()); | ||
146 | + devices.put(device.id(), new VersionedValue<Device>(updated, true, timestamp)); | ||
147 | + // FIXME: broadcast a message telling peers of a device event. | ||
148 | + return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, updated, null); | ||
149 | + } | ||
150 | + | ||
151 | + // Otherwise merely attempt to change availability | ||
152 | + DefaultDevice updated = new DefaultDevice(providerId, device.id(), | ||
153 | + desc.type(), | ||
154 | + desc.manufacturer(), | ||
155 | + desc.hwVersion(), | ||
156 | + desc.swVersion(), | ||
157 | + desc.serialNumber()); | ||
158 | + | ||
159 | + VersionedValue<Device> oldDevice = devices.put(device.id(), new VersionedValue<Device>(updated, true, timestamp)); | ||
160 | + if (!oldDevice.isUp()) { | ||
161 | + return new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null); | ||
162 | + } else { | ||
163 | + return null; | ||
164 | + } | ||
165 | + } | ||
166 | + | ||
167 | + @Override | ||
168 | + public DeviceEvent markOffline(DeviceId deviceId) { | ||
169 | + VersionedValue<Device> device = devices.get(deviceId); | ||
170 | + boolean willRemove = device != null && device.isUp(); | ||
171 | + if (!willRemove) return null; | ||
172 | + Timestamp timestamp = clockService.getTimestamp(deviceId); | ||
173 | + if (replaceIfLatest(device.entity(), false, timestamp)) | ||
174 | + { | ||
175 | + return new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device.entity(), null); | ||
176 | + } | ||
177 | + return null; | ||
178 | + } | ||
179 | + | ||
180 | + // Replace existing value if its timestamp is older. | ||
181 | + private synchronized boolean replaceIfLatest(Device device, boolean isUp, Timestamp timestamp) | ||
182 | + { | ||
183 | + VersionedValue<Device> existingValue = devices.get(device.id()); | ||
184 | + if (timestamp.compareTo(existingValue.timestamp()) > 0) | ||
185 | + { | ||
186 | + devices.put(device.id(), new VersionedValue<Device>(device, isUp, timestamp)); | ||
187 | + return true; | ||
188 | + } | ||
189 | + return false; | ||
190 | + } | ||
191 | + | ||
192 | + @Override | ||
193 | + public List<DeviceEvent> updatePorts(DeviceId deviceId, | ||
194 | + List<PortDescription> portDescriptions) { | ||
195 | + List<DeviceEvent> events = new ArrayList<>(); | ||
196 | + synchronized (this) { | ||
197 | + VersionedValue<Device> device = devices.get(deviceId); | ||
198 | + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
199 | + Map<PortNumber, VersionedValue<Port>> ports = getPortMap(deviceId); | ||
200 | + Timestamp timestamp = clockService.getTimestamp(deviceId); | ||
201 | + | ||
202 | + // Add new ports | ||
203 | + Set<PortNumber> processed = new HashSet<>(); | ||
204 | + for (PortDescription portDescription : portDescriptions) { | ||
205 | + VersionedValue<Port> port = ports.get(portDescription.portNumber()); | ||
206 | + if (port == null) events.add(createPort(device, portDescription, ports, timestamp)); | ||
207 | + Preconditions.checkState(timestamp.compareTo(port.timestamp()) > 0, "Existing port state has a timestamp in the future!"); | ||
208 | + events.add(updatePort(device, port, portDescription, ports, timestamp)); | ||
209 | + processed.add(portDescription.portNumber()); | ||
210 | + } | ||
211 | + | ||
212 | + updatePortMap(deviceId, ports); | ||
213 | + | ||
214 | + events.addAll(pruneOldPorts(device.entity(), ports, processed)); | ||
215 | + } | ||
216 | + return FluentIterable.from(events).filter(notNull()).toList(); | ||
217 | + } | ||
218 | + | ||
219 | + // Creates a new port based on the port description adds it to the map and | ||
220 | + // Returns corresponding event. | ||
221 | + //@GuardedBy("this") | ||
222 | + private DeviceEvent createPort(VersionedValue<Device> device, PortDescription portDescription, | ||
223 | + Map<PortNumber, VersionedValue<Port>> ports, Timestamp timestamp) { | ||
224 | + Port port = new DefaultPort(device.entity(), portDescription.portNumber(), | ||
225 | + portDescription.isEnabled()); | ||
226 | + ports.put(port.number(), new VersionedValue<Port>(port, true, timestamp)); | ||
227 | + updatePortMap(device.entity().id(), ports); | ||
228 | + return new DeviceEvent(PORT_ADDED, device.entity(), port); | ||
229 | + } | ||
230 | + | ||
231 | + // Checks if the specified port requires update and if so, it replaces the | ||
232 | + // existing entry in the map and returns corresponding event. | ||
233 | + //@GuardedBy("this") | ||
234 | + private DeviceEvent updatePort(VersionedValue<Device> device, VersionedValue<Port> port, | ||
235 | + PortDescription portDescription, | ||
236 | + Map<PortNumber, VersionedValue<Port>> ports, | ||
237 | + Timestamp timestamp) { | ||
238 | + if (port.entity().isEnabled() != portDescription.isEnabled()) { | ||
239 | + VersionedValue<Port> updatedPort = new VersionedValue<Port>( | ||
240 | + new DefaultPort(device.entity(), portDescription.portNumber(), | ||
241 | + portDescription.isEnabled()), | ||
242 | + portDescription.isEnabled(), | ||
243 | + timestamp); | ||
244 | + ports.put(port.entity().number(), updatedPort); | ||
245 | + updatePortMap(device.entity().id(), ports); | ||
246 | + return new DeviceEvent(PORT_UPDATED, device.entity(), updatedPort.entity()); | ||
247 | + } | ||
248 | + return null; | ||
249 | + } | ||
250 | + | ||
251 | + // Prunes the specified list of ports based on which ports are in the | ||
252 | + // processed list and returns list of corresponding events. | ||
253 | + //@GuardedBy("this") | ||
254 | + private List<DeviceEvent> pruneOldPorts(Device device, | ||
255 | + Map<PortNumber, VersionedValue<Port>> ports, | ||
256 | + Set<PortNumber> processed) { | ||
257 | + List<DeviceEvent> events = new ArrayList<>(); | ||
258 | + Iterator<PortNumber> iterator = ports.keySet().iterator(); | ||
259 | + while (iterator.hasNext()) { | ||
260 | + PortNumber portNumber = iterator.next(); | ||
261 | + if (!processed.contains(portNumber)) { | ||
262 | + events.add(new DeviceEvent(PORT_REMOVED, device, | ||
263 | + ports.get(portNumber).entity())); | ||
264 | + iterator.remove(); | ||
265 | + } | ||
266 | + } | ||
267 | + if (!events.isEmpty()) { | ||
268 | + updatePortMap(device.id(), ports); | ||
269 | + } | ||
270 | + return events; | ||
271 | + } | ||
272 | + | ||
273 | + // Gets the map of ports for the specified device; if one does not already | ||
274 | + // exist, it creates and registers a new one. | ||
275 | + // WARN: returned value is a copy, changes made to the Map | ||
276 | + // needs to be written back using updatePortMap | ||
277 | + //@GuardedBy("this") | ||
278 | + private Map<PortNumber, VersionedValue<Port>> getPortMap(DeviceId deviceId) { | ||
279 | + Map<PortNumber, VersionedValue<Port>> ports = devicePorts.get(deviceId); | ||
280 | + if (ports == null) { | ||
281 | + ports = new HashMap<>(); | ||
282 | + // this probably is waste of time in most cases. | ||
283 | + updatePortMap(deviceId, ports); | ||
284 | + } | ||
285 | + return ports; | ||
286 | + } | ||
287 | + | ||
288 | + //@GuardedBy("this") | ||
289 | + private void updatePortMap(DeviceId deviceId, Map<PortNumber, VersionedValue<Port>> ports) { | ||
290 | + devicePorts.put(deviceId, ports); | ||
291 | + } | ||
292 | + | ||
293 | + @Override | ||
294 | + public DeviceEvent updatePortStatus(DeviceId deviceId, | ||
295 | + PortDescription portDescription) { | ||
296 | + VersionedValue<Device> device = devices.get(deviceId); | ||
297 | + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
298 | + Map<PortNumber, VersionedValue<Port>> ports = getPortMap(deviceId); | ||
299 | + VersionedValue<Port> port = ports.get(portDescription.portNumber()); | ||
300 | + Timestamp timestamp = clockService.getTimestamp(deviceId); | ||
301 | + return updatePort(device, port, portDescription, ports, timestamp); | ||
302 | + } | ||
303 | + | ||
304 | + @Override | ||
305 | + public List<Port> getPorts(DeviceId deviceId) { | ||
306 | + Map<PortNumber, VersionedValue<Port>> versionedPorts = devicePorts.get(deviceId); | ||
307 | + if (versionedPorts == null) return Collections.emptyList(); | ||
308 | + List<Port> ports = new ArrayList<Port>(); | ||
309 | + for (VersionedValue<Port> port : versionedPorts.values()) { | ||
310 | + ports.add(port.entity()); | ||
311 | + } | ||
312 | + return ports; | ||
313 | + } | ||
314 | + | ||
315 | + @Override | ||
316 | + public Port getPort(DeviceId deviceId, PortNumber portNumber) { | ||
317 | + Map<PortNumber, VersionedValue<Port>> ports = devicePorts.get(deviceId); | ||
318 | + return ports == null ? null : ports.get(portNumber).entity(); | ||
319 | + } | ||
320 | + | ||
321 | + @Override | ||
322 | + public boolean isAvailable(DeviceId deviceId) { | ||
323 | + return devices.get(deviceId).isUp(); | ||
324 | + } | ||
325 | + | ||
326 | + @Override | ||
327 | + public DeviceEvent removeDevice(DeviceId deviceId) { | ||
328 | + VersionedValue<Device> previousDevice = devices.remove(deviceId); | ||
329 | + return previousDevice == null ? null : | ||
330 | + new DeviceEvent(DEVICE_REMOVED, previousDevice.entity(), null); | ||
331 | + } | ||
332 | +} |
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.store.Timestamp; | ||
4 | + | ||
5 | +/** | ||
6 | + * Wrapper class for a entity that is versioned | ||
7 | + * and can either be up or down. | ||
8 | + * | ||
9 | + * @param <T> type of the value. | ||
10 | + */ | ||
11 | +public class VersionedValue<T> { | ||
12 | + private final T entity; | ||
13 | + private final Timestamp timestamp; | ||
14 | + private final boolean isUp; | ||
15 | + | ||
16 | + public VersionedValue(T entity, boolean isUp, Timestamp timestamp) { | ||
17 | + this.entity = entity; | ||
18 | + this.isUp = isUp; | ||
19 | + this.timestamp = timestamp; | ||
20 | + } | ||
21 | + | ||
22 | + /** | ||
23 | + * Returns the value. | ||
24 | + * @return value. | ||
25 | + */ | ||
26 | + public T entity() { | ||
27 | + return entity; | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * Tells whether the entity is up or down. | ||
32 | + * @return true if up, false otherwise. | ||
33 | + */ | ||
34 | + public boolean isUp() { | ||
35 | + return isUp; | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * Returns the timestamp (version) associated with this entity. | ||
40 | + * @return timestamp. | ||
41 | + */ | ||
42 | + public Timestamp timestamp() { | ||
43 | + return timestamp; | ||
44 | + } | ||
45 | +} |
1 | package org.onlab.onos.store.impl; | 1 | package org.onlab.onos.store.impl; |
2 | 2 | ||
3 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | import static com.google.common.base.Preconditions.checkArgument; | 3 | import static com.google.common.base.Preconditions.checkArgument; |
5 | 4 | ||
6 | import java.util.Objects; | 5 | import java.util.Objects; |
7 | 6 | ||
8 | -import org.onlab.onos.net.ElementId; | ||
9 | import org.onlab.onos.store.Timestamp; | 7 | import org.onlab.onos.store.Timestamp; |
10 | 8 | ||
11 | import com.google.common.base.MoreObjects; | 9 | import com.google.common.base.MoreObjects; |
... | @@ -14,22 +12,20 @@ import com.google.common.collect.ComparisonChain; | ... | @@ -14,22 +12,20 @@ import com.google.common.collect.ComparisonChain; |
14 | // If it is store specific, implement serializable interfaces? | 12 | // If it is store specific, implement serializable interfaces? |
15 | /** | 13 | /** |
16 | * Default implementation of Timestamp. | 14 | * Default implementation of Timestamp. |
15 | + * TODO: Better documentation. | ||
17 | */ | 16 | */ |
18 | public final class OnosTimestamp implements Timestamp { | 17 | public final class OnosTimestamp implements Timestamp { |
19 | 18 | ||
20 | - private final ElementId id; | ||
21 | private final int termNumber; | 19 | private final int termNumber; |
22 | private final int sequenceNumber; | 20 | private final int sequenceNumber; |
23 | 21 | ||
24 | /** | 22 | /** |
25 | * Default version tuple. | 23 | * Default version tuple. |
26 | * | 24 | * |
27 | - * @param id identifier of the element | ||
28 | * @param termNumber the mastership termNumber | 25 | * @param termNumber the mastership termNumber |
29 | * @param sequenceNumber the sequenceNumber number within the termNumber | 26 | * @param sequenceNumber the sequenceNumber number within the termNumber |
30 | */ | 27 | */ |
31 | - public OnosTimestamp(ElementId id, int termNumber, int sequenceNumber) { | 28 | + public OnosTimestamp(int termNumber, int sequenceNumber) { |
32 | - this.id = checkNotNull(id); | ||
33 | this.termNumber = termNumber; | 29 | this.termNumber = termNumber; |
34 | this.sequenceNumber = sequenceNumber; | 30 | this.sequenceNumber = sequenceNumber; |
35 | } | 31 | } |
... | @@ -38,9 +34,6 @@ public final class OnosTimestamp implements Timestamp { | ... | @@ -38,9 +34,6 @@ public final class OnosTimestamp implements Timestamp { |
38 | public int compareTo(Timestamp o) { | 34 | public int compareTo(Timestamp o) { |
39 | checkArgument(o instanceof OnosTimestamp, "Must be OnosTimestamp", o); | 35 | checkArgument(o instanceof OnosTimestamp, "Must be OnosTimestamp", o); |
40 | OnosTimestamp that = (OnosTimestamp) o; | 36 | OnosTimestamp that = (OnosTimestamp) o; |
41 | - checkArgument(this.id.equals(that.id), | ||
42 | - "Cannot compare version for different element this:%s, that:%s", | ||
43 | - this, that); | ||
44 | 37 | ||
45 | return ComparisonChain.start() | 38 | return ComparisonChain.start() |
46 | .compare(this.termNumber, that.termNumber) | 39 | .compare(this.termNumber, that.termNumber) |
... | @@ -50,7 +43,7 @@ public final class OnosTimestamp implements Timestamp { | ... | @@ -50,7 +43,7 @@ public final class OnosTimestamp implements Timestamp { |
50 | 43 | ||
51 | @Override | 44 | @Override |
52 | public int hashCode() { | 45 | public int hashCode() { |
53 | - return Objects.hash(id, termNumber, sequenceNumber); | 46 | + return Objects.hash(termNumber, sequenceNumber); |
54 | } | 47 | } |
55 | 48 | ||
56 | @Override | 49 | @Override |
... | @@ -62,30 +55,19 @@ public final class OnosTimestamp implements Timestamp { | ... | @@ -62,30 +55,19 @@ public final class OnosTimestamp implements Timestamp { |
62 | return false; | 55 | return false; |
63 | } | 56 | } |
64 | OnosTimestamp that = (OnosTimestamp) obj; | 57 | OnosTimestamp that = (OnosTimestamp) obj; |
65 | - return Objects.equals(this.id, that.id) && | 58 | + return Objects.equals(this.termNumber, that.termNumber) && |
66 | - Objects.equals(this.termNumber, that.termNumber) && | ||
67 | Objects.equals(this.sequenceNumber, that.sequenceNumber); | 59 | Objects.equals(this.sequenceNumber, that.sequenceNumber); |
68 | } | 60 | } |
69 | 61 | ||
70 | @Override | 62 | @Override |
71 | public String toString() { | 63 | public String toString() { |
72 | return MoreObjects.toStringHelper(getClass()) | 64 | return MoreObjects.toStringHelper(getClass()) |
73 | - .add("id", id) | ||
74 | .add("termNumber", termNumber) | 65 | .add("termNumber", termNumber) |
75 | .add("sequenceNumber", sequenceNumber) | 66 | .add("sequenceNumber", sequenceNumber) |
76 | .toString(); | 67 | .toString(); |
77 | } | 68 | } |
78 | 69 | ||
79 | /** | 70 | /** |
80 | - * Returns the element. | ||
81 | - * | ||
82 | - * @return element identifier | ||
83 | - */ | ||
84 | - public ElementId id() { | ||
85 | - return id; | ||
86 | - } | ||
87 | - | ||
88 | - /** | ||
89 | * Returns the termNumber. | 71 | * Returns the termNumber. |
90 | * | 72 | * |
91 | * @return termNumber | 73 | * @return termNumber |
... | @@ -102,4 +84,4 @@ public final class OnosTimestamp implements Timestamp { | ... | @@ -102,4 +84,4 @@ public final class OnosTimestamp implements Timestamp { |
102 | public int sequenceNumber() { | 84 | public int sequenceNumber() { |
103 | return sequenceNumber; | 85 | return sequenceNumber; |
104 | } | 86 | } |
105 | -} | 87 | +} |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | -import org.onlab.onos.net.ElementId; | ||
4 | import org.onlab.onos.store.impl.OnosTimestamp; | 3 | import org.onlab.onos.store.impl.OnosTimestamp; |
5 | 4 | ||
6 | import com.esotericsoftware.kryo.Kryo; | 5 | import com.esotericsoftware.kryo.Kryo; |
... | @@ -20,18 +19,17 @@ public class OnosTimestampSerializer extends Serializer<OnosTimestamp> { | ... | @@ -20,18 +19,17 @@ public class OnosTimestampSerializer extends Serializer<OnosTimestamp> { |
20 | // non-null, immutable | 19 | // non-null, immutable |
21 | super(false, true); | 20 | super(false, true); |
22 | } | 21 | } |
22 | + | ||
23 | @Override | 23 | @Override |
24 | public void write(Kryo kryo, Output output, OnosTimestamp object) { | 24 | public void write(Kryo kryo, Output output, OnosTimestamp object) { |
25 | - kryo.writeClassAndObject(output, object.id()); | ||
26 | output.writeInt(object.termNumber()); | 25 | output.writeInt(object.termNumber()); |
27 | output.writeInt(object.sequenceNumber()); | 26 | output.writeInt(object.sequenceNumber()); |
28 | } | 27 | } |
29 | 28 | ||
30 | @Override | 29 | @Override |
31 | public OnosTimestamp read(Kryo kryo, Input input, Class<OnosTimestamp> type) { | 30 | public OnosTimestamp read(Kryo kryo, Input input, Class<OnosTimestamp> type) { |
32 | - ElementId id = (ElementId) kryo.readClassAndObject(input); | ||
33 | final int term = input.readInt(); | 31 | final int term = input.readInt(); |
34 | final int sequence = input.readInt(); | 32 | final int sequence = input.readInt(); |
35 | - return new OnosTimestamp(id, term, sequence); | 33 | + return new OnosTimestamp(term, sequence); |
36 | } | 34 | } |
37 | } | 35 | } | ... | ... |
-
Please register or login to post a comment