今天对solr的分发机制研究一翻。。心中有几个疑问,IndexSearcher的切换是否导致服务停止?答案是不会。。
查看了solr实现这一切换的思路:
首先处理solr分发的类org.apache.solr.handler.ReplicationHandler,其中有一段
if (command.equalsIgnoreCase(CMD_FETCH_INDEX)) {
String masterUrl = solrParams.get(MASTER_URL);
if (!isSlave && masterUrl == null) {
rsp.add(STATUS,ERR_STATUS);
rsp.add("message","No slave configured or no 'masterUrl' Specified");
return;
}
final SolrParams paramsCopy = new ModifiableSolrParams(solrParams);
new Thread() {
public void run() {
doFetch(paramsCopy);
}
}.start();
rsp.add(STATUS, OK_STATUS);
}
可以看出是启动了一个线程来处理分发请求,主要是从主机那拷贝索引来。
if (!modifiedConfFiles.isEmpty()) {
downloadConfFiles(confFilesToDownload, latestVersion);
if (isFullCopyNeeded) {
modifyIndexProps(tmpIndexDir.getName());
} else {
successfulInstall = copyIndexFiles(tmpIndexDir, indexDir);
}
if (successfulInstall) {
LOG.info("Configuration files are modified, core will be reloaded");
logReplicationTimeAndConfFiles(modifiedConfFiles, successfulInstall);//write to a file time of replication and conf files.
reloadCore();
}
} else {
terminateAndWaitFsyncService();
if (isFullCopyNeeded) {
successfulInstall = modifyIndexProps(tmpIndexDir.getName());
deleteTmpIdxDir = false;
} else {
successfulInstall = copyIndexFiles(tmpIndexDir, indexDir);
}
if (successfulInstall) {
logReplicationTimeAndConfFiles(modifiedConfFiles, successfulInstall);
doCommit();
}
}
拷贝完主机索引后,此时子机接收到新的索引,此时如果solrconfig.xml或者schema.xml配置文件发生改变,会启动一个新线程重新加载新的SolrCore对象
private void reloadCore() {
new Thread() {
public void run() {
try {
solrCore.getCoreDescriptor().getCoreContainer().reload(solrCore.getName());
} catch (Exception e) {
LOG.error("Could not restart core ", e);
}
}
}.start();
}
重新加载schema.xml与solrconfig.xml里的实例与组件。
CoreContainer存放多个solrCore,由
protected final Map<String, SolrCore> cores = new LinkedHashMap<String, SolrCore>();
一个链表hashMap来存储,根据不同的名称映射其对象的引用空间。
synchronized (cores) {
old = cores.put(name, core);
core.setName(name);
}
加载完solrcore后替换旧的solrcore引用地址。。
如果配置文件没有发生改变,则重用原来的solrcore,重新打开writer与indexSearcher,其中切换IndexSearcher的部分代码如下。
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();
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();
}
}
}
在切换过程中有启动多条线程来进行拷贝旧的IndexSearcher中的缓存与处理事件。
——————————————————————————————————
newSearcher.warm(currSearcher);
————————————————————————
for (SolrEventListener listener : firstSearcherListeners) {
listener.newSearcher(newSearcher,null);
}
——————————————————————————————
for (SolrEventListener listener : newSearcherListeners) {
listener.newSearcher(newSearcher, currSearcher);
}
————————————————————————————————————
还有个疑问,在替换原来的索引文件时,会进行删除的动作,这样旧的索引文件就会被删除掉,那么,旧的IndexSearcher在处理请求时,读取旧索引文件,这个会出现异常吗?
答案是不会的,因为从操作系统的角度来讲,一旦一个文件被打开一个inputstream也即打开了一个文件描述符,在内核中,此文件会保持reference count,只要reader 还没有关闭,文件描述符还在,文件是不会被删除的,仅仅reference count 减一。
本文链接:http://blog.csdn.net/duck_genuine/archive/2011/04/26/6363844.aspx