/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2014 Boundless
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.cluster.hazelcast;
import static java.lang.String.format;
import static org.geoserver.cluster.hazelcast.HazelcastUtil.localAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import org.geoserver.cluster.Event;
import org.geoserver.config.GeoServer;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.yammer.metrics.Metrics;
/**
* Synchronizer that does a full geoserver reload on any event.
* <p>
* This synchronizer assumes a shared data directory among nodes in the cluster.
* </p>
*
* @author Justin Deoliveira, OpenGeo
*/
public class ReloadHzSynchronizer extends HzSynchronizer {
/** lock during reload */
protected AtomicBoolean eventLock = new AtomicBoolean();
final ExecutorService reloadService;
public ReloadHzSynchronizer(HzCluster cluster, GeoServer gs) {
super(cluster, gs);
ThreadFactory threadFactory = new ThreadFactoryBuilder().setDaemon(true)
.setNameFormat("Hz-GeoServer-Reload-%d").build();
RejectedExecutionHandler rejectionHandler = new ThreadPoolExecutor.DiscardPolicy();
// a thread pool executor operating out of a blocking queue with maximum of 1 element, which
// discards execute requests if the queue is full
reloadService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1), threadFactory, rejectionHandler);
}
@Override
protected void processEvent(Event event) throws Exception {
// submit task and return immediately. The task will be ignored if another one is already
// scheduled
reloadService.submit(new Runnable() {
@Override
public void run() {
// lock during event processing
eventLock.set(true);
try {
gs.reload();
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Reload failed", e);
} finally {
eventLock.set(false);
}
}
});
}
@Override
protected void dispatch(Event e) {
// check lock, if locked it means event in response to configuration reload, don't propagate
if (eventLock.get()) {
return;
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(format("%s - Publishing event %s", nodeId(), e));
}
e.setSource(localAddress(cluster.getHz()));
topic.publish(e);
Metrics.newCounter(getClass(), "dispatched").inc();
}
}