2006-09-10 Francisco Javier F. Serrador <serrador@openshine.com>
[beagle.git] / beagled / Lucene.Net / Store / FSDirectory.cs
blob1cc421ef0b42a4a6b50c841d757c32d6b8e6a974
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.
16 using System;
17 using Mono.Unix.Native;
18 using Constants = Lucene.Net.Util.Constants;
19 namespace Lucene.Net.Store
22 /// <summary> Straightforward implementation of {@link Directory} as a directory of files.
23 /// <p>If the system property 'disableLuceneLocks' has the String value of
24 /// "true", lock creation will be disabled.
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.DISABLE_LOCKS || Enclosing_Instance.DisableLocks)
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 ();
125 Log ("Obtained lock " + lockFile.FullName);
126 return true;
128 catch (Exception e)
130 Log ("Exception in CreateNew for file:" + lockFile.FullName + ":" + e);
131 return false;
134 public override void Release()
136 if (Lucene.Net.Store.FSDirectory.DISABLE_LOCKS || Enclosing_Instance.DisableLocks)
137 return ;
138 bool tmpBool;
139 if (System.IO.File.Exists(lockFile.FullName))
141 System.IO.File.Delete(lockFile.FullName);
142 tmpBool = true;
144 else if (System.IO.Directory.Exists(lockFile.FullName))
146 System.IO.Directory.Delete(lockFile.FullName);
147 tmpBool = true;
149 else
150 tmpBool = false;
151 if (System.IO.File.Exists(lockFile.FullName)) {
152 Log ("Release didnt delete lockfile {0}.", lockFile.FullName);
153 tmpBool = false;
155 bool generatedAux = tmpBool;
156 if (tmpBool)
157 Log ("Released lock {0}", lockFile.FullName);
158 else
159 Log ("Failed to release lock {0}", lockFile.FullName);
161 public override bool IsLocked()
163 if (Lucene.Net.Store.FSDirectory.DISABLE_LOCKS || Enclosing_Instance.DisableLocks)
164 return false;
165 bool tmpBool;
166 if (System.IO.File.Exists(lockFile.FullName))
167 tmpBool = true;
168 else
169 tmpBool = System.IO.Directory.Exists(lockFile.FullName);
170 return tmpBool;
173 public override System.String ToString()
175 return lockFile.FullName;
178 /// <summary>This cache of directories ensures that there is a unique Directory
179 /// instance per path, so that synchronization on the Directory can be used to
180 /// synchronize access between readers and writers.
181 ///
182 /// This should be a WeakHashMap, so that entries can be GC'd, but that would
183 /// require Java 1.2. Instead we use refcounts...
184 /// </summary>
185 private static readonly System.Collections.Hashtable DIRECTORIES = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
187 private static readonly bool DISABLE_LOCKS;
189 /// <summary> Directory specified by <code>Lucene.Net.lockdir</code>
190 /// or <code>java.io.tmpdir</code> system property
191 /// </summary>
192 public static readonly System.String LOCK_DIR = SupportClass.AppSettings.Get("Lucene.Net.lockdir", System.IO.Path.GetTempPath());
194 /// <summary>The default class which implements filesystem-based directories. </summary>
195 private static System.Type IMPL;
197 private static System.Security.Cryptography.MD5 DIGESTER;
199 private bool disable_locks = false;
200 public bool DisableLocks {
201 get { return disable_locks; }
202 set { disable_locks = value; }
205 /// <summary>A buffer optionally used in renameTo method </summary>
206 private byte[] buffer = null;
208 /// <summary>Returns the directory instance for the named location.
209 ///
210 /// <p>Directories are cached, so that, for a given canonical path, the same
211 /// FSDirectory instance will always be returned. This permits
212 /// synchronization on directories.
213 ///
214 /// </summary>
215 /// <param name="path">the path to the directory.
216 /// </param>
217 /// <param name="create">if true, create, or erase any existing contents.
218 /// </param>
219 /// <returns> the FSDirectory for the named file.
220 /// </returns>
221 public static FSDirectory GetDirectory(System.String path, bool create)
223 return GetDirectory(new System.IO.FileInfo(path), null, create, false);
226 /// <summary>Returns the directory instance for the named location.
227 ///
228 /// <p>Directories are cached, so that, for a given canonical path, the same
229 /// FSDirectory instance will always be returned. This permits
230 /// synchronization on directories.
231 ///
232 /// </summary>
233 /// <param name="file">the path to the directory.
234 /// </param>
235 /// <param name="create">if true, create, or erase any existing contents.
236 /// </param>
237 /// <returns> the FSDirectory for the named file.
238 /// </returns>
239 public static FSDirectory GetDirectory(System.IO.FileInfo file, bool create)
241 return GetDirectory(file, null, create, false);
244 /// <summary>Returns the directory instance for the named location.
245 ///
246 /// <p>Directories are cached, so that, for a given canonical path, the same
247 /// FSDirectory instance will always be returned. This permits
248 /// synchronization on directories.
249 ///
250 /// </summary>
251 /// <param name="path">the path to the directory.
252 /// </param>
253 /// <param name="tmpDir">the path to use as lock directory.
254 /// </param>
255 /// <param name="create">if true, create, or erase any existing contents.
256 /// </param>
257 /// <returns> the FSDirectory for the named file.
258 /// </returns>
259 public static FSDirectory GetDirectory(System.String path, System.String tmpDir, bool create)
261 return GetDirectory(new System.IO.FileInfo(path), tmpDir, create, false);
264 /// <summary>Returns the directory instance for the named location.
265 ///
266 /// <p>Directories are cached, so that, for a given canonical path, the same
267 /// FSDirectory instance will always be returned. This permits
268 /// synchronization on directories.
269 ///
270 /// </summary>
271 /// <param name="path">the path to the directory.
272 /// </param>
273 /// <param name="tmpDir">the path to use as lock directory.
274 /// </param>
275 /// <param name="create">if true, create, or erase any existing contents.
276 /// </param>
277 /// <param name="disable_locks">if true, disable internal locking
278 /// </param>
279 /// <returns> the FSDirectory for the named file.
280 /// </returns>
281 public static FSDirectory GetDirectory(System.String path, System.String tmpDir, bool create, bool disable_locks)
283 return GetDirectory(new System.IO.FileInfo(path), tmpDir, create, disable_locks);
286 /// <summary>Returns the directory instance for the named location.
287 ///
288 /// <p>Directories are cached, so that, for a given canonical path, the same
289 /// FSDirectory instance will always be returned. This permits
290 /// synchronization on directories.
291 ///
292 /// </summary>
293 /// <param name="file">the path to the directory.
294 /// </param>
295 /// <param name="tmpDir">the path to use as lock directory.
296 /// </param>
297 /// <param name="create">if true, create, or erase any existing contents.
298 /// </param>
299 /// <param name="disable_locks">if true, disable internal locking
300 /// </param>
301 /// <returns> the FSDirectory for the named file.
302 /// </returns>
303 public static FSDirectory GetDirectory(System.IO.FileInfo file, System.String tmpdir, bool create, bool disable_locks)
305 file = new System.IO.FileInfo(file.FullName);
306 FSDirectory dir;
307 lock (DIRECTORIES.SyncRoot)
309 dir = (FSDirectory) DIRECTORIES[file];
310 if (dir == null)
314 dir = (FSDirectory) System.Activator.CreateInstance(IMPL);
316 catch (System.Exception e)
318 throw new System.SystemException("cannot load FSDirectory class: " + e.ToString());
320 dir.Init(file, tmpdir, create, disable_locks);
321 DIRECTORIES[file] = dir;
323 else if (create)
325 dir.Create();
328 lock (dir)
330 dir.refCount++;
332 return dir;
335 private System.IO.FileInfo directory = null;
336 private int refCount;
337 private System.IO.FileInfo lockDir;
339 public FSDirectory()
343 // permit subclassing
345 private void Init(System.IO.FileInfo path, System.String tmpDir, bool create, bool disable_locks)
347 directory = path;
348 this.disable_locks = disable_locks;
350 if (tmpDir != null)
352 lockDir = new System.IO.FileInfo(tmpDir);
354 else if (LOCK_DIR == null)
356 lockDir = directory;
358 else
360 lockDir = new System.IO.FileInfo(LOCK_DIR);
362 if (create)
364 Create();
367 if (!System.IO.Directory.Exists(directory.FullName))
368 throw new System.IO.IOException(path + " not a directory");
371 private void Create()
373 lock (this)
375 bool tmpBool;
376 if (System.IO.File.Exists(directory.FullName))
377 tmpBool = true;
378 else
379 tmpBool = System.IO.Directory.Exists(directory.FullName);
380 if (!tmpBool)
384 System.IO.Directory.CreateDirectory(directory.FullName);
386 catch (Exception)
388 throw new System.IO.IOException("Cannot create directory: " + directory);
392 System.String[] files = System.IO.Directory.GetFileSystemEntries(directory.FullName); // clear old files
393 for (int i = 0; i < files.Length; i++)
395 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, files[i]));
396 bool tmpBool2;
397 if (System.IO.File.Exists(file.FullName))
399 System.IO.File.Delete(file.FullName);
400 tmpBool2 = true;
402 else if (System.IO.Directory.Exists(file.FullName))
404 System.IO.Directory.Delete(file.FullName);
405 tmpBool2 = true;
407 else
408 tmpBool2 = false;
409 if (!tmpBool2)
410 throw new System.IO.IOException("Cannot delete " + files[i]);
413 System.String lockPrefix = GetLockPrefix().ToString(); // clear old locks
414 files = System.IO.Directory.GetFileSystemEntries(lockDir.FullName);
415 for (int i = 0; i < files.Length; i++)
417 if (!files[i].StartsWith(lockPrefix))
418 continue;
419 System.IO.FileInfo lockFile = new System.IO.FileInfo(System.IO.Path.Combine(lockDir.FullName, files[i]));
420 bool tmpBool3;
421 if (System.IO.File.Exists(lockFile.FullName))
423 System.IO.File.Delete(lockFile.FullName);
424 tmpBool3 = true;
426 else if (System.IO.Directory.Exists(lockFile.FullName))
428 System.IO.Directory.Delete(lockFile.FullName);
429 tmpBool3 = true;
431 else
432 tmpBool3 = false;
433 if (!tmpBool3)
434 throw new System.IO.IOException("Cannot delete " + files[i]);
439 /// <summary>Returns an array of strings, one for each file in the directory. </summary>
440 public override System.String[] List()
442 return System.IO.Directory.GetFileSystemEntries(directory.FullName);
445 /// <summary>Returns true iff a file with the given name exists. </summary>
446 public override bool FileExists(System.String name)
448 string path = System.IO.Path.Combine (directory.FullName, name);
450 return System.IO.File.Exists (path) || System.IO.Directory.Exists (path);
453 /// <summary>Returns the time the named file was last modified. </summary>
454 public override long FileModified(System.String name)
456 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
457 return (file.LastWriteTimeUtc.Ticks);
460 /// <summary>Returns the time the named file was last modified. </summary>
461 public static long FileModified(System.IO.FileInfo directory, System.String name)
463 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
464 return (file.LastWriteTimeUtc.Ticks);
467 /// <summary>Set the modified time of an existing file to now. </summary>
468 public override void TouchFile(System.String name)
470 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
471 file.LastWriteTime = System.DateTime.UtcNow;
474 /// <summary>Returns the length in bytes of a file in the directory. </summary>
475 public override long FileLength(System.String name)
477 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
478 return file.Exists ? file.Length : 0;
481 /// <summary>Removes an existing file in the directory. </summary>
482 public override void DeleteFile(System.String name)
484 System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name));
485 bool tmpBool;
486 if (System.IO.File.Exists(file.FullName))
488 System.IO.File.Delete(file.FullName);
489 tmpBool = true;
491 else if (System.IO.Directory.Exists(file.FullName))
493 System.IO.Directory.Delete(file.FullName);
494 tmpBool = true;
496 else
497 tmpBool = false;
498 if (!tmpBool)
499 throw new System.IO.IOException("Cannot delete " + name);
502 /// <summary>Renames an existing file in the directory. </summary>
503 public override void RenameFile(System.String from, System.String to)
505 lock (this)
507 System.IO.FileInfo old = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, from));
508 System.IO.FileInfo nu = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, to));
510 /* This is not atomic. If the program crashes between the call to
511 delete() and the call to renameTo() then we're screwed, but I've
512 been unable to figure out how else to do this... */
514 bool tmpBool;
515 if (System.IO.File.Exists(nu.FullName))
516 tmpBool = true;
517 else
518 tmpBool = System.IO.Directory.Exists(nu.FullName);
519 if (tmpBool)
521 bool tmpBool2;
522 if (System.IO.File.Exists(nu.FullName))
524 System.IO.File.Delete(nu.FullName);
525 tmpBool2 = true;
527 else if (System.IO.Directory.Exists(nu.FullName))
529 System.IO.Directory.Delete(nu.FullName);
530 tmpBool2 = true;
532 else
533 tmpBool2 = false;
534 if (!tmpBool2)
535 throw new System.IO.IOException("Cannot delete " + to);
538 // Rename the old file to the new one. Unfortunately, the renameTo()
539 // method does not work reliably under some JVMs. Therefore, if the
540 // rename fails, we manually rename by copying the old file to the new one
543 old.MoveTo(nu.FullName);
545 catch (System.Exception ex)
547 System.IO.BinaryReader in_Renamed = null;
548 System.IO.Stream out_Renamed = null;
551 in_Renamed = new System.IO.BinaryReader(System.IO.File.Open(old.FullName, System.IO.FileMode.Open, System.IO.FileAccess.Read));
552 out_Renamed = new System.IO.FileStream(nu.FullName, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite);
553 // see if the buffer needs to be initialized. Initialization is
554 // only done on-demand since many VM's will never run into the renameTo
555 // bug and hence shouldn't waste 1K of mem for no reason.
556 if (buffer == null)
558 buffer = new byte[1024];
560 int len;
561 len = in_Renamed.Read(buffer, 0, buffer.Length);
562 out_Renamed.Write(buffer, 0, len);
564 // delete the old file.
565 bool tmpBool3;
566 if (System.IO.File.Exists(old.FullName))
568 System.IO.File.Delete(old.FullName);
569 tmpBool3 = true;
571 else if (System.IO.Directory.Exists(old.FullName))
573 System.IO.Directory.Delete(old.FullName);
574 tmpBool3 = true;
576 else
577 tmpBool3 = false;
578 bool generatedAux = tmpBool3;
580 catch (System.IO.IOException e)
582 throw new System.IO.IOException("Cannot rename " + from + " to " + to);
584 finally
586 if (in_Renamed != null)
590 in_Renamed.Close();
592 catch (System.IO.IOException e)
594 throw new System.SystemException("Cannot close input stream: " + e.ToString());
597 if (out_Renamed != null)
601 out_Renamed.Close();
603 catch (System.IO.IOException e)
605 throw new System.SystemException("Cannot close output stream: " + e.ToString());
613 /// <summary>Creates a new, empty file in the directory with the given name.
614 /// Returns a stream writing this file.
615 /// </summary>
616 public override IndexOutput CreateOutput(System.String name)
618 return new FSIndexOutput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)));
621 /// <summary>Returns a stream reading an existing file. </summary>
622 public override IndexInput OpenInput(System.String name)
624 return new FSIndexInput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)));
627 static public Beagle.Util.Logger Logger = null;
628 //static public Beagle.Util.Logger Logger = Beagle.Util.Logger.Log;
629 static public void Log (string format, params object[] args)
631 if (Logger != null)
632 Logger.Debug (format, args);
635 static public void Log (Exception e)
637 if (Logger != null)
638 Logger.Debug (e);
641 /// <summary> So we can do some byte-to-hexchar conversion below</summary>
642 private static readonly char[] HEX_DIGITS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
644 /// <summary>Constructs a {@link Lock} with the specified name. Locks are implemented
645 /// with {@link File#createNewFile() }.
646 ///
647 /// <p>In JDK 1.1 or if system property <I>disableLuceneLocks</I> is the
648 /// string "true", locks are disabled. Assigning this property any other
649 /// string will <B>not</B> prevent creation of lock files. This is useful for
650 /// using Lucene on read-only medium, such as CD-ROM.
651 ///
652 /// </summary>
653 /// <param name="name">the name of the lock file
654 /// </param>
655 /// <returns> an instance of <code>Lock</code> holding the lock
656 /// </returns>
657 public override Lock MakeLock(System.String name)
659 System.Text.StringBuilder buf = GetLockPrefix();
660 buf.Append("-");
661 buf.Append(name);
663 // create a lock file
664 System.IO.FileInfo lockFile = new System.IO.FileInfo(System.IO.Path.Combine(lockDir.FullName, buf.ToString()));
666 return new AnonymousClassLock(lockFile, this);
669 private System.Text.StringBuilder GetLockPrefix()
671 System.String dirName; // name to be hashed
674 dirName = directory.FullName;
676 catch (System.IO.IOException e)
678 throw new System.SystemException(e.ToString());
681 byte[] digest;
682 lock (DIGESTER)
684 digest = DIGESTER.ComputeHash(System.Text.Encoding.UTF8.GetBytes(dirName));
686 System.Text.StringBuilder buf = new System.Text.StringBuilder();
687 buf.Append("lucene-");
688 for (int i = 0; i < digest.Length; i++)
690 int b = digest[i];
691 buf.Append(HEX_DIGITS[(b >> 4) & 0xf]);
692 buf.Append(HEX_DIGITS[b & 0xf]);
695 return buf;
698 /// <summary>Closes the store to future operations. </summary>
699 public override void Close()
701 lock (this)
703 if (--refCount <= 0)
705 lock (DIRECTORIES.SyncRoot)
707 DIRECTORIES.Remove(directory);
713 public virtual System.IO.FileInfo GetFile()
715 return directory;
718 /// <summary>For debug output. </summary>
719 public override System.String ToString()
721 return this.GetType().FullName + "@" + directory;
723 static FSDirectory()
725 DISABLE_LOCKS = System.Configuration.ConfigurationSettings.AppSettings.Get("disableLuceneLocks") != null;
729 System.String name = SupportClass.AppSettings.Get("Lucene.Net.FSDirectory.class", typeof(FSDirectory).FullName);
730 IMPL = System.Type.GetType(name);
732 catch (System.Exception e)
734 throw new System.SystemException("cannot load FSDirectory class: " + e.ToString());
740 DIGESTER = System.Security.Cryptography.MD5.Create();
742 catch (System.Exception e)
744 throw new System.SystemException(e.ToString());
751 public class FSIndexInput : BufferedIndexInput, System.ICloneable
753 private class Descriptor : System.IO.BinaryReader
755 private void InitBlock(FSIndexInput enclosingInstance)
757 this.enclosingInstance = enclosingInstance;
759 private FSIndexInput enclosingInstance;
760 public FSIndexInput Enclosing_Instance
764 return enclosingInstance;
768 public long position;
769 // {{Aroush-1.4.3 is this right?
770 public Descriptor(FSIndexInput enclosingInstance, System.IO.FileInfo file, System.IO.FileAccess fileAccess)
771 : base(new System.IO.FileStream(file.FullName, System.IO.FileMode.Open, fileAccess, System.IO.FileShare.ReadWrite))
773 InitBlock(enclosingInstance);
775 // Aroush-1.4.3}}
777 /* DEBUG */
778 //public void close() throws IOException {
779 // debug_printInfo("CLOSE");
780 // super.close();
783 //private void debug_printInfo(String op) {
784 // try { throw new Exception(op + " <" + name + ">");
785 // } catch (Exception e) {
786 // java.io.StringWriter sw = new java.io.StringWriter();
787 // java.io.PrintWriter pw = new java.io.PrintWriter(sw);
788 // e.printStackTrace(pw);
789 // System.out.println(sw.getBuffer().ToString());
790 // }
792 /* DEBUG */
795 private Descriptor file = null;
796 internal bool isClone;
797 private long length;
799 public FSIndexInput(System.IO.FileInfo path)
801 file = new Descriptor(this, path, System.IO.FileAccess.Read);
802 length = file.BaseStream.Length;
805 /// <summary>InputStream methods </summary>
806 public override void ReadInternal(byte[] b, int offset, int len)
808 lock (file)
810 long position = GetFilePointer();
811 if (position != file.position)
813 file.BaseStream.Seek(position, System.IO.SeekOrigin.Begin);
814 file.position = position;
816 int total = 0;
819 int i = file.Read(b, offset + total, len - total);
820 if (i <= 0)
821 throw new System.IO.IOException("read past EOF");
822 file.position += i;
823 total += i;
825 while (total < len);
829 public override void Close()
831 if (!isClone && file != null)
832 file.Close();
833 System.GC.SuppressFinalize(this);
836 /// <summary>Random-access methods </summary>
837 public override void SeekInternal(long position)
841 public override long Length()
843 return length;
846 ~FSIndexInput()
848 Close(); // close the file
851 public override System.Object Clone()
853 FSIndexInput clone = (FSIndexInput) base.Clone();
854 clone.isClone = true;
855 return clone;
858 /// <summary>Method used for testing. Returns true if the underlying
859 /// file descriptor is valid.
860 /// </summary>
861 public /*internal*/ virtual bool IsFDValid()
863 return file.BaseStream.CanRead;
868 class FSIndexOutput : BufferedIndexOutput
870 internal System.IO.BinaryWriter file = null;
872 public FSIndexOutput(System.IO.FileInfo path)
874 file = new System.IO.BinaryWriter(new System.IO.FileStream(path.FullName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite));
877 /// <summary>output methods: </summary>
878 public override void FlushBuffer(byte[] b, int size)
880 file.Write(b, 0, size);
882 public override void Close()
884 base.Close();
885 file.Close();
886 System.GC.SuppressFinalize(this);
889 /// <summary>Random-access methods </summary>
890 public override void Seek(long pos)
892 base.Seek(pos);
893 file.BaseStream.Seek(pos, System.IO.SeekOrigin.Begin);
895 public override long Length()
897 return file.BaseStream.Length;
900 ~FSIndexOutput()
902 file.Close(); // close the file