/*
* 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 http://mozilla.org/MPL/2.0/.
*/
package com.github.geophile.erdo.consolidate;
import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
class DurableConsolidator extends Consolidator
{
// Consolidator interface
@Override
public void noteNewElement()
{
try {
if (LOG.isLoggable(Level.FINER)) {
consolidationSet.describe(
LOG,
Level.FINER,
"Consolidation set prior to enqueueing fractal consolidation");
}
if (threadPool != null) {
threadPool.execute(new ConsolidationTask(this, null));
}
} catch (RejectedExecutionException e) {
LOG.log(Level.WARNING, "Shutting down, skipping durable consolidation");
}
}
@Override
public void stopThreads() throws IOException, InterruptedException
{
if (threadPool != null) {
boolean timeout;
try {
threadPool.shutdownNow();
timeout = !threadPool.awaitTermination(MAXIMUM_SHUTDOWN_WAIT_SEC, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new ShutdownError();
}
if (timeout) {
throw new ShutdownError();
}
}
}
@Override
public void noteConsolidationStart()
{
inProgress.incrementAndGet();
}
@Override
public void noteConsolidationEnd(Throwable termination)
{
super.noteConsolidationEnd(termination);
inProgress.decrementAndGet();
}
// DurableConsolidator interface
public static DurableConsolidator usingThreadPool(ConsolidationSet consolidationSet,
ConsolidationPlanner planner)
{
return new DurableConsolidator(consolidationSet,
planner,
ThreadPoolType.MULTIPLE_THREADS);
}
public static DurableConsolidator runPeriodically(ConsolidationSet consolidationSet,
ConsolidationPlanner planner)
{
return new DurableConsolidator(consolidationSet,
planner,
ThreadPoolType.ONE_PERIODIC_THREAD);
}
// For use by this class
private DurableConsolidator(ConsolidationSet consolidationSet,
ConsolidationPlanner planner,
ThreadPoolType threadPoolType)
{
super(consolidationSet, planner);
int threads = consolidationSet.configuration().consolidationThreads();
// threads = 0 means we want NO background conslidation
if (threads > 0) {
switch (threadPoolType) {
case MULTIPLE_THREADS:
threadPool = Executors.newFixedThreadPool(threads, newThreadFactory(threadPoolType.toString()));
break;
case ONE_PERIODIC_THREAD:
ScheduledExecutorService executorService =
Executors.newSingleThreadScheduledExecutor(newThreadFactory(threadPoolType.toString()));
executorService.scheduleWithFixedDelay(
new Runnable()
{
public void run()
{
try {
new ConsolidationTask(DurableConsolidator.this, null).run();
} catch (Exception e) {
LOG.log
(Level.WARNING,
"Periodic DurableConsolidator terminated by exception",
e);
} catch (Throwable e) {
LOG.log
(Level.SEVERE,
"Periodic DurableConsolidator terminated by error",
e);
}
}
},
// TODO: Make interval configurable
100, 100, TimeUnit.MILLISECONDS);
threadPool = executorService;
break;
default:
assert false;
threadPool = null;
break;
}
} else {
threadPool = null;
}
}
// Class state
private static final Logger LOG = Logger.getLogger(DurableConsolidator.class.getName());
// Object state
private final ExecutorService threadPool;
private AtomicInteger inProgress = new AtomicInteger(0);
// Inner classes
private enum ThreadPoolType { MULTIPLE_THREADS, ONE_PERIODIC_THREAD }
}