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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 using System.Collections.Generic;
21 // Used only for WRITE_LOCK_NAME in deprecated create=true case:
22 using IndexFileNameFilter = Mono.Lucene.Net.Index.IndexFileNameFilter;
23 using IndexWriter = Mono.Lucene.Net.Index.IndexWriter;
24 using Constants = Mono.Lucene.Net.Util.Constants;
26 namespace Mono.Lucene.Net.Store
29 /// <summary> <a name="subclasses"/>
30 /// Base class for Directory implementations that store index
31 /// files in the file system. There are currently three core
36 /// <li> {@link SimpleFSDirectory} is a straightforward
37 /// implementation using java.io.RandomAccessFile.
38 /// However, it has poor concurrent performance
39 /// (multiple threads will bottleneck) as it
40 /// synchronizes when multiple threads read from the
43 /// <li> {@link NIOFSDirectory} uses java.nio's
44 /// FileChannel's positional io when reading to avoid
45 /// synchronization when reading from the same file.
46 /// Unfortunately, due to a Windows-only <a
47 /// href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6265734">Sun
48 /// JRE bug</a> this is a poor choice for Windows, but
49 /// on all other platforms this is the preferred
50 /// choice. Applications using {@link Thread#interrupt()} or
51 /// <code>Future#cancel(boolean)</code> (on Java 1.5) should use
52 /// {@link SimpleFSDirectory} instead. See {@link NIOFSDirectory} java doc
57 /// <li> {@link MMapDirectory} uses memory-mapped IO when
58 /// reading. This is a good choice if you have plenty
59 /// of virtual memory relative to your index size, eg
60 /// if you are running on a 64 bit JRE, or you are
61 /// running on a 32 bit JRE but your index sizes are
62 /// small enough to fit into the virtual memory space.
63 /// Java has currently the limitation of not being able to
64 /// unmap files from user code. The files are unmapped, when GC
65 /// releases the byte buffers. Due to
66 /// <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038">
67 /// this bug</a> in Sun's JRE, MMapDirectory's {@link IndexInput#close}
68 /// is unable to close the underlying OS file handle. Only when
69 /// GC finally collects the underlying objects, which could be
70 /// quite some time later, will the file handle be closed.
71 /// This will consume additional transient disk usage: on Windows,
72 /// attempts to delete or overwrite the files will result in an
73 /// exception; on other platforms, which typically have a "delete on
74 /// last close" semantics, while such operations will succeed, the bytes
75 /// are still consuming space on disk. For many applications this
76 /// limitation is not a problem (e.g. if you have plenty of disk space,
77 /// and you don't rely on overwriting files on Windows) but it's still
78 /// an important limitation to be aware of. This class supplies a
79 /// (possibly dangerous) workaround mentioned in the bug report,
80 /// which may fail on non-Sun JVMs.</li>
82 /// Applications using {@link Thread#interrupt()} or
83 /// <code>Future#cancel(boolean)</code> (on Java 1.5) should use
84 /// {@link SimpleFSDirectory} instead. See {@link MMapDirectory}
85 /// java doc for details.
88 /// Unfortunately, because of system peculiarities, there is
89 /// no single overall best implementation. Therefore, we've
90 /// added the {@link #open} method, to allow Lucene to choose
91 /// the best FSDirectory implementation given your
92 /// environment, and the known limitations of each
93 /// implementation. For users who have no reason to prefer a
94 /// specific implementation, it's best to simply use {@link
95 /// #open}. For all others, you should instantiate the
96 /// desired implementation directly.
98 /// <p/>The locking implementation is by default {@link
99 /// NativeFSLockFactory}, but can be changed by
100 /// passing in a custom {@link LockFactory} instance.
101 /// The deprecated <code>getDirectory</code> methods default to use
102 /// {@link SimpleFSLockFactory} for backwards compatibility.
103 /// The system properties
104 /// <code>org.apache.lucene.store.FSDirectoryLockFactoryClass</code>
105 /// and <code>org.apache.lucene.FSDirectory.class</code>
106 /// are deprecated and only used by the deprecated
107 /// <code>getDirectory</code> methods. The system property
108 /// <code>org.apache.lucene.lockDir</code> is ignored completely,
109 /// If you really want to store locks
110 /// elsewhere, you can create your own {@link
111 /// SimpleFSLockFactory} (or {@link NativeFSLockFactory},
112 /// etc.) passing in your preferred lock directory.
114 /// <p/><em>In 3.0 this class will become abstract.</em>
117 /// <seealso cref="Directory">
119 // TODO: in 3.0 this will become an abstract base class
120 public class FSDirectory:Directory
123 /// <summary>This cache of directories ensures that there is a unique Directory
124 /// instance per path, so that synchronization on the Directory can be used to
125 /// synchronize access between readers and writers. We use
126 /// refcounts to ensure when the last use of an FSDirectory
127 /// instance for a given canonical path is closed, we remove the
128 /// instance from the cache. See LUCENE-776
129 /// for some relevant discussion.
131 /// <deprecated> Not used by any non-deprecated methods anymore
133 [Obsolete("Not used by any non-deprecated methods anymore")]
134 private static readonly Dictionary<string, FSDirectory> DIRECTORIES = new Dictionary<string, FSDirectory>();
136 private static bool disableLocks = false;
138 // TODO: should this move up to the Directory base class? Also: should we
139 // make a per-instance (in addition to the static "default") version?
141 /// <summary> Set whether Lucene's use of lock files is disabled. By default,
142 /// lock files are enabled. They should only be disabled if the index
143 /// is on a read-only medium like a CD-ROM.
145 /// <deprecated> Use a {@link #open(File, LockFactory)} or a constructor
146 /// that takes a {@link LockFactory} and supply
147 /// {@link NoLockFactory#getNoLockFactory}. This setting does not work
148 /// with {@link #open(File)} only the deprecated <code>getDirectory</code>
149 /// respect this setting.
151 [Obsolete("Use a Open(File, LockFactory) or a constructor that takes a LockFactory and supply NoLockFactory.GetNoLockFactory. This setting does not work with Open(File) only the deprecated GetDirectory respect this setting.")]
152 public static void SetDisableLocks(bool doDisableLocks)
154 FSDirectory.disableLocks = doDisableLocks;
157 /// <summary> Returns whether Lucene's use of lock files is disabled.</summary>
158 /// <returns> true if locks are disabled, false if locks are enabled.
160 /// <seealso cref="setDisableLocks">
162 /// <deprecated> Use a constructor that takes a {@link LockFactory} and
163 /// supply {@link NoLockFactory#getNoLockFactory}.
165 [Obsolete("Use a constructor that takes a LockFactory and supply NoLockFactory.GetNoLockFactory.")]
166 public static bool GetDisableLocks()
168 return FSDirectory.disableLocks;
171 /// <summary> Directory specified by <code>org.apache.lucene.lockDir</code>
172 /// or <code>java.io.tmpdir</code> system property.
174 /// <deprecated> As of 2.1, <code>LOCK_DIR</code> is unused
175 /// because the write.lock is now stored by default in the
176 /// index directory. If you really want to store locks
177 /// elsewhere, you can create your own {@link
178 /// SimpleFSLockFactory} (or {@link NativeFSLockFactory},
179 /// etc.) passing in your preferred lock directory. Then,
180 /// pass this <code>LockFactory</code> instance to one of
181 /// the <code>open</code> methods that take a
182 /// <code>lockFactory</code> (for example, {@link #open(File, LockFactory)}).
184 //[Obsolete("As of 2.1, LOCK_DIR is unused because the write.lock is now stored by default in the index directory. ")]
185 //public static readonly System.String LOCK_DIR = SupportClass.AppSettings.Get("Mono.Lucene.Net.lockDir", System.IO.Path.GetTempPath());
187 /// <summary>The default class which implements filesystem-based directories. </summary>
190 private static readonly System.Type IMPL = typeof(Mono.Lucene.Net.Store.SimpleFSDirectory);
192 private static System.Security.Cryptography.HashAlgorithm DIGESTER;
194 /// <summary>A buffer optionally used in renameTo method </summary>
195 private byte[] buffer = null;
198 /// <summary>Returns the directory instance for the named location.
201 /// <deprecated> Use {@link #Open(File)}
204 /// <param name="path">the path to the directory.
206 /// <returns> the FSDirectory for the named file.
208 [Obsolete("Use Open(File)")]
209 public static FSDirectory GetDirectory(System.String path)
211 return GetDirectory(new System.IO.DirectoryInfo(path), null);
214 /// <summary>Returns the directory instance for the named location.
217 /// <deprecated> Use {@link #Open(File, LockFactory)}
220 /// <param name="path">the path to the directory.
222 /// <param name="lockFactory">instance of {@link LockFactory} providing the
223 /// locking implementation.
225 /// <returns> the FSDirectory for the named file.
227 [Obsolete("Use Open(File, LockFactory)")]
228 public static FSDirectory GetDirectory(System.String path, LockFactory lockFactory)
230 return GetDirectory(new System.IO.DirectoryInfo(path), lockFactory);
233 /// <summary>Returns the directory instance for the named location.
236 /// <deprecated> Use {@link #Open(File)}
239 /// <param name="file">the path to the directory.
241 /// <returns> the FSDirectory for the named file.
243 [Obsolete("Use Open(File)")]
244 public static FSDirectory GetDirectory(System.IO.DirectoryInfo file)
246 return GetDirectory(file, null);
249 /// <summary>Returns the directory instance for the named location.
252 /// <deprecated> Use {@link #Open(File)}
255 /// <param name="file">the path to the directory.
257 /// <returns> the FSDirectory for the named file.
259 [System.Obsolete("Use the constructor that takes a DirectoryInfo, this will be removed in the 3.0 release")]
260 public static FSDirectory GetDirectory(System.IO.FileInfo file)
262 return GetDirectory(new System.IO.DirectoryInfo(file.FullName), null);
265 /// <summary>Returns the directory instance for the named location.
268 /// <deprecated> Use {@link #Open(File, LockFactory)}
271 /// <param name="file">the path to the directory.
273 /// <param name="lockFactory">instance of {@link LockFactory} providing the
274 /// locking implementation.
276 /// <returns> the FSDirectory for the named file.
278 [System.Obsolete("Use the constructor that takes a DirectoryInfo, this will be removed in the 3.0 release")]
279 public static FSDirectory GetDirectory(System.IO.FileInfo file, LockFactory lockFactory)
281 return GetDirectory(new System.IO.DirectoryInfo(file.FullName), lockFactory);
284 /// <summary>Returns the directory instance for the named location.
287 /// <deprecated> Use {@link #Open(File, LockFactory)}
290 /// <param name="file">the path to the directory.
292 /// <param name="lockFactory">instance of {@link LockFactory} providing the
293 /// locking implementation.
295 /// <returns> the FSDirectory for the named file.
297 [Obsolete("Use Open(File, LockFactory)")]
298 public static FSDirectory GetDirectory(System.IO.DirectoryInfo file, LockFactory lockFactory)
303 if(!DIRECTORIES.TryGetValue(file.FullName, out dir))
307 dir = (FSDirectory)System.Activator.CreateInstance(IMPL, true);
309 catch (System.Exception e)
311 throw new System.SystemException("cannot load FSDirectory class: " + e.ToString(), e);
313 dir.Init(file, lockFactory);
314 DIRECTORIES.Add(file.FullName, dir);
318 // Catch the case where a Directory is pulled from the cache, but has a
319 // different LockFactory instance.
320 if (lockFactory != null && lockFactory != dir.GetLockFactory())
322 throw new System.IO.IOException("Directory was previously created with a different LockFactory instance; please pass null as the lockFactory instance and use setLockFactory to change it");
324 dir.checked_Renamed = false;
335 /// <summary>Returns the directory instance for the named location.
338 /// <deprecated> Use IndexWriter's create flag, instead, to
339 /// create a new index.
342 /// <param name="path">the path to the directory.
344 /// <param name="create">if true, create, or erase any existing contents.
346 /// <returns> the FSDirectory for the named file.
348 [Obsolete("Use IndexWriter's create flag, instead, to create a new index.")]
349 public static FSDirectory GetDirectory(System.String path, bool create)
351 return GetDirectory(new System.IO.DirectoryInfo(path), create);
354 /// <summary>Returns the directory instance for the named location.
357 /// <deprecated> Use IndexWriter's create flag, instead, to
358 /// create a new index.
361 /// <param name="file">the path to the directory.
363 /// <param name="create">if true, create, or erase any existing contents.
365 /// <returns> the FSDirectory for the named file.
367 [System.Obsolete("Use the method that takes a DirectoryInfo, this will be removed in the 3.0 release")]
368 public static FSDirectory GetDirectory(System.IO.FileInfo file, bool create)
370 return GetDirectory(new System.IO.DirectoryInfo(file.FullName), create);
373 /// <summary>Returns the directory instance for the named location.
376 /// <deprecated> Use IndexWriter's create flag, instead, to
377 /// create a new index.
380 /// <param name="file">the path to the directory.
382 /// <param name="create">if true, create, or erase any existing contents.
384 /// <returns> the FSDirectory for the named file.
386 [Obsolete("Use IndexWriter's create flag, instead, to create a new index.")]
387 public static FSDirectory GetDirectory(System.IO.DirectoryInfo file, bool create)
389 FSDirectory dir = GetDirectory(file, null);
391 // This is now deprecated (creation should only be done
404 private void Create()
406 if (directory.Exists)
408 System.String[] files = SupportClass.FileSupport.GetLuceneIndexFiles(directory.FullName, IndexFileNameFilter.GetFilter()); // clear old files
410 throw new System.IO.IOException("cannot read directory " + directory.FullName + ": list() returned null");
411 for (int i = 0; i < files.Length; i++)
413 System.String fileOrDir = System.IO.Path.Combine(directory.FullName, files[i]);
414 if (System.IO.File.Exists(fileOrDir))
416 System.IO.File.Delete(fileOrDir);
418 else if (System.IO.Directory.Exists(fileOrDir))
420 System.IO.Directory.Delete(fileOrDir);
422 // no need to throw anything - if a delete fails the exc will propogate to the caller
425 lockFactory.ClearLock(IndexWriter.WRITE_LOCK_NAME);
428 private bool checked_Renamed;
430 internal void CreateDir()
432 if (!checked_Renamed)
434 if (!this.directory.Exists)
438 this.directory.Create();
442 throw new System.IO.IOException("Cannot create directory: " + directory);
444 this.directory.Refresh(); // need to see the creation
447 checked_Renamed = true;
451 /// <summary>Initializes the directory to create a new file with the given name.
452 /// This method should be used in {@link #createOutput}.
454 protected internal void InitOutput(System.String name)
458 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
459 if (file.Exists) // delete existing, if any
467 throw new System.IO.IOException("Cannot overwrite: " + file);
472 /// <summary>The underlying filesystem directory </summary>
473 protected internal System.IO.DirectoryInfo directory = null;
478 private int refCount = 0;
483 protected internal FSDirectory()
486 // permit subclassing
488 /// <summary>Create a new FSDirectory for the named location (ctor for subclasses).</summary>
489 /// <param name="path">the path of the directory
491 /// <param name="lockFactory">the lock factory to use, or null for the default
492 /// ({@link NativeFSLockFactory});
494 /// <throws> IOException </throws>
495 protected internal FSDirectory(System.IO.DirectoryInfo path, LockFactory lockFactory)
497 // new ctors use always NativeFSLockFactory as default:
498 if (lockFactory == null)
500 lockFactory = new NativeFSLockFactory();
502 Init(path, lockFactory);
506 /// <summary>Creates an FSDirectory instance, trying to pick the
507 /// best implementation given the current environment.
508 /// The directory returned uses the {@link NativeFSLockFactory}.
510 /// <p/>Currently this returns {@link SimpleFSDirectory} as
511 /// NIOFSDirectory is currently not supported.
513 /// <p/>Currently this returns {@link SimpleFSDirectory} as
514 /// NIOFSDirectory is currently not supported.
516 /// <p/><b>NOTE</b>: this method may suddenly change which
517 /// implementation is returned from release to release, in
518 /// the event that higher performance defaults become
519 /// possible; if the precise implementation is important to
520 /// your application, please instantiate it directly,
521 /// instead. On 64 bit systems, it may also good to
522 /// return {@link MMapDirectory}, but this is disabled
523 /// because of officially missing unmap support in Java.
524 /// For optimal performance you should consider using
525 /// this implementation on 64 bit JVMs.
527 /// <p/>See <a href="#subclasses">above</a>
529 [System.Obsolete("Use the method that takes a DirectoryInfo, this will be removed in the 3.0 release")]
530 public static FSDirectory Open(System.IO.FileInfo path)
532 System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(path.FullName);
533 return Open(dir, null);
536 /// <summary>Creates an FSDirectory instance, trying to pick the
537 /// best implementation given the current environment.
538 /// The directory returned uses the {@link NativeFSLockFactory}.
540 /// <p/>Currently this returns {@link SimpleFSDirectory} as
541 /// NIOFSDirectory is currently not supported.
543 /// <p/><b>NOTE</b>: this method may suddenly change which
544 /// implementation is returned from release to release, in
545 /// the event that higher performance defaults become
546 /// possible; if the precise implementation is important to
547 /// your application, please instantiate it directly,
548 /// instead. On 64 bit systems, it may also good to
549 /// return {@link MMapDirectory}, but this is disabled
550 /// because of officially missing unmap support in Java.
551 /// For optimal performance you should consider using
552 /// this implementation on 64 bit JVMs.
554 /// <p/>See <a href="#subclasses">above</a>
556 public static FSDirectory Open(System.IO.DirectoryInfo path)
558 return Open(path, null);
561 /// <summary>Just like {@link #Open(File)}, but allows you to
562 /// also specify a custom {@link LockFactory}.
564 public static FSDirectory Open(System.IO.DirectoryInfo path, LockFactory lockFactory)
567 MMapDirectory dir=new MMapDirectory(path, lockFactory);
568 dir.setUseUnmap(true);
572 if (Constants.WINDOWS)
574 return new SimpleFSDirectory(path, lockFactory);
578 //NIOFSDirectory is not implemented in Mono.Lucene.Net
579 //return new NIOFSDirectory(path, lockFactory);
580 return new SimpleFSDirectory(path, lockFactory);
584 /* will move to ctor, when reflection is removed in 3.0 */
585 private void Init(System.IO.DirectoryInfo path, LockFactory lockFactory)
588 // Set up lockFactory with cascaded defaults: if an instance was passed in,
589 // use that; else if locks are disabled, use NoLockFactory; else if the
590 // system property Mono.Lucene.Net.Store.FSDirectoryLockFactoryClass is set,
591 // instantiate that; else, use SimpleFSLockFactory:
595 // due to differences in how Java & .NET refer to files, the checks are a bit different
596 if (!directory.Exists && System.IO.File.Exists(directory.FullName))
598 throw new NoSuchDirectoryException("file '" + directory.FullName + "' exists but is not a directory");
601 if (lockFactory == null)
606 // Locks are disabled:
607 lockFactory = NoLockFactory.GetNoLockFactory();
611 System.String lockClassName = SupportClass.AppSettings.Get("Mono.Lucene.Net.Store.FSDirectoryLockFactoryClass", "");
613 if (lockClassName != null && !lockClassName.Equals(""))
619 c = System.Type.GetType(lockClassName);
621 catch (System.Exception e)
623 throw new System.IO.IOException("unable to find LockClass " + lockClassName);
628 lockFactory = (LockFactory) System.Activator.CreateInstance(c, true);
630 catch (System.UnauthorizedAccessException e)
632 throw new System.IO.IOException("IllegalAccessException when instantiating LockClass " + lockClassName);
634 catch (System.InvalidCastException e)
636 throw new System.IO.IOException("unable to cast LockClass " + lockClassName + " instance to a LockFactory");
638 catch (System.Exception e)
640 throw new System.IO.IOException("InstantiationException when instantiating LockClass " + lockClassName);
645 // Our default lock is SimpleFSLockFactory;
646 // default lockDir is our index directory:
647 lockFactory = new SimpleFSLockFactory();
652 SetLockFactory(lockFactory);
654 // for filesystem based LockFactory, delete the lockPrefix, if the locks are placed
655 // in index dir. If no index dir is given, set ourselves
656 if (lockFactory is FSLockFactory)
658 FSLockFactory lf = (FSLockFactory) lockFactory;
659 System.IO.DirectoryInfo dir = lf.GetLockDir();
660 // if the lock factory has no lockDir set, use the this directory as lockDir
663 lf.SetLockDir(this.directory);
664 lf.SetLockPrefix(null);
666 else if (dir.FullName.Equals(this.directory.FullName))
668 lf.SetLockPrefix(null);
673 /// <summary>Lists all files (not subdirectories) in the
674 /// directory. This method never returns null (throws
675 /// {@link IOException} instead).
678 /// <throws> NoSuchDirectoryException if the directory </throws>
679 /// <summary> does not exist, or does exist but is not a
682 /// <throws> IOException if list() returns null </throws>
683 [System.Obsolete("Use the method that takes a DirectoryInfo, this will be removed in the 3.0 release")]
684 public static System.String[] ListAll(System.IO.FileInfo dir)
686 return ListAll(new System.IO.DirectoryInfo(dir.FullName));
689 /// <summary>Lists all files (not subdirectories) in the
690 /// directory. This method never returns null (throws
691 /// {@link IOException} instead).
694 /// <throws> NoSuchDirectoryException if the directory </throws>
695 /// <summary> does not exist, or does exist but is not a
698 /// <throws> IOException if list() returns null </throws>
699 public static System.String[] ListAll(System.IO.DirectoryInfo dir)
703 throw new NoSuchDirectoryException("directory '" + dir.FullName + "' does not exist");
705 // Exclude subdirs, only the file names, not the paths
706 System.IO.FileInfo[] files = dir.GetFiles();
707 System.String[] result = new System.String[files.Length];
708 for (int i = 0; i < files.Length; i++)
710 result[i] = files[i].Name;
713 // no reason to return null, if the directory cannot be listed, an exception
714 // will be thrown on the above call to dir.GetFiles()
715 // use of LINQ to create the return value array may be a bit more efficient
720 [Obsolete("Mono.Lucene.Net-2.9.1. This method overrides obsolete member Mono.Lucene.Net.Store.Directory.List()")]
721 public override System.String[] List()
724 return SupportClass.FileSupport.GetLuceneIndexFiles(directory.FullName, IndexFileNameFilter.GetFilter());
727 /// <summary>Lists all files (not subdirectories) in the
730 /// <seealso cref="ListAll(File)">
732 public override System.String[] ListAll()
735 return ListAll(directory);
738 /// <summary>Returns true iff a file with the given name exists. </summary>
739 public override bool FileExists(System.String name)
742 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
746 /// <summary>Returns the time the named file was last modified. </summary>
747 public override long FileModified(System.String name)
750 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
751 return (long)file.LastWriteTime.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds; //{{LUCENENET-353}}
754 /// <summary>Returns the time the named file was last modified. </summary>
755 public static long FileModified(System.IO.FileInfo directory, System.String name)
757 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
758 return (long)file.LastWriteTime.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds; //{{LUCENENET-353}}
761 /// <summary>Set the modified time of an existing file to now. </summary>
762 public override void TouchFile(System.String name)
765 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
766 file.LastWriteTime = System.DateTime.Now;
769 /// <summary>Returns the length in bytes of a file in the directory. </summary>
770 public override long FileLength(System.String name)
773 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
774 return file.Exists ? file.Length : 0;
777 /// <summary>Removes an existing file in the directory. </summary>
778 public override void DeleteFile(System.String name)
781 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
788 throw new System.IO.IOException("Cannot delete " + file);
792 /// <summary>Renames an existing file in the directory.
793 /// Warning: This is not atomic.
798 public override void RenameFile(System.String from, System.String to)
803 System.IO.FileInfo old = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, from));
806 old.MoveTo(System.IO.Path.Combine(directory.FullName, to));
808 catch (System.IO.IOException ioe)
810 System.IO.IOException newExc = new System.IO.IOException("Cannot rename " + old + " to " + directory, ioe);
816 /// <summary>Creates an IndexOutput for the file with the given name.
817 /// <em>In 3.0 this method will become abstract.</em>
819 public override IndexOutput CreateOutput(System.String name)
822 return new FSIndexOutput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)));
825 public override void Sync(System.String name)
828 System.IO.FileInfo fullFile = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
829 bool success = false;
831 System.IO.IOException exc = null;
832 while (!success && retryCount < 5)
835 System.IO.FileStream file = null;
840 file = new System.IO.FileStream(fullFile.FullName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
841 SupportClass.FileSupport.Sync(file);
850 catch (System.IO.IOException ioe)
857 System.Threading.Thread.Sleep(new System.TimeSpan((System.Int64) 10000 * 5));
859 catch (System.Threading.ThreadInterruptedException ie)
861 // In 3.0 we will change this to throw
862 // InterruptedException instead
863 SupportClass.ThreadClass.Current().Interrupt();
864 throw new System.SystemException(ie.ToString(), ie);
869 // Throw original exception
874 public override IndexInput OpenInput(System.String name)
877 return OpenInput(name, BufferedIndexInput.BUFFER_SIZE);
880 /// <summary>Creates an IndexInput for the file with the given name.
881 /// <em>In 3.0 this method will become abstract.</em>
883 public override IndexInput OpenInput(System.String name, int bufferSize)
886 return new FSIndexInput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)), bufferSize);
889 /// <summary> So we can do some byte-to-hexchar conversion below</summary>
890 private static readonly char[] HEX_DIGITS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
893 public override System.String GetLockID()
896 System.String dirName; // name to be hashed
899 dirName = directory.FullName;
901 catch (System.IO.IOException e)
903 throw new System.SystemException(e.ToString(), e);
909 digest = DIGESTER.ComputeHash(System.Text.Encoding.UTF8.GetBytes(dirName));
911 System.Text.StringBuilder buf = new System.Text.StringBuilder();
912 buf.Append("lucene-");
913 for (int i = 0; i < digest.Length; i++)
916 buf.Append(HEX_DIGITS[(b >> 4) & 0xf]);
917 buf.Append(HEX_DIGITS[b & 0xf]);
920 return buf.ToString();
923 /// <summary>Closes the store to future operations. </summary>
924 public override void Close()
928 if (isOpen && --refCount <= 0)
933 DIRECTORIES.Remove(directory.FullName);
942 public override void Dispose()
947 [System.Obsolete("A DirectoryInfo is more appropriate, however this is here for backwards compatibility. This will be removed in the 3.0 release")]
948 public virtual System.IO.FileInfo GetFile()
951 return new System.IO.FileInfo(directory.FullName);
955 // Java Lucene implements GetFile() which returns a FileInfo.
956 // For Mono.Lucene.Net, GetDirectory() is more appropriate
957 public virtual System.IO.DirectoryInfo GetDirectory()
963 /// <summary>For debug output. </summary>
964 public override System.String ToString()
966 return this.GetType().FullName + "@" + directory + " lockFactory=" + GetLockFactory();
969 /// <summary> Default read chunk size. This is a conditional
970 /// default: on 32bit JVMs, it defaults to 100 MB. On
971 /// 64bit JVMs, it's <code>Integer.MAX_VALUE</code>.
973 /// <seealso cref="setReadChunkSize">
975 public static readonly int DEFAULT_READ_CHUNK_SIZE;
978 private int chunkSize = DEFAULT_READ_CHUNK_SIZE;
980 /// <summary> Sets the maximum number of bytes read at once from the
981 /// underlying file during {@link IndexInput#readBytes}.
982 /// The default value is {@link #DEFAULT_READ_CHUNK_SIZE};
984 /// <p/> This was introduced due to <a
985 /// href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6478546">Sun
986 /// JVM Bug 6478546</a>, which throws an incorrect
987 /// OutOfMemoryError when attempting to read too many bytes
988 /// at once. It only happens on 32bit JVMs with a large
989 /// maximum heap size.<p/>
991 /// <p/>Changes to this value will not impact any
992 /// already-opened {@link IndexInput}s. You should call
993 /// this before attempting to open an index on the
996 /// <p/> <b>NOTE</b>: This value should be as large as
997 /// possible to reduce any possible performance impact. If
998 /// you still encounter an incorrect OutOfMemoryError,
999 /// trying lowering the chunk size.<p/>
1001 public void SetReadChunkSize(int chunkSize)
1006 throw new System.ArgumentException("chunkSize must be positive");
1008 if (!Constants.JRE_IS_64BIT)
1010 this.chunkSize = chunkSize;
1014 /// <summary> The maximum number of bytes to read at once from the
1015 /// underlying file during {@link IndexInput#readBytes}.
1017 /// <seealso cref="setReadChunkSize">
1019 public int GetReadChunkSize()
1026 /// <deprecated> Use SimpleFSDirectory.SimpleFSIndexInput instead
1028 [Obsolete("Use SimpleFSDirectory.SimpleFSIndexInput instead ")]
1029 public /*protected internal*/ class FSIndexInput:SimpleFSDirectory.SimpleFSIndexInput
1035 new protected internal class Descriptor:SimpleFSDirectory.SimpleFSIndexInput.Descriptor
1040 public Descriptor(/*FSIndexInput enclosingInstance,*/ System.IO.FileInfo file, System.IO.FileAccess mode) : base(file, mode)
1048 public FSIndexInput(System.IO.FileInfo path):base(path)
1055 public FSIndexInput(System.IO.FileInfo path, int bufferSize):base(path, bufferSize)
1060 /// <deprecated> Use SimpleFSDirectory.SimpleFSIndexOutput instead
1062 [Obsolete("Use SimpleFSDirectory.SimpleFSIndexOutput instead ")]
1063 protected internal class FSIndexOutput:SimpleFSDirectory.SimpleFSIndexOutput
1069 public FSIndexOutput(System.IO.FileInfo path):base(path)
1073 static FSDirectory()
1078 System.String name = SupportClass.AppSettings.Get("Mono.Lucene.Net.FSDirectory.class", typeof(SimpleFSDirectory).FullName);
1079 if (typeof(FSDirectory).FullName.Equals(name))
1081 // FSDirectory will be abstract, so we replace it by the correct class
1082 IMPL = typeof(SimpleFSDirectory);
1086 IMPL = System.Type.GetType(name);
1089 catch (System.Security.SecurityException se)
1091 IMPL = typeof(SimpleFSDirectory);
1093 catch (System.Exception e)
1095 throw new System.SystemException("cannot load FSDirectory class: " + e.ToString(), e);
1101 DIGESTER = SupportClass.Cryptography.GetHashAlgorithm();
1103 catch (System.Exception e)
1105 throw new System.SystemException(e.ToString(), e);
1108 DEFAULT_READ_CHUNK_SIZE = Constants.JRE_IS_64BIT?System.Int32.MaxValue:100 * 1024 * 1024;