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 }