@Override protected void addDocument(Term id, Iterable<? extends IndexableField> doc) throws Exception { final long gen = genWriter.addDocument(doc); // Randomly verify the add "took": if (random().nextInt(20) == 2) { if (VERBOSE) { System.out.println(Thread.currentThread().getName() + ": nrt: verify " + id); } nrtNoDeletesThread.waitForGeneration(gen); final IndexSearcher s = nrtNoDeletes.acquire(); if (VERBOSE) { System.out.println(Thread.currentThread().getName() + ": nrt: got searcher=" + s); } try { assertEquals(1, s.search(new TermQuery(id), 10).totalHits); } finally { nrtNoDeletes.release(s); } } lastGens.set(gen); }
// Relies on wall clock time, so it can easily false-fail when the machine is otherwise busy: @AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-5737") // LUCENE-5461 public void testCRTReopen() throws Exception { // test behaving badly // should be high enough int maxStaleSecs = 20; // build crap data just to store it. String s = " abcdefghijklmnopqrstuvwxyz "; char[] chars = s.toCharArray(); StringBuilder builder = new StringBuilder(2048); for (int i = 0; i < 2048; i++) { builder.append(chars[random().nextInt(chars.length)]); } String content = builder.toString(); final SnapshotDeletionPolicy sdp = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy()); final Directory dir = new NRTCachingDirectory(newFSDirectory(createTempDir("nrt")), 5, 128); IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_6, new MockAnalyzer(random())); config.setIndexDeletionPolicy(sdp); config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND); final IndexWriter iw = new IndexWriter(dir, config); SearcherManager sm = new SearcherManager(iw, true, new SearcherFactory()); final TrackingIndexWriter tiw = new TrackingIndexWriter(iw); ControlledRealTimeReopenThread<IndexSearcher> controlledRealTimeReopenThread = new ControlledRealTimeReopenThread<>(tiw, sm, maxStaleSecs, 0); controlledRealTimeReopenThread.setDaemon(true); controlledRealTimeReopenThread.start(); List<Thread> commitThreads = new ArrayList<>(); for (int i = 0; i < 500; i++) { if (i > 0 && i % 50 == 0) { Thread commitThread = new Thread( new Runnable() { @Override public void run() { try { iw.commit(); IndexCommit ic = sdp.snapshot(); for (String name : ic.getFileNames()) { // distribute, and backup // System.out.println(names); assertTrue(slowFileExists(dir, name)); } } catch (Exception e) { throw new RuntimeException(e); } } }); commitThread.start(); commitThreads.add(commitThread); } Document d = new Document(); d.add(new TextField("count", i + "", Field.Store.NO)); d.add(new TextField("content", content, Field.Store.YES)); long start = System.currentTimeMillis(); long l = tiw.addDocument(d); controlledRealTimeReopenThread.waitForGeneration(l); long wait = System.currentTimeMillis() - start; assertTrue("waited too long for generation " + wait, wait < (maxStaleSecs * 1000)); IndexSearcher searcher = sm.acquire(); TopDocs td = searcher.search(new TermQuery(new Term("count", i + "")), 10); sm.release(searcher); assertEquals(1, td.totalHits); } for (Thread commitThread : commitThreads) { commitThread.join(); } controlledRealTimeReopenThread.close(); sm.close(); iw.close(); dir.close(); }
/* * LUCENE-3528 - NRTManager hangs in certain situations */ public void testThreadStarvationNoDeleteNRTReader() throws IOException, InterruptedException { IndexWriterConfig conf = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())); conf.setMergePolicy(NoMergePolicy.INSTANCE); Directory d = newDirectory(); final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch signal = new CountDownLatch(1); LatchedIndexWriter _writer = new LatchedIndexWriter(d, conf, latch, signal); final TrackingIndexWriter writer = new TrackingIndexWriter(_writer); final SearcherManager manager = new SearcherManager(_writer, false, null); Document doc = new Document(); doc.add(newTextField("test", "test", Field.Store.YES)); writer.addDocument(doc); manager.maybeRefresh(); Thread t = new Thread() { @Override public void run() { try { signal.await(); manager.maybeRefresh(); writer.deleteDocuments(new TermQuery(new Term("foo", "barista"))); manager.maybeRefresh(); // kick off another reopen so we inc. the internal gen } catch (Exception e) { e.printStackTrace(); } finally { latch.countDown(); // let the add below finish } } }; t.start(); _writer.waitAfterUpdate = true; // wait in addDocument to let some reopens go through final long lastGen = writer.updateDocument( new Term("foo", "bar"), doc); // once this returns the doc is already reflected in the last reopen assertFalse(manager.isSearcherCurrent()); // false since there is a delete in the queue IndexSearcher searcher = manager.acquire(); try { assertEquals(2, searcher.getIndexReader().numDocs()); } finally { manager.release(searcher); } final ControlledRealTimeReopenThread<IndexSearcher> thread = new ControlledRealTimeReopenThread<>(writer, manager, 0.01, 0.01); thread.start(); // start reopening if (VERBOSE) { System.out.println("waiting now for generation " + lastGen); } final AtomicBoolean finished = new AtomicBoolean(false); Thread waiter = new Thread() { @Override public void run() { try { thread.waitForGeneration(lastGen); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException(ie); } finished.set(true); } }; waiter.start(); manager.maybeRefresh(); waiter.join(1000); if (!finished.get()) { waiter.interrupt(); fail("thread deadlocked on waitForGeneration"); } thread.close(); thread.join(); IOUtils.close(manager, _writer, d); }