1 /*******************************************************************************
2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2022 Huawei Canada Limited.
6 * ==============================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
20 *******************************************************************************/
21 package org.onap.slice.analysis.ms.service.ccvpn;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25 import org.springframework.stereotype.Component;
27 import java.util.ArrayDeque;
29 import java.util.Queue;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentMap;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34 import java.util.stream.Collectors;
37 * This class represents the data structure for storing the CCVPN pm data;
40 public class CCVPNPmDatastore {
42 private static Logger log = LoggerFactory.getLogger(CCVPNPmDatastore.class);
43 private static final Pattern pattern = Pattern.compile("([0-9.]+)\\s*(kb|Kb|mb|Mb|Gb|gb)*");
44 private static final int WINDOW_SIZE = 5;
45 private final ConcurrentMap<String, ServiceState> svcStatus = new ConcurrentHashMap<>();
46 private final ConcurrentMap<String, Integer> endpointToMaxBw = new ConcurrentHashMap<>();
47 private final ConcurrentMap<Endpointkey, EvictingQueue<Integer>> endpointToUsedBw = new ConcurrentHashMap<>();
50 * Given a cllId, return a map between Endpointkey and their corresponding UsedBw Queue.
51 * All Endpoints belongs to this same service
52 * @param cllId target cll instance id
53 * @return a filtered map contains used bandwidth data of endpointkeys whose cllId equals to the given one.
55 public Map<Endpointkey, EvictingQueue<Integer>> getUsedBwOfSvc(String cllId){
56 return endpointToUsedBw.entrySet().stream()
57 .filter(map -> map.getKey().getCllId() == cllId)
58 .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue()));
62 * Return the complete used bandwidth map.
63 * @return a complete endpoint to bandwidth data map
65 public Map<Endpointkey, EvictingQueue<Integer>> getUsedBwMap(){
66 return endpointToUsedBw;
70 * Return max bandwidth of cll service. If max bandwidth is null or missing, return 0;
71 * @param cllId target cll instance id
72 * @return Integer bandwidth value
74 public Integer getMaxBwOfSvc(String cllId){
75 return endpointToMaxBw.getOrDefault(cllId, 0);
79 * Get Service status of this cll service
80 * @param cllId target cll instance id
81 * @return ServiceState of this cll
83 public ServiceState getStatusOfSvc(String cllId){
84 return svcStatus.getOrDefault(cllId, ServiceState.UNKNOWN);
88 * return the complete map of cll service status
89 * @return complete map of serviceStatusMap
91 public ConcurrentMap<String, ServiceState> getSvcStatusMap(){
96 * Override the service status to provided state
97 * @param cllId target cll instance id
98 * @param state new state
100 public void updateSvcState(String cllId, ServiceState state){
101 svcStatus.put(cllId, state);
105 * Update max bandwidth value to given bandwidth string
106 * @param cllId target cll instance id
107 * @param bw new bandwidth
109 public void updateMaxBw(String cllId, String bw){
110 double bwvvaldb = Double.parseDouble(bw);
111 int bwvval = (int) bwvvaldb;
112 updateMaxBw(cllId, bwvval, false);
116 * Update max bandwidth to given bandwidth value;
117 * if @param{override} is false, only write the bandwidth if it is absent.
118 * Otherwise override the old value no matter if it exists or not
119 * Also, when @param{override} is true, compare the provided value with the old value, if equals, return false;
120 * otherwise, return true;
121 * @param cllId target cll instance id
122 * @param bw new bandwidth int value in Mbps
123 * @param override override old value or not
124 * @return whether bandwidth value is changed or not.
126 public boolean updateMaxBw(String cllId, int bw, boolean override){
128 if ( endpointToMaxBw.putIfAbsent(cllId, bw) == null || !override){
131 if (endpointToMaxBw.get(cllId) == bw){
134 endpointToMaxBw.replace(cllId, bw);
141 * Append the latest bandwidth data to associated endpoint
142 * @param cllId target cll instance id
143 * @param uniId target uni id
144 * @param bw latest bandwidth usage data
146 public void addUsedBwToEndpoint(String cllId, String uniId, String bw){
147 Endpointkey enk = new Endpointkey(cllId, uniId);
148 Matcher matcher = pattern.matcher(bw.trim());
149 //Default input bw unit is kbps;
153 if (matcher.find()) {
154 unit = matcher.group(2);
155 if (unit == null || unit.isEmpty() || unit.toLowerCase().equals("kb")) {
156 double val = Double.parseDouble(matcher.group(1));
157 result = (int) Math.ceil((double) val / (int) 1000 ) ;
158 } else if (unit.toLowerCase().equals("mb")){
159 double val = Double.parseDouble(matcher.group(1));
161 } else if (unit.toLowerCase().equals("gb")){
162 double val = Double.parseDouble(matcher.group(1));
163 result = (int) val * (int) 1000;
166 log.warn("Illigal bw string: " + bw);
169 EvictingQueue<Integer> dataq = new EvictingQueue<Integer>(WINDOW_SIZE);
171 EvictingQueue q = endpointToUsedBw.putIfAbsent(enk, dataq);
179 * Copy the used bandwidth queue of specified cllId:uniId to an array and return;
180 * @param cllId target cll id
181 * @param uniId target uni id
182 * @return Object[] contains all the used bandwidth data
184 public Object[] readToArray(String cllId, String uniId){
185 return endpointToUsedBw.get(new Endpointkey(cllId, uniId)).tryReadToArray();
189 * Inner data structure is logically similar to circular buffer, thread-safe through blocking
190 * @param <E> Generic type of data
192 public class EvictingQueue<E> {
193 private final Queue<E> delegate;
197 * Constructor accept a maxsize param
198 * @param maxSize max size
200 EvictingQueue(int maxSize){
202 throw new IllegalArgumentException("Invalid maxsize for initializing EvictingQueue");
204 this.delegate = new ArrayDeque<>(maxSize);
205 this.maxSize = maxSize;
209 * Adding new data to this queue
213 public synchronized boolean offer(E e){
218 * Try copy data to an array and return, only if data has filled up the whole queue
219 * Otherwise, return null
220 * @return the data array
222 public synchronized Object[] tryReadToArray(){
223 if (remainingCapacity() > 0){
230 * Return the size of this queue, and number of data added. It is no larger than the max capacity.
231 * @return int value of output
234 return delegate.size();
238 * return the remaining capacity of this queue
239 * @return int value of output
241 public int remainingCapacity(){
242 return maxSize - size();
245 private Object[] toArray(){
246 return delegate.toArray();
249 private boolean add(E e){
251 throw new IllegalArgumentException("Invalid new item in add method");
256 if (size() == maxSize){