All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.phoenix.monitoring.ReadMetricQueue Maven / Gradle / Ivy

There is a newer version: 4.15.0-HBase-1.5
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.apache.phoenix.monitoring;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;

import javax.annotation.Nonnull;

import org.apache.phoenix.log.LogLevel;
import org.apache.phoenix.monitoring.CombinableMetric.NoOpRequestMetric;

import com.google.common.annotations.VisibleForTesting;

/**
 * Queue of all metrics associated with performing reads from the cluster.
 */
public class ReadMetricQueue {

    private static final int MAX_QUEUE_SIZE = 20000; // TODO: should this be configurable?

    private final ConcurrentMap> metricsMap = new ConcurrentHashMap<>();

    private final List scanMetricsHolderList = new ArrayList();


    private LogLevel connectionLogLevel;

    private boolean isRequestMetricsEnabled;

    public ReadMetricQueue(boolean isRequestMetricsEnabled, LogLevel connectionLogLevel) {
        this.isRequestMetricsEnabled = isRequestMetricsEnabled;
        this.connectionLogLevel = connectionLogLevel;
    }

    public CombinableMetric allotMetric(MetricType type, String tableName) {
        if (type.isLoggingEnabled(connectionLogLevel) || isRequestMetricsEnabled) {
            MetricKey key = new MetricKey(type, tableName);
            Queue q = getMetricQueue(key);
            CombinableMetric metric = getMetric(type);
            q.offer(metric);
            return metric;
        } else {
            return NoOpRequestMetric.INSTANCE;
        }
    }

    @VisibleForTesting
    public CombinableMetric getMetric(MetricType type) {
        CombinableMetric metric = new CombinableMetricImpl(type);
        return metric;
    }

    /**
     * @return map of table name -> list of pair of (metric name, metric value)
     */
    public Map> aggregate() {
        Map> publishedMetrics = new HashMap<>();
        for (Entry> entry : metricsMap.entrySet()) {
            String tableNameToPublish = entry.getKey().tableName;
            Collection metrics = entry.getValue();
            if (metrics.size() > 0) {
                CombinableMetric m = combine(metrics);
                Map map = publishedMetrics.get(tableNameToPublish);
                if (map == null) {
                    map = new HashMap<>();
                    publishedMetrics.put(tableNameToPublish, map);
                }
                map.put(m.getMetricType(), m.getValue());
            }
        }
        return publishedMetrics;
    }

    public void clearMetrics() {
        metricsMap.clear(); // help gc
    }

    private static CombinableMetric combine(Collection metrics) {
        int size = metrics.size();
        if (size == 0) { throw new IllegalArgumentException("Metrics collection needs to have at least one element"); }
        Iterator itr = metrics.iterator();
        //Clone first metric for combining so that aggregate always give consistent result
        CombinableMetric combinedMetric = itr.next().clone();
        while (itr.hasNext()) {
            combinedMetric = combinedMetric.combine(itr.next());
        }
        return combinedMetric;
    }

    /**
     * Combine the metrics. This method should only be called in a single threaded manner when the two metric holders
     * are not getting modified.
     */
    public ReadMetricQueue combineReadMetrics(ReadMetricQueue other) {
        ConcurrentMap> otherMetricsMap = other.metricsMap;
        for (Entry> entry : otherMetricsMap.entrySet()) {
            MetricKey key = entry.getKey();
            Queue otherQueue = entry.getValue();
            CombinableMetric combinedMetric = null;
            // combine the metrics corresponding to this metric key before putting it in the queue.
            for (CombinableMetric m : otherQueue) {
                if (combinedMetric == null) {
                    combinedMetric = m;
                } else {
                    combinedMetric.combine(m);
                }
            }
            if (combinedMetric != null) {
                Queue thisQueue = getMetricQueue(key);
                thisQueue.offer(combinedMetric);
            }
        }
        return this;
    }

    /**
     * Inner class whose instances are used as keys in the metrics map.
     */
    private static class MetricKey {
        @Nonnull
        private final MetricType type;

        @Nonnull
        private final String tableName;

        MetricKey(MetricType type, String tableName) {
            checkNotNull(type);
            checkNotNull(tableName);
            this.type = type;
            this.tableName = tableName;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + tableName.hashCode();
            result = prime * result + type.hashCode();
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null) return false;
            if (getClass() != obj.getClass()) return false;
            MetricKey other = (MetricKey)obj;
            if (tableName.equals(other.tableName) && type == other.type) return true;
            return false;
        }

    }

    private Queue getMetricQueue(MetricKey key) {
        Queue q = metricsMap.get(key);
        if (q == null) {
            q = new LinkedBlockingQueue(MAX_QUEUE_SIZE);
            Queue curQ = metricsMap.putIfAbsent(key, q);
            if (curQ != null) {
                q = curQ;
            }
        }
        return q;
    }

    public void addScanHolder(ScanMetricsHolder holder){
        scanMetricsHolderList.add(holder);
    }

    public List getScanMetricsHolderList() {
        return scanMetricsHolderList;
    }
    
    public boolean isRequestMetricsEnabled() {
        return isRequestMetricsEnabled;
    }    

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy