add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / src / test / org / apache / lucene / store / TestLockFactory.java
1 package org.apache.lucene.store;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Map;
25
26 import org.apache.lucene.analysis.MockAnalyzer;
27 import org.apache.lucene.document.Document;
28 import org.apache.lucene.document.Field;
29 import org.apache.lucene.index.IndexWriter;
30 import org.apache.lucene.index.IndexWriterConfig;
31 import org.apache.lucene.index.Term;
32 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
33 import org.apache.lucene.search.IndexSearcher;
34 import org.apache.lucene.search.Query;
35 import org.apache.lucene.search.TermQuery;
36 import org.apache.lucene.util.LuceneTestCase;
37 import org.apache.lucene.util._TestUtil;
38
39 public class TestLockFactory extends LuceneTestCase {
40
41     // Verify: we can provide our own LockFactory implementation, the right
42     // methods are called at the right time, locks are created, etc.
43
44     public void testCustomLockFactory() throws IOException {
45         Directory dir = new MockDirectoryWrapper(random, new RAMDirectory());
46         MockLockFactory lf = new MockLockFactory();
47         dir.setLockFactory(lf);
48
49         // Lock prefix should have been set:
50         assertTrue("lock prefix was not set by the RAMDirectory", lf.lockPrefixSet);
51
52         IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
53
54         // add 100 documents (so that commit lock is used)
55         for (int i = 0; i < 100; i++) {
56             addDoc(writer);
57         }
58
59         // Both write lock and commit lock should have been created:
60         assertEquals("# of unique locks created (after instantiating IndexWriter)",
61                      1, lf.locksCreated.size());
62         assertTrue("# calls to makeLock is 0 (after instantiating IndexWriter)",
63                    lf.makeLockCount >= 1);
64         
65         for(final String lockName : lf.locksCreated.keySet()) {
66             MockLockFactory.MockLock lock = (MockLockFactory.MockLock) lf.locksCreated.get(lockName);
67             assertTrue("# calls to Lock.obtain is 0 (after instantiating IndexWriter)",
68                        lock.lockAttempts > 0);
69         }
70         
71         writer.close();
72     }
73
74     // Verify: we can use the NoLockFactory with RAMDirectory w/ no
75     // exceptions raised:
76     // Verify: NoLockFactory allows two IndexWriters
77     public void testRAMDirectoryNoLocking() throws IOException {
78         Directory dir = new MockDirectoryWrapper(random, new RAMDirectory());
79         dir.setLockFactory(NoLockFactory.getNoLockFactory());
80
81         assertTrue("RAMDirectory.setLockFactory did not take",
82                    NoLockFactory.class.isInstance(dir.getLockFactory()));
83
84         IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
85         writer.commit(); // required so the second open succeed 
86         // Create a 2nd IndexWriter.  This is normally not allowed but it should run through since we're not
87         // using any locks:
88         IndexWriter writer2 = null;
89         try {
90             writer2 = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.APPEND));
91         } catch (Exception e) {
92             e.printStackTrace(System.out);
93             fail("Should not have hit an IOException with no locking");
94         }
95
96         writer.close();
97         if (writer2 != null) {
98             writer2.close();
99         }
100     }
101
102     // Verify: SingleInstanceLockFactory is the default lock for RAMDirectory
103     // Verify: RAMDirectory does basic locking correctly (can't create two IndexWriters)
104     public void testDefaultRAMDirectory() throws IOException {
105         Directory dir = new RAMDirectory();
106
107         assertTrue("RAMDirectory did not use correct LockFactory: got " + dir.getLockFactory(),
108                    SingleInstanceLockFactory.class.isInstance(dir.getLockFactory()));
109
110         IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)));
111
112         // Create a 2nd IndexWriter.  This should fail:
113         IndexWriter writer2 = null;
114         try {
115             writer2 = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.APPEND));
116             fail("Should have hit an IOException with two IndexWriters on default SingleInstanceLockFactory");
117         } catch (IOException e) {
118         }
119
120         writer.close();
121         if (writer2 != null) {
122             writer2.close();
123         }
124     }
125     
126     public void testSimpleFSLockFactory() throws IOException {
127       // test string file instantiation
128       new SimpleFSLockFactory("test");
129     }
130
131     // Verify: do stress test, by opening IndexReaders and
132     // IndexWriters over & over in 2 threads and making sure
133     // no unexpected exceptions are raised:
134     public void testStressLocks() throws Exception {
135       _testStressLocks(null, _TestUtil.getTempDir("index.TestLockFactory6"));
136     }
137
138     // Verify: do stress test, by opening IndexReaders and
139     // IndexWriters over & over in 2 threads and making sure
140     // no unexpected exceptions are raised, but use
141     // NativeFSLockFactory:
142     public void testStressLocksNativeFSLockFactory() throws Exception {
143       File dir = _TestUtil.getTempDir("index.TestLockFactory7");
144       _testStressLocks(new NativeFSLockFactory(dir), dir);
145     }
146
147     public void _testStressLocks(LockFactory lockFactory, File indexDir) throws Exception {
148       Directory dir = newFSDirectory(indexDir, lockFactory);
149
150         // First create a 1 doc index:
151         IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.CREATE));
152         addDoc(w);
153         w.close();
154
155       WriterThread writer = new WriterThread(100, dir);
156       SearcherThread searcher = new SearcherThread(100, dir);
157       writer.start();
158       searcher.start();
159
160       while(writer.isAlive() || searcher.isAlive()) {
161         Thread.sleep(1000);
162       }
163
164       assertTrue("IndexWriter hit unexpected exceptions", !writer.hitException);
165       assertTrue("IndexSearcher hit unexpected exceptions", !searcher.hitException);
166
167       dir.close();
168       // Cleanup
169       _TestUtil.rmDir(indexDir);
170     }
171
172     // Verify: NativeFSLockFactory works correctly
173     public void testNativeFSLockFactory() throws IOException {
174
175       NativeFSLockFactory f = new NativeFSLockFactory(TEMP_DIR);
176
177       f.setLockPrefix("test");
178       Lock l = f.makeLock("commit");
179       Lock l2 = f.makeLock("commit");
180
181       assertTrue("failed to obtain lock", l.obtain());
182       assertTrue("succeeded in obtaining lock twice", !l2.obtain());
183       l.release();
184
185       assertTrue("failed to obtain 2nd lock after first one was freed", l2.obtain());
186       l2.release();
187
188       // Make sure we can obtain first one again, test isLocked():
189       assertTrue("failed to obtain lock", l.obtain());
190       assertTrue(l.isLocked());
191       assertTrue(l2.isLocked());
192       l.release();
193       assertFalse(l.isLocked());
194       assertFalse(l2.isLocked());
195     }
196
197     
198     // Verify: NativeFSLockFactory works correctly if the lock file exists
199     public void testNativeFSLockFactoryLockExists() throws IOException {
200       
201       File lockFile = new File(TEMP_DIR, "test.lock");
202       lockFile.createNewFile();
203       
204       Lock l = new NativeFSLockFactory(TEMP_DIR).makeLock("test.lock");
205       assertTrue("failed to obtain lock", l.obtain());
206       l.release();
207       assertFalse("failed to release lock", l.isLocked());
208       if (lockFile.exists()) {
209         lockFile.delete();
210       }
211     }
212
213     public void testNativeFSLockReleaseByOtherLock() throws IOException {
214
215       NativeFSLockFactory f = new NativeFSLockFactory(TEMP_DIR);
216
217       f.setLockPrefix("test");
218       Lock l = f.makeLock("commit");
219       Lock l2 = f.makeLock("commit");
220
221       assertTrue("failed to obtain lock", l.obtain());
222       try {
223         assertTrue(l2.isLocked());
224         l2.release();
225         fail("should not have reached here. LockReleaseFailedException should have been thrown");
226       } catch (LockReleaseFailedException e) {
227         // expected
228       } finally {
229         l.release();
230       }
231     }
232
233     // Verify: NativeFSLockFactory assigns null as lockPrefix if the lockDir is inside directory
234     public void testNativeFSLockFactoryPrefix() throws IOException {
235       File fdir1 = _TestUtil.getTempDir("TestLockFactory.8");
236       File fdir2 = _TestUtil.getTempDir("TestLockFactory.8.Lockdir");
237       Directory dir1 = newFSDirectory(fdir1, new NativeFSLockFactory(fdir1));
238       // same directory, but locks are stored somewhere else. The prefix of the lock factory should != null
239       Directory dir2 = newFSDirectory(fdir1, new NativeFSLockFactory(fdir2));
240       
241       String prefix1 = dir1.getLockFactory().getLockPrefix();
242       assertNull("Lock prefix for lockDir same as directory should be null", prefix1);
243       
244       String prefix2 = dir2.getLockFactory().getLockPrefix();
245       assertNotNull("Lock prefix for lockDir outside of directory should be not null", prefix2);
246       
247       dir1.close();
248       dir2.close();
249       
250       _TestUtil.rmDir(fdir1);
251       _TestUtil.rmDir(fdir2);
252     }
253
254     // Verify: default LockFactory has no prefix (ie
255     // write.lock is stored in index):
256     public void testDefaultFSLockFactoryPrefix() throws IOException {
257       // Make sure we get null prefix, which wont happen if setLockFactory is ever called.
258       File dirName = _TestUtil.getTempDir("TestLockFactory.10");
259
260       Directory dir = new SimpleFSDirectory(dirName);
261       assertNull("Default lock prefix should be null", dir.getLockFactory().getLockPrefix());
262       dir.close();
263       
264       dir = new MMapDirectory(dirName);
265       assertNull("Default lock prefix should be null", dir.getLockFactory().getLockPrefix());
266       dir.close();
267       
268       dir = new NIOFSDirectory(dirName);
269       assertNull("Default lock prefix should be null", dir.getLockFactory().getLockPrefix());
270       dir.close();
271  
272       _TestUtil.rmDir(dirName);
273     }
274
275     private class WriterThread extends Thread { 
276         private Directory dir;
277         private int numIteration;
278         public boolean hitException = false;
279         public WriterThread(int numIteration, Directory dir) {
280             this.numIteration = numIteration;
281             this.dir = dir;
282         }
283         @Override
284         public void run() {
285             IndexWriter writer = null;
286             for(int i=0;i<this.numIteration;i++) {
287                 try {
288                     writer = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setOpenMode(OpenMode.APPEND));
289                 } catch (IOException e) {
290                     if (e.toString().indexOf(" timed out:") == -1) {
291                         hitException = true;
292                         System.out.println("Stress Test Index Writer: creation hit unexpected IOException: " + e.toString());
293                         e.printStackTrace(System.out);
294                     } else {
295                         // lock obtain timed out
296                         // NOTE: we should at some point
297                         // consider this a failure?  The lock
298                         // obtains, across IndexReader &
299                         // IndexWriters should be "fair" (ie
300                         // FIFO).
301                     }
302                 } catch (Exception e) {
303                     hitException = true;
304                     System.out.println("Stress Test Index Writer: creation hit unexpected exception: " + e.toString());
305                     e.printStackTrace(System.out);
306                     break;
307                 }
308                 if (writer != null) {
309                     try {
310                         addDoc(writer);
311                     } catch (IOException e) {
312                         hitException = true;
313                         System.out.println("Stress Test Index Writer: addDoc hit unexpected exception: " + e.toString());
314                         e.printStackTrace(System.out);
315                         break;
316                     }
317                     try {
318                         writer.close();
319                     } catch (IOException e) {
320                         hitException = true;
321                         System.out.println("Stress Test Index Writer: close hit unexpected exception: " + e.toString());
322                         e.printStackTrace(System.out);
323                         break;
324                     }
325                     writer = null;
326                 }
327             }
328         }
329     }
330
331     private class SearcherThread extends Thread { 
332         private Directory dir;
333         private int numIteration;
334         public boolean hitException = false;
335         public SearcherThread(int numIteration, Directory dir) {
336             this.numIteration = numIteration;
337             this.dir = dir;
338         }
339         @Override
340         public void run() {
341             IndexSearcher searcher = null;
342             Query query = new TermQuery(new Term("content", "aaa"));
343             for(int i=0;i<this.numIteration;i++) {
344                 try{
345                     searcher = new IndexSearcher(dir, false);
346                 } catch (Exception e) {
347                     hitException = true;
348                     System.out.println("Stress Test Index Searcher: create hit unexpected exception: " + e.toString());
349                     e.printStackTrace(System.out);
350                     break;
351                 }
352                 try {
353                   searcher.search(query, null, 1000);
354                 } catch (IOException e) {
355                   hitException = true;
356                   System.out.println("Stress Test Index Searcher: search hit unexpected exception: " + e.toString());
357                   e.printStackTrace(System.out);
358                   break;
359                 }
360                 // System.out.println(hits.length() + " total results");
361                 try {
362                   searcher.close();
363                 } catch (IOException e) {
364                   hitException = true;
365                   System.out.println("Stress Test Index Searcher: close hit unexpected exception: " + e.toString());
366                   e.printStackTrace(System.out);
367                   break;
368                 }
369             }
370         }
371     }
372
373     public class MockLockFactory extends LockFactory {
374
375         public boolean lockPrefixSet;
376         public Map<String,Lock> locksCreated = Collections.synchronizedMap(new HashMap<String,Lock>());
377         public int makeLockCount = 0;
378
379         @Override
380         public void setLockPrefix(String lockPrefix) {    
381             super.setLockPrefix(lockPrefix);
382             lockPrefixSet = true;
383         }
384
385         @Override
386         synchronized public Lock makeLock(String lockName) {
387             Lock lock = new MockLock();
388             locksCreated.put(lockName, lock);
389             makeLockCount++;
390             return lock;
391         }
392
393         @Override
394         public void clearLock(String specificLockName) {}
395
396         public class MockLock extends Lock {
397             public int lockAttempts;
398
399             @Override
400             public boolean obtain() {
401                 lockAttempts++;
402                 return true;
403             }
404             @Override
405             public void release() {
406                 // do nothing
407             }
408             @Override
409             public boolean isLocked() {
410                 return false;
411             }
412         }
413     }
414
415     private void addDoc(IndexWriter writer) throws IOException {
416         Document doc = new Document();
417         doc.add(newField("content", "aaa", Field.Store.NO, Field.Index.ANALYZED));
418         writer.addDocument(doc);
419     }
420 }