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; } }