package mil.nga.giat.geowave.core.ingest.local;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import mil.nga.giat.geowave.core.index.ByteArrayId;
import mil.nga.giat.geowave.core.ingest.GeoWaveData;
import mil.nga.giat.geowave.core.store.AdapterToIndexMapping;
import mil.nga.giat.geowave.core.store.IndexWriter;
import mil.nga.giat.geowave.core.store.adapter.WritableDataAdapter;
import mil.nga.giat.geowave.core.store.index.PrimaryIndex;
import mil.nga.giat.geowave.core.store.util.DataStoreUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An IngestTask is a thread which listens to items from a blocking queue, and
* writes those items to IndexWriter objects obtained from LocalIngestRunData
* (where they are constructed but also cached from the DataStore object). Read
* items until isTerminated == true.
*/
public class IngestTask implements
Runnable
{
private final static Logger LOGGER = LoggerFactory.getLogger(IngestTask.class);
private final String id;
private final BlockingQueue<GeoWaveData<?>> readQueue;
private final LocalIngestRunData runData;
private final Map<ByteArrayId, PrimaryIndex> specifiedPrimaryIndexes;
private final Map<ByteArrayId, PrimaryIndex> requiredIndexMap;
private volatile boolean isTerminated = false;
private volatile boolean isFinished = false;
private Map<ByteArrayId, IndexWriter> indexWriters;
private Map<ByteArrayId, AdapterToIndexMapping> adapterMappings;
public IngestTask(
String id,
LocalIngestRunData runData,
Map<ByteArrayId, PrimaryIndex> specifiedPrimaryIndexes,
Map<ByteArrayId, PrimaryIndex> requiredIndexMap,
BlockingQueue<GeoWaveData<?>> queue ) {
this.id = id;
this.runData = runData;
this.specifiedPrimaryIndexes = specifiedPrimaryIndexes;
this.requiredIndexMap = requiredIndexMap;
this.readQueue = queue;
this.indexWriters = new HashMap<ByteArrayId, IndexWriter>();
this.adapterMappings = new HashMap<ByteArrayId, AdapterToIndexMapping>();
}
/**
* This function is called by the thread placing items on the blocking
* queue.
*/
public void terminate() {
isTerminated = true;
}
/**
* An identifier, usually (filename)-(counter)
*
* @return
*/
public String getId() {
return this.id;
}
/**
* Whether this worker has terminated.
*
* @return
*/
public boolean isFinished() {
return isFinished;
}
/**
* This function will continue to read from the BlockingQueue until
* isTerminated is true and the queue is empty.
*/
@SuppressWarnings({
"unchecked",
"rawtypes"
})
@Override
public void run() {
int count = 0;
long dbWriteMs = 0L;
try {
LOGGER.debug(String.format(
"Worker executing for plugin [%s]",
this.getId()));
while (true) {
GeoWaveData<?> geowaveData = readQueue.poll(
100,
TimeUnit.MILLISECONDS);
if (geowaveData == null) {
if (isTerminated && readQueue.size() == 0) {
// Done!
break;
}
// Didn't receive an item. Make sure we haven't been
// terminated.
LOGGER.debug(String.format(
"Worker waiting for item [%s]",
this.getId()));
continue;
}
final WritableDataAdapter adapter = runData.getDataAdapter(geowaveData);
if (adapter == null) {
LOGGER.warn(String.format(
"Adapter not found for [%s] worker [%s]",
geowaveData.getValue(),
this.getId()));
continue;
}
// Ingest the data!
dbWriteMs += ingestData(
geowaveData,
adapter);
count++;
}
}
catch (Exception e) {
// This should really never happen, because we don't limit the
// amount of items in the IndexWriter pool.
LOGGER.error(
"Fatal error occured while trying to get an index writer.",
e);
throw new RuntimeException(
"Fatal error occured while trying to get an index writer.",
e);
}
finally {
// Clean up index writers
for (Entry<ByteArrayId, IndexWriter> writerEntry : indexWriters.entrySet()) {
try {
runData.releaseIndexWriter(
adapterMappings.get(writerEntry.getKey()),
writerEntry.getValue());
}
catch (Exception e) {
LOGGER.warn(
String.format(
"Could not return index writer: [%s]",
writerEntry.getKey()),
e);
}
}
LOGGER.debug(String.format(
"Worker exited for plugin [%s]; Ingested %d items in %d seconds",
this.getId(),
count,
(int) dbWriteMs / 1000));
isFinished = true;
}
}
private long ingestData(
GeoWaveData<?> geowaveData,
WritableDataAdapter adapter )
throws Exception {
AdapterToIndexMapping mapping = adapterMappings.get(adapter.getAdapterId());
if (mapping == null) {
List<PrimaryIndex> indices = new ArrayList<PrimaryIndex>();
for (final ByteArrayId indexId : geowaveData.getIndexIds()) {
PrimaryIndex index = specifiedPrimaryIndexes.get(indexId);
if (index == null) {
index = requiredIndexMap.get(indexId);
if (index == null) {
LOGGER.warn(String.format(
"Index '%s' not found for %s; worker [%s]",
indexId.getString(),
geowaveData.getValue(),
this.getId()));
continue;
}
}
indices.add(index);
}
runData.addIndices(indices);
runData.addAdapter(adapter);
mapping = new AdapterToIndexMapping(
adapter.getAdapterId(),
indices.toArray(new PrimaryIndex[indices.size()]));
adapterMappings.put(
mapping.getAdapterId(),
mapping);
// If we have the index checked out already, use that.
if (!indexWriters.containsKey(mapping.getAdapterId())) {
indexWriters.put(
mapping.getAdapterId(),
runData.getIndexWriter(mapping));
}
}
// Write the data to the data store.
IndexWriter writer = indexWriters.get(mapping.getAdapterId());
// Time the DB write
long hack = System.currentTimeMillis();
writer.write(geowaveData.getValue());
long durMs = System.currentTimeMillis() - hack;
return durMs;
}
}