/*
* 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.storage;
import com.navercorp.pinpoint.common.util.CollectionUtils;
import com.navercorp.pinpoint.profiler.context.*;
import com.navercorp.pinpoint.profiler.sender.DataSender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* @author emeroad
* @author jaehong.kim
*/
public class BufferedStorage implements Storage {
private static final Logger logger = LoggerFactory.getLogger(BufferedStorage.class);
private static final boolean isDebug = logger.isDebugEnabled();
private static final int DEFAULT_BUFFER_SIZE = 20;
private final int bufferSize;
private List<SpanEvent> storage;
private final DataSender dataSender;
private final SpanPostProcessor spanPostProcessor;
private final SpanChunkFactory spanChunkFactory;
public BufferedStorage(DataSender dataSender, SpanPostProcessor spanPostProcessor, SpanChunkFactory spanChunkFactory) {
this(dataSender, spanPostProcessor, spanChunkFactory, DEFAULT_BUFFER_SIZE);
}
public BufferedStorage(DataSender dataSender, SpanPostProcessor spanPostProcessor, SpanChunkFactory spanChunkFactory, int bufferSize) {
if (dataSender == null) {
throw new NullPointerException("dataSender must not be null");
}
if (spanPostProcessor == null) {
throw new NullPointerException("spanPostProcessor must not be null");
}
if (spanChunkFactory == null) {
throw new NullPointerException("spanChunkFactory must not be null");
}
this.dataSender = dataSender;
this.spanPostProcessor = spanPostProcessor;
this.spanChunkFactory = spanChunkFactory;
this.bufferSize = bufferSize;
this.storage = allocateBuffer();
}
@Override
public void store(SpanEvent spanEvent) {
final List<SpanEvent> storage = getBuffer();
storage.add(spanEvent);
if (overflow(storage)) {
final List<SpanEvent> flushData = clearBuffer();
final SpanChunk spanChunk = spanChunkFactory.create(flushData);
if (isDebug) {
logger.debug("[BufferedStorage] Flush span-chunk {}", spanChunk);
}
dataSender.send(spanChunk);
}
}
private boolean overflow(List<SpanEvent> storage) {
return storage.size() >= bufferSize;
}
private List<SpanEvent> allocateBuffer() {
return new ArrayList<SpanEvent>(this.bufferSize);
}
private List<SpanEvent> getBuffer() {
List<SpanEvent> copy = this.storage;
if (copy == null) {
copy = allocateBuffer();
this.storage = copy;
}
return copy;
}
private List<SpanEvent> clearBuffer() {
final List<SpanEvent> copy = this.storage;
this.storage = null;
return copy;
}
@Override
public void store(Span span) {
final List<SpanEvent> storage = clearBuffer();
if (CollectionUtils.isNotEmpty(storage)) {
span = spanPostProcessor.postProcess(span, storage);
}
dataSender.send(span);
if (isDebug) {
logger.debug("[BufferedStorage] Flush span {}", span);
}
}
public void flush() {
final List<SpanEvent> storage = clearBuffer();
if (CollectionUtils.isNotEmpty(storage)) {
final SpanChunk spanChunk = spanChunkFactory.create(storage);
dataSender.send(spanChunk);
if (isDebug) {
logger.debug("flush span chunk {}", spanChunk);
}
}
}
@Override
public void close() {
}
@Override
public String toString() {
return "BufferedStorage{" + "bufferSize=" + bufferSize + ", dataSender=" + dataSender + '}';
}
}