/******************************************************************************* * Copyright (c) 2011 The Board of Trustees of the Leland Stanford Junior University * as Operator of the SLAC National Accelerator Laboratory. * Copyright (c) 2011 Brookhaven National Laboratory. * EPICS archiver appliance is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. *******************************************************************************/ package org.epics.archiverappliance.engine.writer; import java.io.IOException; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; import org.epics.archiverappliance.common.BasicContext; import org.epics.archiverappliance.config.ConfigService; import org.epics.archiverappliance.engine.membuf.ArrayListEventStream; import org.epics.archiverappliance.engine.model.ArchiveChannel; import org.epics.archiverappliance.engine.model.SampleBuffer; import org.epics.archiverappliance.engine.model.YearListener; /** * WriterRunnable is scheduled by the executor in the engine context every writing period. * @author Luofeng Li * */ public class WriterRunnable implements Runnable { private static final Logger logger = Logger.getLogger(WriterRunnable.class); /** Minimum write period [seconds] */ private static final double MIN_WRITE_PERIOD = 10.0; /**the sample buffer hash map*/ final private ConcurrentHashMap<String, SampleBuffer> buffers = new ConcurrentHashMap<String, SampleBuffer>(); /**the configservice used by this WriterRunnable*/ private ConfigService configservice = null; /**is running?*/ private boolean isRunning=false; /** * the constructor * @param configservice the configservice used by this WriterRunnable */ public WriterRunnable(ConfigService configservice) { this.configservice = configservice; } /** Add a channel's buffer that this thread reads * @param channel ArchiveChannel */ public void addChannel(final ArchiveChannel channel) { addSampleBuffer(channel.getName(), channel.getSampleBuffer()); } /** * remove one sample buffer from the buffer hash map. * At the same time. it also removes the channel from the channel hash map in the engine context * @param channelName the name of the channel who and whose sample buffer are removed */ public void removeChannel(final String channelName) { buffers.remove(channelName); } /** * add sample buffer into this writer runnable and add year listener to each sample buffer * @param name the name of the channel * @param buffer the sample buffer for this channel */ void addSampleBuffer(final String name, final SampleBuffer buffer) { // buffers.add(buffer); buffers.put(name, buffer); buffer.addYearListener(new YearListener() { @Override public void yearChanged(final SampleBuffer sampleBuffer) { // configservice.getEngineContext().getScheduler().execute(new Runnable(){ @Override public void run() { try { write(sampleBuffer); logger.info(sampleBuffer.getChannelName() + ":year change"); } catch (IOException e) { logger.error("Exception", e); } } }); } }); } /** * set the writing period. when the writing period is at least 10 seonds. * When write_period < 10 , the writing period is 10 seconds actually. * @param write_period the writing period in second * @return the actual writing period in second */ public double setWritingPeriod(double write_period) { double tempwrite_period=write_period; if (tempwrite_period < MIN_WRITE_PERIOD) { tempwrite_period = MIN_WRITE_PERIOD; } return tempwrite_period; } @Override public void run() { try { // final long written = write(); long startTime = System.currentTimeMillis(); write(); long endTime = System.currentTimeMillis(); configservice.getEngineContext().setSecondsConsumedByWritter( (double) (endTime - startTime) / 1000); } catch (Exception e) { logger.error("Exception", e); } } /** * write the sample buffer to the short term storage * @param buffer the sample buffer to be written * @throws IOException error occurs during writing the sample buffer to the short term storage */ private void write(SampleBuffer buffer) throws IOException { if(isRunning) return; isRunning=true; ConcurrentHashMap<String, ArchiveChannel> channelList = configservice .getEngineContext().getChannelList(); String channelNname = buffer.getChannelName(); buffer.resetSamples(); ArrayListEventStream previousSamples = buffer.getPreviousSamples(); try (BasicContext basicContext = new BasicContext()) { if (previousSamples.size() > 0) { ArchiveChannel tempChannel = channelList.get(channelNname); tempChannel.setlastRotateLogsEpochSeconds(System .currentTimeMillis() / 1000); tempChannel.getWriter().appendData(basicContext, channelNname, previousSamples); } } catch (IOException e) { throw (e); } finally{ isRunning=false; } isRunning=false; } /** * write all sample buffers into short term storage * @throws Exception error occurs during writing the sample buffer to the short term storage */ private void write() throws Exception { if(isRunning) return; isRunning=true; ConcurrentHashMap<String, ArchiveChannel> channelList = configservice .getEngineContext().getChannelList(); Iterator<Entry<String, SampleBuffer>> it = buffers.entrySet() .iterator(); while (it.hasNext()) { Entry<String, SampleBuffer> entry = (Entry<String, SampleBuffer>) it .next(); SampleBuffer buffer = entry.getValue(); String channelNname = buffer.getChannelName(); buffer.resetSamples(); ArrayListEventStream previousSamples = buffer.getPreviousSamples(); try (BasicContext basicContext = new BasicContext()) { if (previousSamples.size() > 0) { ArchiveChannel tempChannel = channelList.get(channelNname); tempChannel.setlastRotateLogsEpochSeconds(System .currentTimeMillis() / 1000); tempChannel.getWriter().appendData(basicContext, channelNname, previousSamples); } } catch (IOException e) { throw (e); }finally{ isRunning=false; } } isRunning=false; } /** * flush out the sample buffer to the short term storage before shutting down the engine * @throws Exception error occurs during writing the sample buffer to the short term storage */ public void flushBuffer() throws Exception { write(); } }