/* * INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigação e Desevolvimento em Lisboa * Copyright 2013 INESC-ID and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt 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 3.0 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 org.infinispan.stats.topK; import com.clearspring.analytics.stream.Counter; import com.clearspring.analytics.stream.StreamSummary; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * This contains all the stream lib top keys. Stream lib is a space efficient technique to obtains the top-most * counters. * * @author Pedro Ruivo * @since 5.2 */ public class StreamLibContainer { private static final StreamLibContainer instance = new StreamLibContainer(); public static final int MAX_CAPACITY = 20000; private int capacity = 100; private boolean active = false; private final Map<Stat, StreamSummary<Object>> streamSummaryEnumMap; private final Map<Stat, Lock> lockMap; public static enum Stat { REMOTE_GET, LOCAL_GET, REMOTE_PUT, LOCAL_PUT, MOST_LOCKED_KEYS, MOST_CONTENDED_KEYS, MOST_FAILED_KEYS, MOST_WRITE_SKEW_FAILED_KEYS } private StreamLibContainer() { streamSummaryEnumMap = Collections.synchronizedMap(new EnumMap<Stat, StreamSummary<Object>>(Stat.class)); lockMap = new EnumMap<Stat, Lock>(Stat.class); for (Stat stat : Stat.values()) { lockMap.put(stat, new ReentrantLock()); } clearAll(); setActive(false); } public static StreamLibContainer getInstance() { return instance; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } public void setCapacity(int capacity) { if(capacity <= 0) { this.capacity = 1; } else { this.capacity = capacity; } } public int getCapacity(){ return capacity; } public void addGet(Object key, boolean remote) { if(!isActive()) { return; } syncOffer(remote ? Stat.REMOTE_GET : Stat.LOCAL_GET, key); } public void addPut(Object key, boolean remote) { if(!isActive()) { return; } syncOffer(remote ? Stat.REMOTE_PUT : Stat.LOCAL_PUT, key); } public void addLockInformation(Object key, boolean contention, boolean abort) { if(!isActive()) { return; } syncOffer(Stat.MOST_LOCKED_KEYS, key); if(contention) { syncOffer(Stat.MOST_CONTENDED_KEYS, key); } if(abort) { syncOffer(Stat.MOST_FAILED_KEYS, key); } } public void addWriteSkewFailed(Object key) { syncOffer(Stat.MOST_WRITE_SKEW_FAILED_KEYS, key); } public Map<Object, Long> getTopKFrom(Stat stat) { return getTopKFrom(stat, capacity); } public Map<Object, Long> getTopKFrom(Stat stat, int topK) { try { lockMap.get(stat).lock(); return getStatsFrom(streamSummaryEnumMap.get(stat), topK); } finally { lockMap.get(stat).unlock(); } } private Map<Object, Long> getStatsFrom(StreamSummary<Object> ss, int topK) { List<Counter<Object>> counters = ss.topK(topK <= 0 ? 1 : topK); Map<Object, Long> results = new HashMap<Object, Long>(topK); for(Counter<Object> c : counters) { results.put(c.getItem(), c.getCount()); } return results; } public void resetAll(){ clearAll(); } public void resetStat(Stat stat){ try { lockMap.get(stat).lock(); streamSummaryEnumMap.put(stat, createNewStreamSummary()); } finally { lockMap.get(stat).unlock(); } } private StreamSummary<Object> createNewStreamSummary() { return new StreamSummary<Object>(Math.max(MAX_CAPACITY, capacity)); } private void clearAll() { for (Stat stat : Stat.values()) { resetStat(stat); } } private void syncOffer(final Stat stat, Object key) { try { lockMap.get(stat).lock(); streamSummaryEnumMap.get(stat).offer(key); } finally { lockMap.get(stat).unlock(); } } }