/** * Copyright 2012 Comcast Corporation * * Licensed 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 com.comcast.cmb.common.util; import org.apache.log4j.Logger; /** * This class helps accumulate long values associated with various keys per given VM process * This class is mostly used for accumulating db time to serve a single request. * @author aseem * Class is thread-safe */ public final class ValueAccumulator { private static Logger logger = Logger.getLogger(ValueAccumulator.class); public enum AccumulatorName { CassandraTime, CassandraWrite, CassandraRead, RedisTime, CQSMonitorTime, CMBControllerPreHandleAction, CQSPreDoAction, CNSCQSTime, CNSPublishSendTime, UnitTestTime, IOTime, AsyncQueueTime; } static AccumulatorName[] accumulatorNameValues = AccumulatorName.values(); private final ThreadLocal<long[]> keyToValue = new ThreadLocal<long[]> () { @Override protected long[] initialValue() { long []arr = new long[accumulatorNameValues.length]; for (int i = 0; i < arr.length; i++) { arr[i] = -1L; } return arr; } }; /** * Initialize the counter for key. Should be called at the beginning of servicing a request * @param key */ public void initializeCounters(AccumulatorName ...keys) { for (AccumulatorName key : keys) { if (keyToValue.get()[key.ordinal()] != -1L) { //logger.warn("initializeCounter called but on an in-use counter. Please call deleteCounter()"); } keyToValue.get()[key.ordinal()] = 0L; } } public void initializeAllCounters() { for (AccumulatorName key : accumulatorNameValues) { if (keyToValue.get()[key.ordinal()] != -1L) { //logger.warn("initializeCounter called but on an in-use counter. Please call deleteCounter()"); } keyToValue.get()[key.ordinal()] = 0L; } } /** * Accumulate time in the key bucket * @param key the bucket to accumulate time in * @param ammount the ammount to accumulate */ public void addToCounter(AccumulatorName key, long ammount){ long val = keyToValue.get()[key.ordinal()]; if (val == -1L) { //logger.warn("Must initialize Accumulator before adding to counter with key=" + key + ", not adding to the counter the new ammount=" + ammount); return; } keyToValue.get()[key.ordinal()] = val + ammount; } /** * Get accumulated time or -1 if doesn't exist * @param key * @return */ public long getCounter(AccumulatorName key) { return keyToValue.get()[key.ordinal()]; } /** * Clear the counter for this key. Must be called when we are done with one * HTTP request * @param key */ public void deleteCounter(AccumulatorName key) { keyToValue.get()[key.ordinal()] = -1L; } /** * Clear counters for all keys */ public void deleteAllCounters() { for (AccumulatorName key : accumulatorNameValues) { keyToValue.get()[key.ordinal()] = -1L; } } }