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 // Provisioned bandwidth of each endpoint
47 private final ConcurrentMap<String, Integer> endpointToProvBw = new ConcurrentHashMap<>();
48 // Max bandwidth (upper-bound) of each endpoint
49 private final ConcurrentMap<String, Integer> upperBoundBw = new ConcurrentHashMap<>();
50 // Current bandwidth usage data list from customers
51 private final ConcurrentMap<Endpointkey, EvictingQueue<Integer>> endpointToUsedBw = new ConcurrentHashMap<>();
54 * Given a cllId, return a map between Endpointkey and their corresponding UsedBw Queue.
55 * All Endpoints belongs to this same service
56 * @param cllId target cll instance id
57 * @return a filtered map contains used bandwidth data of endpointkeys whose cllId equals to the given one.
59 public Map<Endpointkey, EvictingQueue<Integer>> getUsedBwOfSvc(String cllId){
60 return endpointToUsedBw.entrySet().stream()
61 .filter(map -> map.getKey().getCllId() == cllId)
62 .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue()));
66 * Return the complete used bandwidth map.
67 * @return a complete endpoint to bandwidth data map
69 public Map<Endpointkey, EvictingQueue<Integer>> getUsedBwMap(){
70 return endpointToUsedBw;
74 * Return provisioned bandwidth of cll service. If provisioned bandwidth is null or missing, return 0;
75 * @param cllId target cll instance id
76 * @return Integer bandwidth value
78 public Integer getProvBwOfSvc(String cllId){
79 return endpointToProvBw.getOrDefault(cllId, 0);
83 * Get Service status of this cll service
84 * @param cllId target cll instance id
85 * @return ServiceState of this cll
87 public ServiceState getStatusOfSvc(String cllId){
88 return svcStatus.getOrDefault(cllId, ServiceState.UNKNOWN);
91 public Integer getUpperBoundBwOfSvc(String cllId){
92 return upperBoundBw.getOrDefault(cllId, Integer.MAX_VALUE);
96 * return the complete map of cll service status
97 * @return complete map of serviceStatusMap
99 public ConcurrentMap<String, ServiceState> getSvcStatusMap(){
104 * Override the service status to provided state
105 * @param cllId target cll instance id
106 * @param state new state
108 public void updateSvcState(String cllId, ServiceState state){
109 svcStatus.put(cllId, state);
113 * Update provisioned bandwidth value to given bandwidth string
114 * @param cllId target cll instance id
115 * @param bw new bandwidth
117 public void updateProvBw(String cllId, String bw){
118 double bwvvaldb = Double.parseDouble(bw);
119 int bwvval = (int) bwvvaldb;
120 updateProvBw(cllId, bwvval, false);
124 * Update upper bound bandwidth value to given bandwidth
125 * @param cllId target cll instance id
126 * @param bw new bandwidth
128 public void updateUpperBoundBw(String cllId, int bw){
129 upperBoundBw.put(cllId, bw);
133 * Update provisioned bandwidth to given bandwidth value;
134 * if @param{override} is false, only write the bandwidth if it is absent.
135 * Otherwise override the old value no matter if it exists or not
136 * Also, when @param{override} is true, compare the provided value with the old value, if equals, return false;
137 * otherwise, return true;
138 * @param cllId target cll instance id
139 * @param bw new bandwidth int value in Mbps
140 * @param override override old value or not
141 * @return whether bandwidth value is changed or not.
143 public boolean updateProvBw(String cllId, int bw, boolean override){
144 if (!override && !endpointToProvBw.containsKey(cllId)){
145 endpointToProvBw.put(cllId, bw);
148 if (endpointToProvBw.get(cllId) == bw){
151 endpointToProvBw.replace(cllId, bw);
158 * Append the latest bandwidth data to associated endpoint
159 * @param cllId target cll instance id
160 * @param uniId target uni id
161 * @param bw latest bandwidth usage data
163 public void addUsedBwToEndpoint(String cllId, String uniId, String bw){
164 Endpointkey enk = new Endpointkey(cllId, uniId);
165 Matcher matcher = pattern.matcher(bw.trim());
166 //Default input bw unit is kbps;
170 if (matcher.find()) {
171 unit = matcher.group(2);
172 if (unit == null || unit.isEmpty() || unit.toLowerCase().equals("kb")) {
173 double val = Double.parseDouble(matcher.group(1));
174 result = (int) Math.ceil((double) val / (int) 1000 ) ;
175 } else if (unit.toLowerCase().equals("mb")){
176 double val = Double.parseDouble(matcher.group(1));
178 } else if (unit.toLowerCase().equals("gb")){
179 double val = Double.parseDouble(matcher.group(1));
180 result = (int) val * (int) 1000;
183 log.warn("Illigal bw string: " + bw);
186 endpointToUsedBw.computeIfAbsent(enk, k -> new EvictingQueue<Integer>(WINDOW_SIZE)).offer(result);
190 * Copy the used bandwidth queue of specified cllId:uniId to an array and return;
191 * @param cllId target cll id
192 * @param uniId target uni id
193 * @return Object[] contains all the used bandwidth data
195 public Object[] readToArray(String cllId, String uniId){
196 return endpointToUsedBw.get(new Endpointkey(cllId, uniId)).tryReadToArray();
200 * Inner data structure is logically similar to circular buffer, thread-safe through blocking
201 * @param <E> Generic type of data
203 public class EvictingQueue<E> {
204 private final Queue<E> delegate;
208 * Constructor accept a maxsize param
209 * @param maxSize max size
211 EvictingQueue(int maxSize){
213 throw new IllegalArgumentException("Invalid maxsize for initializing EvictingQueue");
215 this.delegate = new ArrayDeque<>(maxSize);
216 this.maxSize = maxSize;
220 * Adding new data to this queue
224 public synchronized boolean offer(E e){
229 * Try copy data to an array and return, only if data has filled up the whole queue
230 * Otherwise, return null
231 * @return the data array
233 public synchronized Object[] tryReadToArray(){
234 if (remainingCapacity() > 0){
241 * Return the size of this queue, and number of data added. It is no larger than the max capacity.
242 * @return int value of output
245 return delegate.size();
249 * return the remaining capacity of this queue
250 * @return int value of output
252 public int remainingCapacity(){
253 return maxSize - size();
256 private Object[] toArray(){
257 return delegate.toArray();
260 private boolean add(E e){
262 throw new IllegalArgumentException("Invalid new item in add method");
267 if (size() == maxSize){