/* * Genoogle: Similar DNA Sequences Searching Engine and Tools. (http://genoogle.pih.bio.br) * Copyright (C) 2008,2009 Felipe Fernandes Albrecht (felipe.albrecht@gmail.com) * * For further information check the LICENSE file. */ package bio.pih.genoogle.search; import java.io.BufferedReader; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import bio.pih.genoogle.Genoogle; import bio.pih.genoogle.io.AbstractSequenceDataBank; import bio.pih.genoogle.io.SequencesProvider; import bio.pih.genoogle.io.reader.ParseException; import bio.pih.genoogle.search.SearchParams.Parameter; import bio.pih.genoogle.search.results.SearchResults; import bio.pih.genoogle.seq.IllegalSymbolException; import bio.pih.genoogle.seq.SymbolList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * Manage Searchers, check its status and stores and returns its results. * Each {@link Genoogle} instance has one {@link SearchManager}. * * @author albrecht */ public class SearchManager { private static Logger logger = Logger.getLogger(SearchManager.class.getName()); private static Logger profileLogger = Logger.getLogger("profile"); private Map<String, AbstractSequenceDataBank> databanks; private ExecutorService requestsExecutor = null; /** * @param maxSimulaneousSearchs * */ public SearchManager(int maxSimulaneousSearchs) { databanks = Maps.newHashMap(); requestsExecutor = Executors.newFixedThreadPool(maxSimulaneousSearchs); } /** * Shutdown the search manager.Service */ public void shutdown() throws InterruptedException { requestsExecutor.shutdown(); requestsExecutor.awaitTermination(100, TimeUnit.MILLISECONDS); } /** * @param databank */ public void addDatabank(AbstractSequenceDataBank databank) { databanks.put(databank.getName(), databank); } public AbstractSequenceDataBank getDatabank(String name) { return databanks.get(name); } /** * Process a batch of {@link SearchParams} * * @return {@link List} of {@link SearchResults}, it does not give * guarantee that the first input SearchParam is the first in the * results list. */ public List<SearchResults> doSyncSearch(BufferedReader in, String databankName, Map<Parameter, Object> parameters) throws UnknowDataBankException, InterruptedException, ExecutionException, NoSuchElementException, IOException, IllegalSymbolException, ParseException { long begin = System.currentTimeMillis(); CompletionService<SearchResults> completionService = new ExecutorCompletionService<SearchResults>( requestsExecutor); AbstractSequenceDataBank databank = databanks.get(databankName); if (databank == null) { throw new UnknowDataBankException(databankName); } SequencesProvider provider = new SequencesProvider(in, databank.getAlphabet()); int totalSubmited = 0; while(provider.hasNext()) { SymbolList nextSequence = provider.getNextSequence(); if (nextSequence == null) { break; } SearchParams sp; if (parameters == null) { sp = new SearchParams(nextSequence, databankName); } else { sp = new SearchParams(nextSequence, databankName, parameters); } long id = getNextSearchId(); final AbstractSearcher searcher = SearcherFactory.getSearcher(id, sp, databank); completionService.submit(searcher); totalSubmited ++; } List<SearchResults> results = Lists.newLinkedList(); long prev = System.currentTimeMillis(); for (int i = 0; i < totalSubmited; i++) { Future<SearchResults> future = completionService.take(); SearchResults results2 = future.get(); results.add(results2); long c = System.currentTimeMillis(); long total = c - prev; prev = c; profileLogger.info(" " + (i+1) +"/" +totalSubmited + " in " + (total) + " and total is " + (c - begin)); } return results; } /** * Do a search. * * @param sp * @return {@link SearchResults} of this search. */ public SearchResults doSyncSearch(SearchParams sp) throws UnknowDataBankException, InterruptedException, ExecutionException { logger.info("doSyncSearch on " + sp); AbstractSequenceDataBank databank = databanks.get(sp.getDatabank()); if (databank == null) { throw new UnknowDataBankException(sp.getDatabank()); } long id = getNextSearchId(); final AbstractSearcher searcher = SearcherFactory.getSearcher(id, sp, databank); CompletionService<SearchResults> completionService = new ExecutorCompletionService<SearchResults>( requestsExecutor); completionService.submit(searcher); return completionService.take().get(); } /** * @return {@link Collection} of all {@link AbstractSequenceDataBank} that this * {@link SearchResults} is managing. */ public Collection<AbstractSequenceDataBank> getDatabanks() { return databanks.values(); } /** * The name of the default data bank name. * For while will be the first data bank. * @return name of the default data bank. */ public String getDefaultDataBankName() { return this.databanks.keySet().iterator().next(); } private long searchId = 0; private synchronized long getNextSearchId() { long id = searchId; searchId++; return id; } }