/** * Copyright 2013-2015 Seagate Technology LLC. * * This Source Code Form is subject to the terms of the Mozilla * Public License, v. 2.0. If a copy of the MPL was not * distributed with this file, You can obtain one at * https://mozilla.org/MP:/2.0/. * * This program is distributed in the hope that it will be useful, * but is provided AS-IS, WITHOUT ANY WARRANTY; including without * the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or * FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public * License for more details. * * See www.openkinetic.org for more project information */ package com.seagate.kinetic.simulator.io.provider.nio.udt; import io.netty.channel.ChannelHandlerContext; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import com.seagate.kinetic.simulator.io.provider.spi.MessageService; /** * * Queued request message process runner for simulator nio service. * <p> * Command messages are processed in sequential order within the same * connection. * * @author chiaming * */ public class UdtQueuedRequestProcessRunner implements Runnable { private static final Logger logger = Logger .getLogger(UdtQueuedRequestProcessRunner.class.getName()); private MessageService service = null; // my message queue for the current connection private final LinkedBlockingQueue<UdtRequestMessageContext> lbqueue = new LinkedBlockingQueue<UdtRequestMessageContext>(); // flag running flag private volatile boolean isRunning = false; // close flag private volatile boolean isClosed = false; // reference to current running flag private Thread currentThread = null; public UdtQueuedRequestProcessRunner(MessageService service) { this.service = service; logger.info("nio queued process runner instantiated. message ordering is enforced."); } /** * process request message from IoHandler. * * @param message * request message. * * @throws InterruptedException * if interrupted. */ public void processRequest(ChannelHandlerContext ctx, byte[] message) throws InterruptedException { // request context UdtRequestMessageContext requestContext = new UdtRequestMessageContext( ctx, message); // put to queue this.lbqueue.put(requestContext); // check if there is a thread running. if not, submit to thread pool // for execution. checkRunning(); } /** * Check if there is a thread running and processing the queue. If not, * submit myself to the executor service. */ private void checkRunning() { if (this.isRunning == false) { synchronized (this) { if (this.isRunning == false) { if (this.isClosed) { return; } // set flag to true this.isRunning = true; // execute by the thread pool this.service.execute(this); } } } } @Override public void run() { try { while (isRunning()) { // save the current thread reference this.currentThread = Thread.currentThread(); // poll message from queue UdtRequestMessageContext context = this.lbqueue.poll(6, TimeUnit.SECONDS); if (context != null) { // process message doProcessMessage(context); } else { // break out of loop this.isRunning = false; } } } catch (InterruptedException ie) { // interrupted when closed ; } catch (Exception e) { logger.log(Level.WARNING, e.getMessage(), e); } finally { // set running to false isRunning = false; // thread returning to pool this.currentThread = null; } } /** * check if there is a thread running. * * @return true if the thread is polling the message. */ private boolean isRunning() { return (isRunning && (!isClosed)); } public void close() { // set closed flag if (this.isClosed) { return; } this.isClosed = true; // wake up lbqueue if (this.currentThread != null) { this.currentThread.interrupt(); } logger.fine("nio queued request process runner closed."); } public void doProcessMessage(UdtRequestMessageContext context) { UdtRequestProcessRunner rpr = new UdtRequestProcessRunner(service, context.getChannelHandlerContext(), context.getRequestMessage()); rpr.run(); } }