blob: bdb898eeb8b35a0b0db2c65fe3e0a8c5faa4f310 [file] [log] [blame]
Jian Li92919592017-02-27 17:10:47 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jian Li92919592017-02-27 17:10:47 +09003 *
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 */
16package org.onosproject.mapping.impl;
17
Jian Li252750d2017-03-01 04:50:13 +090018import com.google.common.collect.FluentIterable;
Jian Li791dd322017-04-20 00:15:56 +090019import com.google.common.collect.Lists;
Jian Li92919592017-02-27 17:10:47 +090020import com.google.common.collect.Maps;
Jian Li92919592017-02-27 17:10:47 +090021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Jian Li92919592017-02-27 17:10:47 +090024import org.apache.felix.scr.annotations.Modified;
Jian Li252750d2017-03-01 04:50:13 +090025import org.apache.felix.scr.annotations.Service;
26import org.onosproject.mapping.DefaultMappingEntry;
Jian Li92919592017-02-27 17:10:47 +090027import org.onosproject.mapping.Mapping;
Jian Li252750d2017-03-01 04:50:13 +090028import org.onosproject.mapping.MappingEntry;
Jian Lia1f960b2017-04-25 19:12:53 +090029import org.onosproject.mapping.MappingEntry.MappingEntryState;
Jian Li252750d2017-03-01 04:50:13 +090030import org.onosproject.mapping.MappingEvent;
Jian Li92919592017-02-27 17:10:47 +090031import org.onosproject.mapping.MappingId;
32import org.onosproject.mapping.MappingStore;
Jian Li92919592017-02-27 17:10:47 +090033import org.onosproject.mapping.MappingStoreDelegate;
Jian Li252750d2017-03-01 04:50:13 +090034import org.onosproject.mapping.StoredMappingEntry;
Jian Li92919592017-02-27 17:10:47 +090035import org.onosproject.net.DeviceId;
36import org.onosproject.store.AbstractStore;
37import org.osgi.service.component.ComponentContext;
38import org.slf4j.Logger;
39
Jian Li252750d2017-03-01 04:50:13 +090040import java.util.Collections;
Jian Li92919592017-02-27 17:10:47 +090041import java.util.List;
42import java.util.concurrent.ConcurrentMap;
Jian Li252750d2017-03-01 04:50:13 +090043import java.util.concurrent.CopyOnWriteArrayList;
Jian Li92919592017-02-27 17:10:47 +090044
Jian Li252750d2017-03-01 04:50:13 +090045import static org.onosproject.mapping.MappingEntry.MappingEntryState.PENDING_ADD;
46import static org.onosproject.mapping.MappingEntry.MappingEntryState.PENDING_REMOVE;
47import static org.onosproject.mapping.MappingEvent.Type.MAPPING_ADDED;
48import static org.onosproject.mapping.MappingEvent.Type.MAPPING_REMOVED;
49import static org.onosproject.mapping.MappingEvent.Type.MAPPING_UPDATED;
Jian Li92919592017-02-27 17:10:47 +090050import static org.slf4j.LoggerFactory.getLogger;
51
52/**
53 * Manages inventory of mappings using trivial in-memory implementation.
54 */
55@Component(immediate = true)
56@Service
57public class SimpleMappingStore
58 extends AbstractStore<MappingEvent, MappingStoreDelegate>
59 implements MappingStore {
60
61 private final Logger log = getLogger(getClass());
62
Jian Li252750d2017-03-01 04:50:13 +090063 private static final String UNRECOGNIZED_STORE_MSG = "Unrecognized store type {}";
Jian Li92919592017-02-27 17:10:47 +090064
Jian Li252750d2017-03-01 04:50:13 +090065 private final ConcurrentMap<DeviceId, ConcurrentMap<MappingId,
66 List<StoredMappingEntry>>> mapDbStore = Maps.newConcurrentMap();
Jian Li92919592017-02-27 17:10:47 +090067
Jian Li252750d2017-03-01 04:50:13 +090068 private final ConcurrentMap<DeviceId, ConcurrentMap<MappingId,
69 List<StoredMappingEntry>>> mapCacheStore = Maps.newConcurrentMap();
Jian Li92919592017-02-27 17:10:47 +090070
71 @Activate
72 public void activate() {
73 log.info("Started");
74 }
75
76 @Deactivate
77 public void deactivate() {
78 mapDbStore.clear();
79 mapCacheStore.clear();
80 log.info("Stopped");
81 }
82
83 @Modified
84 public void modified(ComponentContext context) {
85
86 }
87
88 @Override
89 public int getMappingCount(Type type) {
Jian Li252750d2017-03-01 04:50:13 +090090 int sum = 0;
91
Jian Li791dd322017-04-20 00:15:56 +090092 for (ConcurrentMap<MappingId, List<StoredMappingEntry>> mapDb :
93 getMappingStore(type).values()) {
Jian Li252750d2017-03-01 04:50:13 +090094 for (List<StoredMappingEntry> mes : mapDb.values()) {
95 sum += mes.size();
96 }
97 }
98
99 return sum;
100 }
101
Jian Li791dd322017-04-20 00:15:56 +0900102 @Override
103 public Iterable<MappingEntry> getAllMappingEntries(Type type) {
104
105 List<MappingEntry> entries = Lists.newArrayList();
106
107 for (ConcurrentMap<MappingId, List<StoredMappingEntry>> mapDb :
108 getMappingStore(type).values()) {
109 for (List<StoredMappingEntry> mes : mapDb.values()) {
110 entries.addAll(mes);
111 }
112 }
113
114 return entries;
115 }
116
Jian Li252750d2017-03-01 04:50:13 +0900117 /**
118 * Obtains the mapping store for specified device and store type.
119 *
120 * @param type mapping store type
121 * @param deviceId device identifier
122 * @return Map representing Mapping Store of given device and store type
123 */
124 private ConcurrentMap<MappingId, List<StoredMappingEntry>>
125 getMappingStoreByDeviceId(Type type,
126 DeviceId deviceId) {
127 switch (type) {
128 case MAP_DATABASE:
129 return mapDbStore.computeIfAbsent(deviceId,
130 k -> Maps.newConcurrentMap());
131 case MAP_CACHE:
132 return mapCacheStore.computeIfAbsent(deviceId,
133 k -> Maps.newConcurrentMap());
134 default:
135 log.error(UNRECOGNIZED_STORE_MSG, type);
136 return null;
137 }
138 }
139
140 /**
141 * Obtains the mapping store for specified store type.
142 *
143 * @param type mapping store type
144 * @return mapping store
145 */
146 private ConcurrentMap<DeviceId, ConcurrentMap<MappingId, List<StoredMappingEntry>>>
147 getMappingStore(Type type) {
148 switch (type) {
149 case MAP_DATABASE:
150 return mapDbStore;
151 case MAP_CACHE:
152 return mapCacheStore;
153 default:
154 log.error(UNRECOGNIZED_STORE_MSG, type);
155 return null;
156 }
157 }
158
159 /**
160 * Obtains mapping entries for specified device, store type and mapping ID.
161 *
162 * @param type mapping store type
163 * @param deviceId device identifier
164 * @param mappingId mapping identifier
165 * @return a collection of mapping entries
166 */
167 private List<StoredMappingEntry> getMappingEntriesInternal(Type type,
168 DeviceId deviceId,
169 MappingId mappingId) {
170 final ConcurrentMap<MappingId, List<StoredMappingEntry>>
171 store = getMappingStoreByDeviceId(type, deviceId);
172 List<StoredMappingEntry> r = store.get(mappingId);
173 if (r == null) {
174 final List<StoredMappingEntry> concurrentlyAdded;
175 r = new CopyOnWriteArrayList<>();
176 concurrentlyAdded = store.putIfAbsent(mappingId, r);
177 if (concurrentlyAdded != null) {
178 return concurrentlyAdded;
179 }
180 }
181 return r;
182 }
183
184 /**
185 * Obtains a mapping entry for specified device, store type and mapping.
186 *
187 * @param type mapping store type
188 * @param deviceId device identifier
189 * @param mapping mapping identifier
190 * @return a mapping entry
191 */
192 private MappingEntry getMappingEntryInternal(Type type, DeviceId deviceId,
193 Mapping mapping) {
194 List<StoredMappingEntry> mes =
195 getMappingEntriesInternal(type, deviceId, mapping.id());
196 for (StoredMappingEntry me : mes) {
197 if (me.equals(mapping)) {
198 return me;
199 }
200 }
201 return null;
Jian Li92919592017-02-27 17:10:47 +0900202 }
203
204 @Override
205 public MappingEntry getMappingEntry(Type type, Mapping mapping) {
Jian Li252750d2017-03-01 04:50:13 +0900206 return getMappingEntryInternal(type, mapping.deviceId(), mapping);
Jian Li92919592017-02-27 17:10:47 +0900207 }
208
209 @Override
210 public Iterable<MappingEntry> getMappingEntries(Type type, DeviceId deviceId) {
Jian Li252750d2017-03-01 04:50:13 +0900211 // FIXME: a better way is using Java 8 API to return immutable iterables
212 return FluentIterable.from(getMappingStoreByDeviceId(type, deviceId).values())
213 .transformAndConcat(Collections::unmodifiableList);
214 }
215
216 @Override
Jian Lia1f960b2017-04-25 19:12:53 +0900217 public void storeMapping(Type type, MappingEntry mapping) {
Jian Li252750d2017-03-01 04:50:13 +0900218
219 List<StoredMappingEntry> entries =
220 getMappingEntriesInternal(type, mapping.deviceId(), mapping.id());
221
222 synchronized (entries) {
223 if (!entries.contains(mapping)) {
Jian Lia1f960b2017-04-25 19:12:53 +0900224 StoredMappingEntry entry =
225 new DefaultMappingEntry(mapping, mapping.state());
Jian Li252750d2017-03-01 04:50:13 +0900226 entries.add(entry);
227 }
228 }
Jian Li92919592017-02-27 17:10:47 +0900229 }
230
231 @Override
Jian Li2dc9f002017-03-03 04:26:31 +0900232 public void pendingDeleteMapping(Type type, Mapping mapping) {
Jian Li92919592017-02-27 17:10:47 +0900233
Jian Li252750d2017-03-01 04:50:13 +0900234 List<StoredMappingEntry> entries =
235 getMappingEntriesInternal(type, mapping.deviceId(), mapping.id());
236
237 synchronized (entries) {
238 for (StoredMappingEntry entry : entries) {
239 if (entry.equals(mapping)) {
240 synchronized (entry) {
241 entry.setState(PENDING_REMOVE);
242 }
243 }
244 }
245 }
Jian Li92919592017-02-27 17:10:47 +0900246 }
247
248 @Override
249 public MappingEvent addOrUpdateMappingEntry(Type type, MappingEntry entry) {
Jian Li252750d2017-03-01 04:50:13 +0900250
251 List<StoredMappingEntry> entries =
252 getMappingEntriesInternal(type, entry.deviceId(), entry.id());
253 synchronized (entries) {
254 for (StoredMappingEntry stored : entries) {
255 if (stored.equals(entry)) {
256 if (stored.state() == PENDING_ADD) {
Jian Lia1f960b2017-04-25 19:12:53 +0900257 stored.setState(MappingEntryState.ADDED);
Jian Li252750d2017-03-01 04:50:13 +0900258 return new MappingEvent(MAPPING_ADDED, entry);
259 }
260 return new MappingEvent(MAPPING_UPDATED, entry);
261 }
262 }
263 }
264
265 log.error("Mapping was not found in store {} to update", entry);
266
Jian Li92919592017-02-27 17:10:47 +0900267 return null;
268 }
269
270 @Override
Jian Li2dc9f002017-03-03 04:26:31 +0900271 public MappingEvent removeMapping(Type type, Mapping mapping) {
Jian Li252750d2017-03-01 04:50:13 +0900272
273 List<StoredMappingEntry> entries =
Jian Li2dc9f002017-03-03 04:26:31 +0900274 getMappingEntriesInternal(type, mapping.deviceId(), mapping.id());
Jian Li252750d2017-03-01 04:50:13 +0900275 synchronized (entries) {
Jian Li2dc9f002017-03-03 04:26:31 +0900276 if (entries.remove(mapping)) {
277 return new MappingEvent(MAPPING_REMOVED, mapping);
Jian Li252750d2017-03-01 04:50:13 +0900278 }
279 }
Jian Li92919592017-02-27 17:10:47 +0900280 return null;
281 }
282
283 @Override
284 public MappingEvent pendingMappingEntry(Type type, MappingEntry entry) {
Jian Li252750d2017-03-01 04:50:13 +0900285 List<StoredMappingEntry> entries =
286 getMappingEntriesInternal(type, entry.deviceId(), entry.id());
287 synchronized (entries) {
288 for (StoredMappingEntry stored : entries) {
289 if (stored.equals(entry) && (stored.state() != PENDING_ADD)) {
290 synchronized (stored) {
291 stored.setState(PENDING_ADD);
292 return new MappingEvent(MAPPING_UPDATED, entry);
293 }
294 }
295 }
296 }
Jian Li92919592017-02-27 17:10:47 +0900297 return null;
298 }
299
300 @Override
Jian Li252750d2017-03-01 04:50:13 +0900301 public void purgeMappingEntry(Type type, DeviceId deviceId) {
302 getMappingStore(type).remove(deviceId);
303 }
Jian Li92919592017-02-27 17:10:47 +0900304
Jian Li252750d2017-03-01 04:50:13 +0900305 @Override
306 public void purgeMappingEntries(Type type) {
307 getMappingStore(type).clear();
Jian Li92919592017-02-27 17:10:47 +0900308 }
309}
310
311