package com.mongodb.hvdf.tasks;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.hvdf.allocators.CollectionAllocator;
import com.mongodb.hvdf.allocators.SliceDetails;
import com.mongodb.hvdf.channels.ChannelTask;
import com.mongodb.hvdf.configuration.PluginConfiguration;
import com.mongodb.hvdf.configuration.PluginConfiguration.HVDF;
public class IndexingTask extends ChannelTask {
private static Logger logger = LoggerFactory.getLogger(IndexingTask.class);
private final CollectionAllocator allocator;
private final List<PluginConfiguration> indexList;
private final DB db;
private Map<String, IndexRecord> indexCache = new HashMap<String, IndexRecord>();
public IndexingTask(PluginConfiguration config){
this.allocator = config.get(HVDF.ALLOCATOR, CollectionAllocator.class);
this.db = config.get(HVDF.DB, DB.class);
this.indexList = config.getList("indexes", PluginConfiguration.class);
// validate that all index entries at least have keys
for(PluginConfiguration indexConfig : indexList){
indexConfig.get("keys", DBObject.class);
}
}
@Override
public void run() {
// Get a sorted list of slices
List<SliceDetails> slices = allocator.getCollectionSlices();
Collections.sort(slices, SliceDetails.Comparators.MIN_TIME_DESCENDING);
HashSet<String> currentCacheKeys = new HashSet<String>(this.indexCache.keySet());
// For each collection look for the namespace in the cache
int order = 0;
for(SliceDetails slice : slices){
// Find the cache entry for this collection or create it
currentCacheKeys.remove(slice.name);
IndexRecord nsCache = this.indexCache.get(slice.name);
if(nsCache == null){
nsCache = new IndexRecord();
this.indexCache.put(slice.name, nsCache);
}
// process if the cache is not complete for all configured keys
if(nsCache.complete == false){
nsCache.complete = true;
for(PluginConfiguration indexConfig : indexList){
// Index may be configured to not apply to n most recent
int skips = indexConfig.get("skips", Integer.class, 0);
if(order >= skips){
try{
// Now check if the index was already added
DBObject proposed = indexConfig.get("keys", DBObject.class);
if(nsCache.keySet.contains(proposed) == false){
// Add the proposed index per config
DBCollection coll = this.db.getCollection(slice.name);
DBObject options = indexConfig.get("options", DBObject.class, new BasicDBObject());
coll.createIndex(proposed, options);
nsCache.keySet.add(proposed);
}
} catch(Exception ex){
nsCache.complete = false;
logger.warn("Exception in channel task", ex);
}
} else {
// Since this was skipped, mark as incomplete
nsCache.complete = false;
}
}
}
order++;
}
// The remainder of the keys in currentCacheKeys no longer exist
// so they can be removed from the local cache also
for(String togo : currentCacheKeys){
this.indexCache.remove(togo);
}
}
// Record used to track which indexes have already been added
class IndexRecord {
public HashSet<DBObject> keySet = new HashSet<DBObject>();
public boolean complete = false;
}
}