| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| using System; |
| using Lucene.Net.Support; |
| using NUnit.Framework; |
| |
| using WhitespaceAnalyzer = Lucene.Net.Analysis.WhitespaceAnalyzer; |
| using Document = Lucene.Net.Documents.Document; |
| using Field = Lucene.Net.Documents.Field; |
| using IndexWriter = Lucene.Net.Index.IndexWriter; |
| using Term = Lucene.Net.Index.Term; |
| using IndexSearcher = Lucene.Net.Search.IndexSearcher; |
| using Query = Lucene.Net.Search.Query; |
| using ScoreDoc = Lucene.Net.Search.ScoreDoc; |
| using TermQuery = Lucene.Net.Search.TermQuery; |
| using LuceneTestCase = Lucene.Net.Util.LuceneTestCase; |
| using _TestUtil = Lucene.Net.Util._TestUtil; |
| |
| namespace Lucene.Net.Store |
| { |
| |
| [TestFixture] |
| public class TestLockFactory:LuceneTestCase |
| { |
| |
| // Verify: we can provide our own LockFactory implementation, the right |
| // methods are called at the right time, locks are created, etc. |
| |
| [Test] |
| public virtual void TestCustomLockFactory() |
| { |
| Directory dir = new RAMDirectory(); |
| MockLockFactory lf = new MockLockFactory(this); |
| dir.SetLockFactory(lf); |
| |
| // Lock prefix should have been set: |
| Assert.IsTrue(lf.lockPrefixSet, "lock prefix was not set by the RAMDirectory"); |
| |
| IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED); |
| |
| // add 100 documents (so that commit lock is used) |
| for (int i = 0; i < 100; i++) |
| { |
| AddDoc(writer); |
| } |
| |
| // Both write lock and commit lock should have been created: |
| Assert.AreEqual(1, lf.locksCreated.Count, "# of unique locks created (after instantiating IndexWriter)"); |
| Assert.IsTrue(lf.makeLockCount >= 1, "# calls to makeLock is 0 (after instantiating IndexWriter)"); |
| |
| for (System.Collections.IEnumerator e = lf.locksCreated.Keys.GetEnumerator(); e.MoveNext(); ) |
| { |
| System.String lockName = (System.String) e.Current; |
| MockLockFactory.MockLock lock_Renamed = (MockLockFactory.MockLock) lf.locksCreated[lockName]; |
| Assert.IsTrue(lock_Renamed.lockAttempts > 0, "# calls to Lock.obtain is 0 (after instantiating IndexWriter)"); |
| } |
| |
| writer.Close(); |
| } |
| |
| // Verify: we can use the NoLockFactory with RAMDirectory w/ no |
| // exceptions raised: |
| // Verify: NoLockFactory allows two IndexWriters |
| [Test] |
| public virtual void TestRAMDirectoryNoLocking() |
| { |
| Directory dir = new RAMDirectory(); |
| dir.SetLockFactory(NoLockFactory.Instance); |
| |
| Assert.IsTrue(typeof(NoLockFactory).IsInstanceOfType(dir.LockFactory), "RAMDirectory.setLockFactory did not take"); |
| |
| IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED); |
| |
| // Create a 2nd IndexWriter. This is normally not allowed but it should run through since we're not |
| // using any locks: |
| IndexWriter writer2 = null; |
| try |
| { |
| writer2 = new IndexWriter(dir, new WhitespaceAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED); |
| } |
| catch (System.Exception e) |
| { |
| System.Console.Out.WriteLine(e.StackTrace); |
| Assert.Fail("Should not have hit an IOException with no locking"); |
| } |
| |
| writer.Close(); |
| if (writer2 != null) |
| { |
| writer2.Close(); |
| } |
| } |
| |
| // Verify: SingleInstanceLockFactory is the default lock for RAMDirectory |
| // Verify: RAMDirectory does basic locking correctly (can't create two IndexWriters) |
| [Test] |
| public virtual void TestDefaultRAMDirectory() |
| { |
| Directory dir = new RAMDirectory(); |
| |
| Assert.IsTrue(typeof(SingleInstanceLockFactory).IsInstanceOfType(dir.LockFactory), "RAMDirectory did not use correct LockFactory: got " + dir.LockFactory); |
| |
| IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED); |
| |
| // Create a 2nd IndexWriter. This should fail: |
| IndexWriter writer2 = null; |
| |
| Assert.Throws<LockObtainFailedException>( |
| () => writer2 = new IndexWriter(dir, new WhitespaceAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED), |
| "Should have hit an IOException with two IndexWriters on default SingleInstanceLockFactory"); |
| |
| writer.Close(); |
| if (writer2 != null) |
| { |
| writer2.Close(); |
| } |
| } |
| |
| [Test] |
| public void TestSimpleFSLockFactory() |
| { |
| // test string file instantiation |
| new SimpleFSLockFactory("test"); |
| } |
| |
| // Verify: do stress test, by opening IndexReaders and |
| // IndexWriters over & over in 2 threads and making sure |
| // no unexpected exceptions are raised: |
| [Test] |
| public virtual void TestStressLocks() |
| { |
| _testStressLocks(null, _TestUtil.GetTempDir("index.TestLockFactory6")); |
| } |
| |
| // Verify: do stress test, by opening IndexReaders and |
| // IndexWriters over & over in 2 threads and making sure |
| // no unexpected exceptions are raised, but use |
| // NativeFSLockFactory: |
| [Test] |
| public virtual void TestStressLocksNativeFSLockFactory() |
| { |
| System.IO.DirectoryInfo dir = _TestUtil.GetTempDir("index.TestLockFactory7"); |
| _testStressLocks(new NativeFSLockFactory(dir), dir); |
| } |
| |
| public virtual void _testStressLocks(LockFactory lockFactory, System.IO.DirectoryInfo indexDir) |
| { |
| FSDirectory fs1 = FSDirectory.Open(new System.IO.DirectoryInfo(indexDir.FullName), lockFactory); |
| |
| // First create a 1 doc index: |
| IndexWriter w = new IndexWriter(fs1, new WhitespaceAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED); |
| AddDoc(w); |
| w.Close(); |
| |
| WriterThread writer = new WriterThread(this, 100, fs1); |
| SearcherThread searcher = new SearcherThread(this, 100, fs1); |
| writer.Start(); |
| searcher.Start(); |
| |
| while (writer.IsAlive || searcher.IsAlive) |
| { |
| System.Threading.Thread.Sleep(new System.TimeSpan((System.Int64) 10000 * 1000)); |
| } |
| |
| Assert.IsTrue(!writer.hitException, "IndexWriter hit unexpected exceptions"); |
| Assert.IsTrue(!searcher.hitException, "IndexSearcher hit unexpected exceptions"); |
| |
| // Cleanup |
| _TestUtil.RmDir(indexDir); |
| } |
| |
| // Verify: NativeFSLockFactory works correctly |
| [Test] |
| public virtual void TestNativeFSLockFactory() |
| { |
| |
| NativeFSLockFactory f = new NativeFSLockFactory(AppSettings.Get("tempDir", System.IO.Path.GetTempPath())); |
| |
| f.LockPrefix = "test"; |
| Lock l = f.MakeLock("commit"); |
| Lock l2 = f.MakeLock("commit"); |
| |
| Assert.IsTrue(l.Obtain(), "failed to obtain lock"); |
| Assert.IsTrue(!l2.Obtain(), "succeeded in obtaining lock twice"); |
| l.Release(); |
| |
| Assert.IsTrue(l2.Obtain(), "failed to obtain 2nd lock after first one was freed"); |
| l2.Release(); |
| |
| // Make sure we can obtain first one again, test isLocked(): |
| Assert.IsTrue(l.Obtain(), "failed to obtain lock"); |
| Assert.IsTrue(l.IsLocked()); |
| Assert.IsTrue(l2.IsLocked()); |
| l.Release(); |
| Assert.IsFalse(l.IsLocked()); |
| Assert.IsFalse(l2.IsLocked()); |
| } |
| |
| // Verify: NativeFSLockFactory assigns null as lockPrefix if the lockDir is inside directory |
| [Test] |
| public virtual void TestNativeFSLockFactoryPrefix() |
| { |
| |
| System.IO.DirectoryInfo fdir1 = _TestUtil.GetTempDir("TestLockFactory.8"); |
| System.IO.DirectoryInfo fdir2 = _TestUtil.GetTempDir("TestLockFactory.8.Lockdir"); |
| Directory dir1 = FSDirectory.Open(new System.IO.DirectoryInfo(fdir1.FullName), new NativeFSLockFactory(fdir1)); |
| // same directory, but locks are stored somewhere else. The prefix of the lock factory should != null |
| Directory dir2 = FSDirectory.Open(new System.IO.DirectoryInfo(fdir1.FullName), new NativeFSLockFactory(fdir2)); |
| |
| System.String prefix1 = dir1.LockFactory.LockPrefix; |
| Assert.IsNull(prefix1, "Lock prefix for lockDir same as directory should be null"); |
| |
| System.String prefix2 = dir2.LockFactory.LockPrefix; |
| Assert.IsNotNull(prefix2, "Lock prefix for lockDir outside of directory should be not null"); |
| |
| _TestUtil.RmDir(fdir1); |
| _TestUtil.RmDir(fdir2); |
| } |
| |
| // Verify: default LockFactory has no prefix (ie |
| // write.lock is stored in index): |
| [Test] |
| public virtual void TestDefaultFSLockFactoryPrefix() |
| { |
| |
| // Make sure we get null prefix: |
| System.IO.DirectoryInfo dirName = _TestUtil.GetTempDir("TestLockFactory.10"); |
| Directory dir = FSDirectory.Open(dirName); |
| |
| System.String prefix = dir.LockFactory.LockPrefix; |
| |
| Assert.IsTrue(null == prefix, "Default lock prefix should be null"); |
| |
| _TestUtil.RmDir(dirName); |
| } |
| |
| private class WriterThread:ThreadClass |
| { |
| private void InitBlock(TestLockFactory enclosingInstance) |
| { |
| this.enclosingInstance = enclosingInstance; |
| } |
| private TestLockFactory enclosingInstance; |
| public TestLockFactory Enclosing_Instance |
| { |
| get |
| { |
| return enclosingInstance; |
| } |
| |
| } |
| private Directory dir; |
| private int numIteration; |
| public bool hitException = false; |
| public WriterThread(TestLockFactory enclosingInstance, int numIteration, Directory dir) |
| { |
| InitBlock(enclosingInstance); |
| this.numIteration = numIteration; |
| this.dir = dir; |
| } |
| override public void Run() |
| { |
| WhitespaceAnalyzer analyzer = new WhitespaceAnalyzer(); |
| IndexWriter writer = null; |
| for (int i = 0; i < this.numIteration; i++) |
| { |
| try |
| { |
| writer = new IndexWriter(dir, analyzer, false, IndexWriter.MaxFieldLength.LIMITED); |
| } |
| catch (System.IO.IOException e) |
| { |
| if (e.ToString().IndexOf(" timed out:") == - 1) |
| { |
| hitException = true; |
| System.Console.Out.WriteLine("Stress Test Index Writer: creation hit unexpected IOException: " + e.ToString()); |
| System.Console.Out.WriteLine(e.StackTrace); |
| } |
| else |
| { |
| // lock obtain timed out |
| // NOTE: we should at some point |
| // consider this a failure? The lock |
| // obtains, across IndexReader & |
| // IndexWriters should be "fair" (ie |
| // FIFO). |
| } |
| } |
| catch (System.Exception e) |
| { |
| hitException = true; |
| System.Console.Out.WriteLine("Stress Test Index Writer: creation hit unexpected exception: " + e.ToString()); |
| System.Console.Out.WriteLine(e.StackTrace); |
| break; |
| } |
| if (writer != null) |
| { |
| try |
| { |
| Enclosing_Instance.AddDoc(writer); |
| } |
| catch (System.IO.IOException e) |
| { |
| hitException = true; |
| System.Console.Out.WriteLine("Stress Test Index Writer: addDoc hit unexpected exception: " + e.ToString()); |
| System.Console.Out.WriteLine(e.StackTrace); |
| break; |
| } |
| try |
| { |
| writer.Close(); |
| } |
| catch (System.IO.IOException e) |
| { |
| hitException = true; |
| System.Console.Out.WriteLine("Stress Test Index Writer: close hit unexpected exception: " + e.ToString()); |
| System.Console.Out.WriteLine(e.StackTrace); |
| break; |
| } |
| writer = null; |
| } |
| } |
| } |
| } |
| |
| private class SearcherThread:ThreadClass |
| { |
| private void InitBlock(TestLockFactory enclosingInstance) |
| { |
| this.enclosingInstance = enclosingInstance; |
| } |
| private TestLockFactory enclosingInstance; |
| public TestLockFactory Enclosing_Instance |
| { |
| get |
| { |
| return enclosingInstance; |
| } |
| |
| } |
| private Directory dir; |
| private int numIteration; |
| public bool hitException = false; |
| public SearcherThread(TestLockFactory enclosingInstance, int numIteration, Directory dir) |
| { |
| InitBlock(enclosingInstance); |
| this.numIteration = numIteration; |
| this.dir = dir; |
| } |
| override public void Run() |
| { |
| IndexSearcher searcher = null; |
| Query query = new TermQuery(new Term("content", "aaa")); |
| for (int i = 0; i < this.numIteration; i++) |
| { |
| try |
| { |
| searcher = new IndexSearcher(dir, false); |
| } |
| catch (System.Exception e) |
| { |
| hitException = true; |
| System.Console.Out.WriteLine("Stress Test Index Searcher: create hit unexpected exception: " + e.ToString()); |
| System.Console.Out.WriteLine(e.StackTrace); |
| break; |
| } |
| if (searcher != null) |
| { |
| ScoreDoc[] hits = null; |
| try |
| { |
| hits = searcher.Search(query, null, 1000).ScoreDocs; |
| } |
| catch (System.IO.IOException e) |
| { |
| hitException = true; |
| System.Console.Out.WriteLine("Stress Test Index Searcher: search hit unexpected exception: " + e.ToString()); |
| System.Console.Out.WriteLine(e.StackTrace); |
| break; |
| } |
| // System.out.println(hits.length() + " total results"); |
| try |
| { |
| searcher.Close(); |
| } |
| catch (System.IO.IOException e) |
| { |
| hitException = true; |
| System.Console.Out.WriteLine("Stress Test Index Searcher: close hit unexpected exception: " + e.ToString()); |
| System.Console.Out.WriteLine(e.StackTrace); |
| break; |
| } |
| searcher = null; |
| } |
| } |
| } |
| } |
| |
| public class MockLockFactory:LockFactory |
| { |
| public MockLockFactory(TestLockFactory enclosingInstance) |
| { |
| InitBlock(enclosingInstance); |
| } |
| private void InitBlock(TestLockFactory enclosingInstance) |
| { |
| this.enclosingInstance = enclosingInstance; |
| } |
| private TestLockFactory enclosingInstance; |
| public TestLockFactory Enclosing_Instance |
| { |
| get |
| { |
| return enclosingInstance; |
| } |
| |
| } |
| |
| public bool lockPrefixSet; |
| public System.Collections.IDictionary locksCreated = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable(new System.Collections.Hashtable())); |
| public int makeLockCount = 0; |
| |
| public override string LockPrefix |
| { |
| set |
| { |
| base.LockPrefix = value; |
| lockPrefixSet = true; |
| } |
| } |
| |
| public override Lock MakeLock(System.String lockName) |
| { |
| lock (this) |
| { |
| Lock lock_Renamed = new MockLock(this); |
| locksCreated[lockName] = lock_Renamed; |
| makeLockCount++; |
| return lock_Renamed; |
| } |
| } |
| |
| public override void ClearLock(System.String specificLockName) |
| { |
| } |
| |
| public class MockLock:Lock |
| { |
| public MockLock(MockLockFactory enclosingInstance) |
| { |
| InitBlock(enclosingInstance); |
| } |
| private void InitBlock(MockLockFactory enclosingInstance) |
| { |
| this.enclosingInstance = enclosingInstance; |
| } |
| private MockLockFactory enclosingInstance; |
| public MockLockFactory Enclosing_Instance |
| { |
| get |
| { |
| return enclosingInstance; |
| } |
| |
| } |
| public int lockAttempts; |
| |
| public override bool Obtain() |
| { |
| lockAttempts++; |
| return true; |
| } |
| public override void Release() |
| { |
| // do nothing |
| } |
| public override bool IsLocked() |
| { |
| return false; |
| } |
| } |
| } |
| |
| private void AddDoc(IndexWriter writer) |
| { |
| Document doc = new Document(); |
| doc.Add(new Field("content", "aaa", Field.Store.NO, Field.Index.ANALYZED)); |
| writer.AddDocument(doc); |
| } |
| } |
| } |