oracle / opengrok

OpenGrok is a fast and usable source code search and cross reference engine, written in Java
http://oracle.github.io/opengrok/
Other
4.34k stars 745 forks source link

NullPointerException when searching for a non-existing term #2702

Closed stefan-kaltenberger closed 5 years ago

stefan-kaltenberger commented 5 years ago

I recently updated from OpenGrok 1.2.1 to 1.2.2 and now I'm receiving a NullPointerException when searching for a non-existing term. I rebuilt the index to rule out that cause.

OS: CentOS 7.6 JDK: jdk-9.0.4-9.0.4-ga.x86_64 Tomcat: 9.0.16 OpenGrok 1.2.2

Call Stack (which is shown within a HTTP Status 500 page):

java.lang.NullPointerException
    org.opengrok.indexer.web.SearchHelper.destroy(SearchHelper.java:563)
    org.opengrok.web.WebappListener.requestDestroyed(WebappListener.java:136)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:394)
    org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
    org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
    org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    java.base/java.lang.Thread.run(Thread.java:844)

The catalina.out log file furthermore contains the following error:

27-Feb-2019 08:35:54.656 SEVERE [ajp-nio-127.0.0.1-8009-exec-9] org.opengrok.indexer.configuration.RuntimeEnvironment.getIndexSearcher cannot construct IndexSearcher for project /
 org.apache.lucene.index.IndexNotFoundException: no segments* file found in MMapDirectory@/path/to/data/index lockFactory=org.apache.lucene.store.NativeFSLockFactory@76b01172: files: [(projects omitted)]
        at org.apache.lucene.index.SegmentInfos$FindSegmentsFile.run(SegmentInfos.java:683)
        at org.apache.lucene.index.StandardDirectoryReader.open(StandardDirectoryReader.java:81)
        at org.apache.lucene.index.DirectoryReader.open(DirectoryReader.java:63)
        at org.apache.lucene.search.SearcherManager.<init>(SearcherManager.java:125)
        at org.opengrok.indexer.configuration.RuntimeEnvironment.getIndexSearcher(RuntimeEnvironment.java:1731)
        at org.opengrok.indexer.web.SearchHelper.getSuggestions(SearchHelper.java:472)
        at org.apache.jsp.search_jsp._jspService(search_jsp.java:738)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:476)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.opengrok.web.StatisticsFilter.doFilter(StatisticsFilter.java:59)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.opengrok.web.AuthorizationFilter.doFilter(AuthorizationFilter.java:99)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:394)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:844)
SiyiLi commented 5 years ago

Met the same issue with opengrok 1.2.2

vladak commented 5 years ago

Interestingly I just ran into the same problems.

vladak commented 5 years ago

I wonder if this is related to the Lucene 7.7 upgrade in 1.2.2.

vladak commented 5 years ago

The NPE happens likely due to SuperIndexSearcher instance to be null on line 563:

556      public void destroy() {
557          if (searcher != null && closeOnDestroy) {
558              IOUtils.close(searcher.getIndexReader());
559          }
560  
561          for (SuperIndexSearcher is : searcherList) {
562              try {
563                  is.getSearcherManager().release(is);
564              } catch (IOException ex) {
565                  LOGGER.log(Level.WARNING, "cannot release indexSearcher", ex);
566              }
567          }
568      }
tulinkry commented 5 years ago

And isn't it related to the code you just fixed? There could be a null instance in the list

http://demo.opengrok.org/xref/opengrok/opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/RuntimeEnvironment.java?r=e829566c#1722-1745

vladak commented 5 years ago

The change I did for #2700 fixes just a symptom of the same problem I believe.

vladak commented 5 years ago

Actually, it fixes the NPE problem however the SegmentInfos$FindSegmentsFile remains.

vladak commented 5 years ago

In my case the trouble seems to be that getIndexSearcher() is called with / as projectName:

