/*************************************************************************
* Copyright 2009-2014 Eucalyptus Systems, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
************************************************************************/
package com.eucalyptus.cloudwatch.service.queue.listmetrics;
import com.eucalyptus.cloudwatch.common.internal.domain.listmetrics.ListMetric;
import com.eucalyptus.cloudwatch.common.internal.domain.listmetrics.ListMetricManager;
import com.eucalyptus.cloudwatch.common.internal.domain.metricdata.SimpleMetricEntity;
import com.eucalyptus.system.Threads;
import com.eucalyptus.util.metrics.MonitoredAction;
import com.eucalyptus.util.metrics.ThruputMetrics;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.log4j.Logger;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ListMetricQueue {
private static final Logger LOG = Logger.getLogger(ListMetricQueue.class);
private static class NoDupQueue<T> {
private LinkedHashSet<T> items = Sets.newLinkedHashSet();
public synchronized void drainTo(List<T> list) {
list.addAll(items);
items.clear();
}
public synchronized void drainTo(List<T> list, int maxItems) {
List<T> intermediateList = Lists.newArrayList();
int ctr=0;
for (T item: items) {
intermediateList.add(item);
ctr++;
if (ctr == maxItems) break;
}
list.addAll(intermediateList);
items.removeAll(intermediateList);
}
public synchronized void putAll(List<T> list) {
items.addAll(list);
}
public synchronized void put(T item) {
items.add(item);
}
}
final static NoDupQueue<ListMetricQueueItem> dataQueue = new NoDupQueue<ListMetricQueueItem>();
private static final ScheduledExecutorService dataFlushTimer = Executors
.newSingleThreadScheduledExecutor( Threads.threadFactory( "cloudwatch-list-metrics-flush-%d" ) );
private static ListMetricQueue singleton = getInstance();
public static ListMetricQueue getInstance() {
synchronized (ListMetricQueue.class) {
if (singleton == null)
singleton = new ListMetricQueue();
}
return singleton;
}
private void queue(ListMetricQueueItem metricData) {
dataQueue.put(metricData);
}
private static Runnable safeRunner = new Runnable() {
@Override
public void run() {
long before = System.currentTimeMillis();
try {
List<ListMetricQueueItem> dataBatch = Lists.newArrayList();
dataQueue.drainTo(dataBatch);
ThruputMetrics.addDataPoint(MonitoredAction.LIST_METRIC_SIZE, dataBatch.size( ));
long t2 = System.currentTimeMillis();
dataBatch = prune(dataBatch);
long t3 = System.currentTimeMillis();
ThruputMetrics.addDataPoint(MonitoredAction.LIST_METRIC_PRUNE, t3-t2);
List<ListMetric> listMetrics = convertToListMetrics(dataBatch);
long t4 = System.currentTimeMillis();
ThruputMetrics.addDataPoint(MonitoredAction.LIST_METRIC_CONVERT, t4-t3);
ListMetricManager.addMetricBatch(listMetrics);
long t5 = System.currentTimeMillis();
ThruputMetrics.addDataPoint(MonitoredAction.LIST_METRIC_MERTIC_ADD_BATCH, t5-t4);
} catch (Throwable ex) {
LOG.debug("ListMetricQueue:error");
ex.printStackTrace();
LOG.error(ex,ex);
} finally {
ThruputMetrics.addDataPoint(MonitoredAction.LIST_METRIC_TIMING, System.currentTimeMillis()-before);
}
}
};
private static List<ListMetric> convertToListMetrics(List<ListMetricQueueItem> dataBatch) {
if (dataBatch == null) return null;
List<ListMetric> listMetrics = Lists.newArrayList();
for (ListMetricQueueItem item: dataBatch) {
listMetrics.add(ListMetricManager.createListMetric(item.getAccountId(), item.getMetricName(), item.getMetricType(),
item.getNamespace(), item.getDimensionMap()));
}
return listMetrics;
}
private static List<ListMetricQueueItem> prune(List<ListMetricQueueItem> dataBatch) {
Set<ListMetricQueueItem> intermediateSet = Sets.newLinkedHashSet(dataBatch);
List<ListMetricQueueItem> prunedList = Lists.newArrayList(intermediateSet);
return prunedList;
}
static {
dataFlushTimer.scheduleAtFixedRate(safeRunner, 0, 5, TimeUnit.MINUTES);
}
public void addAll(List<SimpleMetricEntity> dataBatch) {
for (SimpleMetricEntity item: dataBatch) {
ListMetricQueueItem metricMetadata = new ListMetricQueueItem();
metricMetadata.setAccountId(item.getAccountId());
metricMetadata.setNamespace(item.getNamespace());
metricMetadata.setMetricName(item.getMetricName());
metricMetadata.setDimensionMap(item.getDimensionMap());
metricMetadata.setMetricType(item.getMetricType());
queue(metricMetadata);
}
}
}