cvsimport
[beagle.git] / beagled / Lucene.Net / Store / FSDirectory.cs
blobcf5d84c1df1876a43993c705c81ef7977ef205de
1 /*
2 * Copyright 2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 using System;
18 using IndexFileNameFilter = Lucene.Net.Index.IndexFileNameFilter;
19 using Mono.Unix.Native;
21 namespace Lucene.Net.Store
24 /// <summary> Straightforward implementation of {@link Directory} as a directory of files.
25 ///
26 /// </summary>
27 /// <seealso cref="Directory">
28 /// </seealso>
29 /// <author> Doug Cutting
30 /// </author>
31 public class FSDirectory : Directory
33 private class AnonymousClassLock : Lock
35 public AnonymousClassLock(System.IO.FileInfo lockFile, FSDirectory enclosingInstance)
37 InitBlock(lockFile, enclosingInstance);
39 private void InitBlock(System.IO.FileInfo lockFile, FSDirectory enclosingInstance)
41 this.lockFile = lockFile;
42 this.enclosingInstance = enclosingInstance;
44 private System.IO.FileInfo lockFile;
45 private FSDirectory enclosingInstance;
46 public FSDirectory Enclosing_Instance
48 get
50 return enclosingInstance;
54 public override bool Obtain()
56 Log ("Trying to obtain lock " + lockFile.FullName);
57 if (Lucene.Net.Store.FSDirectory.disableLocks || Enclosing_Instance.InstanceDisableLock)
58 return true;
60 bool tmpBool;
61 if (System.IO.File.Exists(Enclosing_Instance.lockDir.FullName))
62 tmpBool = true;
63 else
64 tmpBool = System.IO.Directory.Exists(Enclosing_Instance.lockDir.FullName);
65 if (!tmpBool)
67 try
69 System.IO.Directory.CreateDirectory(Enclosing_Instance.lockDir.FullName);
71 catch (Exception)
73 throw new System.IO.IOException("Cannot create lock directory: " + Enclosing_Instance.lockDir);
77 try
79 int fd = Mono.Unix.Native.Syscall.open (
80 lockFile.FullName,
81 Mono.Unix.Native.OpenFlags.O_RDWR |
82 Mono.Unix.Native.OpenFlags.O_CREAT |
83 Mono.Unix.Native.OpenFlags.O_EXCL,
84 Mono.Unix.Native.FilePermissions.S_IRUSR);
85 if (fd == -1)
86 throw new System.IO.IOException ("Could not create lock file: "
87 + Mono.Unix.Native.Stdlib.strerror (
88 Mono.Unix.Native.Stdlib.GetLastError ()
89 ));
91 // This code replaces the commented-out code below because
92 // it ends up being much faster. The reason for this is
93 // that closing a UnixStream causes Syscall.fsync() to be
94 // called, and that apparently is extremely slow!
96 // Time(ms) Count P/call(ms) Method name
97 // 1563.926 68 22.999 Mono.Unix.Native.Syscall::fsync(int)
99 // Since the lock file is written out very often, this time
100 // adds up and noticably slows down indexing.
101 IntPtr ptr = IntPtr.Zero;
102 long ret;
104 try {
105 string s = System.Diagnostics.Process.GetCurrentProcess ().Id.ToString () + "\n";
106 ptr = Mono.Unix.UnixMarshal.StringToHeap (s);
108 do {
109 ret = Mono.Unix.Native.Syscall.write (fd, ptr, (ulong) s.Length);
110 } while (Mono.Unix.UnixMarshal.ShouldRetrySyscall ((int) ret));
111 Mono.Unix.UnixMarshal.ThrowExceptionForLastErrorIf ((int) ret);
112 } finally {
113 Mono.Unix.UnixMarshal.FreeHeap (ptr);
115 do {
116 ret = Mono.Unix.Native.Syscall.close (fd);
117 } while (Mono.Unix.UnixMarshal.ShouldRetrySyscall ((int) ret));
118 Mono.Unix.UnixMarshal.ThrowExceptionForLastErrorIf ((int) ret);
121 //System.IO.StreamWriter w = new System.IO.StreamWriter (new Mono.Unix.UnixStream (fd, true));
122 //w.WriteLine (System.Diagnostics.Process.GetCurrentProcess ().Id);
123 //w.Close ();
124 return true;
126 catch (Exception e)
128 Log ("Exception in CreateNew for file:" + lockFile.FullName + ":" + e);
129 return false;
132 public override void Release()
134 if (Lucene.Net.Store.FSDirectory.disableLocks || Enclosing_Instance.InstanceDisableLock)
135 return ;
136 bool tmpBool;
137 if (System.IO.File.Exists(lockFile.FullName))
139 System.IO.File.Delete(lockFile.FullName);
140 tmpBool = true;
142 else if (System.IO.Directory.Exists(lockFile.FullName))
144 System.IO.Directory.Delete(lockFile.FullName);
145 tmpBool = true;
147 else
148 tmpBool = false;
149 if (System.IO.File.Exists(lockFile.FullName)) {
150 Log ("Release didnt delete lockfile {0}.", lockFile.FullName);
151 tmpBool = false;
153 bool generatedAux = tmpBool;
154 if (tmpBool)
155 Log ("Released lock {0}", lockFile.FullName);
156 else
157 Log ("Failed to release lock {0}", lockFile.FullName);
159 public override bool IsLocked()
161 if (Lucene.Net.Store.FSDirectory.disableLocks || Enclosing_Instance.InstanceDisableLock)
162 return false;
163 bool tmpBool;
164 if (System.IO.File.Exists(lockFile.FullName))
165 tmpBool = true;
166 else
167 tmpBool = System.IO.Directory.Exists(lockFile.FullName);
168 return tmpBool;
171 public override System.String ToString()
173 return lockFile.FullName;
177 /// <summary>This cache of directories ensures that there is a unique Directory
178 /// instance per path, so that synchronization on the Directory can be used to
179 /// synchronize access between readers and writers.
180 ///
181 /// This should be a WeakHashMap, so that entries can be GC'd, but that would
182 /// require Java 1.2. Instead we use refcounts...
183 /// </summary>
184 private static readonly System.Collections.Hashtable DIRECTORIES = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
186 private static bool disableLocks = false;
188 /// <summary> Set whether Lucene's use of lock files is disabled. By default,
189 /// lock files are enabled. They should only be disabled if the index
190 /// is on a read-only medium like a CD-ROM.
191 /// </summary>
192 public static void SetDisableLocks(bool doDisableLocks)
194 FSDirectory.disableLocks = doDisableLocks;
197 /// <summary> Returns whether Lucene's use of lock files is disabled.</summary>
198 /// <returns> true if locks are disabled, false if locks are enabled.
199 /// </returns>
200 public static bool GetDisableLocks()
202 return FSDirectory.disableLocks;
205 private bool instance_disable_lock = false;
206 public bool InstanceDisableLock {
207 get { return instance_disable_lock; }
208 set { instance_disable_lock = value; }
211 /// <summary> Directory specified by <code>Lucene.Net.lockDir</code>
212 /// or <code>java.io.tmpdir</code> system property
213 /// </summary>
214 public static readonly System.String LOCK_DIR = SupportClass.AppSettings.Get("Lucene.Net.lockDir", System.IO.Path.GetTempPath());
216 /// <summary>The default class which implements filesystem-based directories. </summary>
217 private static System.Type IMPL;
219 private static System.Security.Cryptography.MD5 DIGESTER;
221 /// <summary>A buffer optionally used in renameTo method </summary>
222 private byte[] buffer = null;
224 /// <summary>Returns the directory instance for the named location.
225 ///
226 /// <p>Directories are cached, so that, for a given canonical path, the same
227 /// FSDirectory instance will always be returned. This permits
228 /// synchronization on directories.
229 ///
230 /// </summary>
231 /// <param name="path">the path to the directory.
232 /// </param>
233 /// <param name="create">if true, create, or erase any existing contents.
234 /// </param>
235 /// <returns> the FSDirectory for the named file.
236 /// </returns>
237 public static FSDirectory GetDirectory(System.String path, bool create)
239 return GetDirectory(new System.IO.FileInfo(path), null, create, false);
242 /// <summary>Returns the directory instance for the named location.
243 ///
244 /// <p>Directories are cached, so that, for a given canonical path, the same
245 /// FSDirectory instance will always be returned. This permits
246 /// synchronization on directories.
247 ///
248 /// </summary>
249 /// <param name="file">the path to the directory.
250 /// </param>
251 /// <param name="create">if true, create, or erase any existing contents.
252 /// </param>
253 /// <returns> the FSDirectory for the named file.
254 /// </returns>
255 public static FSDirectory GetDirectory(System.IO.FileInfo file, bool create)
257 return GetDirectory(file, null, create, false);
260 /// <summary>Returns the directory instance for the named location.
261 ///
262 /// <p>Directories are cached, so that, for a given canonical path, the same
263 /// FSDirectory instance will always be returned. This permits
264 /// synchronization on directories.
265 ///
266 /// </summary>
267 /// <param name="path">the path to the directory.
268 /// </param>
269 /// <param name="tmpDir">the path to use as lock directory.
270 /// </param>
271 /// <param name="create">if true, create, or erase any existing contents.
272 /// </param>
273 /// <returns> the FSDirectory for the named file.
274 /// </returns>
275 public static FSDirectory GetDirectory(System.String path, System.String tmpDir, bool create)
277 return GetDirectory(new System.IO.FileInfo(path), tmpDir, create, false);
280 /// <summary>Returns the directory instance for the named location.
281 ///
282 /// <p>Directories are cached, so that, for a given canonical path, the same
283 /// FSDirectory instance will always be returned. This permits
284 /// synchronization on directories.
285 ///
286 /// </summary>
287 /// <param name="path">the path to the directory.
288 /// </param>
289 /// <param name="tmpDir">the path to use as lock directory.
290 /// </param>
291 /// <param name="create">if true, create, or erase any existing contents.
292 /// </param>
293 /// <param name="disable_locks">if true, disable internal locking
294 /// </param>
295 /// <returns> the FSDirectory for the named file.
296 /// </returns>
297 public static FSDirectory GetDirectory(System.String path, System.String tmpDir, bool create, bool disable_locks)
299 return GetDirectory(new System.IO.FileInfo(path), tmpDir, create, disable_locks);
302 /// <summary>Returns the directory instance for the named location.
303 ///
304 /// <p>Directories are cached, so that, for a given canonical path, the same
305 /// FSDirectory instance will always be returned. This permits
306 /// synchronization on directories.
307 ///
308 /// </summary>
309 /// <param name="file">the path to the directory.
310 /// </param>
311 /// <param name="tmpDir">the path to use as lock directory.
312 /// </param>
313 /// <param name="create">if true, create, or erase any existing contents.
314 /// </param>
315 /// <param name="disable_locks">if true, disable internal locking
316 /// </param>
317 /// <returns> the FSDirectory for the named file.
318 /// </returns>
319 public static FSDirectory GetDirectory(System.IO.FileInfo file, System.String tmpdir, bool create, bool disable_locks)
321 file = new System.IO.FileInfo(file.FullName);
322 FSDirectory dir;
323 lock (DIRECTORIES.SyncRoot)
325 dir = (FSDirectory) DIRECTORIES[file];
326 if (dir == null)
330 dir = (FSDirectory) System.Activator.CreateInstance(IMPL);
332 catch (System.Exception e)
334 throw new System.SystemException("cannot load FSDirectory class: " + e.ToString());
336 dir.Init(file, tmpdir, create, disable_locks);
337 DIRECTORIES[file] = dir;
339 else if (create)
341 dir.Create();
344 lock (dir)
346 dir.refCount++;
348 return dir;
351 private System.IO.FileInfo directory = null;
352 private int refCount;
353 private System.IO.FileInfo lockDir;
355 public FSDirectory() // protected internal FSDirectory() // {{Aroush}} this shouldn't be 'public' but if it's not the line 'System.Activator.CreateInstance(IMPL);' in function GetDirectory() will fail.
359 // permit subclassing
361 private void Init(System.IO.FileInfo path, System.String tmpDir, bool create, bool disable_locks)
363 directory = path;
364 this.instance_disable_lock = disable_locks;
367 if (tmpDir != null)
369 lockDir = new System.IO.FileInfo(tmpDir);
371 else if (LOCK_DIR == null)
373 lockDir = directory;
375 else
377 lockDir = new System.IO.FileInfo(LOCK_DIR);
379 // Ensure that lockDir exists and is a directory.
380 bool tmpBool;
381 if (System.IO.File.Exists(lockDir.FullName))
382 tmpBool = true;
383 else
384 tmpBool = System.IO.Directory.Exists(lockDir.FullName);
385 if (!tmpBool)
389 System.IO.Directory.CreateDirectory(lockDir.FullName);
391 catch (Exception)
393 throw new System.IO.IOException("Cannot create directory: " + lockDir);
396 else if (!System.IO.Directory.Exists(lockDir.FullName))
398 throw new System.IO.IOException("Found regular file where directory expected: " + lockDir);
400 if (create)
402 Create();
405 if (!System.IO.Directory.Exists(directory.FullName))
406 throw new System.IO.IOException(path + " not a directory");
409 private void Create()
411 lock (this)
413 bool tmpBool;
414 if (System.IO.File.Exists(directory.FullName))
415 tmpBool = true;
416 else
417 tmpBool = System.IO.Directory.Exists(directory.FullName);
418 if (!tmpBool)
422 System.IO.Directory.CreateDirectory(directory.FullName);
424 catch (Exception)
426 throw new System.IO.IOException("Cannot create directory: " + directory);
432 System.IO.Directory.Exists(directory.FullName);
434 catch (Exception)
436 throw new System.IO.IOException(directory + " not a directory");
439 System.String[] files = System.IO.Directory.GetFileSystemEntries(directory.FullName); // clear old files // {{Aroush-1.9}} we want the line below, not this one; how do we make the line below work in C#?!
440 //// System.String[] files = System.IO.Directory.GetFileSystemEntries(new IndexFileNameFilter()); // clear old files
441 for (int i = 0; i < files.Length; i++)
443 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, files[i]));
444 bool tmpBool2;
445 if (System.IO.File.Exists(file.FullName))
447 System.IO.File.Delete(file.FullName);
448 tmpBool2 = true;
450 else if (System.IO.Directory.Exists(file.FullName))
452 System.IO.Directory.Delete(file.FullName);
453 tmpBool2 = true;
455 else
456 tmpBool2 = false;
457 if (!tmpBool2)
458 throw new System.IO.IOException("Cannot delete " + files[i]);
461 System.String lockPrefix = GetLockPrefix().ToString(); // clear old locks
462 files = System.IO.Directory.GetFileSystemEntries(lockDir.FullName);
463 if (files == null)
464 throw new System.IO.IOException("Cannot read lock directory " + lockDir.FullName);
465 for (int i = 0; i < files.Length; i++)
467 if (!files[i].StartsWith(lockPrefix))
468 continue;
469 System.IO.FileInfo lockFile = new System.IO.FileInfo(System.IO.Path.Combine(lockDir.FullName, files[i]));
470 bool tmpBool3;
471 if (System.IO.File.Exists(lockFile.FullName))
473 System.IO.File.Delete(lockFile.FullName);
474 tmpBool3 = true;
476 else if (System.IO.Directory.Exists(lockFile.FullName))
478 System.IO.Directory.Delete(lockFile.FullName);
479 tmpBool3 = true;
481 else
482 tmpBool3 = false;
483 if (!tmpBool3)
484 throw new System.IO.IOException("Cannot delete " + files[i]);
489 /// <summary>Returns an array of strings, one for each file in the directory. </summary>
490 public override System.String[] List()
492 return System.IO.Directory.GetFileSystemEntries(directory.FullName);
495 /// <summary>Returns true iff a file with the given name exists. </summary>
496 public override bool FileExists(System.String name)
498 string path = System.IO.Path.Combine (directory.FullName, name);
500 return System.IO.File.Exists (path) || System.IO.Directory.Exists (path);
503 /// <summary>Returns the time the named file was last modified. </summary>
504 public override long FileModified(System.String name)
506 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
507 return (file.LastWriteTimeUtc.Ticks);
510 /// <summary>Returns the time the named file was last modified. </summary>
511 public static long FileModified(System.IO.FileInfo directory, System.String name)
513 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
514 return (file.LastWriteTimeUtc.Ticks);
517 /// <summary>Set the modified time of an existing file to now. </summary>
518 public override void TouchFile(System.String name)
520 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
521 file.LastWriteTime = System.DateTime.UtcNow;
524 /// <summary>Returns the length in bytes of a file in the directory. </summary>
525 public override long FileLength(System.String name)
527 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
528 return file.Exists ? file.Length : 0;
531 /// <summary>Removes an existing file in the directory. </summary>
532 public override void DeleteFile(System.String name)
534 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
535 bool tmpBool;
536 if (System.IO.File.Exists(file.FullName))
538 System.IO.File.Delete(file.FullName);
539 tmpBool = true;
541 else if (System.IO.Directory.Exists(file.FullName))
543 System.IO.Directory.Delete(file.FullName);
544 tmpBool = true;
546 else
547 tmpBool = false;
548 if (!tmpBool)
549 throw new System.IO.IOException("Cannot delete " + file);
552 /// <summary>Renames an existing file in the directory. </summary>
553 public override void RenameFile(System.String from, System.String to)
555 lock (this)
557 System.IO.FileInfo old = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, from));
558 System.IO.FileInfo nu = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, to));
560 /* This is not atomic. If the program crashes between the call to
561 delete() and the call to renameTo() then we're screwed, but I've
562 been unable to figure out how else to do this... */
564 bool tmpBool;
565 if (System.IO.File.Exists(nu.FullName))
566 tmpBool = true;
567 else
568 tmpBool = System.IO.Directory.Exists(nu.FullName);
569 if (tmpBool)
571 bool tmpBool2;
572 if (System.IO.File.Exists(nu.FullName))
574 System.IO.File.Delete(nu.FullName);
575 tmpBool2 = true;
577 else if (System.IO.Directory.Exists(nu.FullName))
579 System.IO.Directory.Delete(nu.FullName);
580 tmpBool2 = true;
582 else
583 tmpBool2 = false;
584 if (!tmpBool2)
585 throw new System.IO.IOException("Cannot delete " + nu);
588 // Rename the old file to the new one. Unfortunately, the renameTo()
589 // method does not work reliably under some JVMs. Therefore, if the
590 // rename fails, we manually rename by copying the old file to the new one
593 old.MoveTo(nu.FullName);
595 catch (System.Exception)
597 System.IO.Stream in_Renamed = null;
598 System.IO.Stream out_Renamed = null;
601 in_Renamed = new System.IO.FileStream(old.FullName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
602 out_Renamed = new System.IO.FileStream(nu.FullName, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
603 // see if the buffer needs to be initialized. Initialization is
604 // only done on-demand since many VM's will never run into the renameTo
605 // bug and hence shouldn't waste 1K of mem for no reason.
606 if (buffer == null)
608 buffer = new byte[1024];
610 int len;
611 while ((len = in_Renamed.Read(buffer, 0, buffer.Length)) > 0)
613 out_Renamed.Write(buffer, 0, len);
616 // delete the old file.
617 bool tmpBool3;
618 if (System.IO.File.Exists(old.FullName))
620 System.IO.File.Delete(old.FullName);
621 tmpBool3 = true;
623 else if (System.IO.Directory.Exists(old.FullName))
625 System.IO.Directory.Delete(old.FullName);
626 tmpBool3 = true;
628 else
629 tmpBool3 = false;
630 bool generatedAux = tmpBool3;
632 catch (System.IO.IOException ioe)
634 throw new System.IO.IOException("Cannot rename " + old + " to " + nu);
636 finally
638 if (in_Renamed != null)
642 in_Renamed.Close();
644 catch (System.IO.IOException e)
646 throw new System.SystemException("Cannot close input stream: " + e.ToString());
649 if (out_Renamed != null)
653 out_Renamed.Close();
655 catch (System.IO.IOException e)
657 throw new System.SystemException("Cannot close output stream: " + e.ToString());
665 /// <summary>Creates a new, empty file in the directory with the given name.
666 /// Returns a stream writing this file.
667 /// </summary>
668 public override IndexOutput CreateOutput(System.String name)
670 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
671 bool tmpBool;
672 if (System.IO.File.Exists(file.FullName))
673 tmpBool = true;
674 else
675 tmpBool = System.IO.Directory.Exists(file.FullName);
676 bool tmpBool2;
677 if (System.IO.File.Exists(file.FullName))
679 System.IO.File.Delete(file.FullName);
680 tmpBool2 = true;
682 else if (System.IO.Directory.Exists(file.FullName))
684 System.IO.Directory.Delete(file.FullName);
685 tmpBool2 = true;
687 else
688 tmpBool2 = false;
689 if (tmpBool && !tmpBool2)
690 // delete existing, if any
691 throw new System.IO.IOException("Cannot overwrite: " + file);
693 return new FSIndexOutput(file);
696 /// <summary>Returns a stream reading an existing file. </summary>
697 public override IndexInput OpenInput(System.String name)
699 return new FSIndexInput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)));
702 static public Beagle.Util.Logger Logger = null;
703 //static public Beagle.Util.Logger Logger = Beagle.Util.Logger.Log;
704 static public void Log (string format, params object[] args)
706 if (Logger != null)
707 Logger.Debug (format, args);
710 static public void Log (Exception e)
712 if (Logger != null)
713 Logger.Debug (e);
716 /// <summary> So we can do some byte-to-hexchar conversion below</summary>
717 private static readonly char[] HEX_DIGITS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
719 /// <summary>Constructs a {@link Lock} with the specified name. Locks are implemented
720 /// with {@link File#createNewFile()}.
721 ///
722 /// </summary>
723 /// <param name="name">the name of the lock file
724 /// </param>
725 /// <returns> an instance of <code>Lock</code> holding the lock
726 /// </returns>
727 public override Lock MakeLock(System.String name)
729 System.Text.StringBuilder buf = GetLockPrefix();
730 buf.Append("-");
731 buf.Append(name);
733 // create a lock file
734 System.IO.FileInfo lockFile = new System.IO.FileInfo(System.IO.Path.Combine(lockDir.FullName, buf.ToString()));
736 return new AnonymousClassLock(lockFile, this);
739 private System.Text.StringBuilder GetLockPrefix()
741 System.String dirName; // name to be hashed
744 dirName = directory.FullName;
746 catch (System.IO.IOException e)
748 throw new System.SystemException(e.ToString());
751 byte[] digest;
752 lock (DIGESTER)
754 digest = DIGESTER.ComputeHash(System.Text.Encoding.UTF8.GetBytes(dirName));
756 System.Text.StringBuilder buf = new System.Text.StringBuilder();
757 buf.Append("lucene-");
758 for (int i = 0; i < digest.Length; i++)
760 int b = digest[i];
761 buf.Append(HEX_DIGITS[(b >> 4) & 0xf]);
762 buf.Append(HEX_DIGITS[b & 0xf]);
765 return buf;
768 /// <summary>Closes the store to future operations. </summary>
769 public override void Close()
771 lock (this)
773 if (--refCount <= 0)
775 lock (DIRECTORIES.SyncRoot)
777 DIRECTORIES.Remove(directory);
783 public virtual System.IO.FileInfo GetFile()
785 return directory;
788 /// <summary>For debug output. </summary>
789 public override System.String ToString()
791 return this.GetType().FullName + "@" + directory;
794 static FSDirectory()
799 System.String name = SupportClass.AppSettings.Get("Lucene.Net.FSDirectory.class", typeof(FSDirectory).FullName);
800 IMPL = System.Type.GetType(name);
802 catch (System.Security.SecurityException)
806 IMPL = System.Type.GetType(typeof(FSDirectory).FullName);
808 catch (System.Exception e)
810 throw new System.SystemException("cannot load default FSDirectory class: " + e.ToString());
813 catch (System.Exception e)
815 throw new System.SystemException("cannot load FSDirectory class: " + e.ToString());
821 DIGESTER = System.Security.Cryptography.MD5.Create();
823 catch (System.Exception e)
825 throw new System.SystemException(e.ToString());
832 public class FSIndexInput : BufferedIndexInput, System.ICloneable
834 private class Descriptor : System.IO.BinaryReader
836 private void InitBlock(FSIndexInput enclosingInstance)
838 this.enclosingInstance = enclosingInstance;
840 private FSIndexInput enclosingInstance;
841 public FSIndexInput Enclosing_Instance
845 return enclosingInstance;
849 public long position;
850 public Descriptor(FSIndexInput enclosingInstance, System.IO.FileInfo file, System.IO.FileAccess mode)
851 : base(new System.IO.FileStream(file.FullName, System.IO.FileMode.Open, mode, System.IO.FileShare.ReadWrite))
853 InitBlock(enclosingInstance);
857 private Descriptor file = null;
858 internal bool isClone;
859 private long length;
861 public bool IsClone
863 get { return (isClone); }
866 public FSIndexInput(System.IO.FileInfo path)
868 file = new Descriptor(this, path, System.IO.FileAccess.Read);
869 length = file.BaseStream.Length;
872 /// <summary>IndexInput methods </summary>
873 public override void ReadInternal(byte[] b, int offset, int len)
875 lock (file)
877 long position = GetFilePointer();
878 if (position != file.position)
880 file.BaseStream.Seek(position, System.IO.SeekOrigin.Begin);
881 file.position = position;
883 int total = 0;
886 int i = file.Read(b, offset + total, len - total);
887 if (i <= 0)
888 throw new System.IO.IOException("read past EOF");
889 file.position += i;
890 total += i;
892 while (total < len);
896 public override void Close()
898 if (!isClone && file != null)
899 file.Close();
900 System.GC.SuppressFinalize(this);
903 public override void SeekInternal(long position)
907 public override long Length()
909 return length;
912 ~FSIndexInput()
914 Close(); // close the file
917 public override System.Object Clone()
919 FSIndexInput clone = (FSIndexInput) base.Clone();
920 clone.isClone = true;
921 return clone;
924 /// <summary>Method used for testing. Returns true if the underlying
925 /// file descriptor is valid.
926 /// </summary>
927 public /*internal*/ virtual bool IsFDValid()
929 if (file.BaseStream == null)
930 return false;
931 return file.BaseStream.CanRead;
936 class FSIndexOutput : BufferedIndexOutput
938 internal System.IO.BinaryWriter file = null;
940 public FSIndexOutput(System.IO.FileInfo path)
942 file = new System.IO.BinaryWriter(new System.IO.FileStream(path.FullName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite));
945 /// <summary>output methods: </summary>
946 public override void FlushBuffer(byte[] b, int size)
948 file.Write(b, 0, size);
950 public override void Close()
952 base.Close();
953 file.Close();
954 System.GC.SuppressFinalize(this);
957 /// <summary>Random-access methods </summary>
958 public override void Seek(long pos)
960 base.Seek(pos);
961 file.BaseStream.Seek(pos, System.IO.SeekOrigin.Begin);
963 public override long Length()
965 return file.BaseStream.Length;
968 ~FSIndexOutput()
970 file.Close(); // close the file