/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.solr.core; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexDeletionPolicy; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.KeepOnlyLastCommitDeletionPolicy; import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.LinkFSDirectory; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.cache.Cache; import org.apache.lucene.util.cache.SimpleMapCache; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams.EchoParamStyle; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.SolrResourceLoader.PartionKey; import org.apache.solr.handler.component.*; import org.apache.solr.highlight.SolrHighlighter; import org.apache.solr.request.*; import org.apache.solr.request.mdrill.FacetComponent; import org.apache.solr.response.*; import org.apache.solr.response.BinaryResponseWriter; import org.apache.solr.response.JSONResponseWriter; import org.apache.solr.response.QueryResponseWriter; import org.apache.solr.response.RawResponseWriter; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.XMLResponseWriter; import org.apache.solr.schema.IndexSchema; import org.apache.solr.search.QParserPlugin; import org.apache.solr.search.SolrFieldCacheMBean; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.search.ValueSourceParser; import org.apache.solr.update.DirectUpdateHandler2; import org.apache.solr.update.UpdateHandler; import org.apache.solr.update.processor.LogUpdateProcessorFactory; import org.apache.solr.update.processor.RunUpdateProcessorFactory; import org.apache.solr.update.processor.UpdateRequestProcessorChain; import org.apache.solr.update.processor.UpdateRequestProcessorFactory; import org.apache.solr.util.RefCounted; import org.apache.solr.util.plugin.NamedListInitializedPlugin; import org.apache.solr.util.plugin.PluginInfoInitialized; import java.io.File; import java.io.IOException; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alimama.mdrill.solr.realtime.MdrillDirectory; import com.alimama.mdrill.solr.realtime.ReadOnlyDirectory; import com.alimama.mdrill.solr.realtime.RealTimeDirectory; import com.alimama.mdrill.solr.realtime.ShardPartion; import com.alimama.mdrill.utils.HadoopUtil; import com.esotericsoftware.minlog.Log; import java.net.URL; import java.lang.reflect.Constructor; /** * @version $Id: SolrCore.java 1190108 2011-10-28 01:13:25Z yonik $ */ public final class SolrCore implements SolrInfoMBean { public static final String version="1.0"; public static Logger log = LoggerFactory.getLogger(SolrCore.class); private String name; private String logid; // used to show what name is set private final CoreDescriptor coreDescriptor; private final SolrConfig solrConfig; private final SolrResourceLoader resourceLoader; private final IndexSchema schema; private final String dataDir; private final UpdateHandler updateHandler; private final long startTime; private final RequestHandlers reqHandlers; private final Map<String,SearchComponent> searchComponents; private final Map<String,UpdateRequestProcessorChain> updateProcessorChains; private final Map<String, SolrInfoMBean> infoRegistry; private IndexDeletionPolicyWrapper solrDelPolicy; public long getStartTime() { return startTime; } static int boolean_query_max_clause_count = Integer.MIN_VALUE; // only change the BooleanQuery maxClauseCount once for ALL cores... void booleanQueryMaxClauseCount() { synchronized(SolrCore.class) { if (boolean_query_max_clause_count == Integer.MIN_VALUE) { boolean_query_max_clause_count = solrConfig.booleanQueryMaxClauseCount; BooleanQuery.setMaxClauseCount(boolean_query_max_clause_count); } else if (boolean_query_max_clause_count != solrConfig.booleanQueryMaxClauseCount ) { log.debug("BooleanQuery.maxClauseCount= " +boolean_query_max_clause_count+ ", ignoring " +solrConfig.booleanQueryMaxClauseCount); } } } public SolrResourceLoader getResourceLoader() { return resourceLoader; } public String getConfigResource() { return solrConfig.getResourceName(); } @Deprecated public String getConfigFile() { return solrConfig.getResourceName(); } public SolrConfig getSolrConfig() { return solrConfig; } public String getSchemaResource() { return schema.getResourceName(); } @Deprecated public String getSchemaFile() { return schema.getResourceName(); } public IndexSchema getSchema() { return schema; } public String getDataDir() { return dataDir; } public String getIndexDir(String partion) { synchronized (searcherLock) { return this.getDataDir()+"/"+partion; } } public String getRealTimeDir(String partion) { synchronized (searcherLock) { return this.getIndexDir(partion)+"/realtime"; } } public String getName() { return name; } public void setName(String v) { this.name = v; this.logid = (v==null)?"":("["+v+"] "); } public Map<String, SolrInfoMBean> getInfoRegistry() { return infoRegistry; } private void initDeletionPolicy() { PluginInfo info = solrConfig.getPluginInfo(IndexDeletionPolicy.class.getName()); IndexDeletionPolicy delPolicy = null; if(info != null){ delPolicy = createInstance(info.className,IndexDeletionPolicy.class,"Deletion Policy for SOLR"); if (delPolicy instanceof NamedListInitializedPlugin) { ((NamedListInitializedPlugin) delPolicy).init(info.initArgs); } } else { delPolicy = new SolrDeletionPolicy(); } solrDelPolicy = new IndexDeletionPolicyWrapper(delPolicy); } private void initListeners() { final Class<SolrEventListener> clazz = SolrEventListener.class; final String label = "Event Listener"; for (PluginInfo info : solrConfig.getPluginInfos(SolrEventListener.class.getName())) { String event = info.attributes.get("event"); if("firstSearcher".equals(event) ){ SolrEventListener obj = createInitInstance(info,clazz,label,null); firstSearcherListeners.add(obj); log.info(logid + "Added SolrEventListener for firstSearcher: " + obj); } else if("newSearcher".equals(event) ){ SolrEventListener obj = createInitInstance(info,clazz,label,null); newSearcherListeners.add(obj); log.info(logid + "Added SolrEventListener for newSearcher: " + obj); } } } final List<SolrEventListener> firstSearcherListeners = new ArrayList<SolrEventListener>(); final List<SolrEventListener> newSearcherListeners = new ArrayList<SolrEventListener>(); public void registerFirstSearcherListener( SolrEventListener listener ) { firstSearcherListeners.add( listener ); } public void registerNewSearcherListener( SolrEventListener listener ) { newSearcherListeners.add( listener ); } public void registerResponseWriter( String name, QueryResponseWriter responseWriter ){ responseWriters.put(name, responseWriter); } /** Creates an instance by trying a constructor that accepts a SolrCore before * trying the default (no arg) constructor. *@param className the instance class to create *@param cast the class or interface that the instance should extend or implement *@param msg a message helping compose the exception error if any occurs. *@return the desired instance *@throws SolrException if the object could not be instantiated */ private <T extends Object> T createInstance(String className, Class<T> cast, String msg) { Class clazz = null; if (msg == null) msg = "SolrCore Object"; try { clazz = getResourceLoader().findClass(className); if (cast != null && !cast.isAssignableFrom(clazz)) throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,"Error Instantiating "+msg+", "+className+ " is not a " +cast.getName()); //most of the classes do not have constructors which takes SolrCore argument. It is recommended to obtain SolrCore by implementing SolrCoreAware. // So invariably always it will cause a NoSuchMethodException. So iterate though the list of available constructors Constructor[] cons = clazz.getConstructors(); for (Constructor con : cons) { Class[] types = con.getParameterTypes(); if(types.length == 1 && types[0] == SolrCore.class){ return (T)con.newInstance(this); } } return (T) getResourceLoader().newInstance(className);//use the empty constructor } catch (SolrException e) { throw e; } catch (Exception e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,"Error Instantiating "+msg+", "+className+ " failed to instantiate " +cast.getName(), e); } } public <T extends Object> T createInitInstance(PluginInfo info,Class<T> cast, String msg, String defClassName){ if(info == null) return null; T o = createInstance(info.className == null ? defClassName : info.className,cast, msg); if (o instanceof PluginInfoInitialized) { ((PluginInfoInitialized) o).init(info); } else if (o instanceof NamedListInitializedPlugin) { ((NamedListInitializedPlugin) o).init(info.initArgs); } return o; } public SolrEventListener createEventListener(String className) { return createInstance(className, SolrEventListener.class, "Event Listener"); } public SolrRequestHandler createRequestHandler(String className) { return createInstance(className, SolrRequestHandler.class, "Request Handler"); } private UpdateHandler createUpdateHandler(String className) { return createInstance(className, UpdateHandler.class, "Update Handler"); } public SolrCore(String name, String dataDir, SolrConfig config, IndexSchema schema, CoreDescriptor cd) { coreDescriptor = cd; this.setName( name ); resourceLoader = config.getResourceLoader(); if (dataDir == null){ dataDir = config.getDataDir(); if(dataDir == null) dataDir = cd.getDataDir(); } dataDir = SolrResourceLoader.normalizeDir(dataDir); log.info(logid+"Opening new SolrCore at " + resourceLoader.getInstanceDir() + ", dataDir="+dataDir); if (schema==null) { schema = new IndexSchema(config, IndexSchema.DEFAULT_SCHEMA_FILE, null); } //Initialize JMX // if (config.jmxConfig.enabled) { // infoRegistry = new JmxMonitoredMap<String, SolrInfoMBean>(name, String.valueOf(this.hashCode()), config.jmxConfig); // } else { log.info("JMX monitoring not detected for core: " + name); infoRegistry = new ConcurrentHashMap<String, SolrInfoMBean>(); // } infoRegistry.put("fieldCache", new SolrFieldCacheMBean()); this.schema = schema; this.dataDir = dataDir; this.solrConfig = config; this.startTime = System.currentTimeMillis(); // this.maxWarmingSearchers = config.maxWarmingSearchers; booleanQueryMaxClauseCount(); initListeners(); initDeletionPolicy(); initWriters(); initQParsers(); initValueSourceParsers(); this.searchComponents = loadSearchComponents(); // Processors initialized before the handlers updateProcessorChains = loadUpdateProcessorChains(); reqHandlers = new RequestHandlers(this); reqHandlers.initHandlersFromConfig( solrConfig ); // Handle things that should eventually go away // initDeprecatedSupport(); final CountDownLatch latch = new CountDownLatch(1); try { // cause the executor to stall so firstSearcher events won't fire // until after inform() has been called for all components. // searchExecutor must be single-threaded for this to work searcherExecutor.submit(new Callable() { public Object call() throws Exception { latch.await(); return null; } }); // Open the searcher *before* the update handler so we don't end up opening // one in the middle. // With lockless commits in Lucene now, this probably shouldn't be an issue anymore // getSearcher(false,false,null); String updateHandlerClass = solrConfig.getUpdateHandlerInfo().className; updateHandler = createUpdateHandler(updateHandlerClass == null ? DirectUpdateHandler2.class.getName():updateHandlerClass); infoRegistry.put("updateHandler", updateHandler); // Finally tell anyone who wants to know resourceLoader.inform( resourceLoader ); resourceLoader.inform( this ); // last call before the latch is released. // instance = this; // set singleton for backwards compatibility } finally { // allow firstSearcher events to fire latch.countDown(); } infoRegistry.put("core", this); // register any SolrInfoMBeans SolrResourceLoader initialized // // this must happen after the latch is released, because a JMX server impl may // choose to block on registering until properties can be fetched from an MBean, // and a SolrCoreAware MBean may have properties that depend on getting a Searcher // from the core. resourceLoader.inform(infoRegistry); } /** * Load the request processors */ private Map<String,UpdateRequestProcessorChain> loadUpdateProcessorChains() { Map<String, UpdateRequestProcessorChain> map = new HashMap<String, UpdateRequestProcessorChain>(); UpdateRequestProcessorChain def = initPlugins(map,UpdateRequestProcessorChain.class, UpdateRequestProcessorChain.class.getName()); if(def == null){ def = map.get(null); } if (def == null) { // construct the default chain UpdateRequestProcessorFactory[] factories = new UpdateRequestProcessorFactory[]{ new LogUpdateProcessorFactory(), new RunUpdateProcessorFactory() }; def = new UpdateRequestProcessorChain(factories, this); } map.put(null, def); map.put("", def); return map; } /** * @return an update processor registered to the given name. Throw an exception if this chain is undefined */ public UpdateRequestProcessorChain getUpdateProcessingChain( final String name ) { UpdateRequestProcessorChain chain = updateProcessorChains.get( name ); if( chain == null ) { throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "unknown UpdateRequestProcessorChain: "+name ); } return chain; } // this core current usage count private final AtomicInteger refCount = new AtomicInteger(1); final void open() { refCount.incrementAndGet(); } public void close() { int count = refCount.decrementAndGet(); if (count > 0) return; // close is called often, and only actually closes if nothing is using it. if (count < 0) { log.error("Too many close [count:{}] on {}. Please report this exception to solr-user@lucene.apache.org", count, this ); return; } log.info(logid+" CLOSING SolrCore " + this); // // if( closeHooks != null ) { // for( CloseHook hook : closeHooks ) { // try { // hook.preClose( this ); // } catch (Throwable e) { // SolrException.log(log, e); // } // } // } try { infoRegistry.clear(); } catch (Exception e) { SolrException.log(log, e); } try { updateHandler.close(); } catch (Exception e) { SolrException.log(log,e); } try { searcherExecutor.shutdown(); if (!searcherExecutor.awaitTermination(60, TimeUnit.SECONDS)) { log.error("Timeout waiting for searchExecutor to terminate"); } } catch (Exception e) { SolrException.log(log,e); } // if( closeHooks != null ) { // for( CloseHook hook : closeHooks ) { // try { // hook.postClose( this ); // } catch (Throwable e) { // SolrException.log(log, e); // } // } // } } /** Current core usage count. */ public int getOpenCount() { return refCount.get(); } /** Whether this core is closed. */ public boolean isClosed() { return refCount.get() <= 0; } @Override protected void finalize() throws Throwable { try { if (getOpenCount() != 0) { log.error("REFCOUNT ERROR: unreferenced " + this + " (" + getName() + ") has a reference count of " + getOpenCount()); } } finally { super.finalize(); } } // private Collection<CloseHook> closeHooks = null; // // /** // * Add a close callback hook // */ // public void addCloseHook( CloseHook hook ) // { // if( closeHooks == null ) { // closeHooks = new ArrayList<CloseHook>(); // } // closeHooks.add( hook ); // } /** * Returns a Request object based on the admin/pingQuery section * of the Solr config file. * * @deprecated use {@link org.apache.solr.handler.PingRequestHandler} instead */ @Deprecated public SolrQueryRequest getPingQueryRequest() { return solrConfig.getPingQueryRequest(this); } //////////////////////////////////////////////////////////////////////////////// // Request Handler //////////////////////////////////////////////////////////////////////////////// /** * Get the request handler registered to a given name. * * This function is thread safe. */ public SolrRequestHandler getRequestHandler(String handlerName) { return reqHandlers.get(handlerName); } /** * Returns an unmodifieable Map containing the registered handlers of the specified type. */ public Map<String,SolrRequestHandler> getRequestHandlers(Class clazz) { return reqHandlers.getAll(clazz); } /** * Returns an unmodifieable Map containing the registered handlers */ public Map<String,SolrRequestHandler> getRequestHandlers() { return reqHandlers.getRequestHandlers(); } /** * Get the SolrHighlighter */ @Deprecated public SolrHighlighter getHighlighter() { HighlightComponent hl = (HighlightComponent) searchComponents.get(HighlightComponent.COMPONENT_NAME); return hl==null? null: hl.getHighlighter(); } public SolrRequestHandler registerRequestHandler(String handlerName, SolrRequestHandler handler) { return reqHandlers.register(handlerName,handler); } /** * Register the default search components */ private Map<String, SearchComponent> loadSearchComponents() { Map<String, SearchComponent> components = new HashMap<String, SearchComponent>(); initPlugins(components,SearchComponent.class); for (Map.Entry<String, SearchComponent> e : components.entrySet()) { SearchComponent c = e.getValue(); if (c instanceof HighlightComponent) { HighlightComponent hl = (HighlightComponent) c; if(!HighlightComponent.COMPONENT_NAME.equals(e.getKey())){ components.put(HighlightComponent.COMPONENT_NAME,hl); } break; } } // addIfNotPresent(components,HighlightComponent.COMPONENT_NAME,HighlightComponent.class); addIfNotPresent(components,QueryComponent.COMPONENT_NAME,QueryComponent.class); addIfNotPresent(components,FacetComponent.COMPONENT_NAME,FacetComponent.class); // addIfNotPresent(components,MoreLikeThisComponent.COMPONENT_NAME,MoreLikeThisComponent.class); // addIfNotPresent(components,StatsComponent.COMPONENT_NAME,StatsComponent.class); // addIfNotPresent(components,DebugComponent.COMPONENT_NAME,DebugComponent.class); return components; } private <T> void addIfNotPresent(Map<String ,T> registry, String name, Class<? extends T> c){ if(!registry.containsKey(name)){ T searchComp = (T) resourceLoader.newInstance(c.getName()); registry.put(name, searchComp); if (searchComp instanceof SolrInfoMBean){ infoRegistry.put(((SolrInfoMBean)searchComp).getName(), (SolrInfoMBean)searchComp); } } } /** * @return a Search Component registered to a given name. Throw an exception if the component is undefined */ public SearchComponent getSearchComponent( String name ) { SearchComponent component = searchComponents.get( name ); if( component == null ) { throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Unknown Search Component: "+name ); } return component; } /** * Accessor for all the Search Components * @return An unmodifiable Map of Search Components */ public Map<String, SearchComponent> getSearchComponents() { return Collections.unmodifiableMap(searchComponents); } //////////////////////////////////////////////////////////////////////////////// // Update Handler //////////////////////////////////////////////////////////////////////////////// /** * RequestHandlers need access to the updateHandler so they can all talk to the * same RAM indexer. */ public UpdateHandler getUpdateHandler() { return updateHandler; } //////////////////////////////////////////////////////////////////////////////// // Searcher Control //////////////////////////////////////////////////////////////////////////////// // The current searcher used to service queries. // Don't access this directly!!!! use getSearcher() to // get it (and it will increment the ref count at the same time). // This reference is protected by searcherLock. // private RefCounted<SolrIndexSearcher> _searcher; // All of the open searchers. Don't access this directly. // protected by synchronizing on searcherLock. // private final LinkedList<RefCounted<SolrIndexSearcher>> _searchers = new LinkedList<RefCounted<SolrIndexSearcher>>(); final ExecutorService searcherExecutor = Executors.newSingleThreadExecutor(); // private int onDeckSearchers; // number of searchers preparing private Object searcherLock = new Object(); // the sync object for the searcher // private final int maxWarmingSearchers; // max number of on-deck searchers allowed private static Integer cacheSize = 16; private static Integer cacheSizeHb = 4; private static final Object listlock=new Object(); public static Cache<String,RefCounted<SolrIndexSearcher>> searchCache=null; public static Cache<String,RefCounted<SolrIndexSearcher>> searchCacheForHb=null; public static final LinkedList<RefCounted<SolrIndexSearcher>> clearlist=new LinkedList<RefCounted<SolrIndexSearcher>>(); public static String binglogType="hdfs"; public static String getBinglogType() { return binglogType; } public static void setBinglogType(String binglogType) { SolrCore.binglogType = binglogType; } public static void setSearchCacheSize(int cacheSize) { SolrCore.cacheSize = cacheSize; } private void initSearchCache() { if (searchCache == null) { final float LOADFACTOR = 0.75f; SimpleMapCache<String, RefCounted<SolrIndexSearcher>> ccache = (new SimpleMapCache<String, RefCounted<SolrIndexSearcher>>( new LinkedHashMap<String, RefCounted<SolrIndexSearcher>>( (int) Math.ceil(cacheSize / LOADFACTOR) + 1, LOADFACTOR, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry<String, RefCounted<SolrIndexSearcher>> eldest) { boolean rtn= size() > cacheSize; if(rtn) { DropSearch(eldest.getValue()); log.info("SolrIndexSearcher clear:" + eldest.getKey()+","+this.size()+"@"+cacheSize); } return rtn; } })); searchCache = Cache.synchronizedCache(ccache); } if (searchCacheForHb == null) { final float LOADFACTOR = 0.75f; SimpleMapCache<String, RefCounted<SolrIndexSearcher>> ccache = (new SimpleMapCache<String, RefCounted<SolrIndexSearcher>>( new LinkedHashMap<String, RefCounted<SolrIndexSearcher>>( (int) Math.ceil(cacheSizeHb / LOADFACTOR) + 1, LOADFACTOR, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry<String, RefCounted<SolrIndexSearcher>> eldest) { boolean rtn= size() > cacheSizeHb; if(rtn) { DropSearch(eldest.getValue()); // log.info("SolrIndexSearcher clear for hb:" + eldest.getKey()+","+this.size()+"@"+cacheSizeHb); } return rtn; } })); searchCacheForHb = Cache.synchronizedCache(ccache); } } private void clearPartion() throws IOException { long maxwaittime=1000l*60*30; synchronized (listlock) { long nowtime=System.currentTimeMillis(); ArrayList<RefCounted<SolrIndexSearcher>> refull = new ArrayList<RefCounted<SolrIndexSearcher>>(); RefCounted<SolrIndexSearcher> refCount; while ((refCount = clearlist.poll()) != null) { if (refCount.getRefcount() <= 0||nowtime-refCount.reftime>maxwaittime) { try{ refCount.get().close(); }catch(Throwable e){ } } else { refull.add(refCount); log.info("ref clearpartion "+refCount.toDebugMsg()); } } clearlist.addAll(refull); } } private RefCounted<SolrIndexSearcher> newHolderPartion( SolrIndexSearcher newSearcher) { RefCounted<SolrIndexSearcher> holder = new RefCounted<SolrIndexSearcher>(newSearcher) { @Override public void close() { } }; holder.incref(); return holder; } public void DropSearch(RefCounted<SolrIndexSearcher> search) { synchronized (listlock) { search.reftime=System.currentTimeMillis(); clearlist.add(search); } try { clearPartion(); } catch (IOException e) { e.printStackTrace(); } } public RefCounted<SolrIndexSearcher> getSearcher(String partion,boolean mdirs,boolean isclearCache,boolean ishb) { String corename=this.getName(); if(corename==null) { corename=""; } PartionKey p=new PartionKey(corename, partion); String partionKey=corename+"@"+partion+"@"+SolrResourceLoader.getCacheFlushKey(p); File f = new File(getDataDir(), partion); return getSearcherByPath(p,partionKey, f.getAbsolutePath(), mdirs, isclearCache, ishb); } private static Cache<PartionKey,ReadOnlyDirectory> forReadOnlyDir =(new SimpleMapCache<PartionKey, ReadOnlyDirectory>( new LinkedHashMap<PartionKey, ReadOnlyDirectory>( (int) Math.ceil(16 / 0.75f) + 1, 0.75f, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry<PartionKey, ReadOnlyDirectory> eldest) { boolean rtn= size() > 16; return rtn; } })); private static Cache<PartionKey,RealTimeDirectory> forRealTimeDir =(new SimpleMapCache<PartionKey, RealTimeDirectory>( new LinkedHashMap<PartionKey, RealTimeDirectory>( (int) Math.ceil(16 / 0.75f) + 1, 0.75f, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry<PartionKey, RealTimeDirectory> eldest) { boolean rtn= size() > 16; if(rtn) { eldest.getValue().mergerFinal(); eldest.getValue().syncHdfs(); eldest.getValue().close(); } return rtn; } })); private static Cache<PartionKey,RealTimeDirectory> forWriteDir =(new SimpleMapCache<PartionKey, RealTimeDirectory>( new LinkedHashMap<PartionKey, RealTimeDirectory>( (int) Math.ceil(32 / 0.75f) + 1, 0.75f, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry<PartionKey, RealTimeDirectory> eldest) { boolean rtn= size() > 32; if(rtn) { eldest.getValue().syncHdfs(); eldest.getValue().close(); } return rtn; } })); public static ConcurrentHashMap<String, String> tablemode=new ConcurrentHashMap<String, String>(); public static String getTablemode(String table) { return tablemode.get(table); } public static void setTablemode(String tablename,String tablemode) { SolrCore.tablemode.put(tablename, tablemode); } private MdrillDirectory getForWrite(String partion, boolean forwrite) throws IOException { String corename = this.getName(); if (corename == null) { corename = ""; } PartionKey p = new PartionKey(corename, partion); boolean isWritePool = false; synchronized (forRealTimeDir) { RealTimeDirectory rtn = forRealTimeDir.remove(p); if (forwrite) { isWritePool = true; if (rtn == null) { rtn = forWriteDir.remove(p); } } else { if (rtn == null) { rtn = forWriteDir.remove(p); if (rtn != null) { isWritePool = true; } } } if (rtn == null) { File f = new File(getDataDir(), partion); try{ rtn = new RealTimeDirectory(f, HadoopUtil.hadoopConfDir, ShardPartion .getHdfsRealtimePath(p.tablename, p.partion) .toString(),this,p); }catch(Throwable e) { log.error("getForWrite error",e); rtn=null; } } if (isWritePool) { forWriteDir.put(p, rtn); } else { forRealTimeDir.put(p, rtn); } rtn.setCore(this); rtn.setPartion(p); return rtn; } } public MdrillDirectory getRealTime(String partion,boolean forwrite) throws IOException { String corename=this.getName(); if(corename==null) { corename=""; } boolean isrealtime=forwrite||String.valueOf(getTablemode(corename)).indexOf("@realtime@")>=0; PartionKey p=new PartionKey(corename, partion); if(isrealtime) { synchronized (forReadOnlyDir) { forReadOnlyDir.remove(p); } return getForWrite(partion,forwrite); } synchronized (forReadOnlyDir) { MdrillDirectory rtdir=forReadOnlyDir.get(p); if(rtdir!=null) { rtdir.setCore(this); rtdir.setPartion(p); return rtdir; } File f = new File(getDataDir(), partion); ReadOnlyDirectory ddd=new ReadOnlyDirectory(f , HadoopUtil.hadoopConfDir, ShardPartion.getHdfsRealtimePath(p.tablename,p.partion).toString()); rtdir=ddd; forReadOnlyDir.put(p, ddd); rtdir.setCore(this); rtdir.setPartion(p); return rtdir; } } public synchronized RefCounted<SolrIndexSearcher> getSearcherByPath(PartionKey p,String partionKey,String path,boolean mdirs,boolean isclearCache,boolean ishb) { try { this.clearPartion(); } catch (IOException e1) { e1.printStackTrace(); } this.initSearchCache(); try { RefCounted<SolrIndexSearcher> rtn = searchCache.get(partionKey); if(rtn==null) { rtn=searchCacheForHb.get(partionKey); } if(isclearCache&&rtn != null) { this.DropSearch(rtn); SolrResourceLoader.SetCacheFlushKey(p,System.currentTimeMillis()); rtn=null; searchCache.remove(partionKey); searchCacheForHb.remove(partionKey); } if (rtn != null) { rtn.incref(); return rtn; }else{ File f = new File(path); log.info("getSearcher:" + partionKey + ":" + f.getAbsolutePath()); if (!f.exists()&&mdirs) { f.mkdirs(); } if(!f.exists()) { return null; } Directory dir=null; IndexReader reader=null; if(p==null) { log.info("#######################getSearcher:" + partionKey + ":" + f.getAbsolutePath()+",p=null"); dir=LinkFSDirectory.readOnlyOpen(f);; dir.setCore(this,p); reader=IndexReader.open(dir); }else if(p.partion.equals("default")) { RAMDirectory rd=new RAMDirectory(); rd.setCore(this,p); IndexWriter writer=new IndexWriter(rd, null,new KeepOnlyLastCommitDeletionPolicy(), MaxFieldLength.UNLIMITED); writer.setMergeFactor(10); writer.setUseCompoundFile(false); writer.close(); reader=IndexReader.open(rd); }else{ MdrillDirectory rtdir=getRealTime(p.partion,false); List<Directory> list=rtdir.getForSearch(); IndexReader[] r=new IndexReader[list.size()]; for(int i=0;i<list.size();i++) { Directory d=list.get(i); d.setCore(this,p); r[i]=IndexReader.open(d); } if(r.length==1) { reader= r[0]; }else{ reader=new MultiReader(r,true); } } if(dir==null) { dir=FSDirectory.open(f); dir.setCore(this,p); } File cachedir = null; if(dir instanceof FSDirectory) { FSDirectory d=(FSDirectory)dir; cachedir=new File(d.getDirectory(), "cacheField"); }else{ cachedir=new File(f, "cacheField"); } cachedir.mkdirs(); Directory fieldcacheDir = FSDirectory.open(cachedir); fieldcacheDir.setCore(this,p); SolrIndexSearcher newSearcher = new SolrIndexSearcher(this, schema, "partion_" + partionKey, reader, true); newSearcher.setPartionCacheKey(p); newSearcher.setFieldcacheDir(fieldcacheDir); newSearcher.setPartionKey(partionKey); rtn = newHolderPartion(newSearcher); if(ishb) { searchCacheForHb.put(partionKey, rtn); }else{ searchCache.put(partionKey, rtn); } return rtn; } } catch (IOException e) { SolrCore.log.info(e.toString()); SolrException.log(log, null, e); return null; } } // public RefCounted<SolrIndexSearcher> getSearcher() { // try { // return getSearcher(false,true,null); // } catch (IOException e) { // SolrException.log(log,null,e); // return null; // } // } // /** // * Return the newest {@link RefCounted}<{@link SolrIndexSearcher}> with // * the reference count incremented. It <b>must</b> be decremented when no longer needed. // * If no searcher is currently open, then if openNew==true a new searcher will be opened, // * or null is returned if openNew==false. // */ // public RefCounted<SolrIndexSearcher> getNewestSearcher(boolean openNew) { // synchronized (searcherLock) { // if (_searchers.isEmpty()) { // if (!openNew) return null; // // Not currently implemented since simply calling getSearcher during inform() // // can result in a deadlock. Right now, solr always opens a searcher first // // before calling inform() anyway, so this should never happen. // throw new UnsupportedOperationException(); // } // RefCounted<SolrIndexSearcher> newest = _searchers.getLast(); // newest.incref(); // return newest; // } // } /** * Get a {@link SolrIndexSearcher} or start the process of creating a new one. * <p> * The registered searcher is the default searcher used to service queries. * A searcher will normally be registered after all of the warming * and event handlers (newSearcher or firstSearcher events) have run. * In the case where there is no registered searcher, the newly created searcher will * be registered before running the event handlers (a slow searcher is better than no searcher). * * <p> * These searchers contain read-only IndexReaders. To access a non read-only IndexReader, * see newSearcher(String name, boolean readOnly). * * <p> * If <tt>forceNew==true</tt> then * A new searcher will be opened and registered regardless of whether there is already * a registered searcher or other searchers in the process of being created. * <p> * If <tt>forceNew==false</tt> then:<ul> * <li>If a searcher is already registered, that searcher will be returned</li> * <li>If no searcher is currently registered, but at least one is in the process of being created, then * this call will block until the first searcher is registered</li> * <li>If no searcher is currently registered, and no searchers in the process of being registered, a new * searcher will be created.</li> * </ul> * <p> * If <tt>returnSearcher==true</tt> then a {@link RefCounted}<{@link SolrIndexSearcher}> will be returned with * the reference count incremented. It <b>must</b> be decremented when no longer needed. * <p> * If <tt>waitSearcher!=null</tt> and a new {@link SolrIndexSearcher} was created, * then it is filled in with a Future that will return after the searcher is registered. The Future may be set to * <tt>null</tt> in which case the SolrIndexSearcher created has already been registered at the time * this method returned. * <p> * @param forceNew if true, force the open of a new index searcher regardless if there is already one open. * @param returnSearcher if true, returns a {@link SolrIndexSearcher} holder with the refcount already incremented. * @param waitSearcher if non-null, will be filled in with a {@link Future} that will return after the new searcher is registered. * @throws IOException */ // public RefCounted<SolrIndexSearcher> getSearcher(boolean forceNew, boolean returnSearcher, final Future[] waitSearcher) throws IOException { // // it may take some time to open an index.... we may need to make // // sure that two threads aren't trying to open one at the same time // // if it isn't necessary. // // synchronized (searcherLock) { // // see if we can return the current searcher // if (_searcher!=null && !forceNew) { // if (returnSearcher) { // _searcher.incref(); // return _searcher; // } else { // return null; // } // } // // // check to see if we can wait for someone else's searcher to be set // if (onDeckSearchers>0 && !forceNew && _searcher==null) { // try { // searcherLock.wait(); // } catch (InterruptedException e) { // log.info(SolrException.toStr(e)); // } // } // // // check again: see if we can return right now // if (_searcher!=null && !forceNew) { // if (returnSearcher) { // _searcher.incref(); // return _searcher; // } else { // return null; // } // } // // // At this point, we know we need to open a new searcher... // // first: increment count to signal other threads that we are // // opening a new searcher. // onDeckSearchers++; // if (onDeckSearchers < 1) { // // should never happen... just a sanity check // log.error(logid+"ERROR!!! onDeckSearchers is " + onDeckSearchers); // onDeckSearchers=1; // reset // } else if (onDeckSearchers > maxWarmingSearchers) { // onDeckSearchers--; // String msg="Error opening new searcher. exceeded limit of maxWarmingSearchers="+maxWarmingSearchers + ", try again later."; // log.warn(logid+""+ msg); // // HTTP 503==service unavailable, or 409==Conflict // throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE,msg,true); // } else if (onDeckSearchers > 1) { // log.info(logid+"PERFORMANCE WARNING: Overlapping onDeckSearchers=" + onDeckSearchers); // } // } // // // open the index synchronously // // if this fails, we need to decrement onDeckSearchers again. // SolrIndexSearcher tmp; // RefCounted<SolrIndexSearcher> newestSearcher = null; // // try { // newestSearcher = getNewestSearcher(false); // String newIndexDir = getNewIndexDir(); // File indexDirFile = new File(getIndexDir()).getCanonicalFile(); // File newIndexDirFile = new File(newIndexDir).getCanonicalFile(); // // if (newestSearcher != null && solrConfig.reopenReaders // && indexDirFile.equals(newIndexDirFile)) { // IndexReader currentReader = newestSearcher.get().getReader(); // IndexReader newReader = IndexReader.openIfChanged(currentReader); // // if (newReader == null) { // currentReader.incRef(); // newReader = currentReader; // } // // tmp = new SolrIndexSearcher(this, schema, "main", newReader, true, true); // } else { // IndexReader reader = getIndexReaderFactory().newReader(getDirectoryFactory().open(newIndexDir), true); // tmp = new SolrIndexSearcher(this, schema, "main", reader, true, true); // } // } catch (Throwable th) { // synchronized(searcherLock) { // onDeckSearchers--; // // notify another waiter to continue... it may succeed // // and wake any others. // searcherLock.notify(); // } // // need to close the searcher here??? we shouldn't have to. // throw new RuntimeException(th); // } finally { // if (newestSearcher != null) { // newestSearcher.decref(); // } // } // // final SolrIndexSearcher newSearcher=tmp; // // RefCounted<SolrIndexSearcher> currSearcherHolder=null; // final RefCounted<SolrIndexSearcher> newSearchHolder=newHolder(newSearcher); // // if (returnSearcher) newSearchHolder.incref(); // // // a signal to decrement onDeckSearchers if something goes wrong. // final boolean[] decrementOnDeckCount=new boolean[1]; // decrementOnDeckCount[0]=true; // // try { // // boolean alreadyRegistered = false; // synchronized (searcherLock) { // _searchers.add(newSearchHolder); // // if (_searcher == null) { // // if there isn't a current searcher then we may // // want to register this one before warming is complete instead of waiting. // if (solrConfig.useColdSearcher) { // registerSearcher(newSearchHolder); // decrementOnDeckCount[0]=false; // alreadyRegistered=true; // } // } else { // // get a reference to the current searcher for purposes of autowarming. // currSearcherHolder=_searcher; // currSearcherHolder.incref(); // } // } // // // final SolrIndexSearcher currSearcher = currSearcherHolder==null ? null : currSearcherHolder.get(); // // // // // Note! if we registered the new searcher (but didn't increment it's // // reference count because returnSearcher==false, it's possible for // // someone else to register another searcher, and thus cause newSearcher // // to close while we are warming. // // // // Should we protect against that by incrementing the reference count? // // Maybe we should just let it fail? After all, if returnSearcher==false // // and newSearcher has been de-registered, what's the point of continuing? // // // // Future future=null; // // // warm the new searcher based on the current searcher. // // should this go before the other event handlers or after? // if (currSearcher != null) { // future = searcherExecutor.submit( // new Callable() { // public Object call() throws Exception { // try { // newSearcher.warm(currSearcher); // } catch (Throwable e) { // SolrException.logOnce(log,null,e); // } // return null; // } // } // ); // } // // if (currSearcher==null && firstSearcherListeners.size() > 0) { // future = searcherExecutor.submit( // new Callable() { // public Object call() throws Exception { // try { // for (SolrEventListener listener : firstSearcherListeners) { // listener.newSearcher(newSearcher,null); // } // } catch (Throwable e) { // SolrException.logOnce(log,null,e); // } // return null; // } // } // ); // } // // if (currSearcher!=null && newSearcherListeners.size() > 0) { // future = searcherExecutor.submit( // new Callable() { // public Object call() throws Exception { // try { // for (SolrEventListener listener : newSearcherListeners) { // listener.newSearcher(newSearcher, currSearcher); // } // } catch (Throwable e) { // SolrException.logOnce(log,null,e); // } // return null; // } // } // ); // } // // // WARNING: this code assumes a single threaded executor (that all tasks // // queued will finish first). // final RefCounted<SolrIndexSearcher> currSearcherHolderF = currSearcherHolder; // if (!alreadyRegistered) { // future = searcherExecutor.submit( // new Callable() { // public Object call() throws Exception { // try { // // signal that we no longer need to decrement // // the count *before* registering the searcher since // // registerSearcher will decrement even if it errors. // decrementOnDeckCount[0]=false; // registerSearcher(newSearchHolder); // } catch (Throwable e) { // SolrException.logOnce(log,null,e); // } finally { // // we are all done with the old searcher we used // // for warming... // if (currSearcherHolderF!=null) currSearcherHolderF.decref(); // } // return null; // } // } // ); // } // // if (waitSearcher != null) { // waitSearcher[0] = future; // } // // // Return the searcher as the warming tasks run in parallel // // callers may wait on the waitSearcher future returned. // return returnSearcher ? newSearchHolder : null; // // } catch (Exception e) { // SolrException.logOnce(log,null,e); // if (currSearcherHolder != null) currSearcherHolder.decref(); // // synchronized (searcherLock) { // if (decrementOnDeckCount[0]) { // onDeckSearchers--; // } // if (onDeckSearchers < 0) { // // sanity check... should never happen // log.error(logid+"ERROR!!! onDeckSearchers after decrement=" + onDeckSearchers); // onDeckSearchers=0; // try and recover // } // // if we failed, we need to wake up at least one waiter to continue the process // searcherLock.notify(); // } // // // since the indexreader was already opened, assume we can continue on // // even though we got an exception. // return returnSearcher ? newSearchHolder : null; // } // // } // private RefCounted<SolrIndexSearcher> newHolder(SolrIndexSearcher newSearcher) { // RefCounted<SolrIndexSearcher> holder = new RefCounted<SolrIndexSearcher>(newSearcher) { // @Override // public void close() { // try { // synchronized(searcherLock) { // // it's possible for someone to get a reference via the _searchers queue // // and increment the refcount while RefCounted.close() is being called. // // we check the refcount again to see if this has happened and abort the close. // // This relies on the RefCounted class allowing close() to be called every // // time the counter hits zero. // if (refcount.get() > 0) return; // _searchers.remove(this); // } // resource.close(); // } catch (IOException e) { // log.error("Error closing searcher:" + SolrException.toStr(e)); // } // } // }; // holder.incref(); // set ref count to 1 to account for this._searcher // return holder; // } // Take control of newSearcherHolder (which should have a reference count of at // least 1 already. If the caller wishes to use the newSearcherHolder directly // after registering it, then they should increment the reference count *before* // calling this method. // // onDeckSearchers will also be decremented (it should have been incremented // as a result of opening a new searcher). // private void registerSearcher(RefCounted<SolrIndexSearcher> newSearcherHolder) throws IOException { // synchronized (searcherLock) { // try { // if (_searcher != null) { // _searcher.decref(); // dec refcount for this._searcher // _searcher=null; // } // // _searcher = newSearcherHolder; // SolrIndexSearcher newSearcher = newSearcherHolder.get(); // // /*** // // a searcher may have been warming asynchronously while the core was being closed. // // if this happens, just close the searcher. // if (isClosed()) { // // NOTE: this should not happen now - see close() for details. // // *BUT* if we left it enabled, this could still happen before // // close() stopped the executor - so disable this test for now. // log.error("Ignoring searcher register on closed core:" + newSearcher); // _searcher.decref(); // } // ***/ // // newSearcher.register(); // register subitems (caches) // log.info(logid+"Registered new searcher " + newSearcher); // // } catch (Throwable e) { // log(e); // } finally { // // wake up anyone waiting for a searcher // // even in the face of errors. // onDeckSearchers--; // searcherLock.notifyAll(); // } // } // } public void execute(SolrRequestHandler handler, SolrQueryRequest req, SolrQueryResponse rsp) { if (handler==null) { String msg = "Null Request Handler '" + req.getParams().get(CommonParams.QT) + "'"; if (log.isWarnEnabled()) log.warn(logid + msg + ":" + req); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, msg, true); } // setup response header and handle request final NamedList<Object> responseHeader = new SimpleOrderedMap<Object>(); rsp.add("responseHeader", responseHeader); handler.handleRequest(req,rsp); setResponseHeaderValues(handler,req,rsp); if(req.getParams().get("showlog","0").equals("1")) { // toLog is a local ref to the same NamedList used by the request NamedList toLog = rsp.getToLog(); // for back compat, we set these now just in case other code // are expecting them during handleRequest toLog.add("webapp", req.getContext().get("webapp")); toLog.add("path", req.getContext().get("path")); SolrParams params=req.getParams(); NamedList<Object> p=params.toNamedList(); p.remove("mdrill.crc.key.get.crclist"); toLog.add("params", "{" + p.toString() + "}"); StringBuilder sb = new StringBuilder(logid); for (int i=0; i<toLog.size(); i++) { String name = toLog.getName(i); Object val = toLog.getVal(i); sb.append(name).append("=").append(val).append(" "); } String loginfo=sb.toString(); log.info(loginfo.substring(0,Math.min(2048, loginfo.length()))); } } /** * @deprecated Use {@link #execute(SolrRequestHandler, SolrQueryRequest, SolrQueryResponse)} instead. */ @Deprecated public void execute(SolrQueryRequest req, SolrQueryResponse rsp) { SolrRequestHandler handler = getRequestHandler(req.getQueryType()); if (handler==null) { log.warn(logid+"Unknown Request Handler '" + req.getQueryType() +"' :" + req); throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"Unknown Request Handler '" + req.getQueryType() + "'", true); } execute(handler, req, rsp); } public static void setResponseHeaderValues(SolrRequestHandler handler, SolrQueryRequest req, SolrQueryResponse rsp) { // TODO should check that responseHeader has not been replaced by handler NamedList responseHeader = rsp.getResponseHeader(); final int qtime=(int)(rsp.getEndTime() - req.getStartTime()); int status = 0; Exception exception = rsp.getException(); if( exception != null ){ if( exception instanceof SolrException ) status = ((SolrException)exception).code(); else status = 500; } responseHeader.add("status",status); responseHeader.add("QTime",qtime); rsp.getToLog().add("status",status); rsp.getToLog().add("QTime",qtime); SolrParams params = req.getParams(); if( params.getBool(CommonParams.HEADER_ECHO_HANDLER, false) ) { responseHeader.add("handler", handler.getName() ); } // Values for echoParams... false/true/all or false/explicit/all ??? String ep = params.get( CommonParams.HEADER_ECHO_PARAMS, null ); if( ep != null ) { EchoParamStyle echoParams = EchoParamStyle.get( ep ); if( echoParams == null ) { throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"Invalid value '" + ep + "' for " + CommonParams.HEADER_ECHO_PARAMS + " parameter, use '" + EchoParamStyle.EXPLICIT + "' or '" + EchoParamStyle.ALL + "'" ); } if( echoParams == EchoParamStyle.EXPLICIT ) { responseHeader.add("params", req.getOriginalParams().toNamedList()); } else if( echoParams == EchoParamStyle.ALL ) { responseHeader.add("params", req.getParams().toNamedList()); } } } final public static void log(Throwable e) { SolrException.logOnce(log,null,e); } private QueryResponseWriter defaultResponseWriter; private final Map<String, QueryResponseWriter> responseWriters = new HashMap<String, QueryResponseWriter>(); public static final Map<String ,QueryResponseWriter> DEFAULT_RESPONSE_WRITERS ; static{ HashMap<String, QueryResponseWriter> m= new HashMap<String, QueryResponseWriter>(); m.put("xml", new XMLResponseWriter()); m.put("standard", m.get("xml")); m.put("json", new JSONResponseWriter()); // m.put("python", new PythonResponseWriter()); // m.put("php", new PHPResponseWriter()); // m.put("phps", new PHPSerializedResponseWriter()); // m.put("ruby", new RubyResponseWriter()); m.put("raw", new RawResponseWriter()); m.put("javabin", new BinaryResponseWriter()); m.put("csv", new CSVResponseWriter()); DEFAULT_RESPONSE_WRITERS = Collections.unmodifiableMap(m); } /** Configure the query response writers. There will always be a default writer; additional * writers may also be configured. */ private void initWriters() { defaultResponseWriter = initPlugins(responseWriters, QueryResponseWriter.class); for (Map.Entry<String, QueryResponseWriter> entry : DEFAULT_RESPONSE_WRITERS.entrySet()) { if(responseWriters.get(entry.getKey()) == null) responseWriters.put(entry.getKey(), entry.getValue()); } // configure the default response writer; this one should never be null if (defaultResponseWriter == null) { defaultResponseWriter = responseWriters.get("standard"); } } /** Finds a writer by name, or returns the default writer if not found. */ public final QueryResponseWriter getQueryResponseWriter(String writerName) { if (writerName != null) { QueryResponseWriter writer = responseWriters.get(writerName); if (writer != null) { return writer; } } return defaultResponseWriter; } /** Returns the appropriate writer for a request. If the request specifies a writer via the * 'wt' parameter, attempts to find that one; otherwise return the default writer. */ public final QueryResponseWriter getQueryResponseWriter(SolrQueryRequest request) { return getQueryResponseWriter(request.getParams().get(CommonParams.WT)); } private final Map<String, QParserPlugin> qParserPlugins = new HashMap<String, QParserPlugin>(); /** Configure the query parsers. */ private void initQParsers() { initPlugins(qParserPlugins,QParserPlugin.class); // default parsers for (int i=0; i<QParserPlugin.standardPlugins.length; i+=2) { try { String name = (String)QParserPlugin.standardPlugins[i]; if (null == qParserPlugins.get(name)) { Class<QParserPlugin> clazz = (Class<QParserPlugin>)QParserPlugin.standardPlugins[i+1]; QParserPlugin plugin = clazz.newInstance(); qParserPlugins.put(name, plugin); plugin.init(null); } } catch (Exception e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e); } } } public QParserPlugin getQueryPlugin(String parserName) { QParserPlugin plugin = qParserPlugins.get(parserName); if (plugin != null) return plugin; throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown query type '"+parserName+"'"); } private final HashMap<String, ValueSourceParser> valueSourceParsers = new HashMap<String, ValueSourceParser>(); /** Configure the ValueSource (function) plugins */ private void initValueSourceParsers() { initPlugins(valueSourceParsers,ValueSourceParser.class); // default value source parsers for (Map.Entry<String, ValueSourceParser> entry : ValueSourceParser.standardValueSourceParsers.entrySet()) { try { String name = entry.getKey(); if (null == valueSourceParsers.get(name)) { ValueSourceParser valueSourceParser = entry.getValue(); valueSourceParsers.put(name, valueSourceParser); valueSourceParser.init(null); } } catch (Exception e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e); } } } /** * @param registry The map to which the instance should be added to. The key is the name attribute * @param type the class or interface that the instance should extend or implement. * @param defClassName If PluginInfo does not have a classname, use this as the classname * @return The default instance . The one with (default=true) */ public <T> T initPlugins(Map<String ,T> registry, Class<T> type, String defClassName){ return initPlugins(solrConfig.getPluginInfos(type.getName()), registry, type, defClassName); } public <T> T initPlugins(List<PluginInfo> pluginInfos, Map<String, T> registry, Class<T> type, String defClassName) { T def = null; for (PluginInfo info : pluginInfos) { T o = createInitInstance(info,type, type.getSimpleName(), defClassName); registry.put(info.name, o); if(info.isDefault()){ def = o; } } return def; } /**For a given List of PluginInfo return the instances as a List * @param defClassName The default classname if PluginInfo#className == null * @return The instances initialized */ public <T> List<T> initPlugins(List<PluginInfo> pluginInfos, Class<T> type, String defClassName) { if(pluginInfos.isEmpty()) return Collections.emptyList(); List<T> result = new ArrayList<T>(); for (PluginInfo info : pluginInfos) result.add(createInitInstance(info,type, type.getSimpleName(), defClassName)); return result; } public <T> T initPlugins(Map<String, T> registry, Class<T> type) { return initPlugins(registry, type, null); } public ValueSourceParser getValueSourceParser(String parserName) { return valueSourceParsers.get(parserName); } public CoreDescriptor getCoreDescriptor() { return coreDescriptor; } public IndexDeletionPolicyWrapper getDeletionPolicy(){ return solrDelPolicy; } ///////////////////////////////////////////////////////////////////// // SolrInfoMBean stuff: Statistics and Module Info ///////////////////////////////////////////////////////////////////// public String getVersion() { return SolrCore.version; } public String getDescription() { return "SolrCore"; } public Category getCategory() { return Category.CORE; } public String getSourceId() { return "$Id: SolrCore.java 1190108 2011-10-28 01:13:25Z yonik $"; } public String getSource() { return "$URL: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_5/solr/core/src/java/org/apache/solr/core/SolrCore.java $"; } public URL[] getDocs() { return null; } public NamedList getStatistics() { NamedList lst = new SimpleOrderedMap(); lst.add("coreName", name==null ? "(null)" : name); lst.add("startTime", new Date(startTime)); lst.add("refCount", getOpenCount()); // lst.add("aliases", getCoreDescriptor().getCoreContainer().getCoreNames(this)); return lst; } }