All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pageseeder.flint.indexing.IndexJobQueue Maven / Gradle / Ivy

/*
 * Copyright 2015 Allette Systems (Australia)
 * http://www.allette.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.pageseeder.flint.indexing;

import org.pageseeder.flint.Index;
import org.pageseeder.flint.Requester;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * The queue containing index jobs.
 *
 * 

This class uses a {@link PriorityBlockingQueue} so that when the queue is empty, * the calling thread will be delayed. * * @author Jean-Baptiste Reure * @author Christophe Lauret * * @version 28 February 2013 */ public final class IndexJobQueue { /** * The actual queue. */ private final PriorityBlockingQueue _queue; /** * The single thread queue. */ private final PriorityBlockingQueue _singleThreadQueue; /** * Simple Constructor. * * @param withSingleThreadQueue if there's only one queue */ public IndexJobQueue(boolean withSingleThreadQueue) { this._queue = new PriorityBlockingQueue<>(); this._singleThreadQueue = withSingleThreadQueue ? new PriorityBlockingQueue<>() : null; } // public external methods // ---------------------------------------------------------------------------------------------- /** * Add a new update job to the indexing queue. * * @param job The job to add to this queue. */ public void addSingleThreadJob(IndexJob job) { addJob(job, true); } /** * Add a new update job to the indexing queue. * * @param job The job to add to this queue. */ public void addMultiThreadJob(IndexJob job) { addJob(job, false); } /** * Returns the list of jobs for the specified requester. * *

Note that by the time each job is checked, they might have run already so the method * {@link IndexJob#isFinished()} should be called before parsing the job. * *

The list will never be null. * * @param requester the Requester * @return the list of jobs (never null) */ public List getJobsForRequester(Requester requester) { if (requester == null) return getAllJobs(); List jobs = new ArrayList<>(); for (IndexJob job : this._queue) { if (job.isForRequester(requester)) { jobs.add(job); } } if (this._singleThreadQueue != null) { for (IndexJob job : this._singleThreadQueue) { if (job.isForRequester(requester)) { jobs.add(job); } } } return jobs; } /** * Returns the number of jobs for the specified requester. * *

Note that some jobs may have been processed by the time this method returns. * * @param requester the requester * * @return the number of jobs for the specified requester. */ public int countJobsForRequester(Requester requester) { if (requester == null) return this._queue.size(); int count = 0; for (IndexJob job : this._queue) { if (job.isForRequester(requester)) { count++; } } if (this._singleThreadQueue != null) { for (IndexJob job : this._singleThreadQueue) { if (job.isForRequester(requester)) { count++; } } } return count; } /** * Removes the jobs for the index provided. * * @param index the index */ public void clearJobsForIndex(Index index) { if (index == null) return; List jobs = new ArrayList<>(); for (IndexJob job : this._queue) { if (job.isForIndex(index)) { jobs.add(job); } } this._queue.removeAll(jobs); if (this._singleThreadQueue != null) { jobs.clear(); for (IndexJob job : this._singleThreadQueue) { if (job.isForIndex(index)) { jobs.add(job); } } this._singleThreadQueue.removeAll(jobs); } } /** * Returns the list of jobs for the index provided. * *

Note that by the time each job is checked, they might have run already so the method * {@link IndexJob#isFinished()} should be called before parsing the job. * *

The list will never be null. * * @param index the index * @return the list of jobs (never null) */ public List getJobsForIndex(Index index) { if (index == null) return getAllJobs(); List jobs = new ArrayList<>(); for (IndexJob job : this._queue) { if (job.isForIndex(index)) { jobs.add(job); } } if (this._singleThreadQueue != null) { for (IndexJob job : this._singleThreadQueue) { if (job.isForIndex(index)) { jobs.add(job); } } } return jobs; } /** *

Note that some jobs may have been processed by the time this method returns. * * @param index the index * @return true if there is at least one job for the index provided. */ public boolean hasJobsForIndex(Index index) { if (index != null) { for (IndexJob job : this._queue) { if (job.isForIndex(index)) return true; } if (this._singleThreadQueue != null) { for (IndexJob job : this._singleThreadQueue) { if (job.isForIndex(index)) return true; } } } return false; } /** * Returns the number of jobs for the specified index provided. * *

Note that some jobs may have been processed by the time this method returns. * * @param index the index * @return the number of jobs for the specified provided. */ public int countJobsForIndex(Index index) { if (index == null) return this._queue.size(); int count = 0; for (IndexJob job : this._queue) { if (job.isForIndex(index)) { count++; } } if (this._singleThreadQueue != null) { for (IndexJob job : this._singleThreadQueue) { if (job.isForIndex(index)) { count++; } } } return count; } /** * Returns the complete list of jobs. * *

Note that by the time each job is checked, they might have run already so the method * {@link IndexJob#isFinished()} should be called before parsing the job. * *

The list will never be null. * * @return the list of jobs waiting (never null) */ public List getAllJobs() { ArrayList list = new ArrayList<>(this._queue); if (this._singleThreadQueue != null) list.addAll(this._singleThreadQueue); return list; } /** * Poll the next job in the queue (null if the queue is currently empty). * * @return the next job in the queue (null if the queue is currently empty). * * @throws InterruptedException if the thread was interrupted when waiting for the next job */ public IndexJob nextMultiThreadJob() throws InterruptedException { return this._queue.take(); } /** * Poll the next job in the queue (null if the queue is currently empty). * * @return the next job in the queue (null if the queue is currently empty). * * @throws InterruptedException if the thread was interrupted when waiting for the next job */ public IndexJob nextSingleThreadJob() throws InterruptedException { return this._singleThreadQueue != null ? this._singleThreadQueue.take() : null; } /** * Indicates whether the queue is currently empty. * * @return true if there are currently no jobs; * false otherwise. */ public boolean isMultiThreadsEmpty() { return this._queue.isEmpty(); } /** * Indicates whether the queue is currently empty. * * @return true if there are currently no jobs; * false otherwise. */ public boolean isSingleThreadEmpty() { return this._singleThreadQueue == null || this._singleThreadQueue.isEmpty(); } /** * clear all queues */ public void clear() { this._queue.clear(); if (this._singleThreadQueue != null) this._singleThreadQueue.clear(); } // ----------------------------------------------------------------------- // private methods // ----------------------------------------------------------------------- private void addJob(IndexJob job, boolean singleThread) { // check if similar job already there IndexJob existing; synchronized (this._queue) { existing = this._queue.stream().filter(ajob -> ajob.isSimilar(job)).findFirst().orElse(null); } // in the other queue? boolean foundInSingleQueue = false; if (existing == null && this._singleThreadQueue != null) { synchronized (this._singleThreadQueue) { existing = this._singleThreadQueue.stream().filter(ajob -> ajob.isSimilar(job)).findFirst().orElse(null); foundInSingleQueue = existing != null; } } // if there is one similar, and this one has higher priority, add this one and remove the old one boolean higherPriority = existing != null && existing.getPriority() == IndexJob.Priority.LOW && job.getPriority() == IndexJob.Priority.HIGH; // force job if in a batch with a clear job boolean force = job.isBatch() && job.getBatch().hasClearJob(); // don't remove existing if in batch with a clear job boolean existingHasPriority = existing != null && existing.isBatch() && existing.getBatch().hasClearJob(); if (!existingHasPriority && (existing == null || force || higherPriority)) { if (singleThread && this._singleThreadQueue != null) { synchronized (this._singleThreadQueue) { if (existing != null && !force) this.removeExistingJob(job, existing, foundInSingleQueue); this._singleThreadQueue.put(job); } } else { synchronized (this._queue) { if (existing != null && !force) this.removeExistingJob(job, existing, foundInSingleQueue); this._queue.put(job); } } } else { // if a batch, decrease total except if last job IndexBatch batch = job.getBatch(); if (batch != null && batch.getCurrentCount() != batch.getTotalDocuments() - 1) batch.remove(1); } } private void removeExistingJob(IndexJob job, IndexJob existing, boolean foundInSingleQueue) { // don't remove last job of batch IndexBatch batch = existing.getBatch(); if (batch != null && batch.getCurrentCount() != batch.getTotalDocuments() - 1) batch.remove(1); // remove from queue if (foundInSingleQueue) this._singleThreadQueue.remove(existing); else this._queue.remove(existing); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy