package com.constellio.data.dao.services.solr;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.common.SolrInputDocument;
import com.constellio.data.utils.ThreadList;
public class QueuedSolrClient {
SolrClient solrClient;
BlockingQueue<QueuedSolrClientTask> queue;
List<SolrInputDocument> currentBatch;
int batchSize;
int threadsCount;
ThreadList<Thread> threadList;
private QueuedSolrClient(SolrClient solrClient, int batchSize, int threadsCount) {
this.solrClient = solrClient;
this.queue = new LinkedBlockingQueue<QueuedSolrClientTask>((int) (threadsCount * 1.5));
this.currentBatch = new ArrayList<>(batchSize);
this.batchSize = batchSize;
this.threadsCount = threadsCount;
}
public static QueuedSolrClient createAndStart(SolrClient solrClient, int batchSize, int threadsCount) {
QueuedSolrClient queuedSolrClient = new QueuedSolrClient(solrClient, batchSize, threadsCount);
queuedSolrClient.start(threadsCount);
return queuedSolrClient;
}
private void start(int threadsCount) {
this.threadList = new ThreadList<>();
for (int i = 0; i < threadsCount; i++) {
threadList.add(new QueuedSolrClientThread());
}
try {
threadList.startAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void addAsync(List<SolrInputDocument> solrInputDocuments) {
for (SolrInputDocument solrInputDocument : solrInputDocuments) {
addAsync(solrInputDocument);
}
}
public void addAsync(SolrInputDocument solrInputDocument) {
synchronized (this) {
currentBatch.add(solrInputDocument);
if (currentBatch.size() >= batchSize) {
try {
queue.put(new QueuedSolrClientTask(currentBatch));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
currentBatch = new ArrayList<>(batchSize);
}
}
}
private static class QueuedSolrClientTask {
List<SolrInputDocument> documents;
public QueuedSolrClientTask(List<SolrInputDocument> documents) {
this.documents = documents;
}
}
private class QueuedSolrClientThread extends Thread {
@Override
public void run() {
boolean running = true;
while (running) {
try {
QueuedSolrClientTask task = queue.take();
if (task.documents == null) {
running = false;
} else {
try {
solrClient.add(task.documents);
} catch (SolrServerException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public void flush() {
commit();
}
public void close() {
try {
if (!currentBatch.isEmpty()) {
queue.put(new QueuedSolrClientTask(currentBatch));
}
for (int i = 0; i < threadsCount; i++) {
this.queue.put(new QueuedSolrClientTask(null));
}
threadList.joinAll();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
commit();
}
private void commit() {
try {
solrClient.commit();
} catch (SolrServerException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}