package com.ldbc.driver.workloads.ldbc.snb.interactive;
import com.google.common.collect.EvictingQueue;
import com.google.common.collect.Ordering;
import com.google.common.collect.Queues;
import com.ldbc.driver.ChildOperationGenerator;
import com.ldbc.driver.Operation;
import com.ldbc.driver.WorkloadException;
import com.ldbc.driver.generator.RandomDataGeneratorFactory;
import com.ldbc.driver.util.Tuple;
import com.ldbc.driver.util.Tuple2;
import org.apache.commons.math3.random.RandomDataGenerator;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static java.lang.String.format;
public class LdbcSnbShortReadGenerator implements ChildOperationGenerator
{
private final double initialProbability;
private final LdbcShortQueryFactory[] shortReadFactories;
private final double[] probabilityDegradationFactors;
private final Queue<Long> personIdBuffer;
private final Queue<Long> messageIdBuffer;
private final long[] interleavesAsMilli;
private final BufferReplenishFun bufferReplenishFun;
public static enum SCHEDULED_START_TIME_POLICY
{
PREVIOUS_OPERATION_SCHEDULED_START_TIME,
PREVIOUS_OPERATION_ACTUAL_FINISH_TIME,
ESTIMATED
}
public LdbcSnbShortReadGenerator( double initialProbability,
double probabilityDegradationFactor,
long updateInterleaveAsMilli,
Set<Class> enabledShortReadOperationTypes,
double compressionRatio,
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
RandomDataGeneratorFactory randomFactory,
Map<Integer,Long> longReadInterleaves,
SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy,
BufferReplenishFun bufferReplenishFun )
{
this.initialProbability = initialProbability;
this.personIdBuffer = personIdBuffer;
this.messageIdBuffer = messageIdBuffer;
this.bufferReplenishFun = bufferReplenishFun;
int maxReadOperationType =
Ordering.<Integer>natural().max( LdbcQuery14.TYPE, LdbcShortQuery7MessageReplies.TYPE ) + 1;
this.interleavesAsMilli = new long[maxReadOperationType];
for ( Integer longReadOperationType : longReadInterleaves.keySet() )
{
this.interleavesAsMilli[longReadOperationType] =
Math.round( Math.ceil( compressionRatio * longReadInterleaves.get( longReadOperationType ) ) );
}
this.interleavesAsMilli[LdbcShortQuery1PersonProfile.TYPE] =
Math.round( Math.ceil( compressionRatio * updateInterleaveAsMilli ) );
this.interleavesAsMilli[LdbcShortQuery2PersonPosts.TYPE] =
Math.round( Math.ceil( compressionRatio * updateInterleaveAsMilli ) );
this.interleavesAsMilli[LdbcShortQuery3PersonFriends.TYPE] =
Math.round( Math.ceil( compressionRatio * updateInterleaveAsMilli ) );
this.interleavesAsMilli[LdbcShortQuery4MessageContent.TYPE] =
Math.round( Math.ceil( compressionRatio * updateInterleaveAsMilli ) );
this.interleavesAsMilli[LdbcShortQuery5MessageCreator.TYPE] =
Math.round( Math.ceil( compressionRatio * updateInterleaveAsMilli ) );
this.interleavesAsMilli[LdbcShortQuery6MessageForum.TYPE] =
Math.round( Math.ceil( compressionRatio * updateInterleaveAsMilli ) );
this.interleavesAsMilli[LdbcShortQuery7MessageReplies.TYPE] =
Math.round( Math.ceil( compressionRatio * updateInterleaveAsMilli ) );
int maxOperationType = Ordering.<Integer>natural().max( LdbcQuery14.TYPE, LdbcShortQuery7MessageReplies.TYPE,
LdbcUpdate8AddFriendship.TYPE ) + 1;
this.shortReadFactories = new LdbcShortQueryFactory[maxOperationType];
this.probabilityDegradationFactors = new double[maxOperationType];
for ( int i = 0; i < probabilityDegradationFactors.length; i++ )
{
probabilityDegradationFactors[i] = 0;
}
/*
ENABLED
S1_INDEX -> true/false
S2_INDEX -> true/false
S3_INDEX -> true/false
S4_INDEX -> true/false
S5_INDEX -> true/false
S6_INDEX -> true/false
S7_INDEX -> true/false
*/
boolean[] enabledShortReads = new boolean[maxOperationType];
enabledShortReads[LdbcShortQuery1PersonProfile.TYPE] =
enabledShortReadOperationTypes.contains( LdbcShortQuery1PersonProfile.class );
enabledShortReads[LdbcShortQuery2PersonPosts.TYPE] =
enabledShortReadOperationTypes.contains( LdbcShortQuery2PersonPosts.class );
enabledShortReads[LdbcShortQuery3PersonFriends.TYPE] =
enabledShortReadOperationTypes.contains( LdbcShortQuery3PersonFriends.class );
enabledShortReads[LdbcShortQuery4MessageContent.TYPE] =
enabledShortReadOperationTypes.contains( LdbcShortQuery4MessageContent.class );
enabledShortReads[LdbcShortQuery5MessageCreator.TYPE] =
enabledShortReadOperationTypes.contains( LdbcShortQuery5MessageCreator.class );
enabledShortReads[LdbcShortQuery6MessageForum.TYPE] =
enabledShortReadOperationTypes.contains( LdbcShortQuery6MessageForum.class );
enabledShortReads[LdbcShortQuery7MessageReplies.TYPE] =
enabledShortReadOperationTypes.contains( LdbcShortQuery7MessageReplies.class );
/*
MAPPING
S1_INDEX -> S1
S2_INDEX -> S2
S3_INDEX -> S3
S4_INDEX -> S4
S5_INDEX -> S5
S6_INDEX -> S6
S7_INDEX -> S7
*/
LdbcShortQueryFactory[] baseShortReadFactories = new LdbcShortQueryFactory[maxOperationType];
baseShortReadFactories[LdbcShortQuery1PersonProfile.TYPE] =
new LdbcShortQuery1Factory( scheduledStartTimePolicy );
baseShortReadFactories[LdbcShortQuery2PersonPosts.TYPE] =
new LdbcShortQuery2Factory( scheduledStartTimePolicy );
baseShortReadFactories[LdbcShortQuery3PersonFriends.TYPE] =
new LdbcShortQuery3Factory( scheduledStartTimePolicy );
baseShortReadFactories[LdbcShortQuery4MessageContent.TYPE] =
new LdbcShortQuery4Factory( scheduledStartTimePolicy );
baseShortReadFactories[LdbcShortQuery5MessageCreator.TYPE] =
new LdbcShortQuery5Factory( scheduledStartTimePolicy );
baseShortReadFactories[LdbcShortQuery6MessageForum.TYPE] =
new LdbcShortQuery6Factory( scheduledStartTimePolicy );
baseShortReadFactories[LdbcShortQuery7MessageReplies.TYPE] =
new LdbcShortQuery7Factory( scheduledStartTimePolicy );
/*
FACTORIES
S1_INDEX -> <if> (false == ENABLED[S1]) <then> ERROR
S2_INDEX -> <if> (false == ENABLED[S2]) <then> ERROR
S3_INDEX -> <if> (false == ENABLED[S3]) <then> ERROR
S4_INDEX -> <if> (false == ENABLED[S4]) <then> ERROR
S5_INDEX -> <if> (false == ENABLED[S5]) <then> ERROR
S6_INDEX -> <if> (false == ENABLED[S6]) <then> ERROR
S7_INDEX -> <if> (false == ENABLED[S7]) <then> ERROR
*/
if ( false == enabledShortReads[LdbcShortQuery1PersonProfile.TYPE] )
{
shortReadFactories[LdbcShortQuery1PersonProfile.TYPE] =
new ErrorFactory( LdbcShortQuery1PersonProfile.class );
}
if ( false == enabledShortReads[LdbcShortQuery2PersonPosts.TYPE] )
{
shortReadFactories[LdbcShortQuery2PersonPosts.TYPE] = new ErrorFactory( LdbcShortQuery2PersonPosts.class );
}
if ( false == enabledShortReads[LdbcShortQuery3PersonFriends.TYPE] )
{
shortReadFactories[LdbcShortQuery3PersonFriends.TYPE] =
new ErrorFactory( LdbcShortQuery3PersonFriends.class );
}
if ( false == enabledShortReads[LdbcShortQuery4MessageContent.TYPE] )
{
shortReadFactories[LdbcShortQuery4MessageContent.TYPE] =
new ErrorFactory( LdbcShortQuery4MessageContent.class );
}
if ( false == enabledShortReads[LdbcShortQuery5MessageCreator.TYPE] )
{
shortReadFactories[LdbcShortQuery5MessageCreator.TYPE] =
new ErrorFactory( LdbcShortQuery5MessageCreator.class );
}
if ( false == enabledShortReads[LdbcShortQuery6MessageForum.TYPE] )
{
shortReadFactories[LdbcShortQuery6MessageForum.TYPE] =
new ErrorFactory( LdbcShortQuery6MessageForum.class );
}
if ( false == enabledShortReads[LdbcShortQuery7MessageReplies.TYPE] )
{
shortReadFactories[LdbcShortQuery7MessageReplies.TYPE] =
new ErrorFactory( LdbcShortQuery7MessageReplies.class );
}
/*
(FIRST_PERSON,FIRST_PERSON_INDEX) = ...
(FIRST_MESSAGE,FIRST_MESSAGE_INDEX) = ...
*/
Tuple2<Integer,LdbcShortQueryFactory> firstPersonQueryAndIndex =
firstPersonQueryOrNoOp( enabledShortReadOperationTypes, randomFactory, 0, initialProbability,
scheduledStartTimePolicy );
Tuple2<Integer,LdbcShortQueryFactory> firstMessageQueryAndIndex =
firstMessageQueryOrNoOp( enabledShortReadOperationTypes, randomFactory, 0, initialProbability,
scheduledStartTimePolicy );
/*
FIRST_PERSON = <if> (MAX_INTEGER == FIRST_PERSON_INDEX) <then> FIRST_MESSAGE <else> FIRST_PERSON
FIRST_MESSAGE = <if> (MAX_INTEGER == FIRST_MESSAGE_INDEX) <then> FIRST_PERSON <else> FIRST_MESSAGE
*/
LdbcShortQueryFactory firstPersonQuery = (Integer.MAX_VALUE == firstPersonQueryAndIndex._1())
? firstMessageQueryAndIndex._2()
: firstPersonQueryAndIndex._2();
LdbcShortQueryFactory firstMessageQuery = (Integer.MAX_VALUE == firstMessageQueryAndIndex._1())
? firstPersonQueryAndIndex._2()
: firstMessageQueryAndIndex._2();
/*
RANDOM_FIRST = RANDOM(FIRST_PERSON,FIRST_MESSAGE)
*/
LdbcShortQueryFactory randomFirstQuery = selectRandomFirstShortQuery( firstPersonQuery, firstMessageQuery );
/*
LAST_PERSON_INDEX = ...
LAST_MESSAGE_INDEX = ...
*/
int lastPersonQueryIndex = lastPersonQueryIndex( enabledShortReadOperationTypes );
int lastMessageQueryIndex = lastMessageQueryIndex( enabledShortReadOperationTypes );
if ( Integer.MAX_VALUE != lastPersonQueryIndex )
{ probabilityDegradationFactors[lastPersonQueryIndex] = probabilityDegradationFactor; }
if ( Integer.MAX_VALUE != lastMessageQueryIndex )
{ probabilityDegradationFactors[lastMessageQueryIndex] = probabilityDegradationFactor; }
/*
FACTORIES
[LONG_READ_INDEXES] -> RANDOM_FIRST
[UPDATE_INDEXES] -> NO_OP
*/
shortReadFactories[LdbcQuery1.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery2.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery3.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery4.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery5.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery6.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery7.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery8.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery9.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery10.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery11.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery12.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery13.TYPE] = randomFirstQuery;
shortReadFactories[LdbcQuery14.TYPE] = randomFirstQuery;
shortReadFactories[LdbcUpdate1AddPerson.TYPE] = new NoOpFactory();
shortReadFactories[LdbcUpdate2AddPostLike.TYPE] = new NoOpFactory();
shortReadFactories[LdbcUpdate3AddCommentLike.TYPE] = new NoOpFactory();
shortReadFactories[LdbcUpdate4AddForum.TYPE] = new NoOpFactory();
shortReadFactories[LdbcUpdate5AddForumMembership.TYPE] = new NoOpFactory();
shortReadFactories[LdbcUpdate6AddPost.TYPE] = new NoOpFactory();
shortReadFactories[LdbcUpdate7AddComment.TYPE] = new NoOpFactory();
shortReadFactories[LdbcUpdate8AddFriendship.TYPE] = new NoOpFactory();
shortReadFactories[LdbcShortQuery1PersonProfile.TYPE] = null;
shortReadFactories[LdbcShortQuery2PersonPosts.TYPE] = null;
shortReadFactories[LdbcShortQuery3PersonFriends.TYPE] = null;
shortReadFactories[LdbcShortQuery4MessageContent.TYPE] = null;
shortReadFactories[LdbcShortQuery5MessageCreator.TYPE] = null;
shortReadFactories[LdbcShortQuery6MessageForum.TYPE] = null;
shortReadFactories[LdbcShortQuery7MessageReplies.TYPE] = null;
/*
FACTORIES
<if> (LAST_PERSON_INDEX != MAX_INTEGER) <then>
LAST_PERSON_INDEX (S1/S2/S3) -> FIRST_MESSAGE
<if> (LAST_MESSAGE_INDEX != MAX_INTEGER) <then>
LAST_MESSAGE_INDEX (S4/S5/S6/S7) -> FIRST_PERSON
*/
if ( Integer.MAX_VALUE != lastPersonQueryIndex )
{ shortReadFactories[lastPersonQueryIndex] = firstMessageQuery; }
if ( Integer.MAX_VALUE != lastMessageQueryIndex )
{ shortReadFactories[lastMessageQueryIndex] = firstPersonQuery; }
/*
FACTORIES
S1_INDEX -> <if> (ENABLED[S1_INDEX] && UNASSIGNED == FACTORIES[S1_INDEX]) <then>
index = indexOfNextEnabledAndUnassigned(MAPPING,S1_INDEX)
<if> (index > LAST_PERSON_INDEX) <then> FIRST_MESSAGE <else> MAPPING[index]
S2_INDEX -> <if> (ENABLED[S2_INDEX] && UNASSIGNED == FACTORIES[S2_INDEX]) <then>
index = indexOfNextEnabledAndUnassigned(MAPPING,S2_INDEX)
<if> (index > LAST_PERSON_INDEX) <then> FIRST_MESSAGE <else> MAPPING[index]
S3_INDEX -> // must have already been assigned, or is disabled
S4_INDEX -> <if> (ENABLED[S4_INDEX] && UNASSIGNED == FACTORIES[S4_INDEX]) <then>
index = indexOfNextEnabledAndUnassigned(MAPPING,S4_INDEX)
<if> (index > LAST_MESSAGE_INDEX) <then> FIRST_PERSON <else> MAPPING[index]
S5_INDEX -> <if> (ENABLED[S5_INDEX] && UNASSIGNED == FACTORIES[S5_INDEX]) <then>
index = indexOfNextEnabledAndUnassigned(MAPPING,S5_INDEX)
<if> (index > LAST_MESSAGE_INDEX) <then> FIRST_PERSON <else> MAPPING[index]
S6_INDEX -> <if> (ENABLED[S6_INDEX] && UNASSIGNED == FACTORIES[S6_INDEX]) <then>
index = indexOfNextEnabledAndUnassigned(MAPPING,S6_INDEX)
<if> (index > LAST_MESSAGE_INDEX) <then> FIRST_PERSON <else> MAPPING[index]
S7_INDEX -> // must have already been assigned, or is disabled
*/
for ( int i = LdbcShortQuery1PersonProfile.TYPE; i <= LdbcShortQuery3PersonFriends.TYPE; i++ )
{
if ( enabledShortReads[i] && null == shortReadFactories[i] )
{
int index = indexOfNextEnabled( enabledShortReads, i );
if ( index > lastPersonQueryIndex )
{ shortReadFactories[i] = firstMessageQuery; }
else
{ shortReadFactories[i] = baseShortReadFactories[index]; }
}
}
for ( int i = LdbcShortQuery4MessageContent.TYPE; i <= LdbcShortQuery7MessageReplies.TYPE; i++ )
{
if ( enabledShortReads[i] && null == shortReadFactories[i] )
{
int index = indexOfNextEnabled( enabledShortReads, i );
if ( index > lastMessageQueryIndex )
{ shortReadFactories[i] = firstPersonQuery; }
else
{ shortReadFactories[i] = baseShortReadFactories[index]; }
}
}
}
private int indexOfNextEnabled( boolean[] enabledShortReads, int shortReadType )
{
for ( int i = shortReadType + 1; i <= LdbcShortQuery7MessageReplies.TYPE; i++ )
{
if ( enabledShortReads[i] )
{ return i; }
}
return Integer.MAX_VALUE;
}
private Tuple2<Integer,LdbcShortQueryFactory> firstPersonQueryOrNoOp( Set<Class> enabledShortReadOperationTypes,
RandomDataGeneratorFactory randomFactory,
double minProbability,
double maxProbability,
SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
if ( enabledShortReadOperationTypes.contains( LdbcShortQuery1PersonProfile.class ) )
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
LdbcShortQuery1PersonProfile.TYPE,
new CoinTossingFactory( randomFactory.newRandom(),
new LdbcShortQuery1Factory( scheduledStartTimePolicy ), minProbability, maxProbability )
);
}
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery2PersonPosts.class ) )
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
LdbcShortQuery2PersonPosts.TYPE,
new CoinTossingFactory( randomFactory.newRandom(),
new LdbcShortQuery2Factory( scheduledStartTimePolicy ), minProbability, maxProbability )
);
}
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery3PersonFriends.class ) )
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
LdbcShortQuery3PersonFriends.TYPE,
new CoinTossingFactory( randomFactory.newRandom(),
new LdbcShortQuery3Factory( scheduledStartTimePolicy ), minProbability, maxProbability )
);
}
else
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
Integer.MAX_VALUE,
new NoOpFactory()
);
}
}
private Tuple2<Integer,LdbcShortQueryFactory> firstMessageQueryOrNoOp( Set<Class> enabledShortReadOperationTypes,
RandomDataGeneratorFactory randomFactory,
double minProbability,
double maxProbability,
SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
if ( enabledShortReadOperationTypes.contains( LdbcShortQuery4MessageContent.class ) )
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
LdbcShortQuery4MessageContent.TYPE,
new CoinTossingFactory(
randomFactory.newRandom(),
new LdbcShortQuery4Factory( scheduledStartTimePolicy ),
minProbability,
maxProbability
)
);
}
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery5MessageCreator.class ) )
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
LdbcShortQuery5MessageCreator.TYPE,
new CoinTossingFactory(
randomFactory.newRandom(),
new LdbcShortQuery5Factory( scheduledStartTimePolicy ),
minProbability,
maxProbability
)
);
}
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery6MessageForum.class ) )
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
LdbcShortQuery6MessageForum.TYPE,
new CoinTossingFactory(
randomFactory.newRandom(),
new LdbcShortQuery6Factory( scheduledStartTimePolicy ),
minProbability,
maxProbability
)
);
}
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery7MessageReplies.class ) )
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
LdbcShortQuery7MessageReplies.TYPE,
new CoinTossingFactory( randomFactory.newRandom(),
new LdbcShortQuery7Factory( scheduledStartTimePolicy ), minProbability, maxProbability )
);
}
else
{
return Tuple.<Integer,LdbcShortQueryFactory>tuple2(
Integer.MAX_VALUE,
new NoOpFactory()
);
}
}
private int lastPersonQueryIndex( Set<Class> enabledShortReadOperationTypes )
{
if ( enabledShortReadOperationTypes.contains( LdbcShortQuery3PersonFriends.class ) )
{ return LdbcShortQuery3PersonFriends.TYPE; }
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery2PersonPosts.class ) )
{ return LdbcShortQuery2PersonPosts.TYPE; }
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery1PersonProfile.class ) )
{ return LdbcShortQuery1PersonProfile.TYPE; }
else
{ return Integer.MAX_VALUE; }
}
private int lastMessageQueryIndex( Set<Class> enabledShortReadOperationTypes )
{
if ( enabledShortReadOperationTypes.contains( LdbcShortQuery7MessageReplies.class ) )
{ return LdbcShortQuery7MessageReplies.TYPE; }
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery6MessageForum.class ) )
{ return LdbcShortQuery6MessageForum.TYPE; }
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery5MessageCreator.class ) )
{ return LdbcShortQuery5MessageCreator.TYPE; }
else if ( enabledShortReadOperationTypes.contains( LdbcShortQuery4MessageContent.class ) )
{ return LdbcShortQuery4MessageContent.TYPE; }
else
{ return Integer.MAX_VALUE; }
}
private LdbcShortQueryFactory selectRandomFirstShortQuery(
LdbcShortQueryFactory firstPersonQueryFactory,
LdbcShortQueryFactory firstMessageQueryFactory )
{
if ( firstPersonQueryFactory.describe().equals( firstMessageQueryFactory.describe() ) )
{ return firstPersonQueryFactory; }
else if ( (false == firstPersonQueryFactory.getClass().equals( NoOpFactory.class )) &&
firstMessageQueryFactory.getClass().equals( NoOpFactory.class ) )
{ return firstPersonQueryFactory; }
else if ( firstPersonQueryFactory.getClass().equals( NoOpFactory.class ) &&
(false == firstMessageQueryFactory.getClass().equals( NoOpFactory.class )) )
{ return firstMessageQueryFactory; }
else
{ return new RoundRobbinFactory( firstPersonQueryFactory, firstMessageQueryFactory ); }
}
@Override
public double initialState()
{
return initialProbability;
}
@Override
public Operation nextOperation(
double state,
Operation operation,
Object result,
long actualStartTimeAsMilli,
long runDurationAsNano ) throws WorkloadException
{
bufferReplenishFun.replenish( operation, result );
return shortReadFactories[operation.type()].create(
personIdBuffer,
messageIdBuffer,
operation,
actualStartTimeAsMilli,
runDurationAsNano,
state
);
}
@Override
public double updateState( double previousState, int previousOperationType )
{
double degradeBy = probabilityDegradationFactors[previousOperationType];
return previousState - degradeBy;
}
/*
BufferReplenishFun
*/
public static interface BufferReplenishFun
{
void replenish( Operation operation, Object result );
}
public static class NoOpBufferReplenishFun implements BufferReplenishFun
{
@Override
public void replenish( Operation operation, Object result )
{
}
}
public static class ResultBufferReplenishFun implements BufferReplenishFun
{
private final Queue<Long> personIdBuffer;
private final Queue<Long> messageIdBuffer;
public ResultBufferReplenishFun( Queue<Long> personIdBuffer, Queue<Long> messageIdBuffer )
{
this.personIdBuffer = personIdBuffer;
this.messageIdBuffer = messageIdBuffer;
}
@Override
public void replenish( Operation operation, Object result )
{
switch ( operation.type() )
{
case LdbcQuery1.TYPE:
{
List<LdbcQuery1Result> typedResults = (List<LdbcQuery1Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
personIdBuffer.add( typedResults.get( i ).friendId() );
}
break;
}
case LdbcQuery2.TYPE:
{
List<LdbcQuery2Result> typedResults = (List<LdbcQuery2Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
LdbcQuery2Result typedResult = typedResults.get( i );
personIdBuffer.add( typedResult.personId() );
messageIdBuffer.add( typedResult.postOrCommentId() );
}
break;
}
case LdbcQuery3.TYPE:
{
List<LdbcQuery3Result> typedResults = (List<LdbcQuery3Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
personIdBuffer.add( typedResults.get( i ).personId() );
}
break;
}
case LdbcQuery7.TYPE:
{
List<LdbcQuery7Result> typedResults = (List<LdbcQuery7Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
LdbcQuery7Result typedResult = typedResults.get( i );
personIdBuffer.add( typedResult.personId() );
messageIdBuffer.add( typedResult.commentOrPostId() );
}
break;
}
case LdbcQuery8.TYPE:
{
List<LdbcQuery8Result> typedResults = (List<LdbcQuery8Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
LdbcQuery8Result typedResult = typedResults.get( i );
personIdBuffer.add( typedResult.personId() );
messageIdBuffer.add( typedResult.commentId() );
}
break;
}
case LdbcQuery9.TYPE:
{
List<LdbcQuery9Result> typedResults = (List<LdbcQuery9Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
LdbcQuery9Result typedResult = typedResults.get( i );
personIdBuffer.add( typedResult.personId() );
messageIdBuffer.add( typedResult.commentOrPostId() );
}
break;
}
case LdbcQuery10.TYPE:
{
List<LdbcQuery10Result> typedResults = (List<LdbcQuery10Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
personIdBuffer.add( typedResults.get( i ).personId() );
}
break;
}
case LdbcQuery11.TYPE:
{
List<LdbcQuery11Result> typedResults = (List<LdbcQuery11Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
personIdBuffer.add( typedResults.get( i ).personId() );
}
break;
}
case LdbcQuery12.TYPE:
{
List<LdbcQuery12Result> typedResults = (List<LdbcQuery12Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
personIdBuffer.add( typedResults.get( i ).personId() );
}
break;
}
case LdbcQuery14.TYPE:
{
List<LdbcQuery14Result> typedResults = (List<LdbcQuery14Result>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
for ( Number personId : typedResults.get( i ).personsIdsInPath() )
{
personIdBuffer.add( personId.longValue() );
}
}
break;
}
case LdbcShortQuery2PersonPosts.TYPE:
{
List<LdbcShortQuery2PersonPostsResult> typedResults = (List<LdbcShortQuery2PersonPostsResult>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
LdbcShortQuery2PersonPostsResult typedResult = typedResults.get( i );
personIdBuffer.add( typedResult.originalPostAuthorId() );
messageIdBuffer.add( typedResult.messageId() );
messageIdBuffer.add( typedResult.originalPostId() );
}
break;
}
case LdbcShortQuery3PersonFriends.TYPE:
{
List<LdbcShortQuery3PersonFriendsResult> typedResults =
(List<LdbcShortQuery3PersonFriendsResult>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
personIdBuffer.add( typedResults.get( i ).personId() );
}
break;
}
case LdbcShortQuery5MessageCreator.TYPE:
{
LdbcShortQuery5MessageCreatorResult typedResult = (LdbcShortQuery5MessageCreatorResult) result;
personIdBuffer.add( typedResult.personId() );
break;
}
case LdbcShortQuery6MessageForum.TYPE:
{
LdbcShortQuery6MessageForumResult typedResult = (LdbcShortQuery6MessageForumResult) result;
personIdBuffer.add( typedResult.moderatorId() );
break;
}
case LdbcShortQuery7MessageReplies.TYPE:
{
List<LdbcShortQuery7MessageRepliesResult> typedResults =
(List<LdbcShortQuery7MessageRepliesResult>) result;
for ( int i = 0; i < typedResults.size(); i++ )
{
LdbcShortQuery7MessageRepliesResult typedResult = typedResults.get( i );
personIdBuffer.add( typedResult.replyAuthorId() );
messageIdBuffer.add( typedResult.commentId() );
}
break;
}
}
}
}
/*
LdbcShortQueryFactory
*/
private interface LdbcShortQueryFactory
{
Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state );
String describe();
}
private class NoOpFactory implements LdbcShortQueryFactory
{
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
return null;
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class ErrorFactory implements LdbcShortQueryFactory
{
private final Class operationType;
private ErrorFactory( Class operationType )
{
this.operationType = operationType;
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
throw new RuntimeException(
format( "Encountered disabled short read: %s - it should not have been executed",
operationType.getSimpleName() ) );
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class CoinTossingFactory implements LdbcShortQueryFactory
{
private final RandomDataGenerator random;
private final LdbcShortQueryFactory innerFactory;
private final double min;
private final double max;
private CoinTossingFactory( RandomDataGenerator random,
LdbcShortQueryFactory innerFactory,
double min,
double max )
{
this.random = random;
this.innerFactory = innerFactory;
this.min = min;
this.max = max;
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
double coinToss = random.nextUniform( min, max );
if ( state > coinToss )
{
return innerFactory.create(
personIdBuffer,
messageIdBuffer,
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano,
state
);
}
else
{ return null; }
}
@Override
public String describe()
{
return getClass().getSimpleName() + "[" + innerFactory.describe() + "]";
}
}
private class RoundRobbinFactory implements LdbcShortQueryFactory
{
private final LdbcShortQueryFactory[] innerFactories;
private final int innerFactoriesCount;
private int nextFactoryIndex;
private RoundRobbinFactory( LdbcShortQueryFactory... innerFactories )
{
this.innerFactories = innerFactories;
this.innerFactoriesCount = innerFactories.length;
this.nextFactoryIndex = -1;
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
nextFactoryIndex = (nextFactoryIndex + 1) % innerFactoriesCount;
return innerFactories[nextFactoryIndex].create(
personIdBuffer,
messageIdBuffer,
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano,
state
);
}
@Override
public String describe()
{
String description = getClass().getSimpleName() + "[";
if ( innerFactories.length > 0 )
{
description += innerFactories[0].describe();
for ( int i = 1; i < innerFactories.length; i++ )
{
description += "," + innerFactories[i].describe();
}
}
return description + "]";
}
}
private class LdbcShortQuery1Factory implements LdbcShortQueryFactory
{
private final ScheduledStartTimeFactory scheduledStartTimeFactory;
private LdbcShortQuery1Factory( SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
switch ( scheduledStartTimePolicy )
{
case ESTIMATED:
{
this.scheduledStartTimeFactory = new EstimatedScheduledStartTimeFactory();
break;
}
case PREVIOUS_OPERATION_ACTUAL_FINISH_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationActualFinishTimeFactory();
break;
}
case PREVIOUS_OPERATION_SCHEDULED_START_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationScheduledStartTimeFactory();
break;
}
default:
{
throw new RuntimeException( format( "Unexpected value, should be one of %s but was %s",
Arrays.toString( SCHEDULED_START_TIME_POLICY.values() ),
scheduledStartTimePolicy.name() ) );
}
}
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
Long id = personIdBuffer.poll();
if ( null == id )
{
return null;
}
else
{
Operation operation = new LdbcShortQuery1PersonProfile( id );
operation.setScheduledStartTimeAsMilli(
scheduledStartTimeFactory.nextScheduledStartTime(
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano
)
);
return operation;
}
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class LdbcShortQuery2Factory implements LdbcShortQueryFactory
{
private final ScheduledStartTimeFactory scheduledStartTimeFactory;
private LdbcShortQuery2Factory( SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
switch ( scheduledStartTimePolicy )
{
case ESTIMATED:
{
this.scheduledStartTimeFactory = new EstimatedScheduledStartTimeFactory();
break;
}
case PREVIOUS_OPERATION_ACTUAL_FINISH_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationActualFinishTimeFactory();
break;
}
case PREVIOUS_OPERATION_SCHEDULED_START_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationScheduledStartTimeFactory();
break;
}
default:
{
throw new RuntimeException( format( "Unexpected value, should be one of %s but was %s",
Arrays.toString( SCHEDULED_START_TIME_POLICY.values() ),
scheduledStartTimePolicy.name() ) );
}
}
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
Long id = personIdBuffer.poll();
if ( null == id )
{
return null;
}
else
{
Operation operation = new LdbcShortQuery2PersonPosts( id, LdbcShortQuery2PersonPosts.DEFAULT_LIMIT );
operation.setScheduledStartTimeAsMilli(
scheduledStartTimeFactory.nextScheduledStartTime(
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano
)
);
return operation;
}
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class LdbcShortQuery3Factory implements LdbcShortQueryFactory
{
private final ScheduledStartTimeFactory scheduledStartTimeFactory;
private LdbcShortQuery3Factory( SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
switch ( scheduledStartTimePolicy )
{
case ESTIMATED:
{
this.scheduledStartTimeFactory = new EstimatedScheduledStartTimeFactory();
break;
}
case PREVIOUS_OPERATION_ACTUAL_FINISH_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationActualFinishTimeFactory();
break;
}
case PREVIOUS_OPERATION_SCHEDULED_START_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationScheduledStartTimeFactory();
break;
}
default:
{
throw new RuntimeException( format( "Unexpected value, should be one of %s but was %s",
Arrays.toString( SCHEDULED_START_TIME_POLICY.values() ),
scheduledStartTimePolicy.name() ) );
}
}
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
Long id = personIdBuffer.poll();
if ( null == id )
{
return null;
}
else
{
Operation operation = new LdbcShortQuery3PersonFriends( id );
operation.setScheduledStartTimeAsMilli(
scheduledStartTimeFactory.nextScheduledStartTime(
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano
)
);
return operation;
}
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class LdbcShortQuery4Factory implements LdbcShortQueryFactory
{
private final ScheduledStartTimeFactory scheduledStartTimeFactory;
private LdbcShortQuery4Factory( SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
switch ( scheduledStartTimePolicy )
{
case ESTIMATED:
{
this.scheduledStartTimeFactory = new EstimatedScheduledStartTimeFactory();
break;
}
case PREVIOUS_OPERATION_ACTUAL_FINISH_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationActualFinishTimeFactory();
break;
}
case PREVIOUS_OPERATION_SCHEDULED_START_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationScheduledStartTimeFactory();
break;
}
default:
{
throw new RuntimeException( format( "Unexpected value, should be one of %s but was %s",
Arrays.toString( SCHEDULED_START_TIME_POLICY.values() ),
scheduledStartTimePolicy.name() ) );
}
}
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
Long id = messageIdBuffer.poll();
if ( null == id )
{
return null;
}
else
{
Operation operation = new LdbcShortQuery4MessageContent( id );
operation.setScheduledStartTimeAsMilli(
scheduledStartTimeFactory.nextScheduledStartTime(
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano
)
);
return operation;
}
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class LdbcShortQuery5Factory implements LdbcShortQueryFactory
{
private final ScheduledStartTimeFactory scheduledStartTimeFactory;
private LdbcShortQuery5Factory( SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
switch ( scheduledStartTimePolicy )
{
case ESTIMATED:
{
this.scheduledStartTimeFactory = new EstimatedScheduledStartTimeFactory();
break;
}
case PREVIOUS_OPERATION_ACTUAL_FINISH_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationActualFinishTimeFactory();
break;
}
case PREVIOUS_OPERATION_SCHEDULED_START_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationScheduledStartTimeFactory();
break;
}
default:
{
throw new RuntimeException( format( "Unexpected value, should be one of %s but was %s",
Arrays.toString( SCHEDULED_START_TIME_POLICY.values() ),
scheduledStartTimePolicy.name() ) );
}
}
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
Long id = messageIdBuffer.poll();
if ( null == id )
{
return null;
}
else
{
Operation operation = new LdbcShortQuery5MessageCreator( id );
operation.setScheduledStartTimeAsMilli(
scheduledStartTimeFactory.nextScheduledStartTime(
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano
)
);
return operation;
}
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class LdbcShortQuery6Factory implements LdbcShortQueryFactory
{
private final ScheduledStartTimeFactory scheduledStartTimeFactory;
private LdbcShortQuery6Factory( SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
switch ( scheduledStartTimePolicy )
{
case ESTIMATED:
{
this.scheduledStartTimeFactory = new EstimatedScheduledStartTimeFactory();
break;
}
case PREVIOUS_OPERATION_ACTUAL_FINISH_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationActualFinishTimeFactory();
break;
}
case PREVIOUS_OPERATION_SCHEDULED_START_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationScheduledStartTimeFactory();
break;
}
default:
{
throw new RuntimeException( format( "Unexpected value, should be one of %s but was %s",
Arrays.toString( SCHEDULED_START_TIME_POLICY.values() ),
scheduledStartTimePolicy.name() ) );
}
}
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
Long id = messageIdBuffer.poll();
if ( null == id )
{
return null;
}
else
{
Operation operation = new LdbcShortQuery6MessageForum( id );
operation.setScheduledStartTimeAsMilli(
scheduledStartTimeFactory.nextScheduledStartTime(
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano
)
);
return operation;
}
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
private class LdbcShortQuery7Factory implements LdbcShortQueryFactory
{
private final ScheduledStartTimeFactory scheduledStartTimeFactory;
private LdbcShortQuery7Factory( SCHEDULED_START_TIME_POLICY scheduledStartTimePolicy )
{
switch ( scheduledStartTimePolicy )
{
case ESTIMATED:
{
this.scheduledStartTimeFactory = new EstimatedScheduledStartTimeFactory();
break;
}
case PREVIOUS_OPERATION_ACTUAL_FINISH_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationActualFinishTimeFactory();
break;
}
case PREVIOUS_OPERATION_SCHEDULED_START_TIME:
{
this.scheduledStartTimeFactory = new PreviousOperationScheduledStartTimeFactory();
break;
}
default:
{
throw new RuntimeException( format( "Unexpected value, should be one of %s but was %s",
Arrays.toString( SCHEDULED_START_TIME_POLICY.values() ),
scheduledStartTimePolicy.name() ) );
}
}
}
@Override
public Operation create(
Queue<Long> personIdBuffer,
Queue<Long> messageIdBuffer,
Operation previousOperation,
long previousOperationActualStartTimeAsMilli,
long previousOperationRunDurationAsNano,
double state )
{
Long id = messageIdBuffer.poll();
if ( null == id )
{
return null;
}
else
{
Operation operation = new LdbcShortQuery7MessageReplies( id );
operation.setScheduledStartTimeAsMilli(
scheduledStartTimeFactory.nextScheduledStartTime(
previousOperation,
previousOperationActualStartTimeAsMilli,
previousOperationRunDurationAsNano
)
);
return operation;
}
}
@Override
public String describe()
{
return getClass().getSimpleName();
}
}
/*
ScheduledStartTimeFactory
*/
private interface ScheduledStartTimeFactory
{
long nextScheduledStartTime( Operation previousOperation, long actualStartTimeAsMilli,
long previousOperationRunDurationAsNano );
}
private class EstimatedScheduledStartTimeFactory implements ScheduledStartTimeFactory
{
@Override
public long nextScheduledStartTime( Operation previousOperation, long actualStartTimeAsMilli,
long previousOperationRunDurationAsNano )
{
return previousOperation.scheduledStartTimeAsMilli() + interleavesAsMilli[previousOperation.type()];
}
}
private class PreviousOperationActualFinishTimeFactory implements ScheduledStartTimeFactory
{
@Override
public long nextScheduledStartTime( Operation previousOperation, long actualStartTimeAsMilli,
long previousOperationRunDurationAsNano )
{
return actualStartTimeAsMilli + TimeUnit.NANOSECONDS.toMillis( previousOperationRunDurationAsNano );
}
}
private class PreviousOperationScheduledStartTimeFactory implements ScheduledStartTimeFactory
{
@Override
public long nextScheduledStartTime( Operation previousOperation, long actualStartTimeAsMilli,
long previousOperationRunDurationAsNano )
{
return previousOperation.scheduledStartTimeAsMilli();
}
}
/*
Buffer
*/
static Queue<Long> synchronizedCircularQueueBuffer( int bufferSize )
{
return Queues.synchronizedQueue( EvictingQueue.<Long>create( bufferSize ) );
}
static Queue<Long> constantBuffer( final long value )
{
return new Queue<Long>()
{
@Override
public boolean add( Long aLong )
{
return true;
}
@Override
public boolean offer( Long aLong )
{
return true;
}
@Override
public Long remove()
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public Long poll()
{
return value;
}
@Override
public Long element()
{
return value;
}
@Override
public Long peek()
{
return value;
}
@Override
public int size()
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public boolean isEmpty()
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public boolean contains( Object o )
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public Iterator<Long> iterator()
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public Object[] toArray()
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public <T> T[] toArray( T[] a )
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public boolean remove( Object o )
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public boolean containsAll( Collection<?> c )
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public boolean addAll( Collection<? extends Long> c )
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public boolean removeAll( Collection<?> c )
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public boolean retainAll( Collection<?> c )
{
throw new UnsupportedOperationException( "Method not implemented" );
}
@Override
public void clear()
{
throw new UnsupportedOperationException( "Method not implemented" );
}
};
}
}