| Method from org.apache.solr.core.SolrCore Detail: |
public void close() {
log.info("CLOSING SolrCore!");
try {
closeSearcher();
} catch (Exception e) {
SolrException.log(log,e);
}
try {
searcherExecutor.shutdown();
} catch (Exception e) {
SolrException.log(log,e);
}
try {
updateHandler.close();
} catch (Exception e) {
SolrException.log(log,e);
}
}
|
public void closeSearcher() {
log.info("Closing main searcher on request.");
synchronized (searcherLock) {
if (_searcher != null) {
_searcher.decref(); // dec refcount for this._searcher
_searcher=null;
SolrInfoRegistry.getRegistry().remove("currentSearcher");
}
}
}
|
public void execute(SolrQueryRequest req,
SolrQueryResponse rsp) {
SolrRequestHandler handler = getRequestHandler(req.getQueryType());
if (handler==null) {
log.warning("Unknown Request Handler '" + req.getQueryType() +"' :" + req);
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"Unknown Request Handler '" + req.getQueryType() + "'", true);
}
execute(handler, req, rsp);
}
|
public void execute(SolrRequestHandler handler,
SolrQueryRequest req,
SolrQueryResponse rsp) {
// setup response header and handle request
final NamedList< Object > responseHeader = new SimpleOrderedMap< Object >();
rsp.add("responseHeader", responseHeader);
handler.handleRequest(req,rsp);
setResponseHeaderValues(handler,responseHeader,req,rsp);
log.info(req.getContext().get("path") + " "
+ req.getParamString()+ " 0 "+
(int)(rsp.getEndTime() - req.getStartTime()));
}
|
protected void finalize() {
close();
}
|
public String getDataDir() {
return dataDir;
}
|
public String getIndexDir() {
return index_path;
}
|
public final QueryResponseWriter getQueryResponseWriter(String writerName) {
if (writerName != null) {
QueryResponseWriter writer = responseWriters.get(writerName);
if (writer != null) {
return writer;
}
}
return defaultResponseWriter;
}
Finds a writer by name, or returns the default writer if not found. |
public final QueryResponseWriter getQueryResponseWriter(SolrQueryRequest request) {
return getQueryResponseWriter(request.getParam("wt"));
}
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 SolrRequestHandler getRequestHandler(String handlerName) {
return reqHandlers.get(handlerName);
}
Get the request handler registered to a given name.
This function is thread safe. |
public Map getRequestHandlers() {
return reqHandlers.getRequestHandlers();
}
Returns an unmodifieable Map containing the registered handlers |
public IndexSchema getSchema() {
return schema;
}
|
public RefCounted getSearcher() {
// max number of on-deck searchers allowed
try {
return getSearcher(false,true,null);
} catch (IOException e) {
SolrException.log(log,null,e);
return null;
}
}
|
public RefCounted getSearcher(boolean forceNew,
boolean returnSearcher,
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.severe("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.warning(msg);
// HTTP 503==service unavailable, or 409==Conflict
throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE,msg,true);
} else if (onDeckSearchers > 1) {
log.info("PERFORMANCE WARNING: Overlapping onDeckSearchers=" + onDeckSearchers);
}
}
// open the index synchronously
// if this fails, we need to decrement onDeckSearchers again.
SolrIndexSearcher tmp;
try {
tmp = new SolrIndexSearcher(schema, "main", index_path, 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);
}
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) {
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.config.getBool("query/useColdSearcher",false)) {
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,null);
}
} 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.severe("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;
}
}
Get a SolrIndexSearcher or start the process of creating a new one.
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).
If forceNew==true 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.
If forceNew==false then:
- If a searcher is already registered, that searcher will be returned
- 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
- If no searcher is currently registered, and no searchers in the process of being registered, a new
searcher will be created.
If returnSearcher==true then a RefCounted <SolrIndexSearcher > will be returned with
the reference count incremented. It must be decremented when no longer needed.
If waitSearcher!=null and a new 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
null in which case the SolrIndexSearcher created has already been registered at the time
this method returned.
|
public static SolrCore getSolrCore() {
synchronized (SolrCore.class) {
if (core==null) core = new SolrCore(null,null);
return core;
}
}
|
public long getStartTime() {
return startTime;
}
|
public UpdateHandler getUpdateHandler() {
return updateHandler;
}
RequestHandlers need access to the updateHandler so they can all talk to the
same RAM indexer. |
void initIndex() {
try {
File dirFile = new File(getIndexDir());
boolean indexExists = dirFile.canRead();
boolean removeLocks = SolrConfig.config.getBool("mainIndex/unlockOnStartup", false);
if (removeLocks) {
// to remove locks, the directory must already exist... so we create it
// if it didn't exist already...
Directory dir = FSDirectory.getDirectory(dirFile, !indexExists);
if (IndexReader.isLocked(dir)) {
log.warning("WARNING: Solr index directory '" + getIndexDir() + "' is locked. Unlocking...");
IndexReader.unlock(dir);
}
}
// Create the index if it doesn't exist. Note that indexExists was tested *before*
// lock removal, since that will result in the creation of the directory.
if(!indexExists) {
log.warning("Solr index directory '" + dirFile + "' doesn't exist."
+ " Creating new index...");
SolrIndexWriter writer = new SolrIndexWriter("SolrCore.initIndex",getIndexDir(), true, schema, mainIndexConfig);
writer.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
|
public static final void log(Throwable e) {
SolrException.logOnce(log,null,e);
}
|
public SolrIndexSearcher newSearcher(String name) throws IOException {
return new SolrIndexSearcher(schema, name,getIndexDir(),false);
}
|
public static List parseListener(String path) {
BooleanQuery.setMaxClauseCount(SolrConfig.config.getInt("query/maxBooleanClauses",BooleanQuery.getMaxClauseCount()));
if (mainIndexConfig.writeLockTimeout != -1) IndexWriter.setDefaultWriteLockTimeout(mainIndexConfig.writeLockTimeout);
List< SolrEventListener > lst = new ArrayList< SolrEventListener >();
log.info("Searching for listeners: " +path);
NodeList nodes = (NodeList)SolrConfig.config.evaluate(path, XPathConstants.NODESET);
if (nodes!=null) {
for (int i=0; i< nodes.getLength(); i++) {
Node node = nodes.item(i);
String className = DOMUtil.getAttr(node,"class");
SolrEventListener listener = (SolrEventListener)Config.newInstance(className);
listener.init(DOMUtil.childNodesToNamedList(node));
lst.add(listener);
log.info("added SolrEventListener: " + listener);
}
}
return lst;
}
|
public SolrRequestHandler registerRequestHandler(String handlerName,
SolrRequestHandler handler) {
return reqHandlers.register(handlerName,handler);
}
Registers a handler at the specified location. If one exists there, it will be replaced.
To remove a handler, register null at its path
Once registered the handler can be accessed through:
http://${host}:${port}/${context}/${handlerName}
or:
http://${host}:${port}/${context}/select?qt=${handlerName}
Handlers must be initalized before getting registered. Registered
handlers can immediatly accept requests.
This call is thread safe. |
protected void setResponseHeaderValues(SolrRequestHandler handler,
NamedList responseHeader,
SolrQueryRequest req,
SolrQueryResponse rsp) {
// TODO should check that responseHeader has not been replaced by handler
final int qtime=(int)(rsp.getEndTime() - req.getStartTime());
responseHeader.add("status",rsp.getException()==null ? 0 : 500);
responseHeader.add("QTime",qtime);
SolrParams params = req.getParams();
if( params.getBool(SolrParams.HEADER_ECHO_HANDLER, false) ) {
responseHeader.add("handler", handler.getName() );
}
// Values for echoParams... false/true/all or false/explicit/all ???
String ep = params.get( SolrParams.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 " + SolrParams.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());
}
}
}
|