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