[monkeydoc] Merge/add monkeydoc to master.
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Store / FSDirectory.cs
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 using System.Collections.Generic;
20
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;
25
26 namespace Mono.Lucene.Net.Store
27 {
28         
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
32         /// subclasses:
33         /// 
34         /// <ul>
35         /// 
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
41         /// same file.</li>
42         /// 
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
53     /// for details.
54     ///        
55     ///        
56         /// 
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 &quot;delete on
74         /// last close&quot; 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>
81     ///       
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.
86         /// </ul>
87         /// 
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.
97         /// 
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.
113         /// 
114         /// <p/><em>In 3.0 this class will become abstract.</em>
115         /// 
116         /// </summary>
117         /// <seealso cref="Directory">
118         /// </seealso>
119         // TODO: in 3.0 this will become an abstract base class
120         public class FSDirectory:Directory
121         {
122                 
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.
130                 /// </summary>
131                 /// <deprecated> Not used by any non-deprecated methods anymore
132                 /// </deprecated>
133         [Obsolete("Not used by any non-deprecated methods anymore")]
134         private static readonly Dictionary<string, FSDirectory> DIRECTORIES = new Dictionary<string, FSDirectory>();
135                 
136                 private static bool disableLocks = false;
137                 
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?
140                 
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.
144                 /// </summary>
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.   
150                 /// </deprecated>
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)
153                 {
154                         FSDirectory.disableLocks = doDisableLocks;
155                 }
156                 
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.
159                 /// </returns>
160                 /// <seealso cref="setDisableLocks">
161                 /// </seealso>
162                 /// <deprecated> Use a constructor that takes a {@link LockFactory} and
163                 /// supply {@link NoLockFactory#getNoLockFactory}.
164                 /// </deprecated>
165         [Obsolete("Use a constructor that takes a LockFactory and supply NoLockFactory.GetNoLockFactory.")]
166                 public static bool GetDisableLocks()
167                 {
168                         return FSDirectory.disableLocks;
169                 }
170                 
171                 /// <summary> Directory specified by <code>org.apache.lucene.lockDir</code>
172                 /// or <code>java.io.tmpdir</code> system property.
173                 /// </summary>
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)}).
183                 /// </deprecated>
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());
186                 
187                 /// <summary>The default class which implements filesystem-based directories. </summary>
188                 // deprecated
189         [Obsolete]
190         private static readonly System.Type IMPL = typeof(Mono.Lucene.Net.Store.SimpleFSDirectory);
191                 
192                 private static System.Security.Cryptography.HashAlgorithm DIGESTER;
193                 
194                 /// <summary>A buffer optionally used in renameTo method </summary>
195                 private byte[] buffer = null;
196                 
197                 
198                 /// <summary>Returns the directory instance for the named location.
199                 /// 
200                 /// </summary>
201                 /// <deprecated> Use {@link #Open(File)}
202                 /// 
203                 /// </deprecated>
204                 /// <param name="path">the path to the directory.
205                 /// </param>
206                 /// <returns> the FSDirectory for the named file.  
207                 /// </returns>
208         [Obsolete("Use Open(File)")]
209                 public static FSDirectory GetDirectory(System.String path)
210                 {
211                         return GetDirectory(new System.IO.DirectoryInfo(path), null);
212                 }
213                 
214                 /// <summary>Returns the directory instance for the named location.
215                 /// 
216                 /// </summary>
217                 /// <deprecated> Use {@link #Open(File, LockFactory)}
218                 /// 
219                 /// </deprecated>
220                 /// <param name="path">the path to the directory.
221                 /// </param>
222                 /// <param name="lockFactory">instance of {@link LockFactory} providing the
223                 /// locking implementation.
224                 /// </param>
225                 /// <returns> the FSDirectory for the named file.  
226                 /// </returns>
227         [Obsolete("Use Open(File, LockFactory)")]
228                 public static FSDirectory GetDirectory(System.String path, LockFactory lockFactory)
229                 {
230                         return GetDirectory(new System.IO.DirectoryInfo(path), lockFactory);
231                 }
232                 
233                 /// <summary>Returns the directory instance for the named location.
234                 /// 
235                 /// </summary>
236                 /// <deprecated> Use {@link #Open(File)}
237                 /// 
238                 /// </deprecated>
239                 /// <param name="file">the path to the directory.
240                 /// </param>
241                 /// <returns> the FSDirectory for the named file.  
242                 /// </returns>
243         [Obsolete("Use Open(File)")]
244                 public static FSDirectory GetDirectory(System.IO.DirectoryInfo file)
245                 {
246                         return GetDirectory(file, null);
247                 }
248
249         /// <summary>Returns the directory instance for the named location.
250         /// 
251         /// </summary>
252         /// <deprecated> Use {@link #Open(File)}
253         /// 
254         /// </deprecated>
255         /// <param name="file">the path to the directory.
256         /// </param>
257         /// <returns> the FSDirectory for the named file.  
258         /// </returns>
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)
261         {
262             return GetDirectory(new System.IO.DirectoryInfo(file.FullName), null);
263         }
264                 
265                 /// <summary>Returns the directory instance for the named location.
266                 /// 
267                 /// </summary>
268                 /// <deprecated> Use {@link #Open(File, LockFactory)}
269                 /// 
270                 /// </deprecated>
271                 /// <param name="file">the path to the directory.
272                 /// </param>
273                 /// <param name="lockFactory">instance of {@link LockFactory} providing the
274                 /// locking implementation.
275                 /// </param>
276                 /// <returns> the FSDirectory for the named file.  
277                 /// </returns>
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)
280                 {
281             return GetDirectory(new System.IO.DirectoryInfo(file.FullName), lockFactory);
282                 }
283
284         /// <summary>Returns the directory instance for the named location.
285         /// 
286         /// </summary>
287         /// <deprecated> Use {@link #Open(File, LockFactory)}
288         /// 
289         /// </deprecated>
290         /// <param name="file">the path to the directory.
291         /// </param>
292         /// <param name="lockFactory">instance of {@link LockFactory} providing the
293         /// locking implementation.
294         /// </param>
295         /// <returns> the FSDirectory for the named file.  
296         /// </returns>
297         [Obsolete("Use Open(File, LockFactory)")]
298         public static FSDirectory GetDirectory(System.IO.DirectoryInfo file, LockFactory lockFactory)
299         {
300             FSDirectory dir;
301             lock (DIRECTORIES)
302             {
303                 if(!DIRECTORIES.TryGetValue(file.FullName, out dir))
304                 {
305                     try
306                     {
307                         dir = (FSDirectory)System.Activator.CreateInstance(IMPL, true);
308                     }
309                     catch (System.Exception e)
310                     {
311                         throw new System.SystemException("cannot load FSDirectory class: " + e.ToString(), e);
312                     }
313                     dir.Init(file, lockFactory);
314                     DIRECTORIES.Add(file.FullName, dir);
315                 }
316                 else
317                 {
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())
321                     {
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");
323                     }
324                     dir.checked_Renamed = false;
325                 }
326             }
327             lock (dir)
328             {
329                 dir.refCount++;
330             }
331             return dir;
332         }
333                 
334                 
335                 /// <summary>Returns the directory instance for the named location.
336                 /// 
337                 /// </summary>
338                 /// <deprecated> Use IndexWriter's create flag, instead, to
339                 /// create a new index.
340                 /// 
341                 /// </deprecated>
342                 /// <param name="path">the path to the directory.
343                 /// </param>
344                 /// <param name="create">if true, create, or erase any existing contents.
345                 /// </param>
346                 /// <returns> the FSDirectory for the named file.  
347                 /// </returns>
348         [Obsolete("Use IndexWriter's create flag, instead, to create a new index.")]
349                 public static FSDirectory GetDirectory(System.String path, bool create)
350                 {
351                         return GetDirectory(new System.IO.DirectoryInfo(path), create);
352                 }
353                 
354                 /// <summary>Returns the directory instance for the named location.
355                 /// 
356                 /// </summary>
357                 /// <deprecated> Use IndexWriter's create flag, instead, to
358                 /// create a new index.
359                 /// 
360                 /// </deprecated>
361                 /// <param name="file">the path to the directory.
362                 /// </param>
363                 /// <param name="create">if true, create, or erase any existing contents.
364                 /// </param>
365                 /// <returns> the FSDirectory for the named file.  
366                 /// </returns>
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)
369                 {
370                         return GetDirectory(new System.IO.DirectoryInfo(file.FullName), create);
371                 }
372
373         /// <summary>Returns the directory instance for the named location.
374         /// 
375         /// </summary>
376         /// <deprecated> Use IndexWriter's create flag, instead, to
377         /// create a new index.
378         /// 
379         /// </deprecated>
380         /// <param name="file">the path to the directory.
381         /// </param>
382         /// <param name="create">if true, create, or erase any existing contents.
383         /// </param>
384         /// <returns> the FSDirectory for the named file.  
385         /// </returns>
386         [Obsolete("Use IndexWriter's create flag, instead, to create a new index.")]
387         public static FSDirectory GetDirectory(System.IO.DirectoryInfo file, bool create)
388         {
389             FSDirectory dir = GetDirectory(file, null);
390
391             // This is now deprecated (creation should only be done
392             // by IndexWriter):
393             if (create)
394             {
395                 dir.Create();
396             }
397
398             return dir;
399         }
400                 
401                 /// <deprecated> 
402                 /// </deprecated>
403         [Obsolete]
404                 private void  Create()
405                 {
406                         if (directory.Exists)
407                         {
408                                 System.String[] files = SupportClass.FileSupport.GetLuceneIndexFiles(directory.FullName, IndexFileNameFilter.GetFilter()); // clear old files
409                                 if (files == null)
410                                         throw new System.IO.IOException("cannot read directory " + directory.FullName + ": list() returned null");
411                                 for (int i = 0; i < files.Length; i++)
412                                 {
413                     System.String fileOrDir = System.IO.Path.Combine(directory.FullName, files[i]);
414                     if (System.IO.File.Exists(fileOrDir))
415                                         {
416                         System.IO.File.Delete(fileOrDir);
417                                         }
418                     else if (System.IO.Directory.Exists(fileOrDir))
419                                         {
420                         System.IO.Directory.Delete(fileOrDir);
421                                         }
422                     // no need to throw anything - if a delete fails the exc will propogate to the caller
423                                 }
424                         }
425                         lockFactory.ClearLock(IndexWriter.WRITE_LOCK_NAME);
426                 }
427                 
428                 private bool checked_Renamed;
429                 
430                 internal void  CreateDir()
431                 {
432                         if (!checked_Renamed)
433                         {
434                 if (!this.directory.Exists)
435                 {
436                     try
437                     {
438                         this.directory.Create();
439                     }
440                     catch (Exception)
441                     {
442                         throw new System.IO.IOException("Cannot create directory: " + directory);
443                     }
444                     this.directory.Refresh(); // need to see the creation
445                 }
446                                 
447                                 checked_Renamed = true;
448                         }
449                 }
450                 
451                 /// <summary>Initializes the directory to create a new file with the given name.
452                 /// This method should be used in {@link #createOutput}. 
453                 /// </summary>
454                 protected internal void  InitOutput(System.String name)
455                 {
456                         EnsureOpen();
457                         CreateDir();
458                         System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
459             if (file.Exists) // delete existing, if any
460             {
461                 try
462                 {
463                     file.Delete();
464                 }
465                 catch (Exception)
466                 {
467                     throw new System.IO.IOException("Cannot overwrite: " + file);
468                 }
469             }
470                 }
471                 
472                 /// <summary>The underlying filesystem directory </summary>
473                 protected internal System.IO.DirectoryInfo directory = null;
474                 
475                 /// <deprecated> 
476                 /// </deprecated>
477         [Obsolete]
478                 private int refCount = 0;
479                 
480                 /// <deprecated> 
481                 /// </deprecated>
482         [Obsolete]
483                 protected internal FSDirectory()
484                 {
485                 }
486                  // permit subclassing
487                 
488                 /// <summary>Create a new FSDirectory for the named location (ctor for subclasses).</summary>
489                 /// <param name="path">the path of the directory
490                 /// </param>
491                 /// <param name="lockFactory">the lock factory to use, or null for the default
492                 /// ({@link NativeFSLockFactory});
493                 /// </param>
494                 /// <throws>  IOException </throws>
495                 protected internal FSDirectory(System.IO.DirectoryInfo path, LockFactory lockFactory)
496                 {
497                         // new ctors use always NativeFSLockFactory as default:
498                         if (lockFactory == null)
499                         {
500                                 lockFactory = new NativeFSLockFactory();
501                         }
502                         Init(path, lockFactory);
503                         refCount = 1;
504                 }
505                 
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}.
509         /// 
510         /// <p/>Currently this returns {@link SimpleFSDirectory} as
511         /// NIOFSDirectory is currently not supported.
512                 /// 
513                 /// <p/>Currently this returns {@link SimpleFSDirectory} as
514                 /// NIOFSDirectory is currently not supported.
515                 /// 
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.
526                 /// 
527                 /// <p/>See <a href="#subclasses">above</a> 
528                 /// </summary>
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)
531                 {
532                         System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(path.FullName);
533                         return Open(dir, null);
534                 }
535                 
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}.
539                 /// 
540                 /// <p/>Currently this returns {@link SimpleFSDirectory} as
541                 /// NIOFSDirectory is currently not supported.
542                 /// 
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.
553                 /// 
554                 /// <p/>See <a href="#subclasses">above</a> 
555                 /// </summary>
556                 public static FSDirectory Open(System.IO.DirectoryInfo path)
557                 {
558                         return Open(path, null);
559                 }
560                 
561                 /// <summary>Just like {@link #Open(File)}, but allows you to
562                 /// also specify a custom {@link LockFactory}. 
563                 /// </summary>
564                 public static FSDirectory Open(System.IO.DirectoryInfo path, LockFactory lockFactory)
565                 {
566                         /* For testing:
567                         MMapDirectory dir=new MMapDirectory(path, lockFactory);
568                         dir.setUseUnmap(true);
569                         return dir;
570                         */
571                         
572                         if (Constants.WINDOWS)
573                         {
574                                 return new SimpleFSDirectory(path, lockFactory);
575                         }
576                         else
577                         {
578                 //NIOFSDirectory is not implemented in Mono.Lucene.Net
579                                 //return new NIOFSDirectory(path, lockFactory);
580                 return new SimpleFSDirectory(path, lockFactory);
581                         }
582         }
583                 
584                 /* will move to ctor, when reflection is removed in 3.0 */
585                 private void  Init(System.IO.DirectoryInfo path, LockFactory lockFactory)
586                 {
587                         
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:
592                         
593                         directory = path;
594                         
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))
597             {
598                 throw new NoSuchDirectoryException("file '" + directory.FullName + "' exists but is not a directory");
599             }
600                         
601                         if (lockFactory == null)
602                         {
603                                 
604                                 if (disableLocks)
605                                 {
606                                         // Locks are disabled:
607                                         lockFactory = NoLockFactory.GetNoLockFactory();
608                                 }
609                                 else
610                                 {
611                                         System.String lockClassName = SupportClass.AppSettings.Get("Mono.Lucene.Net.Store.FSDirectoryLockFactoryClass", "");
612                                         
613                                         if (lockClassName != null && !lockClassName.Equals(""))
614                                         {
615                                                 System.Type c;
616                                                 
617                                                 try
618                                                 {
619                                                         c = System.Type.GetType(lockClassName);
620                                                 }
621                                                 catch (System.Exception e)
622                                                 {
623                                                         throw new System.IO.IOException("unable to find LockClass " + lockClassName);
624                                                 }
625                                                 
626                                                 try
627                                                 {
628                                                         lockFactory = (LockFactory) System.Activator.CreateInstance(c, true);
629                                                 }
630                                                 catch (System.UnauthorizedAccessException e)
631                                                 {
632                                                         throw new System.IO.IOException("IllegalAccessException when instantiating LockClass " + lockClassName);
633                                                 }
634                                                 catch (System.InvalidCastException e)
635                                                 {
636                                                         throw new System.IO.IOException("unable to cast LockClass " + lockClassName + " instance to a LockFactory");
637                                                 }
638                                                 catch (System.Exception e)
639                                                 {
640                                                         throw new System.IO.IOException("InstantiationException when instantiating LockClass " + lockClassName);
641                                                 }
642                                         }
643                                         else
644                                         {
645                                                 // Our default lock is SimpleFSLockFactory;
646                                                 // default lockDir is our index directory:
647                                                 lockFactory = new SimpleFSLockFactory();
648                                         }
649                                 }
650                         }
651                         
652                         SetLockFactory(lockFactory);
653                         
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)
657                         {
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
661                                 if (dir == null)
662                                 {
663                                         lf.SetLockDir(this.directory);
664                                         lf.SetLockPrefix(null);
665                                 }
666                                 else if (dir.FullName.Equals(this.directory.FullName))
667                                 {
668                                         lf.SetLockPrefix(null);
669                                 }
670                         }
671                 }
672                 
673                 /// <summary>Lists all files (not subdirectories) in the
674                 /// directory.  This method never returns null (throws
675                 /// {@link IOException} instead).
676                 /// 
677                 /// </summary>
678                 /// <throws>  NoSuchDirectoryException if the directory </throws>
679                 /// <summary>   does not exist, or does exist but is not a
680                 /// directory.
681                 /// </summary>
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)
685                 {
686                         return ListAll(new System.IO.DirectoryInfo(dir.FullName));
687                 }
688                 
689         /// <summary>Lists all files (not subdirectories) in the
690         /// directory.  This method never returns null (throws
691         /// {@link IOException} instead).
692         /// 
693         /// </summary>
694         /// <throws>  NoSuchDirectoryException if the directory </throws>
695         /// <summary>   does not exist, or does exist but is not a
696         /// directory.
697         /// </summary>
698         /// <throws>  IOException if list() returns null  </throws>
699         public static System.String[] ListAll(System.IO.DirectoryInfo dir)
700         {
701             if (!dir.Exists)
702             {
703                 throw new NoSuchDirectoryException("directory '" + dir.FullName + "' does not exist");
704             }
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++)
709             {
710                 result[i] = files[i].Name;
711             }
712
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
716
717             return result;
718         }
719                 
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()
722                 {
723                         EnsureOpen();
724                         return SupportClass.FileSupport.GetLuceneIndexFiles(directory.FullName, IndexFileNameFilter.GetFilter());
725                 }
726                 
727                 /// <summary>Lists all files (not subdirectories) in the
728                 /// directory.
729                 /// </summary>
730                 /// <seealso cref="ListAll(File)">
731                 /// </seealso>
732                 public override System.String[] ListAll()
733                 {
734                         EnsureOpen();
735                         return ListAll(directory);
736                 }
737                 
738                 /// <summary>Returns true iff a file with the given name exists. </summary>
739                 public override bool FileExists(System.String name)
740                 {
741                         EnsureOpen();
742                         System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
743             return file.Exists;
744                 }
745                 
746                 /// <summary>Returns the time the named file was last modified. </summary>
747                 public override long FileModified(System.String name)
748                 {
749                         EnsureOpen();
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}}
752                 }
753                 
754                 /// <summary>Returns the time the named file was last modified. </summary>
755                 public static long FileModified(System.IO.FileInfo directory, System.String name)
756                 {
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}}
759                 }
760                 
761                 /// <summary>Set the modified time of an existing file to now. </summary>
762                 public override void  TouchFile(System.String name)
763                 {
764                         EnsureOpen();
765                         System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
766                         file.LastWriteTime = System.DateTime.Now;
767                 }
768                 
769                 /// <summary>Returns the length in bytes of a file in the directory. </summary>
770                 public override long FileLength(System.String name)
771                 {
772                         EnsureOpen();
773                         System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
774                         return file.Exists ? file.Length : 0;
775                 }
776                 
777                 /// <summary>Removes an existing file in the directory. </summary>
778                 public override void  DeleteFile(System.String name)
779                 {
780                         EnsureOpen();
781                         System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
782             try
783             {
784                 file.Delete();
785             }
786             catch (Exception)
787             {
788                 throw new System.IO.IOException("Cannot delete " + file);
789             }
790                 }
791                 
792                 /// <summary>Renames an existing file in the directory. 
793                 /// Warning: This is not atomic.
794                 /// </summary>
795                 /// <deprecated> 
796                 /// </deprecated>
797         [Obsolete]
798                 public override void  RenameFile(System.String from, System.String to)
799                 {
800                         lock (this)
801                         {
802                                 EnsureOpen();
803                 System.IO.FileInfo old = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, from));
804                 try
805                 {
806                     old.MoveTo(System.IO.Path.Combine(directory.FullName, to));
807                 }
808                 catch (System.IO.IOException ioe)
809                 {
810                     System.IO.IOException newExc = new System.IO.IOException("Cannot rename " + old + " to " + directory, ioe);
811                     throw newExc;
812                 }
813                         }
814                 }
815                 
816                 /// <summary>Creates an IndexOutput for the file with the given name.
817                 /// <em>In 3.0 this method will become abstract.</em> 
818                 /// </summary>
819                 public override IndexOutput CreateOutput(System.String name)
820                 {
821                         InitOutput(name);
822                         return new FSIndexOutput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)));
823                 }
824                 
825                 public override void  Sync(System.String name)
826                 {
827                         EnsureOpen();
828                         System.IO.FileInfo fullFile = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
829                         bool success = false;
830                         int retryCount = 0;
831                         System.IO.IOException exc = null;
832                         while (!success && retryCount < 5)
833                         {
834                                 retryCount++;
835                                 System.IO.FileStream file = null;
836                                 try
837                                 {
838                                         try
839                                         {
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);
842                         success = true;
843                                         }
844                                         finally
845                                         {
846                                                 if (file != null)
847                                                         file.Close();
848                                         }
849                                 }
850                                 catch (System.IO.IOException ioe)
851                                 {
852                                         if (exc == null)
853                                                 exc = ioe;
854                                         try
855                                         {
856                                                 // Pause 5 msec
857                                                 System.Threading.Thread.Sleep(new System.TimeSpan((System.Int64) 10000 * 5));
858                                         }
859                                         catch (System.Threading.ThreadInterruptedException ie)
860                                         {
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);
865                                         }
866                                 }
867                         }
868                         if (!success)
869                         // Throw original exception
870                                 throw exc;
871                 }
872                 
873                 // Inherit javadoc
874                 public override IndexInput OpenInput(System.String name)
875                 {
876                         EnsureOpen();
877                         return OpenInput(name, BufferedIndexInput.BUFFER_SIZE);
878                 }
879                 
880                 /// <summary>Creates an IndexInput for the file with the given name.
881                 /// <em>In 3.0 this method will become abstract.</em> 
882                 /// </summary>
883                 public override IndexInput OpenInput(System.String name, int bufferSize)
884                 {
885                         EnsureOpen();
886                         return new FSIndexInput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)), bufferSize);
887                 }
888                 
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'};
891                 
892                 
893                 public override System.String GetLockID()
894                 {
895                         EnsureOpen();
896                         System.String dirName; // name to be hashed
897                         try
898                         {
899                                 dirName = directory.FullName;
900                         }
901                         catch (System.IO.IOException e)
902                         {
903                                 throw new System.SystemException(e.ToString(), e);
904                         }
905                         
906                         byte[] digest;
907                         lock (DIGESTER)
908                         {
909                                 digest = DIGESTER.ComputeHash(System.Text.Encoding.UTF8.GetBytes(dirName));
910                         }
911                         System.Text.StringBuilder buf = new System.Text.StringBuilder();
912                         buf.Append("lucene-");
913                         for (int i = 0; i < digest.Length; i++)
914                         {
915                                 int b = digest[i];
916                                 buf.Append(HEX_DIGITS[(b >> 4) & 0xf]);
917                                 buf.Append(HEX_DIGITS[b & 0xf]);
918                         }
919                         
920                         return buf.ToString();
921                 }
922                 
923                 /// <summary>Closes the store to future operations. </summary>
924                 public override void  Close()
925                 {
926                         lock (this)
927                         {
928                                 if (isOpen && --refCount <= 0)
929                                 {
930                                         isOpen = false;
931                                         lock (DIRECTORIES)
932                                         {
933                                                 DIRECTORIES.Remove(directory.FullName);
934                                         }
935                                 }
936                         }
937                 }
938
939         /// <summary>
940         /// .NET
941         /// </summary>
942         public override void Dispose()
943         {
944             Close();
945         }
946
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()
949                 {
950                         EnsureOpen();
951                         return new System.IO.FileInfo(directory.FullName);
952                 }
953
954
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()
958         {
959             EnsureOpen();
960             return directory;
961         }
962                 
963                 /// <summary>For debug output. </summary>
964                 public override System.String ToString()
965                 {
966             return this.GetType().FullName + "@" + directory + " lockFactory=" + GetLockFactory();
967                 }
968                 
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>.
972                 /// </summary>
973                 /// <seealso cref="setReadChunkSize">
974                 /// </seealso>
975                 public static readonly int DEFAULT_READ_CHUNK_SIZE;
976                 
977                 // LUCENE-1566
978                 private int chunkSize = DEFAULT_READ_CHUNK_SIZE;
979                 
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};
983                 /// 
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/>
990                 /// 
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
994                 /// directory.<p/>
995                 /// 
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/>
1000                 /// </summary>
1001                 public void  SetReadChunkSize(int chunkSize)
1002                 {
1003                         // LUCENE-1566
1004                         if (chunkSize <= 0)
1005                         {
1006                                 throw new System.ArgumentException("chunkSize must be positive");
1007                         }
1008                         if (!Constants.JRE_IS_64BIT)
1009                         {
1010                                 this.chunkSize = chunkSize;
1011                         }
1012                 }
1013                 
1014                 /// <summary> The maximum number of bytes to read at once from the
1015                 /// underlying file during {@link IndexInput#readBytes}.
1016                 /// </summary>
1017                 /// <seealso cref="setReadChunkSize">
1018                 /// </seealso>
1019                 public int GetReadChunkSize()
1020                 {
1021                         // LUCENE-1566
1022                         return chunkSize;
1023                 }
1024                 
1025                 
1026                 /// <deprecated> Use SimpleFSDirectory.SimpleFSIndexInput instead 
1027                 /// </deprecated>
1028         [Obsolete("Use SimpleFSDirectory.SimpleFSIndexInput instead ")]
1029                 public /*protected internal*/ class FSIndexInput:SimpleFSDirectory.SimpleFSIndexInput
1030                 {
1031                         
1032                         /// <deprecated> 
1033                         /// </deprecated>
1034             [Obsolete]
1035                         new protected internal class Descriptor:SimpleFSDirectory.SimpleFSIndexInput.Descriptor
1036                         {
1037                                 /// <deprecated> 
1038                                 /// </deprecated>
1039                 [Obsolete]
1040                                 public Descriptor(/*FSIndexInput enclosingInstance,*/ System.IO.FileInfo file, System.IO.FileAccess mode) : base(file, mode)
1041                                 {
1042                                 }
1043                         }
1044                         
1045                         /// <deprecated> 
1046                         /// </deprecated>
1047             [Obsolete]
1048                         public FSIndexInput(System.IO.FileInfo path):base(path)
1049                         {
1050                         }
1051                         
1052                         /// <deprecated> 
1053                         /// </deprecated>
1054             [Obsolete]
1055                         public FSIndexInput(System.IO.FileInfo path, int bufferSize):base(path, bufferSize)
1056                         {
1057                         }
1058                 }
1059                 
1060                 /// <deprecated> Use SimpleFSDirectory.SimpleFSIndexOutput instead 
1061                 /// </deprecated>
1062         [Obsolete("Use SimpleFSDirectory.SimpleFSIndexOutput instead ")]
1063                 protected internal class FSIndexOutput:SimpleFSDirectory.SimpleFSIndexOutput
1064                 {
1065                         
1066                         /// <deprecated> 
1067                         /// </deprecated>
1068             [Obsolete]
1069                         public FSIndexOutput(System.IO.FileInfo path):base(path)
1070                         {
1071                         }
1072                 }
1073                 static FSDirectory()
1074                 {
1075                         {
1076                                 try
1077                                 {
1078                                         System.String name = SupportClass.AppSettings.Get("Mono.Lucene.Net.FSDirectory.class", typeof(SimpleFSDirectory).FullName);
1079                                         if (typeof(FSDirectory).FullName.Equals(name))
1080                                         {
1081                                                 // FSDirectory will be abstract, so we replace it by the correct class
1082                                                 IMPL = typeof(SimpleFSDirectory);
1083                                         }
1084                                         else
1085                                         {
1086                                                 IMPL = System.Type.GetType(name);
1087                                         }
1088                                 }
1089                                 catch (System.Security.SecurityException se)
1090                                 {
1091                                         IMPL = typeof(SimpleFSDirectory);
1092                                 }
1093                                 catch (System.Exception e)
1094                                 {
1095                                         throw new System.SystemException("cannot load FSDirectory class: " + e.ToString(), e);
1096                                 }
1097                         }
1098                         {
1099                                 try
1100                                 {
1101                                         DIGESTER = SupportClass.Cryptography.GetHashAlgorithm();
1102                                 }
1103                                 catch (System.Exception e)
1104                                 {
1105                                         throw new System.SystemException(e.ToString(), e);
1106                                 }
1107                         }
1108                         DEFAULT_READ_CHUNK_SIZE = Constants.JRE_IS_64BIT?System.Int32.MaxValue:100 * 1024 * 1024;
1109                 }
1110         }
1111 }