/** * Test that's meant to be run with many iterations to expose a leak of SolrIndexSearcher when a * core is closed due to a reload. Without the fix, this test fails with most iters=1000 runs. */ @Test public void testReloadLeak() throws Exception { final ExecutorService executor = ExecutorUtil.newMDCAwareFixedThreadPool(1, new DefaultSolrThreadFactory("testReloadLeak")); // Continuously open new searcher while core is not closed, and reload core to try to reproduce // searcher leak. // While in practice we never continuously open new searchers, this is trying to make up for the // fact that opening // a searcher in this empty core is very fast by opening new searchers continuously to increase // the likelihood // for race. SolrCore core = h.getCore(); assertTrue("Refcount != 1", core.getOpenCount() == 1); executor.execute(new NewSearcherRunnable(core)); // Since we called getCore() vs getCoreInc() and don't own a refCount, the container should // decRef the core // and close it when we call reload. h.reload(); executor.shutdown(); executor.awaitTermination(1, TimeUnit.MINUTES); // Check that all cores are closed and no searcher references are leaked. assertTrue("SolrCore " + core + " is not closed", core.isClosed()); assertTrue(core.areAllSearcherReferencesEmpty()); }
@Test public void testRefCount() throws Exception { SolrCore core = h.getCore(); assertTrue("Refcount != 1", core.getOpenCount() == 1); final CoreContainer cores = h.getCoreContainer(); SolrCore c1 = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME); assertTrue("Refcount != 2", core.getOpenCount() == 2); ClosingRequestHandler handler1 = new ClosingRequestHandler(); handler1.inform(core); String path = "/this/is A path /that won't be registered!"; SolrRequestHandler old = core.registerRequestHandler(path, handler1); assertNull(old); // should not be anything... assertEquals(core.getRequestHandlers().get(path), handler1); SolrCore c2 = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME); c1.close(); assertTrue("Refcount < 1", core.getOpenCount() >= 1); assertTrue("Handler is closed", handler1.closed == false); c1 = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME); assertTrue("Refcount < 2", core.getOpenCount() >= 2); assertTrue("Handler is closed", handler1.closed == false); c2.close(); assertTrue("Refcount < 1", core.getOpenCount() >= 1); assertTrue("Handler is closed", handler1.closed == false); c1.close(); cores.shutdown(); assertTrue("Refcount != 0", core.getOpenCount() == 0); assertTrue("Handler not closed", core.isClosed() && handler1.closed == true); }
@Test public void testRefCountMT() throws Exception { SolrCore core = h.getCore(); assertTrue("Refcount != 1", core.getOpenCount() == 1); final ClosingRequestHandler handler1 = new ClosingRequestHandler(); handler1.inform(core); String path = "/this/is A path /that won't be registered!"; SolrRequestHandler old = core.registerRequestHandler(path, handler1); assertNull(old); // should not be anything... assertEquals(core.getRequestHandlers().get(path), handler1); final int LOOP = 100; final int MT = 16; ExecutorService service = ExecutorUtil.newMDCAwareFixedThreadPool(MT, new DefaultSolrThreadFactory("refCountMT")); List<Callable<Integer>> callees = new ArrayList<>(MT); final CoreContainer cores = h.getCoreContainer(); for (int i = 0; i < MT; ++i) { Callable<Integer> call = new Callable<Integer>() { void yield(int n) { try { Thread.sleep(0, (n % 13 + 1) * 10); } catch (InterruptedException xint) { } } @Override public Integer call() { SolrCore core = null; int r = 0; try { for (int l = 0; l < LOOP; ++l) { r += 1; core = cores.getCore(SolrTestCaseJ4.DEFAULT_TEST_CORENAME); // sprinkle concurrency hinting... yield(l); assertTrue("Refcount < 1", core.getOpenCount() >= 1); yield(l); assertTrue("Refcount > 17", core.getOpenCount() <= 17); yield(l); assertTrue("Handler is closed", handler1.closed == false); yield(l); core.close(); core = null; yield(l); } return r; } finally { if (core != null) core.close(); } } }; callees.add(call); } List<Future<Integer>> results = service.invokeAll(callees); for (Future<Integer> result : results) { assertTrue("loop=" + result.get() + " < " + LOOP, result.get() >= LOOP); } cores.shutdown(); assertTrue("Refcount != 0", core.getOpenCount() == 0); assertTrue("Handler not closed", core.isClosed() && handler1.closed == true); service.shutdown(); assertTrue("Running for too long...", service.awaitTermination(60, TimeUnit.SECONDS)); }