| using J2N; |
| using J2N.Threading; |
| using Lucene.Net.Attributes; |
| using Lucene.Net.Support; |
| using Lucene.Net.Util; |
| using NUnit.Framework; |
| using System; |
| using System.IO; |
| using System.Threading; |
| using Assert = Lucene.Net.TestFramework.Assert; |
| using Console = Lucene.Net.Util.SystemConsole; |
| |
| namespace Lucene.Net.Store |
| { |
| /* |
| * 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 LuceneTestCase = Lucene.Net.Util.LuceneTestCase; |
| using TestUtil = Lucene.Net.Util.TestUtil; |
| |
| [TestFixture] |
| public class TestDirectory : LuceneTestCase |
| { |
| [Test] |
| public virtual void TestDetectClose() |
| { |
| DirectoryInfo tempDir = CreateTempDir(GetType().Name); |
| Directory[] dirs = new Directory[] { new RAMDirectory(), new SimpleFSDirectory(tempDir), new NIOFSDirectory(tempDir) }; |
| |
| foreach (Directory dir in dirs) |
| { |
| dir.Dispose(); |
| try |
| { |
| dir.CreateOutput("test", NewIOContext(Random)); |
| Assert.Fail("did not hit expected exception"); |
| } |
| #pragma warning disable 168 |
| catch (ObjectDisposedException ace) |
| #pragma warning restore 168 |
| { |
| } |
| } |
| } |
| |
| // test is occasionally very slow, i dont know why |
| // try this seed: 7D7E036AD12927F5:93333EF9E6DE44DE |
| [Test] |
| [Slow] |
| //[Nightly] // This was marked Nightly in Java, but we are not seeing very bad performance, so leaving it in the normal flow |
| public virtual void TestThreadSafety() |
| { |
| BaseDirectoryWrapper dir = NewDirectory(); |
| dir.CheckIndexOnDispose = false; // we arent making an index |
| if (dir is MockDirectoryWrapper) |
| { |
| ((MockDirectoryWrapper)dir).Throttling = Throttling.NEVER; // makes this test really slow |
| } |
| |
| if (Verbose) |
| { |
| Console.WriteLine(dir); |
| } |
| |
| TheThread theThread = new TheThread("t1", dir); |
| TheThread2 theThread2 = new TheThread2("t2", dir); |
| theThread.Start(); |
| theThread2.Start(); |
| |
| theThread.Join(); |
| theThread2.Join(); |
| |
| dir.Dispose(); |
| } |
| |
| private class TheThread : ThreadJob |
| { |
| private readonly string name; |
| private readonly BaseDirectoryWrapper outerBDWrapper; |
| |
| public TheThread(string name, BaseDirectoryWrapper baseDirectoryWrapper) |
| { |
| this.name = name; |
| outerBDWrapper = baseDirectoryWrapper; |
| } |
| |
| public override void Run() |
| { |
| for (int i = 0; i < 3000; ++i) |
| { |
| string fileName = this.name + i; |
| |
| try |
| { |
| using (IndexOutput output = outerBDWrapper.CreateOutput(fileName, NewIOContext(Random))) { } |
| Assert.IsTrue(SlowFileExists(outerBDWrapper, fileName)); |
| } |
| catch (IOException e) |
| { |
| throw new Exception(e.ToString(), e); |
| } |
| } |
| } |
| } |
| |
| private class TheThread2 : ThreadJob |
| { |
| private string name; |
| private readonly BaseDirectoryWrapper outerBDWrapper; |
| |
| public TheThread2(string name, BaseDirectoryWrapper baseDirectoryWrapper) |
| { |
| this.name = name; |
| outerBDWrapper = baseDirectoryWrapper; |
| } |
| |
| public override void Run() |
| { |
| for (int i = 0; i < 10000; i++) |
| { |
| try |
| { |
| string[] files = outerBDWrapper.ListAll(); |
| foreach (string file in files) |
| { |
| try |
| { |
| using IndexInput input = outerBDWrapper.OpenInput(file, NewIOContext(Random)); |
| } |
| #pragma warning disable 168 |
| catch (FileNotFoundException fne) |
| #pragma warning restore 168 |
| { |
| } |
| // LUCENENET specific - since NoSuchDirectoryException subclasses FileNotFoundException |
| // in Lucene, we need to catch it here to be on the safe side. |
| catch (DirectoryNotFoundException) |
| { |
| } |
| catch (IOException e) |
| { |
| if (!e.Message.Contains("still open for writing")) |
| { |
| throw new Exception(e.ToString(), e); |
| } |
| } |
| if (Random.NextBoolean()) |
| { |
| break; |
| } |
| } |
| } |
| catch (IOException e) |
| { |
| throw new Exception(e.ToString(), e); |
| } |
| } |
| } |
| } |
| |
| // Test that different instances of FSDirectory can coexist on the same |
| // path, can read, write, and lock files. |
| [Test] |
| public virtual void TestDirectInstantiation() |
| { |
| DirectoryInfo path = CreateTempDir("testDirectInstantiation"); |
| |
| byte[] largeBuffer = new byte[Random.Next(256 * 1024)], largeReadBuffer = new byte[largeBuffer.Length]; |
| for (int i = 0; i < largeBuffer.Length; i++) |
| { |
| largeBuffer[i] = (byte)i; // automatically loops with modulo |
| } |
| |
| var dirs = new FSDirectory[] { new SimpleFSDirectory(path, null), new NIOFSDirectory(path, null), new MMapDirectory(path, null) }; |
| |
| for (int i = 0; i < dirs.Length; i++) |
| { |
| FSDirectory dir = dirs[i]; |
| dir.EnsureOpen(); |
| string fname = "foo." + i; |
| string lockname = "foo" + i + ".lck"; |
| IndexOutput @out = dir.CreateOutput(fname, NewIOContext(Random)); |
| @out.WriteByte((byte)i); |
| @out.WriteBytes(largeBuffer, largeBuffer.Length); |
| @out.Dispose(); |
| |
| for (int j = 0; j < dirs.Length; j++) |
| { |
| FSDirectory d2 = dirs[j]; |
| d2.EnsureOpen(); |
| Assert.IsTrue(SlowFileExists(d2, fname)); |
| Assert.AreEqual(1 + largeBuffer.Length, d2.FileLength(fname)); |
| |
| // LUCENENET specific - unmap hack not needed |
| //// don't do read tests if unmapping is not supported! |
| //if (d2 is MMapDirectory && !((MMapDirectory)d2).UseUnmap) |
| //{ |
| // continue; |
| //} |
| |
| IndexInput input = d2.OpenInput(fname, NewIOContext(Random)); |
| Assert.AreEqual((byte)i, input.ReadByte()); |
| // read array with buffering enabled |
| Arrays.Fill(largeReadBuffer, (byte)0); |
| input.ReadBytes(largeReadBuffer, 0, largeReadBuffer.Length, true); |
| Assert.AreEqual(largeBuffer, largeReadBuffer); |
| // read again without using buffer |
| input.Seek(1L); |
| Arrays.Fill(largeReadBuffer, (byte)0); |
| input.ReadBytes(largeReadBuffer, 0, largeReadBuffer.Length, false); |
| Assert.AreEqual(largeBuffer, largeReadBuffer); |
| input.Dispose(); |
| } |
| |
| // delete with a different dir |
| dirs[(i + 1) % dirs.Length].DeleteFile(fname); |
| |
| for (int j = 0; j < dirs.Length; j++) |
| { |
| FSDirectory d2 = dirs[j]; |
| Assert.IsFalse(SlowFileExists(d2, fname)); |
| } |
| |
| Lock @lock = dir.MakeLock(lockname); |
| Assert.IsTrue(@lock.Obtain()); |
| |
| for (int j = 0; j < dirs.Length; j++) |
| { |
| FSDirectory d2 = dirs[j]; |
| Lock lock2 = d2.MakeLock(lockname); |
| try |
| { |
| Assert.IsFalse(lock2.Obtain(1)); |
| } |
| #pragma warning disable 168 |
| catch (LockObtainFailedException e) |
| #pragma warning restore 168 |
| { |
| // OK |
| } |
| } |
| |
| @lock.Dispose(); |
| |
| // now lock with different dir |
| @lock = dirs[(i + 1) % dirs.Length].MakeLock(lockname); |
| Assert.IsTrue(@lock.Obtain()); |
| @lock.Dispose(); |
| } |
| |
| for (int i = 0; i < dirs.Length; i++) |
| { |
| FSDirectory dir = dirs[i]; |
| dir.EnsureOpen(); |
| dir.Dispose(); |
| Assert.IsFalse(dir.IsOpen); |
| } |
| } |
| |
| // LUCENE-1464 |
| [Test] |
| public virtual void TestDontCreate() |
| { |
| var parentFolder = CreateTempDir(this.GetType().Name.ToLowerInvariant()); |
| var path = new DirectoryInfo(Path.Combine(parentFolder.FullName, "doesnotexist")); |
| try |
| { |
| Assert.IsTrue(!path.Exists); |
| Directory dir = new SimpleFSDirectory(path, null); |
| Assert.IsTrue(!path.Exists); |
| dir.Dispose(); |
| } |
| finally |
| { |
| if (path.Exists) System.IO.Directory.Delete(path.FullName, true); |
| } |
| } |
| |
| // LUCENE-1468 |
| [Test] |
| public virtual void TestRAMDirectoryFilter() |
| { |
| CheckDirectoryFilter(new RAMDirectory()); |
| } |
| |
| // LUCENE-1468 |
| [Test] |
| public virtual void TestFSDirectoryFilter() |
| { |
| CheckDirectoryFilter(NewFSDirectory(CreateTempDir("test"))); |
| } |
| |
| private static bool ContainsFile(Directory directory, string file) // LUCENENET specific method to prevent having to use Arrays.AsList(), which creates unnecessary memory allocations |
| { |
| return Array.IndexOf(directory.ListAll(), file) > -1; |
| } |
| |
| // LUCENE-1468 |
| private void CheckDirectoryFilter(Directory dir) |
| { |
| string name = "file"; |
| try |
| { |
| dir.CreateOutput(name, NewIOContext(Random)).Dispose(); |
| Assert.IsTrue(SlowFileExists(dir, name)); |
| Assert.IsTrue(ContainsFile(dir, name)); |
| } |
| finally |
| { |
| dir.Dispose(); |
| } |
| } |
| |
| // LUCENE-1468 |
| [Test] |
| public virtual void TestCopySubdir() |
| { |
| DirectoryInfo path = CreateTempDir("testsubdir"); |
| try |
| { |
| //path.mkdirs(); |
| System.IO.Directory.CreateDirectory(path.FullName); |
| //(new File(path, "subdir")).mkdirs(); |
| System.IO.Directory.CreateDirectory(new DirectoryInfo(Path.Combine(path.FullName, "subdir")).FullName); |
| Directory fsDir = new SimpleFSDirectory(path, null); |
| Assert.AreEqual(0, (new RAMDirectory(fsDir, NewIOContext(Random))).ListAll().Length); |
| } |
| finally |
| { |
| System.IO.Directory.Delete(path.FullName, true); |
| } |
| } |
| |
| // LUCENE-1468 |
| [Test] |
| public virtual void TestNotDirectory() |
| { |
| DirectoryInfo path = CreateTempDir("testnotdir"); |
| Directory fsDir = new SimpleFSDirectory(path, null); |
| try |
| { |
| IndexOutput @out = fsDir.CreateOutput("afile", NewIOContext(Random)); |
| @out.Dispose(); |
| Assert.IsTrue(SlowFileExists(fsDir, "afile")); |
| try |
| { |
| var d = new SimpleFSDirectory(new DirectoryInfo(Path.Combine(path.FullName, "afile")), null); |
| Assert.Fail("did not hit expected exception"); |
| } |
| #pragma warning disable 168 |
| catch (DirectoryNotFoundException nsde) |
| #pragma warning restore 168 |
| { |
| // Expected |
| } |
| } |
| finally |
| { |
| fsDir.Dispose(); |
| System.IO.Directory.Delete(path.FullName, true); |
| } |
| } |
| |
| [Test] |
| public virtual void TestFsyncDoesntCreateNewFiles() |
| { |
| var path = CreateTempDir("nocreate"); |
| Console.WriteLine(path.FullName); |
| |
| using Directory fsdir = new SimpleFSDirectory(path); |
| // write a file |
| using (var o = fsdir.CreateOutput("afile", NewIOContext(Random))) |
| { |
| o.WriteString("boo"); |
| } |
| |
| // delete it |
| try |
| { |
| File.Delete(Path.Combine(path.FullName, "afile")); |
| } |
| catch (Exception e) |
| { |
| Assert.Fail("Deletion of new Directory should never fail.\nException thrown: {0}", e); |
| } |
| |
| // directory is empty |
| Assert.AreEqual(0, fsdir.ListAll().Length); |
| |
| |
| // LUCENENET specific: Since FSDirectory.Sync() does not actually do anything in .NET |
| // we decided to remove the exception as well. This is safe to ignore here. |
| //// fsync it |
| //try |
| //{ |
| // fsdir.Sync(Collections.Singleton("afile")); |
| // Assert.Fail("didn't get expected exception, instead fsync created new files: " + |
| // Collections.ToString(fsdir.ListAll())); |
| //} |
| //catch (FileNotFoundException) |
| //{ |
| // // ok |
| //} |
| //// LUCENENET specific - since NoSuchDirectoryException subclasses FileNotFoundException |
| //// in Lucene, we need to catch it here to be on the safe side. |
| //catch (DirectoryNotFoundException) |
| //{ |
| // // ok |
| //} |
| |
| // directory is still empty |
| Assert.AreEqual(0, fsdir.ListAll().Length); |
| } |
| |
| [Test] |
| [Slow] |
| [LuceneNetSpecific] |
| public virtual void ConcurrentIndexAccessThrowsWithoutSynchronizedStaleFiles() |
| { |
| DirectoryInfo tempDir = CreateTempDir(GetType().Name); |
| using Directory dir = new SimpleFSDirectory(tempDir); |
| var ioContext = NewIOContext(Random); |
| var threads = new Thread[Environment.ProcessorCount]; |
| int file = 0; |
| Exception exception = null; |
| bool stopped = false; |
| |
| using (var @event = new ManualResetEvent(false)) |
| { |
| for (int i = 0; i < threads.Length; i++) |
| { |
| var thread = new Thread(() => |
| { |
| while (!stopped) |
| { |
| int nextFile = Interlocked.Increment(ref file); |
| try |
| { |
| dir.CreateOutput("test" + nextFile, ioContext).Dispose(); |
| } |
| catch (Exception ex) |
| { |
| exception = ex; |
| @event.Set(); |
| break; |
| } |
| } |
| }); |
| thread.Start(); |
| threads[i] = thread; |
| } |
| |
| bool raised = @event.WaitOne(TimeSpan.FromSeconds(5)); |
| |
| stopped = true; |
| |
| if (raised) |
| throw new Exception("Test failed", exception); |
| } |
| |
| foreach (var thread in threads) |
| { |
| thread.Join(); |
| } |
| } |
| |
| |
| #pragma warning disable 612, 618 |
| [Test] |
| [LuceneNetSpecific] |
| public void TestLUCENENET521() |
| { |
| var newDirectoryInfo = CreateTempDir("LUCENENET521"); |
| using (var zipFileStream = this.GetType().FindAndGetManifestResourceStream("LUCENENET521.zip")) |
| { |
| TestUtil.Unzip(zipFileStream, newDirectoryInfo); |
| } |
| |
| var newDirectory = new MMapDirectory(newDirectoryInfo); |
| var conf = new Index.IndexWriterConfig(LuceneVersion.LUCENE_30, new Analysis.Standard.StandardAnalyzer(LuceneVersion.LUCENE_30)); |
| var indexWriter = new Index.IndexWriter(newDirectory, conf); |
| indexWriter.Dispose(); |
| |
| var sharedReader = Index.IndexReader.Open(newDirectory /*, true*/); |
| const int times = 10; |
| const int concurrentTaskCount = 10; |
| var task = new System.Threading.Tasks.Task[concurrentTaskCount]; |
| for (int i = 0; i < concurrentTaskCount; i++) |
| { |
| task[i] = new System.Threading.Tasks.Task(() => Search(sharedReader, times)); |
| task[i].Start(); |
| } |
| |
| System.Threading.Tasks.Task.WaitAll(task); |
| return; |
| } |
| #pragma warning restore 612, 618 |
| |
| private static void Search(Index.IndexReader r, int times) |
| { |
| var searcher = new Search.IndexSearcher(r); |
| var docs = new System.Collections.Generic.List<Documents.Document>(10000); |
| for (int i = 0; i < times; i++) |
| { |
| var q = new Search.TermQuery(new Index.Term("title", "volume")); |
| foreach (var scoreDoc in searcher.Search(q, 100).ScoreDocs) |
| { |
| docs.Add(searcher.Doc(scoreDoc.Doc)); |
| } |
| } |
| } |
| } |
| } |