001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.monitoring.store; 018 019 import org.apache.commons.monitoring.Role; 020 import org.apache.commons.monitoring.configuration.Configuration; 021 import org.apache.commons.monitoring.counters.Counter; 022 import org.apache.commons.monitoring.counters.DefaultCounter; 023 import org.apache.commons.monitoring.gauges.Gauge; 024 025 import java.util.Collection; 026 import java.util.Collections; 027 import java.util.Map; 028 import java.util.TreeMap; 029 import java.util.concurrent.ConcurrentHashMap; 030 import java.util.concurrent.ConcurrentMap; 031 import java.util.concurrent.ConcurrentSkipListMap; 032 import java.util.concurrent.locks.Lock; 033 034 public class DefaultDataStore implements DataStore { 035 private final ConcurrentMap<Counter.Key, Counter> counters = new ConcurrentHashMap<Counter.Key, Counter>(50); 036 private final Map<Role, Map<Long, Double>> gauges = new ConcurrentHashMap<Role, Map<Long, Double>>(); 037 038 @Override 039 public Counter getOrCreateCounter(final Counter.Key key) { 040 Counter counter = counters.get(key); 041 if (counter == null) { 042 counter = new DefaultCounter(key, this); 043 final Counter previous = counters.putIfAbsent(key, counter); 044 if (previous != null) { 045 counter = previous; 046 } 047 } 048 return counter; 049 } 050 051 @Override 052 public void clearCounters() { 053 counters.clear(); 054 } 055 056 @Override 057 public Collection<Counter> getCounters() { 058 return counters.values(); 059 } 060 061 @Override 062 public void addToCounter(final Counter counter, final double delta) { 063 if (!DefaultCounter.class.isInstance(counter)) { 064 throw new IllegalArgumentException(DefaultDataStore.class.getName() + " only supports " + DefaultCounter.class.getName()); 065 } 066 067 final DefaultCounter defaultCounter = DefaultCounter.class.cast(counter); 068 final Lock lock = defaultCounter.getLock(); 069 lock.lock(); 070 try { 071 defaultCounter.addInternal(delta); 072 } finally { 073 lock.unlock(); 074 } 075 } 076 077 @Override 078 public Map<Long, Double> getGaugeValues(GaugeValuesRequest gaugeValuesRequest) { 079 final Map<Long, Double> map = gauges.get(gaugeValuesRequest.getRole()); 080 if (map == null) { 081 return Collections.emptyMap(); 082 } 083 084 final Map<Long, Double> copy = new TreeMap<Long, Double>( map ); 085 086 final Map<Long, Double> out = new TreeMap<Long, Double>(); 087 for (final Map.Entry<Long, Double> entry : copy.entrySet()) { 088 final long time = entry.getKey(); 089 if (time >= gaugeValuesRequest.getStart() && time <= gaugeValuesRequest.getEnd()) { 090 out.put(time, entry.getValue()); 091 } 092 } 093 return out; 094 } 095 096 @Override 097 public void createOrNoopGauge(final Role role) { 098 gauges.put(role, new FixedSizedMap()); 099 } 100 101 @Override 102 public void addToGauge(final Gauge gauge, final long time, final double value) { 103 gauges.get(gauge.role()).put(time, value); 104 } 105 106 // no perf issues here normally since add is called not that often 107 protected static class FixedSizedMap extends ConcurrentSkipListMap<Long, Double> { 108 private static final int MAX_SIZE = Configuration.getInteger(Configuration.COMMONS_MONITORING_PREFIX + "gauge.max-size", 100); 109 110 protected FixedSizedMap() { 111 // no-op 112 } 113 114 protected FixedSizedMap(final Map<Long, Double> value) { 115 super(value); 116 } 117 118 @Override 119 public Double put(final Long key, final Double value) { 120 if (size() >= MAX_SIZE) { 121 remove(keySet().iterator().next()); 122 } 123 return super.put(key, value); 124 } 125 } 126 }