/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.catalog.cache.solr.impl; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.Phaser; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import ddf.catalog.data.Metacard; import ddf.catalog.data.Result; class CacheCommitPhaser extends Phaser { private final ScheduledExecutorService phaseScheduler = Executors.newSingleThreadScheduledExecutor(); private SolrCache cache; public CacheCommitPhaser(SolrCache cache) { // There will always be at least one party which will be the PhaseAdvancer super(1); this.cache = cache; // PhaseAdvancer blocks waiting for next phase advance, delay 1 second between advances // this is used to block queries that request to be indexed before continuing // committing Solr more often than 1 second can cause performance issues and exceptions phaseScheduler.scheduleWithFixedDelay(new PhaseAdvancer(this), 1, 1, TimeUnit.SECONDS); } @Override protected boolean onAdvance(int phase, int registeredParties) { // registeredParties should be 1 since all parties other than the PhaseAdvancer // will arriveAndDeregister in the add method cache.forceCommit(); return super.onAdvance(phase, registeredParties); } /** * Adds results to cache and blocks for next phase advance * * @param results metacards to add to cache */ public void add(List<Result> results) { // block next phase this.register(); // add results to cache cache.create(getMetacards(results)); // unblock phase and wait for all other parties to unblock phase this.awaitAdvance(this.arriveAndDeregister()); } public void shutdown() { this.forceTermination(); phaseScheduler.shutdown(); } private List<Metacard> getMetacards(List<Result> results) { List<Metacard> metacards = new ArrayList<>(results.size()); for (Result result : results) { metacards.add(result.getMetacard()); } return metacards; } /** * Runnable that makes one party arrive to a phaser on each run */ private static class PhaseAdvancer implements Runnable { private final Phaser phaser; public PhaseAdvancer(Phaser phaser) { this.phaser = phaser; } @Override public void run() { phaser.arriveAndAwaitAdvance(); } } }