Yuta HIGUCHI

moving out OptionalCacheLoader

Change-Id: If929ed119df1a0282e311188a00776e971f78991
...@@ -2,7 +2,6 @@ package org.onlab.onos.store.device.impl; ...@@ -2,7 +2,6 @@ package org.onlab.onos.store.device.impl;
2 2
3 import com.google.common.base.Optional; 3 import com.google.common.base.Optional;
4 import com.google.common.cache.CacheBuilder; 4 import com.google.common.cache.CacheBuilder;
5 -import com.google.common.cache.CacheLoader;
6 import com.google.common.cache.LoadingCache; 5 import com.google.common.cache.LoadingCache;
7 import com.google.common.collect.ImmutableList; 6 import com.google.common.collect.ImmutableList;
8 import com.google.common.collect.ImmutableSet; 7 import com.google.common.collect.ImmutableSet;
...@@ -13,6 +12,7 @@ import com.hazelcast.core.HazelcastInstance; ...@@ -13,6 +12,7 @@ import com.hazelcast.core.HazelcastInstance;
13 import com.hazelcast.core.IMap; 12 import com.hazelcast.core.IMap;
14 import com.hazelcast.core.ISet; 13 import com.hazelcast.core.ISet;
15 import com.hazelcast.core.MapEvent; 14 import com.hazelcast.core.MapEvent;
15 +
16 import org.apache.felix.scr.annotations.Activate; 16 import org.apache.felix.scr.annotations.Activate;
17 import org.apache.felix.scr.annotations.Component; 17 import org.apache.felix.scr.annotations.Component;
18 import org.apache.felix.scr.annotations.Deactivate; 18 import org.apache.felix.scr.annotations.Deactivate;
...@@ -33,6 +33,7 @@ import org.onlab.onos.net.device.PortDescription; ...@@ -33,6 +33,7 @@ import org.onlab.onos.net.device.PortDescription;
33 import org.onlab.onos.net.provider.ProviderId; 33 import org.onlab.onos.net.provider.ProviderId;
34 import org.onlab.onos.store.StoreService; 34 import org.onlab.onos.store.StoreService;
35 import org.onlab.onos.store.impl.AbsentInvalidatingLoadingCache; 35 import org.onlab.onos.store.impl.AbsentInvalidatingLoadingCache;
36 +import org.onlab.onos.store.impl.OptionalCacheLoader;
36 import org.slf4j.Logger; 37 import org.slf4j.Logger;
37 38
38 import java.util.ArrayList; 39 import java.util.ArrayList;
...@@ -78,7 +79,6 @@ public class DistributedDeviceStore implements DeviceStore { ...@@ -78,7 +79,6 @@ public class DistributedDeviceStore implements DeviceStore {
78 private IMap<byte[], byte[]> rawDevicePorts; 79 private IMap<byte[], byte[]> rawDevicePorts;
79 private LoadingCache<DeviceId, Optional<Map<PortNumber, Port>>> devicePorts; 80 private LoadingCache<DeviceId, Optional<Map<PortNumber, Port>>> devicePorts;
80 81
81 - // FIXME change to protected once we remove DistributedDeviceManagerTest.
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected StoreService storeService; 83 protected StoreService storeService;
84 84
...@@ -95,30 +95,36 @@ public class DistributedDeviceStore implements DeviceStore { ...@@ -95,30 +95,36 @@ public class DistributedDeviceStore implements DeviceStore {
95 95
96 // TODO decide on Map name scheme to avoid collision 96 // TODO decide on Map name scheme to avoid collision
97 rawDevices = theInstance.getMap("devices"); 97 rawDevices = theInstance.getMap("devices");
98 + final OptionalCacheLoader<DeviceId, DefaultDevice> deviceLoader
99 + = new OptionalCacheLoader<>(storeService, rawDevices);
98 devices = new AbsentInvalidatingLoadingCache<>( 100 devices = new AbsentInvalidatingLoadingCache<>(
99 CacheBuilder.newBuilder() 101 CacheBuilder.newBuilder()
100 - .build(new OptionalCacheLoader<DeviceId, DefaultDevice>(rawDevices))); 102 + .build(deviceLoader));
101 // refresh/populate cache based on notification from other instance 103 // refresh/populate cache based on notification from other instance
102 rawDevices.addEntryListener( 104 rawDevices.addEntryListener(
103 new RemoteEventHandler<>(devices), 105 new RemoteEventHandler<>(devices),
104 includeValue); 106 includeValue);
105 107
106 rawRoles = theInstance.getMap("roles"); 108 rawRoles = theInstance.getMap("roles");
109 + final OptionalCacheLoader<DeviceId, MastershipRole> rolesLoader
110 + = new OptionalCacheLoader<>(storeService, rawRoles);
107 roles = new AbsentInvalidatingLoadingCache<>( 111 roles = new AbsentInvalidatingLoadingCache<>(
108 CacheBuilder.newBuilder() 112 CacheBuilder.newBuilder()
109 - .build(new OptionalCacheLoader<DeviceId, MastershipRole>(rawRoles))); 113 + .build(rolesLoader));
110 // refresh/populate cache based on notification from other instance 114 // refresh/populate cache based on notification from other instance
111 rawRoles.addEntryListener( 115 rawRoles.addEntryListener(
112 new RemoteEventHandler<>(roles), 116 new RemoteEventHandler<>(roles),
113 includeValue); 117 includeValue);
114 118
115 - // TODO cache avai 119 + // TODO cache availableDevices
116 availableDevices = theInstance.getSet("availableDevices"); 120 availableDevices = theInstance.getSet("availableDevices");
117 121
118 rawDevicePorts = theInstance.getMap("devicePorts"); 122 rawDevicePorts = theInstance.getMap("devicePorts");
123 + final OptionalCacheLoader<DeviceId, Map<PortNumber, Port>> devicePortLoader
124 + = new OptionalCacheLoader<>(storeService, rawDevicePorts);
119 devicePorts = new AbsentInvalidatingLoadingCache<>( 125 devicePorts = new AbsentInvalidatingLoadingCache<>(
120 CacheBuilder.newBuilder() 126 CacheBuilder.newBuilder()
121 - .build(new OptionalCacheLoader<DeviceId, Map<PortNumber, Port>>(rawDevicePorts))); 127 + .build(devicePortLoader));
122 // refresh/populate cache based on notification from other instance 128 // refresh/populate cache based on notification from other instance
123 rawDevicePorts.addEntryListener( 129 rawDevicePorts.addEntryListener(
124 new RemoteEventHandler<>(devicePorts), 130 new RemoteEventHandler<>(devicePorts),
...@@ -439,7 +445,7 @@ public class DistributedDeviceStore implements DeviceStore { ...@@ -439,7 +445,7 @@ public class DistributedDeviceStore implements DeviceStore {
439 445
440 @Override 446 @Override
441 public void entryRemoved(EntryEvent<byte[], byte[]> event) { 447 public void entryRemoved(EntryEvent<byte[], byte[]> event) {
442 - cache.invalidate(storeService.<DeviceId>deserialize(event.getKey())); 448 + cache.invalidate(storeService.<K>deserialize(event.getKey()));
443 } 449 }
444 450
445 @Override 451 @Override
...@@ -447,37 +453,4 @@ public class DistributedDeviceStore implements DeviceStore { ...@@ -447,37 +453,4 @@ public class DistributedDeviceStore implements DeviceStore {
447 entryUpdated(event); 453 entryUpdated(event);
448 } 454 }
449 } 455 }
450 -
451 - /**
452 - * CacheLoader to wrap Map value with Optional,
453 - * to handle negative hit on underlying IMap.
454 - *
455 - * @param <K> IMap key type after deserialization
456 - * @param <V> IMap value type after deserialization
457 - */
458 - public final class OptionalCacheLoader<K, V> extends
459 - CacheLoader<K, Optional<V>> {
460 -
461 - private IMap<byte[], byte[]> rawMap;
462 -
463 - /**
464 - * Constructor.
465 - *
466 - * @param rawMap underlying IMap
467 - */
468 - public OptionalCacheLoader(IMap<byte[], byte[]> rawMap) {
469 - this.rawMap = checkNotNull(rawMap);
470 - }
471 -
472 - @Override
473 - public Optional<V> load(K key) throws Exception {
474 - byte[] keyBytes = storeService.serialize(key);
475 - byte[] valBytes = rawMap.get(keyBytes);
476 - if (valBytes == null) {
477 - return Optional.absent();
478 - }
479 - V dev = deserialize(valBytes);
480 - return Optional.of(dev);
481 - }
482 - }
483 } 456 }
......
...@@ -7,9 +7,24 @@ import com.google.common.base.Optional; ...@@ -7,9 +7,24 @@ import com.google.common.base.Optional;
7 import com.google.common.cache.ForwardingLoadingCache.SimpleForwardingLoadingCache; 7 import com.google.common.cache.ForwardingLoadingCache.SimpleForwardingLoadingCache;
8 import com.google.common.cache.LoadingCache; 8 import com.google.common.cache.LoadingCache;
9 9
10 +/**
11 + * Wrapper around LoadingCache to handle negative hit scenario.
12 + * <p>
13 + * When the LoadingCache returned Absent,
14 + * this implementation will invalidate the entry immediately to avoid
15 + * caching negative hits.
16 + *
17 + * @param <K> Cache key type
18 + * @param <V> Cache value type. (Optional{@literal <V>})
19 + */
10 public class AbsentInvalidatingLoadingCache<K, V> extends 20 public class AbsentInvalidatingLoadingCache<K, V> extends
11 SimpleForwardingLoadingCache<K, Optional<V>> { 21 SimpleForwardingLoadingCache<K, Optional<V>> {
12 22
23 + /**
24 + * Constructor.
25 + *
26 + * @param delegate actual {@link LoadingCache} to delegate loading.
27 + */
13 public AbsentInvalidatingLoadingCache(LoadingCache<K, Optional<V>> delegate) { 28 public AbsentInvalidatingLoadingCache(LoadingCache<K, Optional<V>> delegate) {
14 super(delegate); 29 super(delegate);
15 } 30 }
......
1 +package org.onlab.onos.store.impl;
2 +
3 +import static com.google.common.base.Preconditions.checkNotNull;
4 +
5 +import org.onlab.onos.store.StoreService;
6 +
7 +import com.google.common.base.Optional;
8 +import com.google.common.cache.CacheLoader;
9 +import com.hazelcast.core.IMap;
10 +
11 +/**
12 + * CacheLoader to wrap Map value with Optional,
13 + * to handle negative hit on underlying IMap.
14 + *
15 + * @param <K> IMap key type after deserialization
16 + * @param <V> IMap value type after deserialization
17 + */
18 +public final class OptionalCacheLoader<K, V> extends
19 + CacheLoader<K, Optional<V>> {
20 +
21 + private final StoreService storeService;
22 + private IMap<byte[], byte[]> rawMap;
23 +
24 + /**
25 + * Constructor.
26 + *
27 + * @param storeService to use for serialization
28 + * @param rawMap underlying IMap
29 + */
30 + public OptionalCacheLoader(StoreService storeService, IMap<byte[], byte[]> rawMap) {
31 + this.storeService = checkNotNull(storeService);
32 + this.rawMap = checkNotNull(rawMap);
33 + }
34 +
35 + @Override
36 + public Optional<V> load(K key) throws Exception {
37 + byte[] keyBytes = storeService.serialize(key);
38 + byte[] valBytes = rawMap.get(keyBytes);
39 + if (valBytes == null) {
40 + return Optional.absent();
41 + }
42 + V dev = storeService.deserialize(valBytes);
43 + return Optional.of(dev);
44 + }
45 +}