blob: 0b4e2a46445d3462854ccf027f7d442cf47e7646 [file] [log] [blame]
alshabib7bb05012015-08-05 10:15:09 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
alshabib7bb05012015-08-05 10:15:09 -07003 *
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 */
Thomas Vachuska52f2cd12018-11-08 21:20:04 -080016package org.onosproject.store.meter.impl;
alshabib7bb05012015-08-05 10:15:09 -070017
alshabibeadfc8e2015-08-18 15:40:46 -070018import com.google.common.collect.Collections2;
Pier Luigif094c612017-10-14 12:15:02 +020019import com.google.common.collect.Iterables;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070020import com.google.common.collect.Lists;
alshabibeadfc8e2015-08-18 15:40:46 -070021import com.google.common.collect.Maps;
Pier Luigif094c612017-10-14 12:15:02 +020022import org.apache.commons.lang.math.RandomUtils;
Charles Chan593acf92017-11-22 13:55:41 -080023import org.onlab.util.KryoNamespace;
alshabib7bb05012015-08-05 10:15:09 -070024import org.onosproject.cluster.ClusterService;
25import org.onosproject.cluster.NodeId;
alshabib58fe6dc2015-08-19 17:16:13 -070026import org.onosproject.mastership.MastershipService;
Jordi Ortizaa8de492016-12-01 00:21:36 +010027import org.onosproject.net.DeviceId;
Pier Luigif094c612017-10-14 12:15:02 +020028import org.onosproject.net.behaviour.MeterQuery;
29import org.onosproject.net.driver.DriverHandler;
30import org.onosproject.net.driver.DriverService;
alshabib58fe6dc2015-08-19 17:16:13 -070031import org.onosproject.net.meter.Band;
32import org.onosproject.net.meter.DefaultBand;
alshabib10c810b2015-08-18 16:59:04 -070033import org.onosproject.net.meter.DefaultMeter;
Jordi Ortiz6c847762017-01-30 17:13:05 +010034import org.onosproject.net.meter.DefaultMeterFeatures;
alshabib10c810b2015-08-18 16:59:04 -070035import org.onosproject.net.meter.Meter;
36import org.onosproject.net.meter.MeterEvent;
37import org.onosproject.net.meter.MeterFailReason;
Jordi Ortizaa8de492016-12-01 00:21:36 +010038import org.onosproject.net.meter.MeterFeatures;
cansu.toprak409289d2017-10-27 10:04:05 +030039import org.onosproject.net.meter.MeterFeaturesFlag;
Jordi Ortizaa8de492016-12-01 00:21:36 +010040import org.onosproject.net.meter.MeterFeaturesKey;
Jordi Ortiz6c847762017-01-30 17:13:05 +010041import org.onosproject.net.meter.MeterId;
alshabib70aaa1b2015-09-25 14:30:59 -070042import org.onosproject.net.meter.MeterKey;
alshabib10c810b2015-08-18 16:59:04 -070043import org.onosproject.net.meter.MeterOperation;
44import org.onosproject.net.meter.MeterState;
45import org.onosproject.net.meter.MeterStore;
46import org.onosproject.net.meter.MeterStoreDelegate;
47import org.onosproject.net.meter.MeterStoreResult;
alshabib7bb05012015-08-05 10:15:09 -070048import org.onosproject.store.AbstractStore;
Pier Luigif094c612017-10-14 12:15:02 +020049import org.onosproject.store.primitives.DefaultDistributedSet;
alshabibeadfc8e2015-08-18 15:40:46 -070050import org.onosproject.store.serializers.KryoNamespaces;
Pier Luigif094c612017-10-14 12:15:02 +020051import org.onosproject.store.service.AtomicCounterMap;
alshabib7bb05012015-08-05 10:15:09 -070052import org.onosproject.store.service.ConsistentMap;
Pier Luigif094c612017-10-14 12:15:02 +020053import org.onosproject.store.service.DistributedPrimitive;
54import org.onosproject.store.service.DistributedSet;
alshabibeadfc8e2015-08-18 15:40:46 -070055import org.onosproject.store.service.MapEvent;
56import org.onosproject.store.service.MapEventListener;
alshabib7bb05012015-08-05 10:15:09 -070057import org.onosproject.store.service.Serializer;
alshabibeadfc8e2015-08-18 15:40:46 -070058import org.onosproject.store.service.StorageException;
alshabib7bb05012015-08-05 10:15:09 -070059import org.onosproject.store.service.StorageService;
alshabibeadfc8e2015-08-18 15:40:46 -070060import org.onosproject.store.service.Versioned;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Reference;
65import org.osgi.service.component.annotations.ReferenceCardinality;
alshabib7bb05012015-08-05 10:15:09 -070066import org.slf4j.Logger;
67
68import java.util.Collection;
Gamze Abakaf57ef602019-03-11 06:52:48 +000069import java.util.List;
alshabibeadfc8e2015-08-18 15:40:46 -070070import java.util.Map;
Gamze Abakaf57ef602019-03-11 06:52:48 +000071import java.util.Objects;
Pier Luigif094c612017-10-14 12:15:02 +020072import java.util.Set;
alshabibeadfc8e2015-08-18 15:40:46 -070073import java.util.concurrent.CompletableFuture;
Pier Luigif094c612017-10-14 12:15:02 +020074import java.util.stream.Collectors;
alshabib7bb05012015-08-05 10:15:09 -070075
Thomas Vachuska52f2cd12018-11-08 21:20:04 -080076import static org.onosproject.store.meter.impl.DistributedMeterStore.ReuseStrategy.FIRST_FIT;
Jordi Ortizaa8de492016-12-01 00:21:36 +010077import static org.onosproject.net.meter.MeterFailReason.TIMEOUT;
alshabib7bb05012015-08-05 10:15:09 -070078import static org.slf4j.LoggerFactory.getLogger;
79
80/**
81 * A distributed meter store implementation. Meters are stored consistently
82 * across the cluster.
83 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084@Component(immediate = true, service = MeterStore.class)
alshabib7bb05012015-08-05 10:15:09 -070085public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreDelegate>
86 implements MeterStore {
87
88 private Logger log = getLogger(getClass());
89
90 private static final String METERSTORE = "onos-meter-store";
Jordi Ortizaa8de492016-12-01 00:21:36 +010091 private static final String METERFEATURESSTORE = "onos-meter-features-store";
Jordi Ortiz6c847762017-01-30 17:13:05 +010092 private static final String AVAILABLEMETERIDSTORE = "onos-meters-available-store";
Pier Luigif094c612017-10-14 12:15:02 +020093 private static final String METERIDSTORE = "onos-meters-id-store";
alshabib7bb05012015-08-05 10:15:09 -070094
Charles Chan593acf92017-11-22 13:55:41 -080095 private static final KryoNamespace.Builder APP_KRYO_BUILDER = KryoNamespace.newBuilder()
96 .register(KryoNamespaces.API)
97 .register(MeterKey.class)
98 .register(MeterData.class)
99 .register(DefaultMeter.class)
100 .register(DefaultBand.class)
101 .register(Band.Type.class)
102 .register(MeterState.class)
debmaiti1bea2892019-06-04 12:36:38 +0530103 .register(Meter.Unit.class)
104 .register(MeterFailReason.class);
Charles Chan593acf92017-11-22 13:55:41 -0800105
106 private Serializer serializer = Serializer.using(Lists.newArrayList(APP_KRYO_BUILDER.build()));
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7bb05012015-08-05 10:15:09 -0700109 private StorageService storageService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7bb05012015-08-05 10:15:09 -0700112 private MastershipService mastershipService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7bb05012015-08-05 10:15:09 -0700115 private ClusterService clusterService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Pier Luigif094c612017-10-14 12:15:02 +0200118 protected DriverService driverService;
119
alshabib70aaa1b2015-09-25 14:30:59 -0700120 private ConsistentMap<MeterKey, MeterData> meters;
alshabib7bb05012015-08-05 10:15:09 -0700121 private NodeId local;
alshabib7bb05012015-08-05 10:15:09 -0700122
Jordi Ortizaa8de492016-12-01 00:21:36 +0100123 private ConsistentMap<MeterFeaturesKey, MeterFeatures> meterFeatures;
124
HIGUCHI Yuta0574a552015-09-29 14:38:25 -0700125 private MapEventListener<MeterKey, MeterData> mapListener = new InternalMapEventListener();
alshabibeadfc8e2015-08-18 15:40:46 -0700126
alshabib70aaa1b2015-09-25 14:30:59 -0700127 private Map<MeterKey, CompletableFuture<MeterStoreResult>> futures =
alshabibeadfc8e2015-08-18 15:40:46 -0700128 Maps.newConcurrentMap();
alshabib7bb05012015-08-05 10:15:09 -0700129
Pier Luigif094c612017-10-14 12:15:02 +0200130 // Available meter identifiers
131 private DistributedSet<MeterKey> availableMeterIds;
132
133 // Atomic counter map for generation of new identifiers;
134 private AtomicCounterMap<DeviceId> meterIdGenerators;
135
136 /**
137 * Defines possible selection strategies to reuse meter ids.
138 */
139 enum ReuseStrategy {
140 /**
141 * Select randomly an available id.
142 */
143 RANDOM,
144 /**
145 * Select the first one.
146 */
147 FIRST_FIT
148 }
149
150 private ReuseStrategy reuseStrategy = FIRST_FIT;
Jordi Ortiz6c847762017-01-30 17:13:05 +0100151
alshabib7bb05012015-08-05 10:15:09 -0700152 @Activate
153 public void activate() {
alshabib7bb05012015-08-05 10:15:09 -0700154 local = clusterService.getLocalNode().id();
155
alshabib70aaa1b2015-09-25 14:30:59 -0700156 meters = storageService.<MeterKey, MeterData>consistentMapBuilder()
alshabib7bb05012015-08-05 10:15:09 -0700157 .withName(METERSTORE)
Charles Chan593acf92017-11-22 13:55:41 -0800158 .withSerializer(serializer).build();
alshabib7bb05012015-08-05 10:15:09 -0700159
alshabibeadfc8e2015-08-18 15:40:46 -0700160 meters.addListener(mapListener);
alshabib7bb05012015-08-05 10:15:09 -0700161
Jordi Ortizaa8de492016-12-01 00:21:36 +0100162 meterFeatures = storageService.<MeterFeaturesKey, MeterFeatures>consistentMapBuilder()
163 .withName(METERFEATURESSTORE)
Pier Luigif094c612017-10-14 12:15:02 +0200164 .withSerializer(Serializer.using(KryoNamespaces.API,
165 MeterFeaturesKey.class,
166 MeterFeatures.class,
167 DefaultMeterFeatures.class,
168 Band.Type.class,
169 Meter.Unit.class,
cansu.toprak409289d2017-10-27 10:04:05 +0300170 MeterFailReason.class,
171 MeterFeaturesFlag.class)).build();
Jordi Ortizaa8de492016-12-01 00:21:36 +0100172
Pier Luigif094c612017-10-14 12:15:02 +0200173 // Init the set of the available ids
174 availableMeterIds = new DefaultDistributedSet<>(storageService.<MeterKey>setBuilder()
Jordi Ortiz6c847762017-01-30 17:13:05 +0100175 .withName(AVAILABLEMETERIDSTORE)
Pier Luigif094c612017-10-14 12:15:02 +0200176 .withSerializer(Serializer.using(KryoNamespaces.API,
177 MeterKey.class)).build(),
178 DistributedPrimitive.DEFAULT_OPERATION_TIMEOUT_MILLIS);
179
180 // Init atomic map counters
181 meterIdGenerators = storageService.<DeviceId>atomicCounterMapBuilder()
182 .withName(METERIDSTORE)
Yuta HIGUCHI872c9822017-05-25 09:35:14 -0700183 .withSerializer(Serializer.using(KryoNamespaces.API)).build();
Jordi Ortiz6c847762017-01-30 17:13:05 +0100184
alshabib7bb05012015-08-05 10:15:09 -0700185 log.info("Started");
186 }
187
188 @Deactivate
189 public void deactivate() {
alshabibeadfc8e2015-08-18 15:40:46 -0700190 meters.removeListener(mapListener);
alshabib7bb05012015-08-05 10:15:09 -0700191 log.info("Stopped");
192 }
193
alshabib7bb05012015-08-05 10:15:09 -0700194 @Override
alshabibeadfc8e2015-08-18 15:40:46 -0700195 public CompletableFuture<MeterStoreResult> storeMeter(Meter meter) {
Pier Luigif094c612017-10-14 12:15:02 +0200196 // Init steps
alshabibeadfc8e2015-08-18 15:40:46 -0700197 CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
alshabib70aaa1b2015-09-25 14:30:59 -0700198 MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
Pier Luigif094c612017-10-14 12:15:02 +0200199 // Store the future related to the operation
alshabib70aaa1b2015-09-25 14:30:59 -0700200 futures.put(key, future);
Pier Luigif094c612017-10-14 12:15:02 +0200201 // Store the meter data
alshabibeadfc8e2015-08-18 15:40:46 -0700202 MeterData data = new MeterData(meter, null, local);
alshabibeadfc8e2015-08-18 15:40:46 -0700203 try {
alshabib70aaa1b2015-09-25 14:30:59 -0700204 meters.put(key, data);
alshabibeadfc8e2015-08-18 15:40:46 -0700205 } catch (StorageException e) {
Hwanwook Lee8206ad92018-01-02 18:03:50 +0900206 futures.remove(key);
alshabibeadfc8e2015-08-18 15:40:46 -0700207 future.completeExceptionally(e);
alshabib7bb05012015-08-05 10:15:09 -0700208 }
Pier Luigif094c612017-10-14 12:15:02 +0200209 // Done, return the future
alshabibeadfc8e2015-08-18 15:40:46 -0700210 return future;
alshabib7bb05012015-08-05 10:15:09 -0700211 }
212
213 @Override
alshabibeadfc8e2015-08-18 15:40:46 -0700214 public CompletableFuture<MeterStoreResult> deleteMeter(Meter meter) {
Pier Luigif094c612017-10-14 12:15:02 +0200215 // Init steps
alshabibeadfc8e2015-08-18 15:40:46 -0700216 CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
alshabib70aaa1b2015-09-25 14:30:59 -0700217 MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
Pier Luigif094c612017-10-14 12:15:02 +0200218 // Store the future related to the operation
alshabib70aaa1b2015-09-25 14:30:59 -0700219 futures.put(key, future);
Pier Luigif094c612017-10-14 12:15:02 +0200220 // Create the meter data
alshabibeadfc8e2015-08-18 15:40:46 -0700221 MeterData data = new MeterData(meter, null, local);
Pier Luigif094c612017-10-14 12:15:02 +0200222 // Update the state of the meter. It will be pruned by observing
alshabib7bb05012015-08-05 10:15:09 -0700223 // that it has been removed from the dataplane.
alshabibeadfc8e2015-08-18 15:40:46 -0700224 try {
Pier Luigif094c612017-10-14 12:15:02 +0200225 // If it does not exist in the system
alshabib70aaa1b2015-09-25 14:30:59 -0700226 if (meters.computeIfPresent(key, (k, v) -> data) == null) {
Pier Luigif094c612017-10-14 12:15:02 +0200227 // Complete immediately
alshabibe1248b62015-08-20 17:21:55 -0700228 future.complete(MeterStoreResult.success());
229 }
alshabibeadfc8e2015-08-18 15:40:46 -0700230 } catch (StorageException e) {
Hwanwook Lee8206ad92018-01-02 18:03:50 +0900231 futures.remove(key);
alshabibeadfc8e2015-08-18 15:40:46 -0700232 future.completeExceptionally(e);
alshabib7bb05012015-08-05 10:15:09 -0700233 }
Pier Luigif094c612017-10-14 12:15:02 +0200234 // Done, return the future
alshabibeadfc8e2015-08-18 15:40:46 -0700235 return future;
alshabib7bb05012015-08-05 10:15:09 -0700236 }
237
238 @Override
Jordi Ortizaa8de492016-12-01 00:21:36 +0100239 public MeterStoreResult storeMeterFeatures(MeterFeatures meterfeatures) {
240 MeterStoreResult result = MeterStoreResult.success();
241 MeterFeaturesKey key = MeterFeaturesKey.key(meterfeatures.deviceId());
242 try {
243 meterFeatures.putIfAbsent(key, meterfeatures);
244 } catch (StorageException e) {
245 result = MeterStoreResult.fail(TIMEOUT);
246 }
247 return result;
248 }
249
250 @Override
251 public MeterStoreResult deleteMeterFeatures(DeviceId deviceId) {
252 MeterStoreResult result = MeterStoreResult.success();
253 MeterFeaturesKey key = MeterFeaturesKey.key(deviceId);
254 try {
255 meterFeatures.remove(key);
256 } catch (StorageException e) {
257 result = MeterStoreResult.fail(TIMEOUT);
258 }
259 return result;
260 }
261
262 @Override
alshabibeadfc8e2015-08-18 15:40:46 -0700263 public CompletableFuture<MeterStoreResult> updateMeter(Meter meter) {
264 CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
alshabib70aaa1b2015-09-25 14:30:59 -0700265 MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
266 futures.put(key, future);
alshabib7bb05012015-08-05 10:15:09 -0700267
alshabibeadfc8e2015-08-18 15:40:46 -0700268 MeterData data = new MeterData(meter, null, local);
269 try {
alshabib70aaa1b2015-09-25 14:30:59 -0700270 if (meters.computeIfPresent(key, (k, v) -> data) == null) {
alshabibe1248b62015-08-20 17:21:55 -0700271 future.complete(MeterStoreResult.fail(MeterFailReason.INVALID_METER));
272 }
alshabibeadfc8e2015-08-18 15:40:46 -0700273 } catch (StorageException e) {
Hwanwook Lee8206ad92018-01-02 18:03:50 +0900274 futures.remove(key);
alshabibeadfc8e2015-08-18 15:40:46 -0700275 future.completeExceptionally(e);
alshabib7bb05012015-08-05 10:15:09 -0700276 }
alshabibeadfc8e2015-08-18 15:40:46 -0700277 return future;
alshabib7bb05012015-08-05 10:15:09 -0700278 }
279
280 @Override
281 public void updateMeterState(Meter meter) {
alshabib70aaa1b2015-09-25 14:30:59 -0700282 MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
283 meters.computeIfPresent(key, (k, v) -> {
alshabibeadfc8e2015-08-18 15:40:46 -0700284 DefaultMeter m = (DefaultMeter) v.meter();
piere6c47642020-01-08 08:57:46 +0100285 MeterState meterState = m.state();
286 if (meterState == MeterState.PENDING_ADD) {
287 m.setState(meter.state());
288 }
alshabib7bb05012015-08-05 10:15:09 -0700289 m.setProcessedPackets(meter.packetsSeen());
290 m.setProcessedBytes(meter.bytesSeen());
291 m.setLife(meter.life());
alshabibeadfc8e2015-08-18 15:40:46 -0700292 // TODO: Prune if drops to zero.
alshabib7bb05012015-08-05 10:15:09 -0700293 m.setReferenceCount(meter.referenceCount());
Gamze Abakadadae722018-09-12 10:55:35 +0000294 if (meter.referenceCount() == 0) {
295 notifyDelegate(new MeterEvent(MeterEvent.Type.METER_REFERENCE_COUNT_ZERO, m));
296 }
alshabibeadfc8e2015-08-18 15:40:46 -0700297 return new MeterData(m, null, v.origin());
alshabib7bb05012015-08-05 10:15:09 -0700298 });
299 }
300
301 @Override
alshabib70aaa1b2015-09-25 14:30:59 -0700302 public Meter getMeter(MeterKey key) {
303 MeterData data = Versioned.valueOrElse(meters.get(key), null);
alshabibeadfc8e2015-08-18 15:40:46 -0700304 return data == null ? null : data.meter();
alshabib7bb05012015-08-05 10:15:09 -0700305 }
306
307 @Override
308 public Collection<Meter> getAllMeters() {
alshabibeadfc8e2015-08-18 15:40:46 -0700309 return Collections2.transform(meters.asJavaMap().values(),
310 MeterData::meter);
alshabib7bb05012015-08-05 10:15:09 -0700311 }
312
313 @Override
Jordi Ortiz9287b632017-06-22 11:01:37 +0200314 public Collection<Meter> getAllMeters(DeviceId deviceId) {
315 return Collections2.transform(
316 Collections2.filter(meters.asJavaMap().values(),
317 (MeterData m) -> m.meter().deviceId().equals(deviceId)),
318 MeterData::meter);
319 }
320
321 @Override
alshabib7bb05012015-08-05 10:15:09 -0700322 public void failedMeter(MeterOperation op, MeterFailReason reason) {
alshabib70aaa1b2015-09-25 14:30:59 -0700323 MeterKey key = MeterKey.key(op.meter().deviceId(), op.meter().id());
324 meters.computeIfPresent(key, (k, v) ->
alshabibeadfc8e2015-08-18 15:40:46 -0700325 new MeterData(v.meter(), reason, v.origin()));
alshabib7bb05012015-08-05 10:15:09 -0700326 }
327
alshabib5eb79392015-08-19 18:09:55 -0700328 @Override
329 public void deleteMeterNow(Meter m) {
Pier Luigif094c612017-10-14 12:15:02 +0200330 // Create the key
alshabib70aaa1b2015-09-25 14:30:59 -0700331 MeterKey key = MeterKey.key(m.deviceId(), m.id());
Pier Luigif094c612017-10-14 12:15:02 +0200332 // Remove the future
alshabib70aaa1b2015-09-25 14:30:59 -0700333 futures.remove(key);
Pier Luigif094c612017-10-14 12:15:02 +0200334 // Remove the meter
piere6c47642020-01-08 08:57:46 +0100335 if (Versioned.valueOrNull(meters.remove(key)) != null) {
336 // Free the id
337 freeMeterId(m.deviceId(), m.id());
338 // Finally notify the delegate
339 notifyDelegate(new MeterEvent(MeterEvent.Type.METER_REMOVED, m));
340 }
alshabib5eb79392015-08-19 18:09:55 -0700341 }
342
Jordi Ortizaa8de492016-12-01 00:21:36 +0100343 @Override
Gamze Abakaf57ef602019-03-11 06:52:48 +0000344 public void purgeMeter(DeviceId deviceId) {
345
346 List<Versioned<MeterData>> metersPendingRemove = meters.stream()
347 .filter(e -> Objects.equals(e.getKey().deviceId(), deviceId))
348 .map(Map.Entry::getValue)
349 .collect(Collectors.toList());
350
351 metersPendingRemove.forEach(versionedMeterKey
352 -> deleteMeterNow(versionedMeterKey.value().meter()));
353
354 }
355
356 @Override
Jordi Ortizaa8de492016-12-01 00:21:36 +0100357 public long getMaxMeters(MeterFeaturesKey key) {
358 MeterFeatures features = Versioned.valueOrElse(meterFeatures.get(key), null);
359 return features == null ? 0L : features.maxMeter();
360 }
361
Pier Luigif094c612017-10-14 12:15:02 +0200362 // queryMaxMeters is implemented in FullMetersAvailable behaviour.
363 private long queryMaxMeters(DeviceId device) {
364 // Get driver handler for this device
365 DriverHandler handler = driverService.createHandler(device);
366 // If creation failed or the device does not have this behavior
367 if (handler == null || !handler.hasBehaviour(MeterQuery.class)) {
368 // We cannot know max meter
369 return 0L;
370 }
371 // Get the behavior
372 MeterQuery query = handler.behaviour(MeterQuery.class);
373 // Return as max meter the result of the query
374 return query.getMaxMeters();
375 }
376
377 private boolean updateMeterIdAvailability(DeviceId deviceId, MeterId id,
378 boolean available) {
379 // According to available, make available or unavailable a meter key
380 return available ? availableMeterIds.add(MeterKey.key(deviceId, id)) :
381 availableMeterIds.remove(MeterKey.key(deviceId, id));
382 }
383
384 private MeterId getNextAvailableId(Set<MeterId> availableIds) {
385 // If there are no available ids
386 if (availableIds.isEmpty()) {
387 // Just end the cycle
388 return null;
389 }
390 // If it is the first fit
391 if (reuseStrategy == FIRST_FIT || availableIds.size() == 1) {
392 return availableIds.iterator().next();
393 }
394 // If it is random, get the size
395 int size = availableIds.size();
396 // Return a random element
397 return Iterables.get(availableIds, RandomUtils.nextInt(size));
398 }
399
400 // Implements reuse strategy
401 private MeterId firstReusableMeterId(DeviceId deviceId) {
402 // Filter key related to device id, and reduce to meter ids
403 Set<MeterId> localAvailableMeterIds = availableMeterIds.stream()
404 .filter(meterKey -> meterKey.deviceId().equals(deviceId))
405 .map(MeterKey::meterId)
406 .collect(Collectors.toSet());
407 // Get next available id
408 MeterId meterId = getNextAvailableId(localAvailableMeterIds);
409 // Iterate until there are items
410 while (meterId != null) {
411 // If we are able to reserve the id
412 if (updateMeterIdAvailability(deviceId, meterId, false)) {
413 // Just end
414 return meterId;
415 }
416 // Update the set
417 localAvailableMeterIds.remove(meterId);
418 // Try another time
419 meterId = getNextAvailableId(localAvailableMeterIds);
420 }
421 // No reusable ids
422 return null;
423 }
424
425 @Override
426 public MeterId allocateMeterId(DeviceId deviceId) {
427 // Init steps
428 MeterId meterId;
429 long id;
430 // Try to reuse meter id
431 meterId = firstReusableMeterId(deviceId);
432 // We found a reusable id, return
433 if (meterId != null) {
434 return meterId;
435 }
436 // If there was no reusable MeterId we have to generate a new value
437 // using maxMeters as upper limit.
438 long maxMeters = getMaxMeters(MeterFeaturesKey.key(deviceId));
439 // If the device does not give us MeterFeatures
440 if (maxMeters == 0L) {
441 // MeterFeatures couldn't be retrieved, fallback to queryMeters.
442 maxMeters = queryMaxMeters(deviceId);
443 }
444 // If we don't know the max, cannot proceed
445 if (maxMeters == 0L) {
446 return null;
447 }
448 // Get a new value
449 id = meterIdGenerators.incrementAndGet(deviceId);
450 // Check with the max, and if the value is bigger, cannot proceed
451 if (id >= maxMeters) {
452 return null;
453 }
454 // Done, return the value
455 return MeterId.meterId(id);
456 }
457
458 @Override
459 public void freeMeterId(DeviceId deviceId, MeterId meterId) {
Pier Luigibdcd9672017-10-13 13:54:48 +0200460 // Avoid to free meter not allocated
461 if (meterIdGenerators.get(deviceId) < meterId.id()) {
462 return;
463 }
Pier Luigif094c612017-10-14 12:15:02 +0200464 // Update the availability
465 updateMeterIdAvailability(deviceId, meterId, true);
466 }
467
HIGUCHI Yuta0574a552015-09-29 14:38:25 -0700468 private class InternalMapEventListener implements MapEventListener<MeterKey, MeterData> {
alshabibeadfc8e2015-08-18 15:40:46 -0700469 @Override
HIGUCHI Yuta0574a552015-09-29 14:38:25 -0700470 public void event(MapEvent<MeterKey, MeterData> event) {
471 MeterKey key = event.key();
Ray Milkeyd0f017f2018-09-21 12:52:34 -0700472 Versioned<MeterData> value = event.type() == MapEvent.Type.REMOVE ? event.oldValue() : event.newValue();
473 MeterData data = value.value();
alshabibeadfc8e2015-08-18 15:40:46 -0700474 NodeId master = mastershipService.getMasterFor(data.meter().deviceId());
475 switch (event.type()) {
476 case INSERT:
477 case UPDATE:
478 switch (data.meter().state()) {
479 case PENDING_ADD:
480 case PENDING_REMOVE:
481 if (!data.reason().isPresent() && local.equals(master)) {
482 notifyDelegate(
483 new MeterEvent(data.meter().state() == MeterState.PENDING_ADD ?
484 MeterEvent.Type.METER_ADD_REQ : MeterEvent.Type.METER_REM_REQ,
485 data.meter()));
486 } else if (data.reason().isPresent() && local.equals(data.origin())) {
487 MeterStoreResult msr = MeterStoreResult.fail(data.reason().get());
488 //TODO: No future -> no friend
HIGUCHI Yuta0574a552015-09-29 14:38:25 -0700489 futures.get(key).complete(msr);
alshabibeadfc8e2015-08-18 15:40:46 -0700490 }
491 break;
492 case ADDED:
Jordi Ortizdf28ecd2017-03-25 19:22:36 +0100493 if (local.equals(data.origin()) &&
494 (data.meter().state() == MeterState.PENDING_ADD
495 || data.meter().state() == MeterState.ADDED)) {
496 futures.computeIfPresent(key, (k, v) -> {
Gamze Abaka7e65ac72019-03-05 15:40:57 +0000497 v.complete(MeterStoreResult.success());
Jordi Ortizdf28ecd2017-03-25 19:22:36 +0100498 notifyDelegate(
499 new MeterEvent(MeterEvent.Type.METER_ADDED, data.meter()));
500 return null;
501 });
alshabibe1248b62015-08-20 17:21:55 -0700502 }
503 break;
alshabibeadfc8e2015-08-18 15:40:46 -0700504 case REMOVED:
alshabib5eb79392015-08-19 18:09:55 -0700505 if (local.equals(data.origin()) && data.meter().state() == MeterState.PENDING_REMOVE) {
HIGUCHI Yuta0574a552015-09-29 14:38:25 -0700506 futures.remove(key).complete(MeterStoreResult.success());
alshabibeadfc8e2015-08-18 15:40:46 -0700507 }
508 break;
509 default:
510 log.warn("Unknown meter state type {}", data.meter().state());
511 }
512 break;
513 case REMOVE:
514 //Only happens at origin so we do not need to care.
515 break;
516 default:
517 log.warn("Unknown Map event type {}", event.type());
518 }
519
520 }
521 }
522
523
alshabib7bb05012015-08-05 10:15:09 -0700524}