package hu.sztaki.ilab.longneck.process.task; import hu.sztaki.ilab.longneck.Record; import hu.sztaki.ilab.longneck.bootstrap.PropertyUtils; import hu.sztaki.ilab.longneck.process.access.NoMoreRecordsException; import hu.sztaki.ilab.longneck.process.access.Source; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; /** * * @author Molnár Péter <molnarp@sztaki.mta.hu> */ public class SourceReader extends AbstractTask implements Runnable { /** Log to write messages to. */ private final Logger LOG = Logger.getLogger(SourceReader.class); /** Waiting time for source read in milliseconds. */ private final int sourceReadTimeout; /** Waiting time for source queue insert in milliseconds. */ private final int targetQueueWriteTimeout; /** Waiting time for error queue insert in milliseconds. */ private final int errorQueueWriteTimeout; /** The number of records in bulk inserts. */ private final int bulkSize; /** The source to read from. */ private final Source source; /** The source queue for incoming records. */ private final BlockingQueue<QueueItem> sourceQueue; /** Enable thread continuation. */ private volatile boolean running = true; public SourceReader(BlockingQueue<QueueItem> sourceQueue, Source source, Properties runtimeProperties) { this.sourceQueue = sourceQueue; this.source = source; measureTimeEnabled = PropertyUtils.getBooleanProperty( runtimeProperties, "measureTimeEnabled", false); sourceReadTimeout = PropertyUtils.getIntProperty( runtimeProperties, "sourceReader.sourceReadTimeout", 10); targetQueueWriteTimeout = PropertyUtils.getIntProperty( runtimeProperties, "sourceReader.targetQueueWriteTimeout", 10); errorQueueWriteTimeout = PropertyUtils.getIntProperty( runtimeProperties, "sourceReader.errorQueueWriteTimeout", 10); bulkSize = PropertyUtils.getIntProperty( runtimeProperties, "sourceReader.bulkSize", 100); } @Override public void run() { super.run(); LOG.info("Starting up."); try { List<Record> records = new ArrayList<Record>(bulkSize); boolean waitForMoreRecords = true; source.init(); while (running && waitForMoreRecords) { // Get a record and add to queue item pack try { Record r = source.getRecord(); if (r != null) { // Insert into records store records.add(r); stats.in += 1; } else { Thread.sleep(sourceReadTimeout); } } catch (NoMoreRecordsException ex) { waitForMoreRecords = false; LOG.debug("No more records in source.", ex); } // Check, if queue item is full, and insert into source queue if (records.size() >= bulkSize || ! waitForMoreRecords) { // Insert into source queue boolean inserted = false; while (running && ! inserted) { inserted = sourceQueue.offer( new QueueItem(records, (! waitForMoreRecords)), targetQueueWriteTimeout, TimeUnit.MILLISECONDS); } stats.out += records.size(); records.clear(); } } } catch (InterruptedException ex) { LOG.error("Interrupted.", ex); } catch (Exception ex) { LOG.fatal("Fatal error during processing.", ex); } // Close source source.close(); // Log timings if (measureTimeEnabled) { stats.totalTimeMillis = this.getTotalTime(); stats.blockedTimeMillis = mxBean.getThreadInfo(Thread.currentThread().getId()).getBlockedTime(); } stats.setMeasureTimeEnabled(measureTimeEnabled); LOG.info(stats.toString()); LOG.info("Shutting down."); } public boolean isRunning() { return running; } public void setRunning(boolean running) { this.running = running; } public Source getSource() { return source; } public BlockingQueue<QueueItem> getSourceQueue() { return sourceQueue; } public int getBulkSize() { return bulkSize; } public int getErrorQueueWriteTimeout() { return errorQueueWriteTimeout; } public int getSourceReadTimeout() { return sourceReadTimeout; } public int getTargetQueueWriteTimeout() { return targetQueueWriteTimeout; } }