9306514ad05543087676a01eb3bc3230d67090cb
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
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.policy.drools.apps.controlloop.feature.trans;
22
23 import com.google.common.cache.CacheBuilder;
24 import com.google.common.cache.CacheLoader;
25 import com.google.common.cache.LoadingCache;
26 import com.google.common.cache.RemovalListener;
27 import com.google.common.cache.RemovalNotification;
28 import java.time.ZonedDateTime;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Properties;
32 import java.util.UUID;
33 import java.util.concurrent.TimeUnit;
34 import org.onap.policy.controlloop.VirtualControlLoopNotification;
35 import org.onap.policy.drools.persistence.SystemPersistence;
36 import org.onap.policy.drools.system.PolicyController;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Control Loop Metrics Tracker
42  */
43 public interface ControlLoopMetrics {
44
45     /**
46      * gets all transaction identifiers being monitored
47      *
48      * @return transaction id list
49      */
50     List<UUID> getTransactionIds();
51
52     /**
53      * gets all detailed transactions
54      *
55      * @return list of transactions
56      */
57     List<VirtualControlLoopNotification> getTransactions();
58
59     /**
60      * track controller's notification events
61      *
62      * @param controller policy controller sending out notification
63      * @param notification notification
64      */
65     void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification);
66
67     /**
68      * gets an in-progress transaction
69      *
70      * @param requestId request ID
71      * @return in progress notification
72      */
73     VirtualControlLoopNotification getTransaction(UUID requestId);
74
75     /**
76      * removes an in-progress transaction
77      *
78      * @param requestId request ID
79      * @return in progress notification
80      */
81     void removeTransaction(UUID requestId);
82
83     /**
84      * get cache size
85      *
86      * @return cache size
87      */
88     long getCacheSize();
89
90     /**
91      * get cache size
92      *
93      * @return cache size
94      */
95     long getCacheOccupancy();
96
97     /**
98      * sets cache size
99      *
100      * @param cacheSize cache size
101      */
102     void setMaxCacheSize(long cacheSize);
103
104     /**
105      * cached transaction expiration timeout in seconds
106      *
107      * @return transaction timeout in seconds
108      */
109     long getTransactionTimeout();
110
111     /**
112      * sets transaction timeout in seconds
113      *
114      * @param transactionTimeout transaction timeout in seconds
115      */
116     void setTransactionTimeout(long transactionTimeout);
117
118     /**
119      * reset cache
120      *
121      * @param cacheSize new cache size
122      * @param transactionTimeout new transaction timeout in seconds
123      */
124     void resetCache(long cacheSize, long transactionTimeout);
125
126     /**
127      * refresh underlying transaction management
128      */
129     void refresh();
130
131     /**
132      * singleton manager object
133      */
134     ControlLoopMetrics manager = new CacheBasedControlLoopMetricsManager();
135 }
136
137 /**
138  * Control Loop Metrics Tracker Implementation
139  */
140 class CacheBasedControlLoopMetricsManager implements ControlLoopMetrics {
141
142     private static final Logger logger = LoggerFactory.getLogger(CacheBasedControlLoopMetricsManager.class);
143
144     private LoadingCache<UUID, VirtualControlLoopNotification> cache;
145     private long cacheSize = ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT;
146
147     private long transactionTimeout = ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT;
148
149     public CacheBasedControlLoopMetricsManager() {
150
151         Properties properties =
152             SystemPersistence.manager.getProperties(ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME);
153
154         /* cache size */
155
156         try {
157             this.cacheSize =
158                 Long.parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY,
159                     "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT));
160         } catch (Exception e) {
161             logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
162                 ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY, e);
163         }
164
165         /* transaction timeout */
166
167         try {
168             this.transactionTimeout =
169                 Long.parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY,
170                     "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT));
171         } catch (Exception e) {
172             logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
173                 ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY, e);
174         }
175
176         resetCache(this.cacheSize, this.transactionTimeout);
177     }
178
179     @Override
180     public void resetCache(long cacheSize, long transactionTimeout) {
181         this.cacheSize = cacheSize;
182         this.transactionTimeout = transactionTimeout;
183
184         CacheLoader<UUID, VirtualControlLoopNotification> loader = new CacheLoader<UUID, VirtualControlLoopNotification>() {
185
186             @Override
187             public VirtualControlLoopNotification load(UUID key) throws Exception {
188                 return null;
189             }
190         };
191
192         RemovalListener<UUID, VirtualControlLoopNotification> listener = new RemovalListener<UUID, VirtualControlLoopNotification>() {
193             @Override
194             public void onRemoval(RemovalNotification<UUID, VirtualControlLoopNotification> notification) {
195                 if (notification.wasEvicted()) {
196                     evicted(notification.getValue());
197                 } else {
198                     logger.info("REMOVAL: {}->{} from {} because of {}", notification.getValue().getFrom(),
199                         notification.getValue(), notification.getCause().name());
200                 }
201             }
202         };
203
204         synchronized (this) {
205             if (this.cache != null) {
206                 this.cache.cleanUp();
207                 this.cache.invalidateAll();
208             }
209
210             this.cache = CacheBuilder.newBuilder().
211                 maximumSize(this.cacheSize).expireAfterWrite(transactionTimeout, TimeUnit.SECONDS).
212                 removalListener(listener).build(loader);
213         }
214     }
215
216     @Override
217     public void refresh() {
218         this.cache.cleanUp();
219     }
220
221     @Override
222     public List<UUID> getTransactionIds() {
223         return new ArrayList<>(this.cache.asMap().keySet());
224     }
225
226     @Override
227     public List<VirtualControlLoopNotification> getTransactions() {
228         return new ArrayList<>(this.cache.asMap().values());
229     }
230
231     @Override
232     public void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification) {
233         if (notification == null || notification.getRequestID() == null || notification.getNotification() == null) {
234             logger.warn("Invalid notification: {}", notification);
235             return;
236         }
237
238         if (notification.getNotificationTime() == null) {
239             notification.setNotificationTime(ZonedDateTime.now());
240         }
241
242         notification.setFrom(notification.getFrom() + ":" + controller.getName());
243
244         this.metric(notification);
245
246         switch (notification.getNotification()) {
247             case REJECTED:
248             case FINAL_FAILURE:
249             case FINAL_SUCCESS:
250             case FINAL_OPENLOOP:
251                 endTransaction(notification);
252                 break;
253             default:
254                 /* any other value is an in progress transaction */
255                 inProgressTransaction(notification);
256                 break;
257         }
258     }
259
260     @Override
261     public VirtualControlLoopNotification getTransaction(UUID requestId) {
262         return cache.getIfPresent(requestId);
263     }
264
265     @Override
266     public void removeTransaction(UUID requestId) {
267         cache.invalidate(requestId);
268     }
269
270     /**
271      * tracks an in progress control loop transaction
272      *
273      * @param notification control loop notification
274      */
275     protected void inProgressTransaction(VirtualControlLoopNotification notification) {
276         if (cache.getIfPresent(notification.getRequestID()) == null) {
277             cache.put(notification.getRequestID(), notification);
278         }
279     }
280
281     /**
282      * end of a control loop transaction
283      *
284      * @param notification control loop notification
285      */
286     protected void endTransaction(VirtualControlLoopNotification notification) {
287         ZonedDateTime startTime;
288         VirtualControlLoopNotification startNotification = cache.getIfPresent(notification.getRequestID());
289         if (startNotification != null) {
290             startTime = startNotification.getNotificationTime();
291         } else {
292             startTime = notification.getNotificationTime();
293         }
294
295         this.transaction(notification, startTime);
296
297         cache.invalidate(startNotification);
298     }
299
300     protected void evicted(VirtualControlLoopNotification notification) {
301         transaction(notification, ZonedDateTime.now());
302     }
303
304     @Override
305     public long getCacheSize() {
306         return this.cacheSize;
307     }
308
309     @Override
310     public void setMaxCacheSize(long cacheSize) {
311         this.cacheSize = cacheSize;
312     }
313
314     @Override
315     public long getTransactionTimeout() {
316         return this.transactionTimeout;
317     }
318
319     @Override
320     public void setTransactionTimeout(long transactionTimeout) {
321         this.transactionTimeout = transactionTimeout;
322     }
323
324     @Override
325     public long getCacheOccupancy() {
326         return this.cache.size();
327     }
328
329     protected void metric(VirtualControlLoopNotification notification) {
330         // TODO: next review
331         // set up MDC
332         // logger.info(LoggerUtil.METRIC_LOG_MARKER, "METRIC:{}", notification);
333     }
334
335     protected void transaction(VirtualControlLoopNotification notification, ZonedDateTime startTime) {
336         // TODO: next review
337         // set up MDC
338         // Duration.between(notification.getNotificationTime(), ZonedDateTime.now()).toMillis())
339         // logger.info(LoggerUtil.TRANSACTION_LOG_MARKER, "TRANSACTION:{}->{} {} ms.", notification.getRequestID(), notification,
340         //  durationMs);
341     }
342
343     @Override
344     public String toString() {
345         final StringBuffer sb = new StringBuffer("CacheBasedControlLoopMetricsManager{");
346         sb.append("cacheSize=").append(cacheSize);
347         sb.append(", transactionTimeout=").append(transactionTimeout);
348         sb.append('}');
349         return sb.toString();
350     }
351 }