blob: 29c05b977a9974674a01f6271122b8577712d8c4 [file] [log] [blame]
/*
* 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);
}
}
}