9c86f6e7adbc10ff76ec47833e64019207cf16e4
[dcaegen2/services.git] /
1 /*******************************************************************************
2  *  ============LICENSE_START=======================================================
3  *  slice-analysis-ms
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
10  *
11  *          http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  *
20  *******************************************************************************/
21 package org.onap.slice.analysis.ms.service.ccvpn;
22
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25 import org.springframework.stereotype.Component;
26
27 import java.util.ArrayDeque;
28 import java.util.Map;
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;
35
36 /**
37  * This class represents the data structure for storing the CCVPN pm data;
38  */
39 @Component
40 public class CCVPNPmDatastore {
41
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<>();
48
49     /**
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.
54      */
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()));
59     }
60
61     /**
62      * Return the complete used bandwidth map.
63      * @return a complete endpoint to bandwidth data map
64      */
65     public Map<Endpointkey, EvictingQueue<Integer>> getUsedBwMap(){
66         return endpointToUsedBw;
67     }
68
69     /**
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
73      */
74     public Integer getMaxBwOfSvc(String cllId){
75         return endpointToMaxBw.getOrDefault(cllId, 0);
76     }
77
78     /**
79      * Get Service status of this cll service
80      * @param cllId target cll instance id
81      * @return ServiceState of this cll
82      */
83     public ServiceState getStatusOfSvc(String cllId){
84         return svcStatus.getOrDefault(cllId, ServiceState.UNKNOWN);
85     }
86
87     /**
88      * return the complete map of cll service status
89      * @return complete map of serviceStatusMap
90      */
91     public ConcurrentMap<String, ServiceState> getSvcStatusMap(){
92         return svcStatus;
93     }
94
95     /**
96      * Override the service status to provided state
97      * @param cllId target cll instance id
98      * @param state new state
99      */
100     public void updateSvcState(String cllId, ServiceState state){
101         svcStatus.put(cllId, state);
102     }
103
104     /**
105      * Update max bandwidth value to given bandwidth string
106      * @param cllId target cll instance id
107      * @param bw new bandwidth
108      */
109     public void updateMaxBw(String cllId, String bw){
110         double bwvvaldb = Double.parseDouble(bw);
111         int bwvval = (int) bwvvaldb;
112         updateMaxBw(cllId, bwvval, false);
113     }
114
115     /**
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.
125      */
126     public boolean updateMaxBw(String cllId, int bw, boolean override){
127         ;
128         if ( endpointToMaxBw.putIfAbsent(cllId, bw) == null || !override){
129             return true;
130         } else {
131             if (endpointToMaxBw.get(cllId) == bw){
132                 return false;
133             } else {
134                 endpointToMaxBw.replace(cllId, bw);
135                 return true;
136             }
137         }
138     }
139
140     /**
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
145      */
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;
150         String unit = null;
151         // Bw in Mbps;
152         int result = 0;
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));
160                 result = (int) val ;
161             } else if (unit.toLowerCase().equals("gb")){
162                 double val = Double.parseDouble(matcher.group(1));
163                 result = (int) val * (int) 1000;
164             }
165         } else {
166             log.warn("Illigal bw string: " + bw);
167         }
168
169         EvictingQueue<Integer> dataq = new EvictingQueue<Integer>(WINDOW_SIZE);
170         dataq.offer(result);
171         EvictingQueue q = endpointToUsedBw.putIfAbsent(enk, dataq);
172         if (q != null) {
173             q.offer(result);
174         }
175
176     }
177
178     /**
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
183      */
184     public Object[] readToArray(String cllId, String uniId){
185         return endpointToUsedBw.get(new Endpointkey(cllId, uniId)).tryReadToArray();
186     }
187
188     /**
189      * Inner data structure is logically similar to circular buffer, thread-safe through blocking
190      * @param <E> Generic type of data
191      */
192     public class EvictingQueue<E> {
193         private final Queue<E> delegate;
194         final int maxSize;
195
196         /**
197          * Constructor accept a maxsize param
198          * @param maxSize max size
199          */
200         EvictingQueue(int maxSize){
201             if (maxSize < 0){
202                 throw new IllegalArgumentException("Invalid maxsize for initializing EvictingQueue");
203             }
204             this.delegate = new ArrayDeque<>(maxSize);
205             this.maxSize = maxSize;
206         }
207
208         /**
209          * Adding new data to this queue
210          * @param e new data
211          * @return true
212          */
213         public synchronized boolean offer(E e){
214             return add(e);
215         }
216
217         /**
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
221          */
222         public synchronized Object[] tryReadToArray(){
223             if (remainingCapacity() > 0){
224                 return null;
225             }
226             return toArray();
227         }
228
229         /**
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
232          */
233         public int size(){
234             return delegate.size();
235         }
236
237         /**
238          * return the remaining capacity of this queue
239          * @return int value of output
240          */
241         public int remainingCapacity(){
242             return maxSize - size();
243         }
244
245         private Object[] toArray(){
246             return delegate.toArray();
247         }
248
249         private boolean add(E e){
250             if(null == e){
251                 throw new IllegalArgumentException("Invalid new item in add method");
252             }
253             if (maxSize == 0){
254                 return true;
255             }
256             if (size() == maxSize){
257                 delegate.remove();
258             }
259             delegate.add(e);
260             return true;
261         }
262     }
263 }