net.opentsdb.catalog.cache.TSMetaCache.java Source code

Java tutorial

Introduction

Here is the source code for net.opentsdb.catalog.cache.TSMetaCache.java

Source

/**
 * Helios, OpenSource Monitoring
 * Brought to you by the Helios Development Group
 *
 * Copyright 2007, Helios Development Group and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 
 *
 */
package net.opentsdb.catalog.cache;

import java.sql.Connection;
import java.util.List;

import javax.management.ObjectName;

import net.opentsdb.catalog.MetaReader;
import net.opentsdb.catalog.SQLWorker;
import net.opentsdb.catalog.TSDBCachedRowSetImpl;
import net.opentsdb.meta.TSMeta;

import org.helios.jmx.util.helpers.ConfigurationHelper;
import org.helios.tsdb.plugins.cache.CacheStatistics;
import org.helios.tsdb.plugins.util.JMXHelper;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.Callables;

/**
 * <p>Title: TSMetaCache</p>
 * <p>Description: An LRU cache for TSMeta decodes</p> 
 * <p>Company: Helios Development Group LLC</p>
 * @author Whitehead (nwhitehead AT heliosdev DOT org)
 * <p><code>net.opentsdb.catalog.cache.TSMetaCache</code></p>
 */

public class TSMetaCache {
    /** A SQLWorker to execute lookups and inserts */
    protected final SQLWorker sqlWorker;
    /** The underlying guava cache of TSMetas keyed by the TSUID */
    protected final Cache<String, TSMeta> cache;
    /** The cache stats ObjectName if stats are enabled */
    protected final ObjectName objectName;
    /** The meta-reader */
    protected final MetaReader metaReader;
    /** The configuration property name for the maximum size of the cache */
    public static final String MAX_SIZE_PROP = "helios.search.catalog.tsmetacache.maxsize";
    /** The configuration property name for the concurrency of the cache */
    public static final String CONCURRENCY_PROP = "helios.search.catalog.tsmetacache.concurrency";
    /** The configuration property name for the stats enablement of the cache */
    public static final String STATS_ENABLED_PROP = "helios.search.catalog.tsmetacache.stats";

    /** The default maximum size of the cache */
    public static final long DEFAULT_MAX_SIZE = 1000;
    /** The default concurrency of the cache */
    public static final int DEFAULT_CONCURRENCY = 4;
    /** The default stats enablement of the cache */
    public static final boolean DEFAULT_STATS_ENABLED = true;
    /** The configuration property with stats enablement of the cache */
    public static final String SPEC_TEMPLATE_WSTATS = "concurrencyLevel=%s,initialCapacity=%s,maximumSize=%s,recordStats";
    /** The configuration property without stats enablement of the cache */
    public static final String SPEC_TEMPLATE_NOSTATS = "concurrencyLevel=%s,initialCapacity=%s,maximumSize=%s";
    /** The count sql */
    public static final String COUNT_SQL = "SELECT COUNT(*) FROM TSD_TSMETA";
    /** The initial load sql */
    public static final String INITIAL_LOAD_SQL = "SELECT * FROM TSD_TSMETA LIMIT ?";

    /** The load sql */
    public static final String LOAD_SQL = "SELECT * FROM TSD_TSMETA WHERE TSUID = ?";

    /**
     * Creates a new TSMetaCache
     * @param sqlWorker A SQLWorker to execute lookups and inserts
     * @param metaReader The meta-reader to build the TSMeta from a resultset
     */
    public TSMetaCache(SQLWorker sqlWorker, MetaReader metaReader) {
        this.sqlWorker = sqlWorker;
        this.metaReader = metaReader;
        final long maxSize = ConfigurationHelper.getLongSystemThenEnvProperty(MAX_SIZE_PROP, DEFAULT_MAX_SIZE);
        final int concurrency = ConfigurationHelper.getIntSystemThenEnvProperty(CONCURRENCY_PROP,
                DEFAULT_CONCURRENCY);
        final boolean stats = ConfigurationHelper.getBooleanSystemThenEnvProperty(STATS_ENABLED_PROP,
                DEFAULT_STATS_ENABLED);
        final long initialCount = sqlWorker.sqlForLong(COUNT_SQL);
        final long initialSize = (initialCount > maxSize) ? maxSize : initialCount;
        final String spec = String.format(stats ? SPEC_TEMPLATE_WSTATS : SPEC_TEMPLATE_NOSTATS, concurrency,
                initialSize, maxSize);
        cache = CacheBuilder.from(spec).build();
        if (stats) {
            objectName = JMXHelper.objectName(
                    new StringBuilder(getClass().getPackage().getName()).append(":service=TSMetaCache"));
            JMXHelper.registerMBean(objectName, new CacheStatistics(cache, objectName));
        } else {
            objectName = null;
        }
        put(metaReader.readTSMetas(sqlWorker.executeQuery(INITIAL_LOAD_SQL, false, initialSize), true)
                .toArray(new TSMeta[0]));
    }

    /**
     * Shuts down the cache
     */
    public void shutdown() {
        cache.invalidateAll();
        if (objectName != null)
            JMXHelper.unregisterMBean(objectName);
    }

    /**
     * Returns the value associated with {@code key} in this cache
     * @param key The TSMeta name name to look up
     * @param conn The connection to use if the loader is called
     * @return The TSUID name
     */
    public TSMeta get(final String key, final Connection conn) {
        try {
            return cache.get(key, Callables.returning(getName(key, conn)));
        } catch (Exception ex) {
            //throw new RuntimeException("TSMetaCache failed on looking up [" + key + "]", ex);
            return null;
        }
    }

    /**
     * Attempts to retrieve the TSMeta from the DB
     * @param key The UID of the target TSMeta
     * @param conn The optional connection
     * @return the TSMeta or null if one was not found
     */
    protected TSMeta getName(final String key, final Connection conn) {
        TSDBCachedRowSetImpl rset = (TSDBCachedRowSetImpl) sqlWorker.executeQuery(conn, LOAD_SQL, 1, true, key);
        if (rset.size() == 0) {
            return null;
        }
        try {
            rset.setMaxRows(1);
            List<TSMeta> tsMetas = metaReader.readTSMetas(rset, true);
            if (tsMetas == null || tsMetas.isEmpty())
                return null;
            return tsMetas.get(0);
        } catch (Exception ex) {
            throw new RuntimeException("TSMetaCache failed on looking up [" + key + "]", ex);
        }
    }

    /**
     * Determines if the TSMeta with the passed TSUID is in cache
     * @param key The TSMeta's TSUID
     * @return true if present, false otherwise
     */
    public boolean contains(String key) {
        if (key == null || key.trim().isEmpty())
            return false;
        return cache.getIfPresent(key) != null;
    }

    /**
     * Returns the number of entries in this cache
     * @return the number of entries in this cache
     */
    public long size() {
        return cache.size();
    }

    /**
     * Puts an array of TSMetas into cache
     * @param values the TSMetas to cache 
     * @see com.google.common.cache.Cache#put(java.lang.Object, java.lang.Object)
     */
    public void put(TSMeta... values) {
        for (TSMeta value : values) {
            if (value != null && value.getTSUID() != null && !value.getTSUID().trim().isEmpty()) {
                cache.put(value.getTSUID().trim(), value);
            }
        }
    }

    /**
     * Clears all the cache entries
     */
    public void clear() {
        cache.invalidateAll();
    }

}