package org.elasticsearch.plugin.degraphmalizer.updater;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class UpdaterQueue implements Runnable,UpdaterQueueMBean {
private static final ESLogger LOG = Loggers.getLogger(UpdaterQueue.class);
private final BlockingQueue<DelayedImpl<Change>> inputQueue = new LinkedBlockingQueue<DelayedImpl<Change>>();
private final BlockingQueue<DelayedImpl<Change>> outputQueue = new DelayQueue<DelayedImpl<Change>>();
private final UpdaterOverflowFileManager overflowFileManager;
private int limit;
private String index;
private boolean shuttingDown = false;
public UpdaterQueue(final String logPath, final String index, final int limit) {
this.limit = limit/2;
this.index = index;
this.overflowFileManager = new UpdaterOverflowFileManager(logPath, index, limit);
registerMBean();
}
@Override
public void run() {
while (!shuttingDown) {
if (outputQueue.size() < limit) {
if (outputQueue.isEmpty() && !overflowFileManager.isEmpty()) {
overflowFileManager.load(outputQueue);
} else {
try {
final DelayedImpl<Change> delayedChange = inputQueue.poll(1, TimeUnit.SECONDS); // Use poll() instead of take() to not miss the shutdown flag getting flipped to true.
if (delayedChange != null) {
outputQueue.add(delayedChange);
}
} catch (InterruptedException e) {
LOG.warn("Getting change from input queue interrupted: " + e.getMessage());
}
}
} else {
if (inputQueue.size() >= limit) {
overflowFileManager.save(inputQueue);
}
}
}
flushInMemoryQueuesToDisk();
}
public void add(final DelayedImpl<Change> change) {
inputQueue.add(change);
}
public DelayedImpl<Change> take() throws InterruptedException {
return outputQueue.take();
}
public boolean isEmpty() {
return inputQueue.isEmpty() && outputQueue.isEmpty() && overflowFileManager.isEmpty();
}
@Override
public int size() {
return inputQueue.size() + outputQueue.size() + overflowFileManager.size();
}
@Override
public int getInputQueueSize() {
return inputQueue.size();
}
@Override
public int getOutputQueueSize() {
return outputQueue.size();
}
@Override
public int getOverflowSize() {
return overflowFileManager.size();
}
@Override
public String getIndex() {
return index;
}
public void shutdown() {
shuttingDown = true; // Flag for thread to shut down
}
@Override
public void clear() {
inputQueue.clear();
outputQueue.clear();
overflowFileManager.clear();
}
private void flushInMemoryQueuesToDisk() {
while (!outputQueue.isEmpty()) {
overflowFileManager.save(outputQueue);
}
while (!inputQueue.isEmpty()) {
overflowFileManager.save(inputQueue);
}
}
private void registerMBean() {
try {
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
final ObjectName name = new ObjectName("org.elasticsearch.plugin.degraphmalizer.updater:type=UpdaterQueue,name=UpdaterQueue-"+index);
if (mbs.isRegistered(name)) {
mbs.unregisterMBean(name);
}
mbs.registerMBean(this, name);
LOG.info("Registered MBean");
} catch (Exception e) {
LOG.error("Failed to register MBean", e);
}
}
}