package com.appmetr.hercules.mutations;
import com.appmetr.hercules.Hercules;
import com.appmetr.hercules.HerculesMonitoringGroup;
import com.appmetr.monblank.MonblankConst;
import com.appmetr.monblank.Monitoring;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
@Singleton
public class MutationsQueue implements Runnable {
private static final int SLEEP_CREATE_MS = 3000;
private static final int STOP_SLEEP_BEFORE_INTERRUPT_MS = 3000;
public static final int DEFAULT_PRIORITY = 1;
public static final int HIGH_PRIORITY = 5;
public static final int MAX_RETRIES = 15;
@Inject protected Hercules hercules;
@Inject protected Monitoring monitoringService;
private Logger logger = LoggerFactory.getLogger(MutationsQueue.class);
private PriorityBlockingQueue<ExecutableMutation> queue = new PriorityBlockingQueue<ExecutableMutation>();
private volatile Thread pollingThread = null;
@Override
public void run() {
try {
pollingThread = Thread.currentThread();
logger.info("MutationsQueue polling started!");
Set<String> columnFamilyNames = hercules.getColumnFamilies();
while (!pollingThread.isInterrupted()) {
try {
ExecutableMutation mutation = queue.take();
monitoringService.inc(HerculesMonitoringGroup.EM_PARTITION, "MutationQueue mutation taken");
if (mutation.getType() == ExecutableMutation.MutationType.CREATE) {
if (columnFamilyNames.contains(mutation.getCfName())) {
mutation.skipped();
} else {
if (executeMutationSafe(mutation)) {
columnFamilyNames.add(mutation.getCfName());
}
}
} else if (mutation.getType() == ExecutableMutation.MutationType.DELETE) {
if (columnFamilyNames.contains(mutation.getCfName())) {
if (executeMutationSafe(mutation)) {
columnFamilyNames.remove(mutation.getCfName());
}
} else {
mutation.skipped();
}
} else {
logger.error("Unsupported mutation type: " + mutation);
}
} catch (InterruptedException ie) {
logger.info("Interrupted while polling the queue.");
pollingThread.interrupt();
}
}
logger.info("MutationsQueue polling stopped!");
} catch (Exception e) {
logger.error("Exception in MutationsQueue: ", e);
}
}
private boolean executeMutationSafe(ExecutableMutation mutation) {
try {
mutation.execute();
return true;
} catch (Exception e) {
logger.error("Exception while executing mutation: " + mutation, e);
logger.info("Scheduling mutation with increased priority: " + mutation);
if (mutation.getRetryCount() < MAX_RETRIES) {
add(mutation.retry());
}
return false;
} finally {
try {
Thread.sleep(SLEEP_CREATE_MS);
} catch (InterruptedException e) {
logger.info("Interrupted while sleeping in mutation create.");
}
}
}
public void add(ExecutableMutation mutation) {
monitoringService.inc(HerculesMonitoringGroup.EM_PARTITION, "MutationQueue mutations queued");
queue.add(mutation);
}
public void addAll(List<ExecutableMutation> mutations) {
monitoringService.add(HerculesMonitoringGroup.EM_PARTITION, "MutationQueue mutations queued", MonblankConst.COUNT, mutations.size());
queue.addAll(mutations);
}
public void stop() {
if (pollingThread != null) {
pollingThread.interrupt();
}
}
}