Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
SimpleFSDirectory.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 
20 namespace Lucene.Net.Store
21 {
22 
23  /// <summary>A straightforward implementation of <see cref="FSDirectory" />
24  /// using java.io.RandomAccessFile. However, this class has
25  /// poor concurrent performance (multiple threads will
26  /// bottleneck) as it synchronizes when multiple threads
27  /// read from the same file. It's usually better to use
28  /// <see cref="NIOFSDirectory" /> or <see cref="MMapDirectory" /> instead.
29  /// </summary>
31  {
32  /// <summary>Create a new SimpleFSDirectory for the named location.
33  ///
34  /// </summary>
35  /// <param name="path">the path of the directory
36  /// </param>
37  /// <param name="lockFactory">the lock factory to use, or null for the default.
38  /// </param>
39  /// <throws> IOException </throws>
40  public SimpleFSDirectory(System.IO.DirectoryInfo path, LockFactory lockFactory)
41  : base(path, lockFactory)
42  {
43  }
44 
45  /// <summary>Create a new SimpleFSDirectory for the named location and the default lock factory.
46  ///
47  /// </summary>
48  /// <param name="path">the path of the directory
49  /// </param>
50  /// <throws> IOException </throws>
51  public SimpleFSDirectory(System.IO.DirectoryInfo path) : base(path, null)
52  {
53  }
54 
55  /// <summary>Creates an IndexOutput for the file with the given name. </summary>
56  public override IndexOutput CreateOutput(System.String name)
57  {
58  InitOutput(name);
59  return new SimpleFSIndexOutput(new System.IO.FileInfo(System.IO.Path.Combine(internalDirectory.FullName, name)));
60  }
61 
62  /// <summary>Creates an IndexInput for the file with the given name. </summary>
63  public override IndexInput OpenInput(System.String name, int bufferSize)
64  {
65  EnsureOpen();
66 
67  Exception e = null;
68  for (var i = 0; i < 10; i++)
69  {
70  try
71  {
72  return new SimpleFSIndexInput(new System.IO.FileInfo(
73  System.IO.Path.Combine(internalDirectory.FullName, name)), bufferSize, ReadChunkSize);
74  }
75  catch (System.UnauthorizedAccessException ex)
76  {
77  e = ex;
78  System.Threading.Thread.Sleep(1);
79  }
80  }
81 
82  throw e;
83  }
84 
85  protected internal class SimpleFSIndexInput : BufferedIndexInput
86  {
87  // TODO: This is a bad way to handle memory and disposing
88  protected internal class Descriptor : System.IO.BinaryReader
89  {
90  // remember if the file is open, so that we don't try to close it
91  // more than once
92  protected internal volatile bool isOpen;
93  internal long position;
94  internal long length;
95 
96  private bool isDisposed;
97 
98  public Descriptor(/*FSIndexInput enclosingInstance,*/ System.IO.FileInfo file, System.IO.FileAccess mode)
99  : base(new System.IO.FileStream(file.FullName, System.IO.FileMode.Open, mode, System.IO.FileShare.ReadWrite))
100  {
101  isOpen = true;
102  length = file.Length;
103  }
104 
105  protected override void Dispose(bool disposing)
106  {
107  if (isDisposed) return;
108 
109  if (disposing)
110  {
111  if (isOpen)
112  {
113  isOpen = false;
114  }
115  }
116 
117  isDisposed = true;
118  base.Dispose(disposing);
119  }
120 
121  ~Descriptor()
122  {
123  try
124  {
125  Dispose(false);
126  }
127  finally
128  {
129  }
130  }
131  }
132 
133  protected internal Descriptor file;
134  internal bool isClone;
135  private bool isDisposed;
136  // LUCENE-1566 - maximum read length on a 32bit JVM to prevent incorrect OOM
137  protected internal int chunkSize;
138 
139  public SimpleFSIndexInput(System.IO.FileInfo path, int bufferSize, int chunkSize)
140  : base(bufferSize)
141  {
142  file = new Descriptor(path, System.IO.FileAccess.Read);
143  this.chunkSize = chunkSize;
144  }
145 
146  /// <summary>IndexInput methods </summary>
147  public override void ReadInternal(byte[] b, int offset, int len)
148  {
149  lock (file)
150  {
151  long position = FilePointer;
152  if (position != file.position)
153  {
154  file.BaseStream.Seek(position, System.IO.SeekOrigin.Begin);
155  file.position = position;
156  }
157  int total = 0;
158 
159  try
160  {
161  do
162  {
163  int readLength;
164  if (total + chunkSize > len)
165  {
166  readLength = len - total;
167  }
168  else
169  {
170  // LUCENE-1566 - work around JVM Bug by breaking very large reads into chunks
171  readLength = chunkSize;
172  }
173  int i = file.Read(b, offset + total, readLength);
174  if (i == - 1)
175  {
176  throw new System.IO.IOException("read past EOF");
177  }
178  file.position += i;
179  total += i;
180  }
181  while (total < len);
182  }
183  catch (System.OutOfMemoryException e)
184  {
185  // propagate OOM up and add a hint for 32bit VM Users hitting the bug
186  // with a large chunk size in the fast path.
187  System.OutOfMemoryException outOfMemoryError = new System.OutOfMemoryException("OutOfMemoryError likely caused by the Sun VM Bug described in " + "https://issues.apache.org/jira/browse/LUCENE-1566; try calling FSDirectory.setReadChunkSize " + "with a a value smaller than the current chunks size (" + chunkSize + ")", e);
188  throw outOfMemoryError;
189  }
190  }
191  }
192 
193  protected override void Dispose(bool disposing)
194  {
195  if (isDisposed) return;
196  if (disposing)
197  {
198  // only close the file if this is not a clone
199  if (!isClone && file != null)
200  {
201  file.Close();
202  file = null;
203  }
204  }
205 
206  isDisposed = true;
207  }
208 
209  public override void SeekInternal(long position)
210  {
211  }
212 
213  public override long Length()
214  {
215  return file.length;
216  }
217 
218  public override System.Object Clone()
219  {
220  SimpleFSIndexInput clone = (SimpleFSIndexInput) base.Clone();
221  clone.isClone = true;
222  return clone;
223  }
224 
225  /// <summary>Method used for testing. Returns true if the underlying
226  /// file descriptor is valid.
227  /// </summary>
228  public /*internal*/ virtual bool IsFDValid()
229  {
230  return file.BaseStream != null;
231  }
232 
233  public bool isClone_ForNUnit
234  {
235  get { return isClone; }
236  }
237  }
238 
239  /*protected internal*/ public class SimpleFSIndexOutput:BufferedIndexOutput
240  {
241  internal System.IO.FileStream file = null;
242 
243  // remember if the file is open, so that we don't try to close it
244  // more than once
245  private volatile bool isOpen;
246 
247  public SimpleFSIndexOutput(System.IO.FileInfo path)
248  {
249  file = new System.IO.FileStream(path.FullName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
250  isOpen = true;
251  }
252 
253  /// <summary>output methods: </summary>
254  public override void FlushBuffer(byte[] b, int offset, int size)
255  {
256  file.Write(b, offset, size);
257  // {{dougsale-2.4.0}}
258  // FSIndexOutput.Flush
259  // When writing frequently with small amounts of data, the data isn't flushed to disk.
260  // Thus, attempting to read the data soon after this method is invoked leads to
261  // BufferedIndexInput.Refill() throwing an IOException for reading past EOF.
262  // Test\Index\TestDoc.cs demonstrates such a situation.
263  // Forcing a flush here prevents said issue.
264  // {{DIGY 2.9.0}}
265  // This code is not available in Lucene.Java 2.9.X.
266  // Can there be a indexing-performance problem?
267  file.Flush();
268  }
269 
270  protected override void Dispose(bool disposing)
271  {
272  // only close the file if it has not been closed yet
273  if (isOpen)
274  {
275  bool success = false;
276  try
277  {
278  base.Dispose(disposing);
279  success = true;
280  }
281  finally
282  {
283  isOpen = false;
284  if (!success)
285  {
286  try
287  {
288  file.Dispose();
289  }
290  catch (System.Exception)
291  {
292  // Suppress so we don't mask original exception
293  }
294  }
295  else
296  file.Dispose();
297  }
298  }
299  }
300 
301  /// <summary>Random-access methods </summary>
302  public override void Seek(long pos)
303  {
304  base.Seek(pos);
305  file.Seek(pos, System.IO.SeekOrigin.Begin);
306  }
307 
308  public override long Length
309  {
310  get { return file.Length; }
311  }
312 
313  public override void SetLength(long length)
314  {
315  file.SetLength(length);
316  }
317  }
318  }
319 }