package at.ac.ait.ubicity.fileloader;
/**
Copyright (C) 2013 AIT / Austrian Institute of Technology
http://www.ait.ac.at
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see http://www.gnu.org/licenses/agpl-3.0.html
*/
import at.ac.ait.ubicity.fileloader.aggregation.AggregationJob;
import at.ac.ait.ubicity.fileloader.aggregation.Aggregator;
import static at.ac.ait.ubicity.fileloader.cassandra.AstyanaxInitializer.log;
import at.ac.ait.ubicity.fileloader.cassandra.LogLineColumn;
import com.lmax.disruptor.EventHandler;
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.MutationBatch;
import com.netflix.astyanax.connectionpool.OperationResult;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.connectionpool.exceptions.OperationTimeoutException;
import java.text.SimpleDateFormat;
import java.util.StringTokenizer;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Jan van Oort
*/
final class SingleLogLineAsStringEventHandler implements EventHandler<SingleLogLineAsString> {
static int batchSize;
final static Logger logger = Logger.getLogger( "EventHandler" );
static Keyspace keySpace;
static MutationBatch batch;
static long _waitOnTimeOut = 500;
static final SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" );
static String LOG_ID;
static LongTimeStampSorter tsSorter;
static AggregationJob aggregationJob;
/**
* No-arg constructor, necessary by contract with LMAX Disruptor
*/
public SingleLogLineAsStringEventHandler( ) {
}
/**
*
* We will, foreseeably, never need LogLineTokenizer for some
* other purpose than for having its implementation handy here; hence, we might
* as well use a lambda expression, which saves us some maintenance pain.
*/
@Override
public final void onEvent(final SingleLogLineAsString event, final long sequence, final boolean endOfBatch) throws Exception {
/**
* Tokenize the payload of our event, and use a database column schema
* to attribute the right token to the right column.
* Take the LMAX ringbuffer sequence number as line_id, always works;
* also has the advantage that line_ids in the database *always* mirror the exact order of insertion;
* exact order of insertion = exact order of line loading into the ringbuffer = exact order of reading from the log file
*
*/
String[] __tokens = new String[ 15 ];
int _counter = 0;
StringTokenizer _stokenizer = new StringTokenizer( event.value, " " );
while( _stokenizer.hasMoreTokens( ) ) {
__tokens[ _counter ] = _stokenizer.nextToken();
_counter++;
}
__tokens[ 12 ] = event.value;
__tokens[ 13 ] = __tokens[ 0 ];
long _longTimeStamp = dateFormat.parse( __tokens[ 0 ] ).getTime() ;
__tokens[ 14 ] = Long.toString( _longTimeStamp );
tsSorter.timeStamps.add( _longTimeStamp );
aggregationJob.offer( __tokens );
LogLineColumn _col = LogLineColumn.ID;
batch.withRow( log, __tokens[ 0] ).putColumn( _col.name, LOG_ID );
for ( int i = 0; i < 15; i++ ) {
String __tok = __tokens[ i ];
if ( ( _col = _col.next() ) != LogLineColumn.NONE ) {
batch.withRow( log, __tokens[ 0 ] ).putColumn( _col.name, __tok );
}
}
try {
if( sequence % batchSize == 0 ) {
OperationResult r = batch.executeAsync().get();
System.out.print( "batch performed on " + log.getName() );
System.out.print( " " + sequence + " " );
System.out.println( "operation result was " + r.getResult() );
}
}
catch( ExecutionException | OperationTimeoutException opTimedOut ) {
try {
logger.warning( "backing off for " + _waitOnTimeOut + " millis before retrying" );
logger.warning( "here comes the stack trace:\n" );
opTimedOut.printStackTrace();
Thread.sleep( _waitOnTimeOut );
//exponential back-off
_waitOnTimeOut = 2 * _waitOnTimeOut;
//try again
onEvent( event, sequence, endOfBatch );
}
catch( InterruptedException interrupt ) {
Thread.interrupted();
}
}
catch( ConnectionException e ) {
logger.log( Level.SEVERE, e.toString() );
}
}
}