Package com.espertech.esper.epl.metric

Source Code of com.espertech.esper.epl.metric.StatementMetricArray

/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
* http://esper.codehaus.org                                                          *
* http://www.espertech.com                                                           *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license       *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package com.espertech.esper.epl.metric;

import com.espertech.esper.client.metric.StatementMetric;
import com.espertech.esper.util.ManagedReadWriteLock;

import java.util.HashSet;
import java.util.Set;

/**
* Holder for statement group's statement metrics.
* <p>
* Changes to StatementMetric instances must be done in a read-lock:
<pre>
getRwLock.readLock.lock()
metric = getAddMetric(index)
metric.accountFor(cpu, wall, etc)
getRwLock.readLock.unlock()
</pre>
* <p>
* All other changes are done under write lock for this class.
* <p>
* This is a collection backed by an array that grows by 50% each time expanded, maintains a free/busy list of statement names,
* maintains an element number of last used element.
* <p>
* The flush operaton copies the complete array, thereby keeping array size. Statement names are only removed on the next flush.
*/
public class StatementMetricArray
{
    private final String engineURI;

    // Lock
    //  Read lock applies to each current transaction on a StatementMetric instance
    //  Write lock applies to flush and to add a new statement
    private final ManagedReadWriteLock rwLock;
    private final boolean isReportInactive;

    // Active statements
    private String[] statementNames;

    // Count of active statements
    private int currentLastElement;

    // Flushed metric per statement
    private volatile StatementMetric[] metrics;

    // Statements ids to remove with the next flush
    private Set<String> removedStatementNames;

    /**
     * Ctor.
     * @param engineURI engine URI
     * @param name name of statement group
     * @param initialSize initial size of array
     * @param isReportInactive true to indicate to report on inactive statements
     */
    public StatementMetricArray(String engineURI, String name, int initialSize, boolean isReportInactive)
    {
        this.engineURI = engineURI;
        this.isReportInactive = isReportInactive;
       
        metrics = new StatementMetric[initialSize];
        statementNames = new String[initialSize];
        currentLastElement = -1;
        rwLock = new ManagedReadWriteLock("StatementMetricArray-" + name, true);
        removedStatementNames = new HashSet<String>();
    }

    /**
     * Remove a statement.
     * <p>
     * Next flush actually frees the slot that this statement occupied.
     * @param statementName to remove
     */
    public void removeStatement(String statementName)
    {
        rwLock.acquireWriteLock();
        try
        {
            removedStatementNames.add(statementName);

            if (removedStatementNames.size() > 1000) {
                for (int i = 0; i <= currentLastElement; i++)
                {
                    if (removedStatementNames.contains(statementNames[i]))
                    {
                        statementNames[i] = null;
                    }
                }
                removedStatementNames.clear();
            }
        }
        finally
        {
            rwLock.releaseWriteLock();
        }
    }

    /**
     * Adds a statement and returns the index added at.
     * <p>
     * May reuse an empty slot, grow the underlying array, or append to the end.
     * @param statementName to add
     * @return index added to
     */
    public int addStatementGetIndex(String statementName)
    {
        rwLock.acquireWriteLock();
        try
        {
            // see if there is room
            if ((currentLastElement + 1) < metrics.length)
            {
                currentLastElement++;
                statementNames[currentLastElement] = statementName;
                return currentLastElement;
            }

            // no room, try to use an existing slot of a removed statement
            for (int i = 0; i < statementNames.length; i++)
            {
                if (statementNames[i] == null)
                {
                    statementNames[i] = statementName;
                    if ((i + 1) > currentLastElement)
                    {
                        currentLastElement = i;
                    }
                    return i;
                }
            }

            // still no room, expand storage by 50%
            int newSize = (int) (metrics.length * 1.5);
            String[] newStatementNames = new String[newSize];
            StatementMetric[] newMetrics = new StatementMetric[newSize];
            System.arraycopy(statementNames, 0, newStatementNames, 0, statementNames.length);
            System.arraycopy(metrics, 0, newMetrics, 0, metrics.length);

            statementNames = newStatementNames;
            metrics = newMetrics;

            currentLastElement++;
            statementNames[currentLastElement] = statementName;

            return currentLastElement;
        }
        finally
        {
            rwLock.releaseWriteLock();
        }
    }

    /**
     * Flushes the existing metrics via array copy and swap.
     * <p>
     * May report all statements (empty and non-empty slots) and thereby null values.
     * <p>
     * Returns null to indicate no reports to do.
     * @return metrics
     */
    public StatementMetric[] flushMetrics()
    {
        rwLock.acquireWriteLock();
        try
        {
            boolean isEmpty = false;
            if (currentLastElement == -1)
            {
                isEmpty = true;
            }

            // first fill in the blanks if there are no reports and we report inactive statements
            if (isReportInactive)
            {
                for (int i = 0; i <= currentLastElement; i++)
                {
                    if (statementNames[i] != null)
                    {
                        metrics[i] = new StatementMetric(engineURI, statementNames[i]);
                    }
                }
            }

            // remove statement ids that disappeared during the interval
            if ((currentLastElement > -1) && (!removedStatementNames.isEmpty()))
            {
                for (int i = 0; i <= currentLastElement; i++)
                {
                    if (removedStatementNames.contains(statementNames[i]))
                    {
                        statementNames[i] = null;
                    }
                }
            }

            // adjust last used element
            while ((currentLastElement != -1) && (statementNames[currentLastElement] == null))
            {
                currentLastElement--;
            }

            if (isEmpty)
            {
                return null;    // no copies made if empty collection
            }

            // perform flush
            StatementMetric[] newMetrics = new StatementMetric[metrics.length];
            StatementMetric[] oldMetrics = metrics;
            metrics = newMetrics;
            return oldMetrics;
        }
        finally
        {
            rwLock.releaseWriteLock();
        }
    }

    /**
     * Returns the read-write lock, for read-lock when modifications are made.
     * @return lock
     */
    public ManagedReadWriteLock getRwLock()
    {
        return rwLock;
    }

    /**
     * Returns an existing or creates a new statement metric for the index.
     * @param index of statement
     * @return metric to modify under read lock
     */
    public StatementMetric getAddMetric(int index)
    {
        StatementMetric metric = metrics[index];
        if (metric == null)
        {
            metric = new StatementMetric(engineURI, statementNames[index]);
            metrics[index] = metric;
        }
        return metric;
    }

    /**
     * Returns maximum collection size (last used element), which may not truely reflect the number
     * of actual statements held as some slots may empty up when statements are removed.
     * @return known maximum size
     */
    public int sizeLastElement()
    {
        return currentLastElement + 1;
    }
}
TOP

Related Classes of com.espertech.esper.epl.metric.StatementMetricArray

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.