/*
* 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.sender;
import com.navercorp.pinpoint.common.util.PinpointThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.ThreadFactory;
/**
* @author Taejin Koo
*/
public class StandbySpanStreamDataSendWorker implements Runnable {
private static final long DEFAULT_BLOCK_TIME = 1000;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final StandbySpanStreamDataFlushHandler flushHandler;
private final StandbySpanStreamDataStorage standbySpanStreamDataStorage;
private final long blockTime;
private final Object lock = new Object();
private Thread workerThread;
private boolean isStarted = false;
public StandbySpanStreamDataSendWorker(StandbySpanStreamDataFlushHandler flushHandler, StandbySpanStreamDataStorage dataStorage) {
this(flushHandler, dataStorage, DEFAULT_BLOCK_TIME);
}
public StandbySpanStreamDataSendWorker(StandbySpanStreamDataFlushHandler flushHandler, StandbySpanStreamDataStorage dataStorage, long blockTime) {
this.flushHandler = flushHandler;
this.standbySpanStreamDataStorage = dataStorage;
this.blockTime = blockTime;
}
public void start() {
final ThreadFactory threadFactory = new PinpointThreadFactory(this.getClass().getSimpleName(), true);
this.workerThread = threadFactory.newThread(this);
logger.info("start() started.");
if (!workerThread.isAlive()) {
this.isStarted = true;
this.workerThread.start();
logger.info("start() completed.");
} else {
logger.info("start() failed. caused:already started.", this.getClass().getSimpleName());
}
}
public void stop() {
logger.info("stop() started.");
this.isStarted = false;
long startTimeMillis = System.currentTimeMillis();
long maxWaitTimeMillis = 3000;
while (workerThread != null && workerThread.isAlive()) {
workerThread.interrupt();
try {
workerThread.join(100L);
if (System.currentTimeMillis() - startTimeMillis > maxWaitTimeMillis) {
break;
}
} catch (InterruptedException ignored) {
}
}
logger.info("stop() completed.");
}
boolean addStandbySpanStreamData(SpanStreamSendData standbySpanStreamData) {
synchronized (lock) {
boolean isAdded = standbySpanStreamDataStorage.addStandbySpanStreamData(standbySpanStreamData);
lock.notifyAll();
return isAdded;
}
}
SpanStreamSendData getStandbySpanStreamSendData(int availableCapacity) {
synchronized (lock) {
return standbySpanStreamDataStorage.getStandbySpanStreamSendData(availableCapacity);
}
}
SpanStreamSendData getStandbySpanStreamSendData() {
synchronized (lock) {
return standbySpanStreamDataStorage.getStandbySpanStreamSendData();
}
}
private List<SpanStreamSendData> getForceFlushSpanStreamDataList() {
synchronized (lock) {
return standbySpanStreamDataStorage.getForceFlushSpanStreamDataList();
}
}
@Override
public void run() {
while (isStarted) {
boolean onEvent = await();
if (!isStarted) {
break;
}
List<SpanStreamSendData> forceFlushSpanStreamDataList = getForceFlushSpanStreamDataList();
forceFlush(forceFlushSpanStreamDataList);
}
}
private boolean await() {
synchronized (lock) {
long timeBlocked = standbySpanStreamDataStorage.getLeftWaitTime(blockTime);
long startTimeMillis = System.currentTimeMillis();
if (timeBlocked > 0) {
try {
lock.wait(timeBlocked);
} catch (InterruptedException ignore) {
}
if (isOverWaitTime(timeBlocked, startTimeMillis)) {
return false;
}
}
return true;
}
}
private boolean isOverWaitTime(long waitTimeMillis, long startTimeMillis) {
return waitTimeMillis < (System.currentTimeMillis() - startTimeMillis);
}
private void forceFlush(List<SpanStreamSendData> forceFlushSpanStreamDataList) {
if (forceFlushSpanStreamDataList == null) {
return;
}
for (SpanStreamSendData spanStreamSendData : forceFlushSpanStreamDataList) {
try {
flushHandler.handleFlush(spanStreamSendData);
} catch (Exception e) {
flushHandler.exceptionCaught(spanStreamSendData, e);
}
}
}
}