/*
* Copyright 2014 NAVER Corp.
*
* 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.navercorp.pinpoint.profiler.context.active;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.navercorp.pinpoint.profiler.monitor.metric.response.ReuseResponseTimeCollector;
import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeValue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
/**
* @author Taejin Koo
*/
public class DefaultActiveTraceRepository implements ActiveTraceRepository {
// memory leak defense threshold
private static final int DEFAULT_MAX_ACTIVE_TRACE_SIZE = 1024 * 10;
// oom safe cache
private final ConcurrentMap<Long, ActiveTrace> activeTraceInfoMap;
private final ReuseResponseTimeCollector reuseResponseTimeCollector = new ReuseResponseTimeCollector();
public DefaultActiveTraceRepository() {
this(DEFAULT_MAX_ACTIVE_TRACE_SIZE);
}
public DefaultActiveTraceRepository(int maxActiveTraceSize) {
this.activeTraceInfoMap = createCache(maxActiveTraceSize);
}
private ConcurrentMap<Long, ActiveTrace> createCache(int maxActiveTraceSize) {
final CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
cacheBuilder.concurrencyLevel(64);
cacheBuilder.initialCapacity(maxActiveTraceSize);
cacheBuilder.maximumSize(maxActiveTraceSize);
// OOM defense
cacheBuilder.weakValues();
final Cache<Long, ActiveTrace> localCache = cacheBuilder.build();
return localCache.asMap();
}
@Override
public void put(ActiveTrace activeTrace) {
this.activeTraceInfoMap.put(activeTrace.getId(), activeTrace);
}
@Override
public ActiveTrace remove(Long key) {
ActiveTrace activeTrace = this.activeTraceInfoMap.remove(key);
if (activeTrace != null) {
long responseTime = System.currentTimeMillis() - activeTrace.getStartTime();
reuseResponseTimeCollector.add(responseTime);
}
return activeTrace;
}
// @ThreadSafe
@Override
public List<ActiveTraceInfo> collect() {
final Collection<ActiveTrace> copied = this.activeTraceInfoMap.values();
List<ActiveTraceInfo> collectData = new ArrayList<ActiveTraceInfo>(copied.size());
for (ActiveTrace trace : copied) {
final long startTime = trace.getStartTime();
// not started
if (startTime > 0) {
if (trace.isSampled()) {
ActiveTraceInfo activeTraceInfo = new ActiveTraceInfo(trace.getId(), startTime, trace.getBindThread(), true, trace.getTransactionId(), trace.getEntryPoint());
collectData.add(activeTraceInfo);
} else {
// clear Trace reference
ActiveTraceInfo activeTraceInfo = new ActiveTraceInfo(trace.getId(), startTime, trace.getBindThread());
collectData.add(activeTraceInfo);
}
}
}
return collectData;
}
@Override
public ResponseTimeValue getLatestCompletedActiveTraceResponseTimeValue() {
return reuseResponseTimeCollector.resetAndGetValue();
}
}