package com.ldbc.driver.runtime.metrics;
import com.ldbc.driver.Operation;
import com.ldbc.driver.control.LoggingServiceFactory;
import com.ldbc.driver.csv.simple.SimpleCsvFileWriter;
import com.ldbc.driver.runtime.ConcurrentErrorReporter;
import com.ldbc.driver.runtime.QueueEventFetcher;
import com.ldbc.driver.runtime.metrics.ThreadedQueuedMetricsEvent.GetWorkloadResults;
import com.ldbc.driver.runtime.metrics.ThreadedQueuedMetricsEvent.Shutdown;
import com.ldbc.driver.runtime.metrics.ThreadedQueuedMetricsEvent.Status;
import com.ldbc.driver.runtime.metrics.ThreadedQueuedMetricsEvent.SubmitOperationResult;
import com.ldbc.driver.temporal.TimeSource;
import java.io.IOException;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import static java.lang.String.format;
public class ThreadedQueuedMetricsServiceThread extends Thread
{
private final MetricsManager metricsManager;
private final ConcurrentErrorReporter errorReporter;
private final QueueEventFetcher<ThreadedQueuedMetricsEvent> queueEventFetcher;
private final SimpleCsvFileWriter csvResultsLogWriter;
private final TimeUnit unit;
private Long processedEventCount = 0l;
private Long expectedEventCount = null;
private final String[] operationNames;
public ThreadedQueuedMetricsServiceThread( ConcurrentErrorReporter errorReporter,
Queue<ThreadedQueuedMetricsEvent> metricsEventsQueue,
SimpleCsvFileWriter csvResultsLogWriter,
TimeSource timeSource,
TimeUnit unit,
long maxRuntimeDurationAsNano,
Map<Integer,Class<? extends Operation>> operationTypeToClassMapping,
LoggingServiceFactory loggingServiceFactory ) throws MetricsCollectionException
{
this( errorReporter,
QueueEventFetcher.queueEventFetcherFor( metricsEventsQueue ),
csvResultsLogWriter,
timeSource,
unit,
maxRuntimeDurationAsNano,
operationTypeToClassMapping,
loggingServiceFactory
);
}
private ThreadedQueuedMetricsServiceThread(
ConcurrentErrorReporter errorReporter,
QueueEventFetcher<ThreadedQueuedMetricsEvent> queueEventFetcher,
SimpleCsvFileWriter csvResultsLogWriter,
TimeSource timeSource,
TimeUnit unit,
long maxRuntimeDurationAsNano,
Map<Integer,Class<? extends Operation>> operationTypeToClassMapping,
LoggingServiceFactory loggingServiceFactory ) throws MetricsCollectionException
{
super( ThreadedQueuedMetricsServiceThread.class.getSimpleName() + "-" + System.currentTimeMillis() );
this.errorReporter = errorReporter;
this.queueEventFetcher = queueEventFetcher;
this.csvResultsLogWriter = csvResultsLogWriter;
this.unit = unit;
this.metricsManager = new MetricsManager(
timeSource,
unit,
maxRuntimeDurationAsNano,
operationTypeToClassMapping,
loggingServiceFactory
);
operationNames = MetricsManager.toOperationNameArray( operationTypeToClassMapping );
}
@Override
public void run()
{
while ( null == expectedEventCount || processedEventCount < expectedEventCount )
{
try
{
ThreadedQueuedMetricsEvent event = queueEventFetcher.fetchNextEvent();
onEvent( event );
}
catch ( Throwable e )
{
errorReporter.reportError(
this,
format( "Encountered unexpected exception\n%s",
ConcurrentErrorReporter.stackTraceToString( e ) ) );
return;
}
}
}
public void onEvent( ThreadedQueuedMetricsEvent event ) throws IOException, MetricsCollectionException
{
switch ( event.type() )
{
case SUBMIT_RESULT:
SubmitOperationResult submitOperationResultEvent = (SubmitOperationResult) event;
if ( null != csvResultsLogWriter )
{
csvResultsLogWriter.writeRow(
operationNames[submitOperationResultEvent.operationType()],
Long.toString( submitOperationResultEvent.scheduledStartTimeAsMilli() ),
Long.toString( submitOperationResultEvent.actualStartTimeAsMilli() ),
Long.toString(
unit.convert( submitOperationResultEvent.runDurationAsNano(), TimeUnit.NANOSECONDS ) ),
Integer.toString( submitOperationResultEvent.resultCode() ),
Long.toString( submitOperationResultEvent.originalStartTime() )
);
}
try
{
metricsManager.measure(
submitOperationResultEvent.actualStartTimeAsMilli(),
submitOperationResultEvent.runDurationAsNano(),
submitOperationResultEvent.operationType()
);
}
catch ( MetricsCollectionException e )
{
errorReporter.reportError(
this,
format(
"Encountered error while collecting metrics for result\n"
+ "Operation Type: %s\n"
+ "Scheduled Start Time Ms: %s\n"
+ "Actual Start Time Ms: %s\n"
+ "Duration Ns: %s\n"
+ "Result Code: %s\n"
+ "Original start time: %s\n"
,
submitOperationResultEvent.operationType(),
submitOperationResultEvent.scheduledStartTimeAsMilli(),
submitOperationResultEvent.actualStartTimeAsMilli(),
submitOperationResultEvent.runDurationAsNano(),
submitOperationResultEvent.resultCode(),
submitOperationResultEvent.originalStartTime(),
ConcurrentErrorReporter.stackTraceToString( e )
)
);
}
processedEventCount++;
break;
case WORKLOAD_STATUS:
ThreadedQueuedMetricsService.MetricsStatusFuture statusFuture = ((Status) event).statusFuture();
statusFuture.set( metricsManager.status() );
break;
case WORKLOAD_RESULT:
ThreadedQueuedMetricsService.MetricsWorkloadResultFuture workloadResultFuture =
((GetWorkloadResults) event).workloadResultFuture();
WorkloadResultsSnapshot resultsSnapshot = metricsManager.snapshot();
workloadResultFuture.set( resultsSnapshot );
break;
case SHUTDOWN_SERVICE:
if ( null == expectedEventCount )
{
expectedEventCount = ((Shutdown) event).initiatedEvents();
}
else
{
// this is not the first termination event that the thread has received
errorReporter.reportError(
this,
format(
"Encountered multiple %s events. First expectedEventCount[%s]. Second " +
"expectedEventCount[%s]",
ThreadedQueuedMetricsEvent.MetricsEventType.SHUTDOWN_SERVICE.name(),
expectedEventCount,
((Shutdown) event).initiatedEvents() ) );
}
break;
default:
errorReporter.reportError(
this,
format( "Encountered unexpected event type: %s", event.type().name() ) );
return;
}
}
}