27-Feb-2019 15:41:56.230 WARNING [http-nio-8080-exec-11] org.opengrok.indexer.web.SearchHelper.getSuggestions Got exception while getting spelling suggestions for project /:
 org.apache.lucene.index.IndexNotFoundException: no segments* file found in MMapDirectory@/var/opengrok/data/index lockFactory=org.apache.lucene.store.NativeFSLockFactory@4616f24a: files: [OpenGrok, bar-ren
amed, foo, foo(bar), foo-renamed, foo3, git-plugin, go-test, jna, js-test, mercurial-plugin, my-scripts, on-test, solaris-userland, symlink, symlink2, test-symlinks, tomcat, underscore_test, universal-ctags
, userland-s11u4]
        at org.apache.lucene.index.SegmentInfos$FindSegmentsFile.run(SegmentInfos.java:683)
        at org.apache.lucene.index.StandardDirectoryReader.open(StandardDirectoryReader.java:81)
        at org.apache.lucene.index.DirectoryReader.open(DirectoryReader.java:63)
        at org.apache.lucene.search.SearcherManager.<init>(SearcherManager.java:125)
        at org.opengrok.indexer.configuration.RuntimeEnvironment.getIndexSearcher(RuntimeEnvironment.java:1729)
        at org.opengrok.indexer.web.SearchHelper.getSuggestions(SearchHelper.java:472)
        at org.apache.jsp.search_jsp._jspService(search_jsp.java:731)
...

which comes from:

447      public List<Suggestion> getSuggestions() {
448          if (projects == null) {
449              return new ArrayList<>(0);
450          }
451          String[] name;
452          if (projects.isEmpty()) {
453              name = new String[]{"/"};
tulinkry commented 5 years ago

I see the similar thing in the trace of the author of this issue. How come projects are empty?

stefan-kaltenberger commented 5 years ago

I use the option -P to generate a project for each top-level directory in source root. The source root (/path/to/index/src) itself consists of multiple nested projects, e.g.:

/path/to/index/src
  external
    apache
      fop
      pdfbox
    gnome
      libxml2
      libxslt

The intermediate directories external, apache and gnome do not contain a repository. The child projects (fop, pdfbox, libxml2 and libxslt) are found as the default search depth is 3 (according to the usage output).

vladak commented 5 years ago

This is a problem I have introduced in bf16921901153c82de886d8e291cdfc116f3c15e. The project list in SearchHelper is populated in prepareExec() like so:


258      public SearchHelper prepareExec(SortedSet<String> projects) {
259          if (redirect != null || errorMsg != null) {
260              return this;
261          }
262  
263          mappedAnalysisSettings = null;
264          // the Query created by the QueryBuilder
265          try {
266              indexDir = new File(dataRoot, IndexDatabase.INDEX_DIR);
267              query = builder.build();
268              if (projects == null) {
269                  errorMsg = "No project selected!";
270                  return this;
271              }
272              this.projects = projects;

and the parameter comes from cfg.getRequestedProjects().

Tracing the JSP I realized that the project list in SearchHelper object that is set into the request attribute in search.jsp is not maintained across menu.jspf. The reason is that the cycle that does de-duplication:

89         SortedSet<String> pRequested = cfg.getRequestedProjects();
90         for (Group group : ph.getGroups()) {
91             Set<Project> groupProjects = ph.getAllGrouped(group);
92             if (groupProjects.size() > 0) {
93                 %><optgroup label="<%= group.getName() %>"><%
94                 for (Project p : groupProjects) {
95                     if (!p.isIndexed()) {
96                         continue;
97                     }
98 
99                 // TODO below "selected" has no effect if one refreshes the page
100                 // with F5
101 
102                 %><option value="<%= p.getName() %>"<%
103                     if (pRequested.contains(p.getName())) {
104                         %> selected="selected"<%
105                         pRequested.remove(p.getName());   <===============
106                     }

Given the list of projects is stored in SearchHelper by reference, the remove() will modify it and it will come out empty when the SearchHelper is retrieved again once menu.jspf processing is done.

vladak commented 5 years ago

It seems one of them needs to clone().

stefan-kaltenberger commented 5 years ago

I successfully verified your fix in my installation using release 1.2.3. Thanks for helping me that fast!