1 package org.apache.lucene.search;
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 import org.apache.lucene.util.LuceneTestCase;
20 import org.apache.lucene.store.Directory;
21 import org.apache.lucene.index.IndexReader;
22 import org.apache.lucene.index.IndexWriter;
23 import org.apache.lucene.index.IndexWriterConfig;
24 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
25 import org.apache.lucene.analysis.MockAnalyzer;
26 import org.apache.lucene.document.*;
28 import java.util.Random;
29 import java.util.List;
30 import java.util.concurrent.atomic.AtomicBoolean;
31 import java.io.IOException;
33 public class TestThreadSafe extends LuceneTestCase {
38 class Thr extends Thread {
41 final AtomicBoolean failed;
43 // pass in random in case we want to make things reproducable
44 public Thr(int iter, Random rand, AtomicBoolean failed) {
53 for (int i=0; i<iter; i++) {
55 // pick a random index reader... a shared one, or create your own
59 switch(rand.nextInt(1)) {
60 case 0: loadDoc(ir1); break;
64 } catch (Throwable th) {
66 throw new RuntimeException(th);
71 void loadDoc(IndexReader ir) throws IOException {
72 // beware of deleted docs in the future
73 Document doc = ir.document(rand.nextInt(ir.maxDoc()),
75 public FieldSelectorResult accept(String fieldName) {
76 switch(rand.nextInt(2)) {
77 case 0: return FieldSelectorResult.LAZY_LOAD;
78 case 1: return FieldSelectorResult.LOAD;
79 // TODO: add other options
80 default: return FieldSelectorResult.LOAD;
86 List<Fieldable> fields = doc.getFields();
87 for (final Fieldable f : fields ) {
96 void validateField(Fieldable f) {
97 String val = f.stringValue();
98 if (!val.startsWith("^") || !val.endsWith("$")) {
99 throw new RuntimeException("Invalid field:" + f.toString() + " val=" +val);
103 String[] words = "now is the time for all good men to come to the aid of their country".split(" ");
105 void buildDir(Directory dir, int nDocs, int maxFields, int maxFieldLen) throws IOException {
106 IndexWriter iw = new IndexWriter(dir, new IndexWriterConfig(
107 TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE).setMaxBufferedDocs(10));
108 for (int j=0; j<nDocs; j++) {
109 Document d = new Document();
110 int nFields = random.nextInt(maxFields);
111 for (int i=0; i<nFields; i++) {
112 int flen = random.nextInt(maxFieldLen);
113 StringBuilder sb = new StringBuilder("^ ");
114 while (sb.length() < flen) sb.append(' ').append(words[random.nextInt(words.length)]);
116 Field.Store store = Field.Store.YES; // make random later
117 Field.Index index = Field.Index.ANALYZED; // make random later
118 d.add(newField("f"+i, sb.toString(), store, index));
126 void doTest(int iter, int nThreads) throws Exception {
127 Thr[] tarr = new Thr[nThreads];
128 AtomicBoolean failed = new AtomicBoolean();
129 for (int i=0; i<nThreads; i++) {
130 tarr[i] = new Thr(iter, new Random(random.nextLong()), failed);
133 for (int i=0; i<nThreads; i++) {
136 assertFalse(failed.get());
139 public void testLazyLoadThreadSafety() throws Exception{
140 dir1 = newDirectory();
141 // test w/ field sizes bigger than the buffer of an index input
142 buildDir(dir1, 15, 5, 2000);
144 // do many small tests so the thread locals go away inbetween
145 int num = atLeast(10);
146 for (int i = 0; i < num; i++) {
147 ir1 = IndexReader.open(dir1, false);