blob: d74ea49e95653dc1f356dab67a481218483e1052 [file] [log] [blame]
Yuta HIGUCHIa8a53eb2014-09-25 17:47:55 -07001package org.onlab.onos.store.link.impl;
2
3import static com.google.common.cache.CacheBuilder.newBuilder;
4import static org.onlab.onos.net.Link.Type.DIRECT;
5import static org.onlab.onos.net.Link.Type.INDIRECT;
6import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED;
7import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
8import static org.onlab.onos.net.link.LinkEvent.Type.LINK_UPDATED;
9import static org.slf4j.LoggerFactory.getLogger;
10
11import java.util.HashSet;
12import java.util.Set;
Yuta HIGUCHIb5df76d2014-09-27 20:54:00 -070013
Yuta HIGUCHIa8a53eb2014-09-25 17:47:55 -070014import org.apache.felix.scr.annotations.Activate;
15import org.apache.felix.scr.annotations.Component;
16import org.apache.felix.scr.annotations.Deactivate;
17import org.apache.felix.scr.annotations.Service;
18import org.onlab.onos.net.ConnectPoint;
19import org.onlab.onos.net.DefaultLink;
20import org.onlab.onos.net.DeviceId;
21import org.onlab.onos.net.Link;
22import org.onlab.onos.net.LinkKey;
23import org.onlab.onos.net.link.LinkDescription;
24import org.onlab.onos.net.link.LinkEvent;
25import org.onlab.onos.net.link.LinkStore;
26import org.onlab.onos.net.link.LinkStoreDelegate;
27import org.onlab.onos.net.provider.ProviderId;
Yuta HIGUCHIb5df76d2014-09-27 20:54:00 -070028import org.onlab.onos.store.common.AbsentInvalidatingLoadingCache;
29import org.onlab.onos.store.common.AbstractHazelcastStore;
30import org.onlab.onos.store.common.OptionalCacheLoader;
Yuta HIGUCHIa8a53eb2014-09-25 17:47:55 -070031import org.slf4j.Logger;
32
33import com.google.common.base.Optional;
34import com.google.common.cache.LoadingCache;
35import com.google.common.collect.HashMultimap;
36import com.google.common.collect.ImmutableSet;
37import com.google.common.collect.Multimap;
38import com.google.common.collect.ImmutableSet.Builder;
39import com.hazelcast.core.IMap;
40
41/**
42 * Manages inventory of infrastructure links using Hazelcast-backed map.
43 */
44@Component(immediate = true)
45@Service
46public class DistributedLinkStore
Yuta HIGUCHI2e963892014-09-27 13:00:39 -070047 extends AbstractHazelcastStore<LinkEvent, LinkStoreDelegate>
Yuta HIGUCHIa8a53eb2014-09-25 17:47:55 -070048 implements LinkStore {
49
50 private final Logger log = getLogger(getClass());
51
52 // Link inventory
53 private IMap<byte[], byte[]> rawLinks;
54 private LoadingCache<LinkKey, Optional<DefaultLink>> links;
55
56 // TODO synchronize?
57 // Egress and ingress link sets
58 private final Multimap<DeviceId, Link> srcLinks = HashMultimap.create();
59 private final Multimap<DeviceId, Link> dstLinks = HashMultimap.create();
60
61 @Override
62 @Activate
63 public void activate() {
64 super.activate();
65
66 boolean includeValue = true;
67
68 // TODO decide on Map name scheme to avoid collision
69 rawLinks = theInstance.getMap("links");
70 final OptionalCacheLoader<LinkKey, DefaultLink> linkLoader
71 = new OptionalCacheLoader<>(storeService, rawLinks);
72 links = new AbsentInvalidatingLoadingCache<>(newBuilder().build(linkLoader));
73 // refresh/populate cache based on notification from other instance
74 rawLinks.addEntryListener(new RemoteLinkEventHandler(links), includeValue);
75
76 loadLinkCache();
77
78 log.info("Started");
79 }
80
81 @Deactivate
82 public void deactivate() {
83 super.activate();
84 log.info("Stopped");
85 }
86
87 private void loadLinkCache() {
88 for (byte[] keyBytes : rawLinks.keySet()) {
89 final LinkKey id = deserialize(keyBytes);
90 links.refresh(id);
91 }
92 }
93
94 @Override
95 public int getLinkCount() {
96 return links.asMap().size();
97 }
98
99 @Override
100 public Iterable<Link> getLinks() {
101 Builder<Link> builder = ImmutableSet.builder();
102 for (Optional<DefaultLink> e : links.asMap().values()) {
103 if (e.isPresent()) {
104 builder.add(e.get());
105 }
106 }
107 return builder.build();
108 }
109
110 @Override
111 public Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
112 return ImmutableSet.copyOf(srcLinks.get(deviceId));
113 }
114
115 @Override
116 public Set<Link> getDeviceIngressLinks(DeviceId deviceId) {
117 return ImmutableSet.copyOf(dstLinks.get(deviceId));
118 }
119
120 @Override
121 public Link getLink(ConnectPoint src, ConnectPoint dst) {
122 return links.getUnchecked(new LinkKey(src, dst)).orNull();
123 }
124
125 @Override
126 public Set<Link> getEgressLinks(ConnectPoint src) {
127 Set<Link> egress = new HashSet<>();
128 for (Link link : srcLinks.get(src.deviceId())) {
129 if (link.src().equals(src)) {
130 egress.add(link);
131 }
132 }
133 return egress;
134 }
135
136 @Override
137 public Set<Link> getIngressLinks(ConnectPoint dst) {
138 Set<Link> ingress = new HashSet<>();
139 for (Link link : dstLinks.get(dst.deviceId())) {
140 if (link.dst().equals(dst)) {
141 ingress.add(link);
142 }
143 }
144 return ingress;
145 }
146
147 @Override
148 public LinkEvent createOrUpdateLink(ProviderId providerId,
149 LinkDescription linkDescription) {
150 LinkKey key = new LinkKey(linkDescription.src(), linkDescription.dst());
151 Optional<DefaultLink> link = links.getUnchecked(key);
152 if (!link.isPresent()) {
153 return createLink(providerId, key, linkDescription);
154 }
155 return updateLink(providerId, link.get(), key, linkDescription);
156 }
157
158 // Creates and stores the link and returns the appropriate event.
159 private LinkEvent createLink(ProviderId providerId, LinkKey key,
160 LinkDescription linkDescription) {
161 DefaultLink link = new DefaultLink(providerId, key.src(), key.dst(),
162 linkDescription.type());
163 synchronized (this) {
164 final byte[] keyBytes = serialize(key);
165 rawLinks.put(keyBytes, serialize(link));
166 links.asMap().putIfAbsent(key, Optional.of(link));
167
168 addNewLink(link);
169 }
170 return new LinkEvent(LINK_ADDED, link);
171 }
172
173 // update Egress and ingress link sets
174 private void addNewLink(DefaultLink link) {
175 synchronized (this) {
176 srcLinks.put(link.src().deviceId(), link);
177 dstLinks.put(link.dst().deviceId(), link);
178 }
179 }
180
181 // Updates, if necessary the specified link and returns the appropriate event.
182 private LinkEvent updateLink(ProviderId providerId, DefaultLink link,
183 LinkKey key, LinkDescription linkDescription) {
184 // FIXME confirm Link update condition is OK
185 if (link.type() == INDIRECT && linkDescription.type() == DIRECT) {
186 synchronized (this) {
187
188 DefaultLink updated =
189 new DefaultLink(providerId, link.src(), link.dst(),
190 linkDescription.type());
191 final byte[] keyBytes = serialize(key);
192 rawLinks.put(keyBytes, serialize(updated));
193 links.asMap().replace(key, Optional.of(link), Optional.of(updated));
194
195 replaceLink(link, updated);
196 return new LinkEvent(LINK_UPDATED, updated);
197 }
198 }
199 return null;
200 }
201
202 // update Egress and ingress link sets
203 private void replaceLink(DefaultLink link, DefaultLink updated) {
204 synchronized (this) {
205 srcLinks.remove(link.src().deviceId(), link);
206 dstLinks.remove(link.dst().deviceId(), link);
207
208 srcLinks.put(link.src().deviceId(), updated);
209 dstLinks.put(link.dst().deviceId(), updated);
210 }
211 }
212
213 @Override
214 public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
215 synchronized (this) {
216 LinkKey key = new LinkKey(src, dst);
217 byte[] keyBytes = serialize(key);
218 Link link = deserialize(rawLinks.remove(keyBytes));
219 links.invalidate(key);
220 if (link != null) {
221 removeLink(link);
222 return new LinkEvent(LINK_REMOVED, link);
223 }
224 return null;
225 }
226 }
227
228 // update Egress and ingress link sets
229 private void removeLink(Link link) {
230 synchronized (this) {
231 srcLinks.remove(link.src().deviceId(), link);
232 dstLinks.remove(link.dst().deviceId(), link);
233 }
234 }
235
236 private class RemoteLinkEventHandler extends RemoteEventHandler<LinkKey, DefaultLink> {
237 public RemoteLinkEventHandler(LoadingCache<LinkKey, Optional<DefaultLink>> cache) {
238 super(cache);
239 }
240
241 @Override
242 protected void onAdd(LinkKey key, DefaultLink newVal) {
243 addNewLink(newVal);
244 notifyDelegate(new LinkEvent(LINK_ADDED, newVal));
245 }
246
247 @Override
248 protected void onUpdate(LinkKey key, DefaultLink oldVal, DefaultLink newVal) {
249 replaceLink(oldVal, newVal);
250 notifyDelegate(new LinkEvent(LINK_UPDATED, newVal));
251 }
252
253 @Override
254 protected void onRemove(LinkKey key, DefaultLink val) {
255 removeLink(val);
256 notifyDelegate(new LinkEvent(LINK_REMOVED, val));
257 }
258 }
259}