You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ar...@apache.org on 2008/06/25 04:50:13 UTC

svn commit: r671401 [1/2] - /incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/

Author: aroush
Date: Tue Jun 24 19:50:12 2008
New Revision: 671401

URL: http://svn.apache.org/viewvc?rev=671401&view=rev
Log:
Release: Apache Lucene.Net.2.3.1 build 001 "Alpha"

Added:
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/AlreadyClosedException.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockObtainFailedException.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockReleaseFailedException.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockStressTest.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockVerifyServer.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/VerifyingLockFactory.cs
Modified:
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexInput.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexOutput.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Directory.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/FSDirectory.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexInput.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexOutput.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Lock.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockFactory.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/MMapDirectory.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/NativeFSLockFactory.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Package.html
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMDirectory.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMFile.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMInputStream.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMOutputStream.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SimpleFSLockFactory.cs
    incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SingleInstanceLockFactory.cs

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/AlreadyClosedException.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/AlreadyClosedException.cs?rev=671401&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/AlreadyClosedException.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/AlreadyClosedException.cs Tue Jun 24 19:50:12 2008
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Lucene.Net.Store
+{
+	
+	/// <summary> This exception is thrown when there is an attempt to
+	/// access something that has already been closed.
+	/// </summary>
+	[Serializable]
+	public class AlreadyClosedException : System.SystemException
+	{
+		public AlreadyClosedException(System.String message) : base(message)
+		{
+		}
+	}
+}
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexInput.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/BufferedIndexInput.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexInput.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexInput.cs Tue Jun 24 19:50:12 2008
@@ -23,18 +23,17 @@
 	/// <summary>Base implementation class for buffered {@link IndexInput}. </summary>
 	public abstract class BufferedIndexInput : IndexInput, System.ICloneable
 	{
-		internal static readonly int BUFFER_SIZE;
+		
+		/// <summary>Default buffer size </summary>
+		public const int BUFFER_SIZE = 1024;
+		
+		private int bufferSize = BUFFER_SIZE;
 		
 		private byte[] buffer;
 		
 		private long bufferStart = 0; // position in file of buffer
 		private int bufferLength = 0; // end of valid bytes
 		private int bufferPosition = 0; // next byte to read
-
-        public static int BUFFER_SIZE_ForNUnitTest
-        {
-            get { return BUFFER_SIZE; }
-        }
 		
 		public override byte ReadByte()
 		{
@@ -43,11 +42,70 @@
 			return buffer[bufferPosition++];
 		}
 		
+		public BufferedIndexInput()
+		{
+		}
+		
+		/// <summary>Inits BufferedIndexInput with a specific bufferSize </summary>
+		public BufferedIndexInput(int bufferSize)
+		{
+			CheckBufferSize(bufferSize);
+			this.bufferSize = bufferSize;
+		}
+		
+		/// <summary>Change the buffer size used by this IndexInput </summary>
+		public virtual void  SetBufferSize(int newSize)
+		{
+			System.Diagnostics.Debug.Assert(buffer == null || bufferSize == buffer.Length);
+			if (newSize != bufferSize)
+			{
+				CheckBufferSize(newSize);
+				bufferSize = newSize;
+				if (buffer != null)
+				{
+					// Resize the existing buffer and carefully save as
+					// many bytes as possible starting from the current
+					// bufferPosition
+					byte[] newBuffer = new byte[newSize];
+					int leftInBuffer = bufferLength - bufferPosition;
+					int numToCopy;
+					if (leftInBuffer > newSize)
+						numToCopy = newSize;
+					else
+						numToCopy = leftInBuffer;
+					Array.Copy(buffer, bufferPosition, newBuffer, 0, numToCopy);
+					bufferStart += bufferPosition;
+					bufferPosition = 0;
+					bufferLength = numToCopy;
+					buffer = newBuffer;
+				}
+			}
+		}
+		
+		/// <seealso cref="setBufferSize">
+		/// </seealso>
+		public virtual int GetBufferSize()
+		{
+			return bufferSize;
+		}
+		
+		private void  CheckBufferSize(int bufferSize)
+		{
+			if (bufferSize <= 0)
+				throw new System.ArgumentException("bufferSize must be greater than 0 (got " + bufferSize + ")");
+		}
+		
 		public override void  ReadBytes(byte[] b, int offset, int len)
 		{
+			ReadBytes(b, offset, len, true);
+		}
+		
+		public override void  ReadBytes(byte[] b, int offset, int len, bool useBuffer)
+		{
+			
 			if (len <= (bufferLength - bufferPosition))
 			{
-				// the buffer contains enough data to satistfy this request
+				// the buffer contains enough data to satisfy this request
 				if (len > 0)
 				// to allow b to be null if len is 0...
 					Array.Copy(buffer, bufferPosition, b, offset, len);
@@ -65,9 +123,10 @@
 					bufferPosition += available;
 				}
 				// and now, read the remaining 'len' bytes:
-				if (len < BUFFER_SIZE)
+				if (useBuffer && len < bufferSize)
 				{
-					// If the amount left to read is small enough, do it in the usual
+					// If the amount left to read is small enough, and
+					// we are allowed to use our buffer, do it in the usual
 					// buffered way: fill the buffer and copy from it:
 					Refill();
 					if (bufferLength < len)
@@ -84,10 +143,13 @@
 				}
 				else
 				{
-					// The amount left to read is larger than the buffer - there's no
-					// performance reason not to read it all at once. Note that unlike
-					// the previous code of this function, there is no need to do a seek
-					// here, because there's no need to reread what we had in the buffer.
+					// The amount left to read is larger than the buffer
+					// or we've been asked to not use our buffer -
+					// there's no performance reason not to read it all
+					// at once. Note that unlike the previous code of
+					// this function, there is no need to do a seek
+					// here, because there's no need to reread what we
+					// had in the buffer.
 					long after = bufferStart + bufferPosition + len;
 					if (after > Length())
 						throw new System.IO.IOException("read past EOF");
@@ -102,16 +164,19 @@
 		private void  Refill()
 		{
 			long start = bufferStart + bufferPosition;
-			long end = start + BUFFER_SIZE;
+			long end = start + bufferSize;
 			if (end > Length())
-				// don't read past EOF
+			// don't read past EOF
 				end = Length();
 			bufferLength = (int) (end - start);
 			if (bufferLength <= 0)
 				throw new System.IO.IOException("read past EOF");
 			
 			if (buffer == null)
-				buffer = new byte[BUFFER_SIZE]; // allocate buffer lazily
+			{
+				buffer = new byte[bufferSize]; // allocate buffer lazily
+				SeekInternal(bufferStart);
+			}
 			ReadInternal(buffer, 0, bufferLength);
 			
 			bufferStart = start;
@@ -127,7 +192,7 @@
 		/// </param>
 		/// <param name="length">the number of bytes to read
 		/// </param>
-		public abstract void  ReadInternal(byte[] b, int offset, int length);
+		protected internal abstract void  ReadInternal(byte[] b, int offset, int length);
 		
 		public override long GetFilePointer()
 		{
@@ -138,7 +203,7 @@
 		{
 			if (pos >= bufferStart && pos < (bufferStart + bufferLength))
 				bufferPosition = (int) (pos - bufferStart);
-				// seek within buffer
+			// seek within buffer
 			else
 			{
 				bufferStart = pos;
@@ -151,26 +216,20 @@
 		/// <summary>Expert: implements seek.  Sets current position in this file, where the
 		/// next {@link #ReadInternal(byte[],int,int)} will occur.
 		/// </summary>
-		/// <seealso cref="#ReadInternal(byte[],int,int)">
+		/// <seealso cref="ReadInternal(byte[],int,int)">
 		/// </seealso>
-		public abstract void  SeekInternal(long pos);
+		protected internal abstract void  SeekInternal(long pos);
 		
 		public override System.Object Clone()
 		{
 			BufferedIndexInput clone = (BufferedIndexInput) base.Clone();
 			
-			if (buffer != null)
-			{
-				clone.buffer = new byte[BUFFER_SIZE];
-				Array.Copy(buffer, 0, clone.buffer, 0, bufferLength);
-			}
+			clone.buffer = null;
+			clone.bufferLength = 0;
+			clone.bufferPosition = 0;
+			clone.bufferStart = GetFilePointer();
 			
 			return clone;
 		}
-
-		static BufferedIndexInput()
-		{
-			BUFFER_SIZE = BufferedIndexOutput.BUFFER_SIZE;
-		}
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexOutput.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/BufferedIndexOutput.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexOutput.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/BufferedIndexOutput.cs Tue Jun 24 19:50:12 2008
@@ -23,7 +23,7 @@
 	/// <summary>Base implementation class for buffered {@link IndexOutput}. </summary>
 	public abstract class BufferedIndexOutput : IndexOutput
 	{
-		internal const int BUFFER_SIZE = 1024;
+		internal const int BUFFER_SIZE = 16384;
 		
 		private byte[] buffer = new byte[BUFFER_SIZE];
 		private long bufferStart = 0; // position in file of buffer
@@ -46,14 +46,14 @@
 		/// </param>
 		/// <seealso cref="IndexInput.ReadBytes(byte[],int,int)">
 		/// </seealso>
-		public override void  WriteBytes(byte[] b, int length)
+		public override void  WriteBytes(byte[] b, int offset, int length)
 		{
 			int bytesLeft = BUFFER_SIZE - bufferPosition;
 			// is there enough space in the buffer?
 			if (bytesLeft >= length)
 			{
 				// we add the data to the end of the buffer
-				Array.Copy(b, 0, buffer, bufferPosition, length);
+				Array.Copy(b, offset, buffer, bufferPosition, length);
 				bufferPosition += length;
 				// if the buffer is full, flush it
 				if (BUFFER_SIZE - bufferPosition == 0)
@@ -68,7 +68,7 @@
 					if (bufferPosition > 0)
 						Flush();
 					// and write data at once
-					FlushBuffer(b, length);
+					FlushBuffer(b, offset, length);
 					bufferStart += length;
 				}
 				else
@@ -79,7 +79,7 @@
 					while (pos < length)
 					{
 						pieceLength = (length - pos < bytesLeft)?length - pos:bytesLeft;
-						Array.Copy(b, pos, buffer, bufferPosition, pieceLength);
+						Array.Copy(b, pos + offset, buffer, bufferPosition, pieceLength);
 						pos += pieceLength;
 						bufferPosition += pieceLength;
 						// if the buffer is full, flush it
@@ -109,7 +109,21 @@
 		/// </param>
 		/// <param name="len">the number of bytes to write
 		/// </param>
-		public abstract void  FlushBuffer(byte[] b, int len);
+		private void  FlushBuffer(byte[] b, int len)
+		{
+			FlushBuffer(b, 0, len);
+		}
+		
+		/// <summary>Expert: implements buffer write.  Writes bytes at the current position in
+		/// the output.
+		/// </summary>
+		/// <param name="b">the bytes to write
+		/// </param>
+		/// <param name="offset">the offset in the byte array
+		/// </param>
+		/// <param name="len">the number of bytes to write
+		/// </param>
+		public abstract void  FlushBuffer(byte[] b, int offset, int len);
 		
 		/// <summary>Closes this stream to further operations. </summary>
 		public override void  Close()
@@ -120,7 +134,7 @@
 		/// <summary>Returns the current position in this file, where the next write will
 		/// occur.
 		/// </summary>
-		/// <seealso cref="#Seek(long)">
+		/// <seealso cref="Seek(long)">
 		/// </seealso>
 		public override long GetFilePointer()
 		{
@@ -128,7 +142,7 @@
 		}
 		
 		/// <summary>Sets current position in this file, where the next write will occur.</summary>
-		/// <seealso cref="#GetFilePointer()">
+		/// <seealso cref="GetFilePointer()">
 		/// </seealso>
 		public override void  Seek(long pos)
 		{

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Directory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/Directory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Directory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Directory.cs Tue Jun 24 19:50:12 2008
@@ -48,7 +48,12 @@
 		[NonSerialized]
 		protected internal LockFactory lockFactory;
 		
-		/// <summary>Returns an array of strings, one for each file in the directory. </summary>
+		/// <summary>Returns an array of strings, one for each file in the
+		/// directory.  This method may return null (for example for
+		/// {@link FSDirectory} if the underlying directory doesn't
+		/// exist in the filesystem or there are permissions
+		/// problems).
+		/// </summary>
 		public abstract System.String[] List();
 		
 		/// <summary>Returns true iff a file with the given name exists. </summary>
@@ -84,6 +89,18 @@
 		/// <summary>Returns a stream reading an existing file. </summary>
 		public abstract IndexInput OpenInput(System.String name);
 		
+		/// <summary>Returns a stream reading an existing file, with the
+		/// specified read buffer size.  The particular Directory
+		/// implementation may ignore the buffer size.  Currently
+		/// the only Directory implementations that respect this
+		/// parameter are {@link FSDirectory} and {@link
+		/// Lucene.Net.Index.CompoundFileReader}.
+		/// </summary>
+		public virtual IndexInput OpenInput(System.String name, int bufferSize)
+		{
+			return OpenInput(name);
+		}
+		
 		/// <summary>Construct a {@link Lock}.</summary>
 		/// <param name="name">the name of the lock file
 		/// </param>
@@ -95,7 +112,7 @@
 		/// specified lock.  Only call this at a time when you are
 		/// certain this lock is no longer in use.
 		/// </summary>
-		/// <param name="lockName">name of the lock to be cleared.
+		/// <param name="name">name of the lock to be cleared.
 		/// </param>
 		public virtual void  ClearLock(System.String name)
 		{
@@ -160,6 +177,12 @@
 		public static void  Copy(Directory src, Directory dest, bool closeDirSrc)
 		{
 			System.String[] files = src.List();
+
+			if (files == null)
+			{
+				throw new System.IO.IOException("cannot read directory " + src + ": list() returned null");
+			}
+
 			byte[] buf = new byte[BufferedIndexOutput.BUFFER_SIZE];
 			for (int i = 0; i < files.Length; i++)
 			{
@@ -176,7 +199,7 @@
 					long readCount = 0;
 					while (readCount < len)
 					{
-						int toRead = readCount + BufferedIndexOutput.BUFFER_SIZE > len?(int) (len - readCount):BufferedIndexOutput.BUFFER_SIZE;
+						int toRead = readCount + BufferedIndexOutput.BUFFER_SIZE > len ? (int) (len - readCount) : BufferedIndexOutput.BUFFER_SIZE;
 						is_Renamed.ReadBytes(buf, 0, toRead);
 						os.WriteBytes(buf, toRead);
 						readCount += toRead;

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/FSDirectory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/FSDirectory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/FSDirectory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/FSDirectory.cs Tue Jun 24 19:50:12 2008
@@ -260,7 +260,7 @@
 			{
                 System.String[] files = SupportClass.FileSupport.GetLuceneIndexFiles(directory.FullName, IndexFileNameFilter.GetFilter());
 				if (files == null)
-					throw new System.IO.IOException("Cannot read directory " + directory.FullName);
+					throw new System.IO.IOException("cannot read directory " + directory.FullName + ": list() returned null");
 				for (int i = 0; i < files.Length; i++)
 				{
 					System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, files[i]));
@@ -605,12 +605,18 @@
 			return new FSIndexOutput(file);
 		}
 		
-		/// <summary>Returns a stream reading an existing file. </summary>
+		// Inherit javadoc
 		public override IndexInput OpenInput(System.String name)
 		{
 			return new FSIndexInput(new System.IO.FileInfo(System.IO.Path.Combine(directory.FullName, name)));
 		}
 		
+		// Inherit javadoc
+		public override IndexInput OpenInput(System.String name, int bufferSize)
+		{
+			return new FSIndexInput(new System.IO.FileInfo(directory.FullName + "\\" + name), bufferSize);
+		}
+		
 		/// <summary> So we can do some byte-to-hexchar conversion below</summary>
 		private static readonly char[] HEX_DIGITS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
 		
@@ -669,194 +675,196 @@
 		{
 			return this.GetType().FullName + "@" + directory;
 		}
-
-		static FSDirectory()
+		
+		protected internal class FSIndexInput : BufferedIndexInput, System.ICloneable
 		{
+		
+			private class Descriptor : System.IO.BinaryReader
 			{
-				try
+				// remember if the file is open, so that we don't try to close it
+				// more than once
+				private bool isOpen;
+				internal long position;
+				internal long length;
+			
+	            public Descriptor(FSIndexInput enclosingInstance, System.IO.FileInfo file, System.IO.FileAccess mode) 
+	                : base(new System.IO.FileStream(file.FullName, System.IO.FileMode.Open, mode, System.IO.FileShare.ReadWrite))
+	            {
+					isOpen = true;
+	                length = file.Length;
+				}
+			
+				public override void  Close()
 				{
-					System.String name = SupportClass.AppSettings.Get("Lucene.Net.FSDirectory.class", typeof(FSDirectory).FullName);
-					IMPL = System.Type.GetType(name);
+					if (isOpen)
+					{
+						isOpen = false;
+						base.Close();
+					}
 				}
-				catch (System.Security.SecurityException)
+			
+				~Descriptor()
 				{
 					try
 					{
-						IMPL = System.Type.GetType(typeof(FSDirectory).FullName);
+						Close();
 					}
-					catch (System.Exception e)
+					finally
 					{
-						throw new System.SystemException("cannot load default FSDirectory class: " + e.ToString(), e);
 					}
 				}
-                catch (System.Exception e)
-                {
-                    throw new System.SystemException("cannot load FSDirectory class: " + e.ToString(), e);
-                }
-            }
+			}
+		
+			private Descriptor file;
+			internal bool isClone;
+			
+	        public bool isClone_ForNUnitTest
+	        {
+	            get { return isClone; }
+	        }
+			
+			public FSIndexInput(System.IO.FileInfo path) : this(path, BufferedIndexInput.BUFFER_SIZE)
 			{
-				try
-				{
-					DIGESTER = System.Security.Cryptography.MD5.Create();
-				}
-				catch (System.Exception e)
+			}
+			
+			public FSIndexInput(System.IO.FileInfo path, int bufferSize) : base(bufferSize)
+			{
+				file = new Descriptor(this, path, System.IO.FileAccess.Read);
+			}
+		
+			/// <summary>IndexInput methods </summary>
+			protected internal override void  ReadInternal(byte[] b, int offset, int len)
+			{
+				lock (file)
 				{
-					throw new System.SystemException(e.ToString(), e);
+					long position = GetFilePointer();
+					if (position != file.position)
+					{
+						file.BaseStream.Seek(position, System.IO.SeekOrigin.Begin);
+						file.position = position;
+					}
+					int total = 0;
+					do 
+					{
+						int i = file.Read(b, offset + total, len - total);
+						if (i <= 0)
+							throw new System.IO.IOException("read past EOF");
+						file.position += i;
+						total += i;
+					}
+					while (total < len);
 				}
 			}
-		}
-	}
-	
-	
-	public class FSIndexInput : BufferedIndexInput, System.ICloneable
-	{
-		/// <summary>Method used for testing. Returns true if the underlying
-		/// file descriptor is valid.
-		/// </summary>
-		public virtual bool IsFDValid()
-		{
-			return (file.BaseStream != null);
+			
+			public override void  Close()
+			{
+				// only close the file if this is not a clone
+				if (!isClone)
+					file.Close();
+	            System.GC.SuppressFinalize(this);
+			}
+		
+			protected internal override void  SeekInternal(long position)
+			{
+			}
+			
+			public override long Length()
+			{
+				return file.length;
+			}
+			
+			public override System.Object Clone()
+			{
+				FSIndexInput clone = (FSIndexInput) base.Clone();
+				clone.isClone = true;
+				return clone;
+			}
+
+			/// <summary>Method used for testing. Returns true if the underlying
+			/// file descriptor is valid.
+			/// </summary>
+			public virtual bool IsFDValid()
+			{
+				return (file.BaseStream != null);
+			}
 		}
 		
-		private class Descriptor : System.IO.BinaryReader
+		protected internal class FSIndexOutput : BufferedIndexOutput
 		{
+			internal System.IO.BinaryWriter file = null;
+		
 			// remember if the file is open, so that we don't try to close it
 			// more than once
 			private bool isOpen;
-			internal long position;
-			internal long length;
-			
-            public Descriptor(FSIndexInput enclosingInstance, System.IO.FileInfo file, System.IO.FileAccess mode) 
-                : base(new System.IO.FileStream(file.FullName, System.IO.FileMode.Open, mode, System.IO.FileShare.ReadWrite))
-            {
+		
+			public FSIndexOutput(System.IO.FileInfo path)
+			{
+				file = new System.IO.BinaryWriter(new System.IO.FileStream(path.FullName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite));
 				isOpen = true;
-                length = file.Length;
 			}
-			
+		
+			/// <summary>output methods: </summary>
+			public override void  FlushBuffer(byte[] b, int offset, int size)
+			{
+				file.Write(b, offset, size);
+			}
 			public override void  Close()
 			{
+				// only close the file if it has not been closed yet
 				if (isOpen)
 				{
-					isOpen = false;
 					base.Close();
+					file.Close();
+					isOpen = false;
+	                System.GC.SuppressFinalize(this);
 				}
 			}
-			
-			~Descriptor()
+		
+			/// <summary>Random-access methods </summary>
+			public override void  Seek(long pos)
+			{
+				base.Seek(pos);
+				file.BaseStream.Seek(pos, System.IO.SeekOrigin.Begin);
+			}
+			public override long Length()
+			{
+				return file.BaseStream.Length;
+			}
+		}
+		static FSDirectory()
+		{
 			{
 				try
 				{
-					Close();
+					System.String name = SupportClass.AppSettings.Get("Lucene.Net.FSDirectory.class", typeof(FSDirectory).FullName);
+					IMPL = System.Type.GetType(name);
 				}
-				finally
+				catch (System.Security.SecurityException)
 				{
+					try
+					{
+						IMPL = System.Type.GetType(typeof(FSDirectory).FullName);
+					}
+					catch (System.Exception e)
+					{
+						throw new System.SystemException("cannot load default FSDirectory class: " + e.ToString(), e);
+					}
 				}
-			}
-		}
-		
-		private Descriptor file;
-		internal bool isClone;
-		
-        public bool isClone_ForNUnitTest
-        {
-            get { return isClone; }
-        }
-
-		public FSIndexInput(System.IO.FileInfo path)
-		{
-			file = new Descriptor(this, path, System.IO.FileAccess.Read);
-		}
-		
-		/// <summary>IndexInput methods </summary>
-		public override void  ReadInternal(byte[] b, int offset, int len)
-		{
-			lock (file)
+                catch (System.Exception e)
+                {
+                    throw new System.SystemException("cannot load FSDirectory class: " + e.ToString(), e);
+                }
+            }
 			{
-				long position = GetFilePointer();
-				if (position != file.position)
+				try
 				{
-					file.BaseStream.Seek(position, System.IO.SeekOrigin.Begin);
-					file.position = position;
+					DIGESTER = System.Security.Cryptography.MD5.Create();
 				}
-				int total = 0;
-				do 
+				catch (System.Exception e)
 				{
-					int i = file.Read(b, offset + total, len - total);
-					if (i <= 0)
-						throw new System.IO.IOException("read past EOF");
-					file.position += i;
-					total += i;
+					throw new System.SystemException(e.ToString(), e);
 				}
-				while (total < len);
-			}
-		}
-		
-		public override void  Close()
-		{
-			// only close the file if this is not a clone
-			if (!isClone)
-				file.Close();
-            System.GC.SuppressFinalize(this);
-		}
-		
-		public override void  SeekInternal(long position)
-		{
-		}
-		
-		public override long Length()
-		{
-			return file.length;
-		}
-		
-		public override System.Object Clone()
-		{
-			FSIndexInput clone = (FSIndexInput) base.Clone();
-			clone.isClone = true;
-			return clone;
-		}
-	}
-	
-	
-	class FSIndexOutput : BufferedIndexOutput
-	{
-		internal System.IO.BinaryWriter file = null;
-		
-		// remember if the file is open, so that we don't try to close it
-		// more than once
-		private bool isOpen;
-		
-		public FSIndexOutput(System.IO.FileInfo path)
-		{
-			file = new System.IO.BinaryWriter(new System.IO.FileStream(path.FullName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite));
-			isOpen = true;
-		}
-		
-		/// <summary>output methods: </summary>
-		public override void  FlushBuffer(byte[] b, int size)
-		{
-			file.Write(b, 0, size);
-		}
-		public override void  Close()
-		{
-			// only close the file if it has not been closed yet
-			if (isOpen)
-			{
-				base.Close();
-				file.Close();
-				isOpen = false;
-                System.GC.SuppressFinalize(this);
 			}
 		}
-		
-		/// <summary>Random-access methods </summary>
-		public override void  Seek(long pos)
-		{
-			base.Seek(pos);
-			file.BaseStream.Seek(pos, System.IO.SeekOrigin.Begin);
-		}
-		public override long Length()
-		{
-			return file.BaseStream.Length;
-		}
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexInput.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/IndexInput.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexInput.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexInput.cs Tue Jun 24 19:50:12 2008
@@ -45,6 +45,29 @@
 		/// </seealso>
 		public abstract void  ReadBytes(byte[] b, int offset, int len);
 		
+		/// <summary>Reads a specified number of bytes into an array at the
+		/// specified offset with control over whether the read
+		/// should be buffered (callers who have their own buffer
+		/// should pass in "false" for useBuffer).  Currently only
+		/// {@link BufferedIndexInput} respects this parameter.
+		/// </summary>
+		/// <param name="b">the array to read bytes into
+		/// </param>
+		/// <param name="offset">the offset in the array to start storing bytes
+		/// </param>
+		/// <param name="len">the number of bytes to read
+		/// </param>
+		/// <param name="useBuffer">set to false if the caller will handle
+		/// buffering.
+		/// </param>
+		/// <seealso cref="IndexOutput.WriteBytes(byte[],int)">
+		/// </seealso>
+		public virtual void  ReadBytes(byte[] b, int offset, int len, bool useBuffer)
+		{
+			// Default to ignoring useBuffer entirely
+			ReadBytes(b, offset, len);
+		}
+		
 		/// <summary>Reads four bytes and returns an int.</summary>
 		/// <seealso cref="IndexOutput.WriteInt(int)">
 		/// </seealso>

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexOutput.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/IndexOutput.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexOutput.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/IndexOutput.cs Tue Jun 24 19:50:12 2008
@@ -42,7 +42,21 @@
 		/// </param>
 		/// <seealso cref="IndexInput.ReadBytes(byte[],int,int)">
 		/// </seealso>
-		public abstract void  WriteBytes(byte[] b, int length);
+		public virtual void  WriteBytes(byte[] b, int length)
+		{
+			WriteBytes(b, 0, length);
+		}
+		
+		/// <summary>Writes an array of bytes.</summary>
+		/// <param name="b">the bytes to write
+		/// </param>
+		/// <param name="offset">the offset in the byte array
+		/// </param>
+		/// <param name="length">the number of bytes to write
+		/// </param>
+		/// <seealso cref="IndexInput.ReadBytes(byte[],int,int)">
+		/// </seealso>
+		public abstract void  WriteBytes(byte[] b, int offset, int length);
 		
 		/// <summary>Writes an int as four bytes.</summary>
 		/// <seealso cref="IndexInput.ReadInt()">
@@ -137,6 +151,59 @@
 			}
 		}
 		
+		/// <summary>Writes a sequence of UTF-8 encoded characters from a char[].</summary>
+		/// <param name="s">the source of the characters
+		/// </param>
+		/// <param name="start">the first character in the sequence
+		/// </param>
+		/// <param name="length">the number of characters in the sequence
+		/// </param>
+		/// <seealso cref="IndexInput.ReadChars(char[],int,int)">
+		/// </seealso>
+		public virtual void  WriteChars(char[] s, int start, int length)
+		{
+			int end = start + length;
+			for (int i = start; i < end; i++)
+			{
+				int code = (int) s[i];
+				if (code >= 0x01 && code <= 0x7F)
+					WriteByte((byte) code);
+				else if (((code >= 0x80) && (code <= 0x7FF)) || code == 0)
+				{
+					WriteByte((byte) (0xC0 | (code >> 6)));
+					WriteByte((byte) (0x80 | (code & 0x3F)));
+				}
+				else
+				{
+					WriteByte((byte) (0xE0 | (SupportClass.Number.URShift(code, 12))));
+					WriteByte((byte) (0x80 | ((code >> 6) & 0x3F)));
+					WriteByte((byte) (0x80 | (code & 0x3F)));
+				}
+			}
+		}
+		
+		private static int COPY_BUFFER_SIZE = 16384;
+		private byte[] copyBuffer;
+		
+		/// <summary>Copy numBytes bytes from input to ourself. </summary>
+		public virtual void  CopyBytes(IndexInput input, long numBytes)
+		{
+			long left = numBytes;
+			if (copyBuffer == null)
+				copyBuffer = new byte[COPY_BUFFER_SIZE];
+			while (left > 0)
+			{
+				int toCopy;
+				if (left > COPY_BUFFER_SIZE)
+					toCopy = COPY_BUFFER_SIZE;
+				else
+					toCopy = (int) left;
+				input.ReadBytes(copyBuffer, 0, toCopy);
+				WriteBytes(copyBuffer, 0, toCopy);
+				left -= toCopy;
+			}
+		}
+		
 		/// <summary>Forces any buffered output to be written. </summary>
 		public abstract void  Flush();
 		

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Lock.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/Lock.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Lock.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Lock.cs Tue Jun 24 19:50:12 2008
@@ -29,16 +29,24 @@
 	/// }.run();
 	/// </pre>
 	/// 
+	/// 
 	/// </summary>
-	/// <author>  Doug Cutting
-	/// </author>
-	/// <version>  $Id: Lock.java 472959 2006-11-09 16:21:50Z yonik $
+	/// <version>  $Id: Lock.java 595448 2007-11-15 20:42:54Z mikemccand $
 	/// </version>
-	/// <seealso cref="Directory#MakeLock(String)">
+	/// <seealso cref="Directory.MakeLock(String)">
 	/// </seealso>
 	public abstract class Lock
 	{
+		
+		/// <summary>How long {@link #Obtain(long)} waits, in milliseconds,
+		/// in between attempts to acquire the lock. 
+		/// </summary>
 		public static long LOCK_POLL_INTERVAL = 1000;
+
+		/// <summary>Pass this value to {@link #Obtain(long)} to try
+		/// forever to obtain the lock. 
+		/// </summary>
+		public const long LOCK_OBTAIN_WAIT_FOREVER = - 1;
 		
 		/// <summary>Attempts to obtain exclusive access and immediately return
 		/// upon success or failure.
@@ -53,34 +61,48 @@
 		/// </summary>
 		protected internal System.Exception failureReason;
 		
-		/// <summary>Attempts to obtain an exclusive lock within amount
-		/// of time given. Currently polls once per second until
-		/// lockWaitTimeout is passed.
+		/// <summary>Attempts to obtain an exclusive lock within amount of
+		/// time given. Polls once per {@link #LOCK_POLL_INTERVAL}
+		/// (currently 1000) milliseconds until lockWaitTimeout is
+		/// passed.
 		/// </summary>
-		/// <param name="lockWaitTimeout">length of time to wait in ms
+		/// <param name="lockWaitTimeout">length of time to wait in
+		/// milliseconds or {@link
+		/// #LOCK_OBTAIN_WAIT_FOREVER} to retry forever
 		/// </param>
 		/// <returns> true if lock was obtained
 		/// </returns>
-		/// <throws>  IOException if lock wait times out or obtain() throws an IOException </throws>
+		/// <throws>  LockObtainFailedException if lock wait times out </throws>
+		/// <throws>  IllegalArgumentException if lockWaitTimeout is </throws>
+		/// <summary>         out of bounds
+		/// </summary>
+		/// <throws>  IOException if obtain() throws IOException </throws>
 		public virtual bool Obtain(long lockWaitTimeout)
 		{
 			failureReason = null;
 			bool locked = Obtain();
-			int maxSleepCount = (int) (lockWaitTimeout / LOCK_POLL_INTERVAL);
-			int sleepCount = 0;
+			if (lockWaitTimeout < 0 && lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER)
+				throw new System.ArgumentException("lockWaitTimeout should be LOCK_OBTAIN_WAIT_FOREVER or a non-negative number (got " + lockWaitTimeout + ")");
+			
+			long maxSleepCount = lockWaitTimeout / LOCK_POLL_INTERVAL;
+			long sleepCount = 0;
 			while (!locked)
 			{
-				if (sleepCount++ == maxSleepCount)
+				if (lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER && sleepCount++ >= maxSleepCount)
 				{
 					System.String reason = "Lock obtain timed out: " + this.ToString();
 					if (failureReason != null)
 					{
 						reason += (": " + failureReason);
 					}
-					System.IO.IOException e = new System.IO.IOException(reason);
+					LockObtainFailedException e;
 					if (failureReason != null)
 					{
-                        e = new System.IO.IOException(reason, failureReason);
+						e = new LockObtainFailedException(reason, failureReason);
+					}
+					else
+					{
+						e = new LockObtainFailedException(reason);
 					}
 					throw e;
 				}
@@ -126,8 +148,12 @@
 			/// <summary>Calls {@link #doBody} while <i>lock</i> is obtained.  Blocks if lock
 			/// cannot be obtained immediately.  Retries to obtain lock once per second
 			/// until it is obtained, or until it has tried ten times. Lock is released when
-			/// {@link #doBody} exits. 
+			/// {@link #doBody} exits.
+			/// </summary>
+			/// <throws>  LockObtainFailedException if lock could not </throws>
+			/// <summary> be obtained
 			/// </summary>
+			/// <throws>  IOException if {@link Lock#obtain} throws IOException </throws>
 			public virtual System.Object Run()
 			{
 				bool locked = false;

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockFactory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/LockFactory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockFactory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockFactory.cs Tue Jun 24 19:50:12 2008
@@ -20,9 +20,21 @@
 namespace Lucene.Net.Store
 {
 	
-	/// <summary> Base class for Locking implementation.  {@link Directory} uses
-	/// instances of this class to implement locking.
+	/// <summary> <p>Base class for Locking implementation.  {@link Directory} uses
+	/// instances of this class to implement locking.</p>
+	/// 
+	/// <p>Note that there are some useful tools to verify that
+	/// your LockFactory is working correctly: {@link
+	/// VerifyingLockFactory}, {@link LockStressTest}, {@link
+	/// LockVerifyServer}.</p>
+	/// 
 	/// </summary>
+	/// <seealso cref="LockVerifyServer">
+	/// </seealso>
+	/// <seealso cref="LockStressTest">
+	/// </seealso>
+	/// <seealso cref="VerifyingLockFactory">
+	/// </seealso>
 	
 	public abstract class LockFactory
 	{

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockObtainFailedException.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/LockObtainFailedException.cs?rev=671401&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockObtainFailedException.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockObtainFailedException.cs Tue Jun 24 19:50:12 2008
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Lucene.Net.Store
+{
+	
+	/// <summary> This exception is thrown when the <code>write.lock</code>
+	/// could not be acquired.  This
+	/// happens when a writer tries to open an index
+	/// that another writer already has open.
+	/// </summary>
+	/// <seealso cref="Lock.obtain(long).">
+	/// </seealso>
+	[Serializable]
+	public class LockObtainFailedException : System.IO.IOException
+	{
+		public LockObtainFailedException(System.String message) : base(message)
+		{
+		}
+		
+		public LockObtainFailedException(System.String message, Exception cause) : base(message, cause)
+		{
+		}
+	}
+}
\ No newline at end of file

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockReleaseFailedException.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/LockReleaseFailedException.cs?rev=671401&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockReleaseFailedException.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockReleaseFailedException.cs Tue Jun 24 19:50:12 2008
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Lucene.Net.Store
+{
+	
+	/// <summary> This exception is thrown when the <code>write.lock</code>
+	/// could not be released.
+	/// </summary>
+	/// <seealso cref="Lock.release().">
+	/// </seealso>
+	[Serializable]
+	public class LockReleaseFailedException : System.IO.IOException
+	{
+		public LockReleaseFailedException(System.String message) : base(message)
+		{
+		}
+	}
+}
\ No newline at end of file

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockStressTest.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/LockStressTest.cs?rev=671401&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockStressTest.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockStressTest.cs Tue Jun 24 19:50:12 2008
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Lucene.Net.Store
+{
+	
+	/// <summary> Simple standalone tool that forever acquires & releases a
+	/// lock using a specific LockFactory.  Run without any args
+	/// to see usage.
+	/// 
+	/// </summary>
+	/// <seealso cref="VerifyingLockFactory">
+	/// </seealso>
+	/// <seealso cref="LockVerifyServer">
+	/// </seealso>
+	
+	public class LockStressTest
+	{
+		
+		[STAThread]
+		public static void  Main(System.String[] args)
+		{
+			
+			if (args.Length != 6)
+			{
+				System.Console.Out.WriteLine("\nUsage: java Lucene.Net.Store.LockStressTest myID verifierHostOrIP verifierPort lockFactoryClassName lockDirName sleepTime\n" + "\n" + "  myID = int from 0 .. 255 (should be unique for test process)\n" + "  verifierHostOrIP = host name or IP address where LockVerifyServer is running\n" + "  verifierPort = port that LockVerifyServer is listening on\n" + "  lockFactoryClassName = primary LockFactory class that we will use\n" + "  lockDirName = path to the lock directory (only set for Simple/NativeFSLockFactory\n" + "  sleepTimeMS = milliseconds to pause betweeen each lock obtain/release\n" + "\n" + "You should run multiple instances of this process, each with its own\n" + "unique ID, and each pointing to the same lock directory, to verify\n" + "that locking is working correctly.\n" + "\n" + "Make sure you are first running LockVerifyServer.\n" + "\n");
+				System.Environment.Exit(1);
+			}
+			
+			int myID = System.Int32.Parse(args[0]);
+			
+			if (myID < 0 || myID > 255)
+			{
+				System.Console.Out.WriteLine("myID must be a unique int 0..255");
+				System.Environment.Exit(1);
+			}
+			
+			System.String verifierHost = args[1];
+			int verifierPort = System.Int32.Parse(args[2]);
+			System.String lockFactoryClassName = args[3];
+			System.String lockDirName = args[4];
+			int sleepTimeMS = System.Int32.Parse(args[5]);
+			
+			System.Type c;
+			try
+			{
+				c = System.Type.GetType(lockFactoryClassName);
+			}
+			catch (System.Exception e)
+			{
+				throw new System.IO.IOException("unable to find LockClass " + lockFactoryClassName);
+			}
+			
+			LockFactory lockFactory;
+			try
+			{
+				lockFactory = (LockFactory) System.Activator.CreateInstance(c);
+			}
+			catch (System.UnauthorizedAccessException e)
+			{
+				throw new System.IO.IOException("IllegalAccessException when instantiating LockClass " + lockFactoryClassName);
+			}
+			catch (System.InvalidCastException e)
+			{
+				throw new System.IO.IOException("unable to cast LockClass " + lockFactoryClassName + " instance to a LockFactory");
+			}
+			catch (System.Exception e)
+			{
+				throw new System.IO.IOException("InstantiationException when instantiating LockClass " + lockFactoryClassName);
+			}
+			
+			System.IO.FileInfo lockDir = new System.IO.FileInfo(lockDirName);
+			
+			if (lockFactory is NativeFSLockFactory)
+			{
+				((NativeFSLockFactory) lockFactory).SetLockDir(lockDir);
+			}
+			else if (lockFactory is SimpleFSLockFactory)
+			{
+				((SimpleFSLockFactory) lockFactory).SetLockDir(lockDir);
+			}
+			
+			lockFactory.SetLockPrefix("test");
+			
+			LockFactory verifyLF = new VerifyingLockFactory((byte) myID, lockFactory, verifierHost, verifierPort);
+			
+			Lock l = verifyLF.MakeLock("test.lock");
+			
+			while (true)
+			{
+				
+				bool obtained = false;
+				
+				try
+				{
+					obtained = l.Obtain(10);
+				}
+				catch (LockObtainFailedException e)
+				{
+					System.Console.Out.Write("x");
+				}
+				
+				if (obtained)
+				{
+					System.Console.Out.Write("l");
+					l.Release();
+				}
+				System.Threading.Thread.Sleep(new System.TimeSpan((System.Int64) 10000 * sleepTimeMS));
+			}
+		}
+	}
+}
\ No newline at end of file

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockVerifyServer.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/LockVerifyServer.cs?rev=671401&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockVerifyServer.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/LockVerifyServer.cs Tue Jun 24 19:50:12 2008
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace Lucene.Net.Store
+{
+	
+	/// <summary> Simple standalone server that must be running when you
+	/// use {@link VerifyingLockFactory}.  This server simply
+	/// verifies at most one process holds the lock at a time.
+	/// Run without any args to see usage.
+	/// 
+	/// </summary>
+	/// <seealso cref="VerifyingLockFactory">
+	/// </seealso>
+	/// <seealso cref="LockStressTest">
+	/// </seealso>
+	
+	public class LockVerifyServer
+	{
+		
+		private static System.String GetTime(long startTime)
+		{
+			return "[" + (((System.DateTime.Now.Ticks - 621355968000000000) / 10000 - startTime) / 1000) + "s] ";   // {{Aroush-2.3.1}} Is this OK?!
+		}
+		
+		[STAThread]
+		public static void  Main(System.String[] args)
+		{
+			
+			if (args.Length != 1)
+			{
+				System.Console.Out.WriteLine("\nUsage: java Lucene.Net.Store.LockVerifyServer port\n");
+				System.Environment.Exit(1);
+			}
+			
+			int port = System.Int32.Parse(args[0]);
+			
+			System.Net.Sockets.TcpListener temp_tcpListener;
+			temp_tcpListener = new System.Net.Sockets.TcpListener(System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList[0], port);
+			temp_tcpListener.Server.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, System.Net.Sockets.SocketOptionName.ReuseAddress, 1);
+			temp_tcpListener.Start();
+			System.Net.Sockets.TcpListener s = temp_tcpListener;
+			System.Console.Out.WriteLine("\nReady on port " + port + "...");
+			
+			int lockedID = 0;
+			long startTime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000;
+			
+			while (true)
+			{
+				System.Net.Sockets.TcpClient cs = s.AcceptTcpClient();
+				System.IO.Stream out_Renamed = cs.GetStream();
+				System.IO.Stream in_Renamed = cs.GetStream();
+				
+				int id = in_Renamed.ReadByte();
+				int command = in_Renamed.ReadByte();
+				
+				bool err = false;
+				
+				if (command == 1)
+				{
+					// Locked
+					if (lockedID != 0)
+					{
+						err = true;
+						System.Console.Out.WriteLine(GetTime(startTime) + " ERROR: id " + id + " got lock, but " + lockedID + " already holds the lock");
+					}
+					lockedID = id;
+				}
+				else if (command == 0)
+				{
+					if (lockedID != id)
+					{
+						err = true;
+						System.Console.Out.WriteLine(GetTime(startTime) + " ERROR: id " + id + " released the lock, but " + lockedID + " is the one holding the lock");
+					}
+					lockedID = 0;
+				}
+				else
+					throw new System.SystemException("unrecognized command " + command);
+				
+				System.Console.Out.Write(".");
+				
+				if (err)
+					out_Renamed.WriteByte((System.Byte) 1);
+				else
+					out_Renamed.WriteByte((System.Byte) 0);
+				
+				out_Renamed.Close();
+				in_Renamed.Close();
+				cs.Close();
+			}
+		}
+	}
+}
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/MMapDirectory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/MMapDirectory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/MMapDirectory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/MMapDirectory.cs Tue Jun 24 19:50:12 2008
@@ -123,7 +123,7 @@
                     byte[] data = new byte[rafc.Length];
                     raf.Read(data, 0, (int) rafc.Length);
 
-					int bufSize = (length > (bufferStart + maxBufSize))?maxBufSize:(int) (length - bufferStart);
+					int bufSize = (length > (bufferStart + maxBufSize)) ? maxBufSize : (int) (length - bufferStart);
 					this.buffers[bufNr] = new System.IO.MemoryStream(data);     // rafc.map(MapMode.READ_ONLY, bufferStart, bufSize);     // {{Aroush-1.9}}
 					this.bufSizes[bufNr] = bufSize;
 					bufferStart += bufSize;
@@ -224,5 +224,10 @@
 				raf.Close();
 			}
 		}
+		
+		public override IndexInput OpenInput(System.String name, int bufferSize)
+		{
+			return OpenInput(name);
+		}
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/NativeFSLockFactory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/NativeFSLockFactory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/NativeFSLockFactory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/NativeFSLockFactory.cs Tue Jun 24 19:50:12 2008
@@ -23,35 +23,31 @@
 namespace Lucene.Net.Store
 {
 	
-	/// <summary> Implements {@link LockFactory} using native OS file locks
-	/// (available through java.nio.*).  Note that for certain
-	/// filesystems native locks are possible but must be
-	/// explicity configured and enabled (and may be disabled by
-	/// default).  For example, for NFS servers there sometimes
-	/// must be a separate lockd process running, and other
-	/// configuration may be required such as running the server
-	/// in kernel mode.  Other filesystems may not even support
-	/// native OS locks in which case you must use a different
-	/// {@link LockFactory} implementation.
+	/// <summary> <p>Implements {@link LockFactory} using native OS file
+	/// locks.  Note that because this LockFactory relies on
+	/// java.nio.* APIs for locking, any problems with those APIs
+	/// will cause locking to fail.  Specifically, on certain NFS
+	/// environments the java.nio.* locks will fail (the lock can
+	/// incorrectly be double acquired) whereas {@link
+	/// SimpleFSLockFactory} worked perfectly in those same
+	/// environments.  For NFS based access to an index, it's
+	/// recommended that you try {@link SimpleFSLockFactory}
+	/// first and work around the one limitation that a lock file
+	/// could be left when the JVM exits abnormally.</p>
 	/// 
-	/// <p>The advantage of this lock factory over
-	/// {@link SimpleFSLockFactory} is that the locks should be
-	/// "correct", whereas {@link SimpleFSLockFactory} uses
-	/// java.io.File.createNewFile which
-	/// <a target="_top" href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/File.html#createNewFile()">has warnings</a> about not
-	/// using it for locking.  Furthermore, if the JVM crashes,
-	/// the OS will free any held locks, whereas
-	/// {@link SimpleFSLockFactory} will keep the locks held, requiring
-	/// manual removal before re-running Lucene.</p>
+	/// <p>The primary benefit of {@link NativeFSLockFactory} is
+	/// that lock files will be properly removed (by the OS) if
+	/// the JVM has an abnormal exit.</p>
 	/// 
 	/// <p>Note that, unlike {@link SimpleFSLockFactory}, the existence of
 	/// leftover lock files in the filesystem on exiting the JVM
 	/// is fine because the OS will free the locks held against
 	/// these files even though the files still remain.</p>
 	/// 
-	/// <p>Native locks file names have the substring "-n-", which
-	/// you can use to differentiate them from lock files created
-	/// by {@link SimpleFSLockFactory}.</p>
+	/// <p>If you suspect that this or any other LockFactory is
+	/// not working properly in your environment, you can easily
+	/// test it by using {@link VerifyingLockFactory}, {@link
+	/// LockVerifyServer} and {@link LockStressTest}.</p>
 	/// 
 	/// </summary>
 	/// <seealso cref="LockFactory">
@@ -91,6 +87,16 @@
 			l.Release();
 		}
 		
+		/// <summary> Create a NativeFSLockFactory instance, with null (unset)
+		/// lock directory.  This is package-private and is only
+		/// used by FSDirectory when creating this LockFactory via
+		/// the System property
+		/// Lucene.Net.Store.FSDirectoryLockFactoryClass.
+		/// </summary>
+		internal NativeFSLockFactory() : this((System.IO.FileInfo) null)
+		{
+		}
+		
 		/// <summary> Create a NativeFSLockFactory instance, storing lock
 		/// files into the specified lockDirName:
 		/// 
@@ -109,66 +115,45 @@
 		/// </param>
 		public NativeFSLockFactory(System.IO.FileInfo lockDir)
 		{
-			
+			SetLockDir(lockDir);
+		}
+		
+		/// <summary> Set the lock directory.  This is package-private and is
+		/// only used externally by FSDirectory when creating this
+		/// LockFactory via the System property
+		/// Lucene.Net.Store.FSDirectoryLockFactoryClass.
+		/// </summary>
+		internal virtual void  SetLockDir(System.IO.FileInfo lockDir)
+		{
 			this.lockDir = lockDir;
-			
-			// Ensure that lockDir exists and is a directory.
-			bool tmpBool;
-			if (System.IO.File.Exists(lockDir.FullName))
-				tmpBool = true;
-			else
-				tmpBool = System.IO.Directory.Exists(lockDir.FullName);
-			if (!tmpBool)
+			if (lockDir != null)
 			{
-                try
-                {
-                    System.IO.Directory.CreateDirectory(lockDir.FullName);
-                }
-                catch
-                {
-                    throw new System.IO.IOException("Cannot create directory: " + lockDir.FullName);
-                }
-			}
-			else if (!System.IO.Directory.Exists(lockDir.FullName))
-			{
-				throw new System.IO.IOException("Found regular file where directory expected: " + lockDir.FullName);
+				// Ensure that lockDir exists and is a directory.
+				bool tmpBool;
+				if (System.IO.File.Exists(lockDir.FullName))
+					tmpBool = true;
+				else
+					tmpBool = System.IO.Directory.Exists(lockDir.FullName);
+				if (!tmpBool)
+				{
+	                try
+	                {
+	                    System.IO.Directory.CreateDirectory(lockDir.FullName);
+	                }
+	                catch
+	                {
+	                    throw new System.IO.IOException("Cannot create directory: " + lockDir.FullName);
+	                }
+				}
+				else if (!System.IO.Directory.Exists(lockDir.FullName))
+				{
+					throw new System.IO.IOException("Found regular file where directory expected: " + lockDir.FullName);
+				}
+				
+				AcquireTestLock();
 			}
-			
-			AcquireTestLock();
 		}
 		
-        /// <summary>
-        /// </summary>
-        internal NativeFSLockFactory()
-        {
-            lockDir = null;
-        }
-
-        /// <summary>
-        /// Set the lock directory.  This is package-private and is
-        /// only used externally by FSDirectory when creating this
-        /// LockFactory via the System property
-        /// org.apache.lucene.store.FSDirectoryLockFactoryClass.
-        /// </summary>
-        /// <param name="lockDir"></param>
-        internal void SetLockDir(System.IO.FileInfo lockDir)
-        {
-            this.lockDir = lockDir;
-            if (lockDir != null)
-            {
-                // Ensure that lockDir exists and is a directory.
-                if (!lockDir.Exists)
-                {
-                    if (System.IO.Directory.CreateDirectory(lockDir.FullName) == null)
-                        throw new System.IO.IOException("Cannot create directory: " + lockDir.FullName);
-                }
-                else if (!new System.IO.DirectoryInfo(lockDir.FullName).Exists)
-                {
-                    throw new System.IO.IOException("Found regular file where directory expected: " + lockDir.FullName);
-                }
-            }
-        }
-
 		public override Lock MakeLock(System.String lockName)
 		{
 			lock (this)
@@ -409,66 +394,61 @@
 		{
 			lock (this)
 			{
-				try
+				if (IsLocked())
 				{
-					if (IsLocked())
+					try
+					{
+                        channel.Unlock(0, channel.Length);
+					}
+					finally
 					{
+						lock_Renamed = false;
 						try
 						{
-                            channel.Unlock(0, channel.Length);
+							channel.Close();
 						}
 						finally
 						{
-							lock_Renamed = false;
+							channel = null;
 							try
 							{
-								channel.Close();
+								f.Close();
 							}
 							finally
 							{
-								channel = null;
-								try
+								f = null;
+								lock (LOCK_HELD)
 								{
-									f.Close();
-								}
-								finally
-								{
-									f = null;
-									lock (LOCK_HELD)
-									{
-										LOCK_HELD.Remove(path.FullName);
-									}
+									LOCK_HELD.Remove(path.FullName);
 								}
 							}
 						}
-						bool tmpBool;
-						if (System.IO.File.Exists(path.FullName))
-						{
-							System.IO.File.Delete(path.FullName);
-							tmpBool = true;
-						}
-						else if (System.IO.Directory.Exists(path.FullName))
-						{
-							System.IO.Directory.Delete(path.FullName);
-							tmpBool = true;
-						}
-						else
-							tmpBool = false;
-						bool generatedAux = tmpBool;
 					}
-				}
-				catch (System.IO.IOException e)
-				{
-					// Not sure how to better message/handle this without
-					// changing API?
-					throw new System.SystemException("", e);
+					bool tmpBool;
+					if (System.IO.File.Exists(path.FullName))
+					{
+						System.IO.File.Delete(path.FullName);
+						tmpBool = true;
+					}
+					else if (System.IO.Directory.Exists(path.FullName))
+					{
+						System.IO.Directory.Delete(path.FullName);
+						tmpBool = true;
+					}
+					else
+						tmpBool = false;
+					if (!tmpBool)
+						throw new LockReleaseFailedException("failed to delete " + path);
 				}
 			}
 		}
 		
 		public override bool IsLocked()
 		{
-			return lock_Renamed;
+			lock (this)
+			{
+				return lock_Renamed;
+			}
 		}
 		
 		public override System.String ToString()

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Package.html
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/Package.html?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Package.html (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/Package.html Tue Jun 24 19:50:12 2008
@@ -1,10 +1,10 @@
-<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
-<html>
-<head>
-   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-   <meta name="Author" content="Doug Cutting">
-</head>
-<body>
-Binary i/o API, used for all index data.
-</body>
-</html>
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="Doug Cutting">
+</head>
+<body>
+Binary i/o API, used for all index data.
+</body>
+</html>

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMDirectory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/RAMDirectory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMDirectory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMDirectory.cs Tue Jun 24 19:50:12 2008
@@ -25,7 +25,7 @@
 	/// but can be changed with {@link #setLockFactory}.
 	/// 
 	/// </summary>
-	/// <version>  $Id: RAMDirectory.java 503911 2007-02-05 22:49:42Z dnaber $
+	/// <version>  $Id: RAMDirectory.java 581625 2007-10-03 15:24:12Z mikemccand $
 	/// </version>
     [Serializable]
     public class RAMDirectory : Directory
@@ -89,7 +89,7 @@
 		/// <param name="dir">a <code>File</code> specifying the index directory
 		/// 
 		/// </param>
-		/// <seealso cref="#RAMDirectory(Directory)">
+		/// <seealso cref="RAMDirectory(Directory)">
 		/// </seealso>
 		public RAMDirectory(System.IO.FileInfo dir):this(FSDirectory.GetDirectory(dir), true)
 		{
@@ -101,7 +101,7 @@
 		/// <param name="dir">a <code>String</code> specifying the full index directory path
 		/// 
 		/// </param>
-		/// <seealso cref="#RAMDirectory(Directory)">
+		/// <seealso cref="RAMDirectory(Directory)">
 		/// </seealso>
 		public RAMDirectory(System.String dir) : this(FSDirectory.GetDirectory(dir), true)
 		{
@@ -112,6 +112,7 @@
 		{
 			lock (this)
 			{
+				EnsureOpen();
 				System.String[] result = new System.String[fileMap.Count];
 				int i = 0;
 				System.Collections.IEnumerator it = fileMap.Keys.GetEnumerator();
@@ -126,6 +127,7 @@
 		/// <summary>Returns true iff the named file exists in this directory. </summary>
 		public override bool FileExists(System.String name)
 		{
+			EnsureOpen();
 			RAMFile file;
 			lock (this)
 			{
@@ -138,6 +140,7 @@
 		/// <throws>  IOException if the file does not exist </throws>
 		public override long FileModified(System.String name)
 		{
+			EnsureOpen();
 			RAMFile file;
 			lock (this)
 			{
@@ -152,6 +155,7 @@
 		/// <throws>  IOException if the file does not exist </throws>
 		public override void  TouchFile(System.String name)
 		{
+			EnsureOpen();
 			RAMFile file;
 			lock (this)
 			{
@@ -181,6 +185,7 @@
 		/// <throws>  IOException if the file does not exist </throws>
 		public override long FileLength(System.String name)
 		{
+			EnsureOpen();
 			RAMFile file;
 			lock (this)
 			{
@@ -193,12 +198,13 @@
 		
 		/// <summary>Return total size in bytes of all files in this
 		/// directory.  This is currently quantized to
-		/// BufferedIndexOutput.BUFFER_SIZE. 
+		/// RAMOutputStream.BUFFER_SIZE. 
 		/// </summary>
 		public long SizeInBytes()
 		{
 			lock (this)
 			{
+				EnsureOpen();
 				return sizeInBytes;
 			}
 		}
@@ -209,6 +215,7 @@
 		{
 			lock (this)
 			{
+				EnsureOpen();
 				RAMFile file = (RAMFile) fileMap[name];
 				if (file != null)
 				{
@@ -229,6 +236,7 @@
 		{
 			lock (this)
 			{
+				EnsureOpen();
 				RAMFile fromFile = (RAMFile) fileMap[from];
 				if (fromFile == null)
 					throw new System.IO.FileNotFoundException(from);
@@ -246,6 +254,7 @@
 		/// <summary>Creates a new, empty file in the directory with the given name. Returns a stream writing this file. </summary>
 		public override IndexOutput CreateOutput(System.String name)
 		{
+			EnsureOpen();
 			RAMFile file = new RAMFile(this);
 			lock (this)
 			{
@@ -263,6 +272,7 @@
 		/// <summary>Returns a stream reading an existing file. </summary>
 		public override IndexInput OpenInput(System.String name)
 		{
+			EnsureOpen();
 			RAMFile file;
 			lock (this)
 			{
@@ -278,5 +288,14 @@
 		{
 			fileMap = null;
 		}
+		
+		/// <throws>  AlreadyClosedException if this IndexReader is closed </throws>
+		protected internal void  EnsureOpen()
+		{
+			if (fileMap == null)
+			{
+				throw new AlreadyClosedException("this RAMDirectory is closed");
+			}
+		}
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMFile.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/RAMFile.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMFile.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMFile.cs Tue Jun 24 19:50:12 2008
@@ -26,8 +26,7 @@
 		
 		private const long serialVersionUID = 1L;
 		
-		// Direct read-only access to state supported for streams since a writing stream implies no other concurrent streams
-		internal System.Collections.ArrayList buffers = new System.Collections.ArrayList();
+		private System.Collections.ArrayList buffers = new System.Collections.ArrayList();
 		internal long length;
 		internal RAMDirectory directory;
 		internal long sizeInBytes; // Only maintained if in a directory; updates synchronized on directory
@@ -81,18 +80,49 @@
 		
 		internal byte[] AddBuffer(int size)
 		{
-			byte[] buffer = new byte[size];
-			if (directory != null)
-				lock (directory)
-				{
-					// Ensure addition of buffer and adjustment to directory size are atomic wrt directory
+			lock (this)
+			{
+				byte[] buffer = new byte[size];
+				if (directory != null)
+					lock (directory)
+					{
+						// Ensure addition of buffer and adjustment to directory size are atomic wrt directory
+						buffers.Add(buffer);
+						directory.sizeInBytes += size;
+						sizeInBytes += size;
+					}
+				else
 					buffers.Add(buffer);
-					directory.sizeInBytes += size;
-					sizeInBytes += size;
-				}
-			else
-				buffers.Add(buffer);
-			return buffer;
+				return buffer;
+			}
+		}
+		
+		internal byte[] GetBuffer(int index)
+		{
+			lock (this)
+			{
+				return (byte[]) buffers[index];
+			}
+		}
+		
+		internal int NumBuffers()
+		{
+			lock (this)
+			{
+				return buffers.Count;
+			}
+		}
+		
+		/// <summary> Expert: allocate a new buffer. 
+		/// Subclasses can allocate differently. 
+		/// </summary>
+		/// <param name="size">size of allocated buffer.
+		/// </param>
+		/// <returns> allocated buffer.
+		/// </returns>
+		internal virtual byte[] NewBuffer(int size)
+		{
+			return new byte[size];
 		}
 		
 		// Only valid if in a directory

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMInputStream.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/RAMInputStream.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMInputStream.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMInputStream.cs Tue Jun 24 19:50:12 2008
@@ -20,78 +20,122 @@
 namespace Lucene.Net.Store
 {
 	
-	/// <summary> Licensed to the Apache Software Foundation (ASF) under one or more
-	/// contributor license agreements.  See the NOTICE file distributed with
-	/// this work for additional information regarding copyright ownership.
-	/// The ASF licenses this file to You under the Apache License, Version 2.0
-	/// (the "License"); you may not use this file except in compliance with
-	/// the License.  You may obtain a copy of the License at
-	/// 
-	/// http://www.apache.org/licenses/LICENSE-2.0
-	/// 
-	/// Unless required by applicable law or agreed to in writing, software
-	/// distributed under the License is distributed on an "AS IS" BASIS,
-	/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-	/// See the License for the specific language governing permissions and
-	/// limitations under the License.
-	/// </summary>
-	
 	/// <summary> A memory-resident {@link IndexInput} implementation.
 	/// 
 	/// </summary>
-	/// <version>  $Id: RAMInputStream.java 478014 2006-11-22 02:47:49Z yonik $
+	/// <version>  $Id: RAMInputStream.java 598693 2007-11-27 17:01:21Z mikemccand $
 	/// </version>
 	
-	class RAMInputStream : BufferedIndexInput, System.ICloneable
+	public class RAMInputStream : IndexInput, System.ICloneable
 	{
+		internal static readonly int BUFFER_SIZE;
+		
 		private RAMFile file;
-		private long pointer = 0;
 		private long length;
 		
-		public RAMInputStream(RAMFile f)
+		private byte[] currentBuffer;
+		private int currentBufferIndex;
+		
+		private int bufferPosition;
+		private long bufferStart;
+		private int bufferLength;
+		
+		internal RAMInputStream(RAMFile f)
 		{
 			file = f;
 			length = file.length;
+			if (length / BUFFER_SIZE >= System.Int32.MaxValue)
+			{
+				throw new System.IO.IOException("Too large RAMFile! " + length);
+			}
+			
+			// make sure that we switch to the
+			// first needed buffer lazily
+			currentBufferIndex = - 1;
+			currentBuffer = null;
+		}
+		
+		public override void  Close()
+		{
+			// nothing to do here
+		}
+		
+		public override long Length()
+		{
+			return length;
 		}
 		
-		public override void  ReadInternal(byte[] dest, int destOffset, int len)
+		public override byte ReadByte()
 		{
-			int remainder = len;
-			long start = pointer;
-			while (remainder != 0)
-			{
-				int bufferNumber = (int) (start / BUFFER_SIZE);
-				int bufferOffset = (int) (start % BUFFER_SIZE);
-				int bytesInBuffer = BUFFER_SIZE - bufferOffset;
-				int bytesToCopy = bytesInBuffer >= remainder ? remainder : bytesInBuffer;
-				byte[] buffer = (byte[]) file.buffers[bufferNumber];
-				Array.Copy(buffer, bufferOffset, dest, destOffset, bytesToCopy);
-				destOffset += bytesToCopy;
-				start += bytesToCopy;
-				remainder -= bytesToCopy;
+			if (bufferPosition >= bufferLength)
+			{
+				currentBufferIndex++;
+				SwitchCurrentBuffer();
 			}
-			pointer += len;
+			return currentBuffer[bufferPosition++];
 		}
 		
-		public override void  Close()
+		public override void  ReadBytes(byte[] b, int offset, int len)
 		{
+			while (len > 0)
+			{
+				if (bufferPosition >= bufferLength)
+				{
+					currentBufferIndex++;
+					SwitchCurrentBuffer();
+				}
+				
+				int remainInBuffer = bufferLength - bufferPosition;
+				int bytesToCopy = len < remainInBuffer ? len : remainInBuffer;
+				Array.Copy(currentBuffer, bufferPosition, b, offset, bytesToCopy);
+				offset += bytesToCopy;
+				len -= bytesToCopy;
+				bufferPosition += bytesToCopy;
+			}
 		}
 		
-		public override void  SeekInternal(long pos)
+		private void  SwitchCurrentBuffer()
 		{
-			pointer = pos;
+			if (currentBufferIndex >= file.NumBuffers())
+			{
+				// end of file reached, no more buffers left
+				throw new System.IO.IOException("Read past EOF");
+			}
+			else
+			{
+				currentBuffer = file.GetBuffer(currentBufferIndex);
+				bufferPosition = 0;
+				bufferStart = (long) BUFFER_SIZE * (long) currentBufferIndex;
+				long buflen = length - bufferStart;
+				bufferLength = buflen > BUFFER_SIZE ? BUFFER_SIZE : (int) buflen;
+			}
 		}
 		
-		public override long Length()
+		public override long GetFilePointer()
 		{
-			return length;
+			return currentBufferIndex < 0 ? 0 : bufferStart + bufferPosition;
 		}
-
-		// {{Aroush-1.9}} Do we need this Clone()?!
-		/* virtual public System.Object Clone()
+		
+		public override void  Seek(long pos)
 		{
-			return null;
+			if (currentBuffer == null || pos < bufferStart || pos >= bufferStart + BUFFER_SIZE)
+			{
+				currentBufferIndex = (int) (pos / BUFFER_SIZE);
+				SwitchCurrentBuffer();
+			}
+			bufferPosition = (int) (pos % BUFFER_SIZE);
 		}
+
+        // {{Aroush-1.9}} Do we need this Clone()?!
+        /* override public System.Object Clone()
+        {
+            return null;
+        }
         */
+
+		static RAMInputStream()
+		{
+			BUFFER_SIZE = RAMOutputStream.BUFFER_SIZE;
+		}
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMOutputStream.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/RAMOutputStream.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMOutputStream.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/RAMOutputStream.cs Tue Jun 24 19:50:12 2008
@@ -23,22 +23,35 @@
 	/// <summary> A memory-resident {@link IndexOutput} implementation.
 	/// 
 	/// </summary>
-	/// <version>  $Id: RAMOutputStream.java 488330 2006-12-18 16:45:29Z mikemccand $
+	/// <version>  $Id: RAMOutputStream.java 598693 2007-11-27 17:01:21Z mikemccand $
 	/// </version>
 	
-	public class RAMOutputStream : BufferedIndexOutput
+	public class RAMOutputStream:IndexOutput
 	{
+		internal const int BUFFER_SIZE = 1024;
+		
 		private RAMFile file;
-		private long pointer = 0;
+		
+		private byte[] currentBuffer;
+		private int currentBufferIndex;
+		
+		private int bufferPosition;
+		private long bufferStart;
+		private int bufferLength;
 		
 		/// <summary>Construct an empty output buffer. </summary>
-		public RAMOutputStream() : this(new RAMFile())
+		public RAMOutputStream():this(new RAMFile())
 		{
 		}
 		
 		public /*internal*/ RAMOutputStream(RAMFile f)
 		{
 			file = f;
+			
+			// make sure that we switch to the
+			// first needed buffer lazily
+			currentBufferIndex = - 1;
+			currentBuffer = null;
 		}
 		
 		/// <summary>Copy the current contents of this buffer to the named output. </summary>
@@ -57,7 +70,7 @@
 					// at the last buffer
 					length = (int) (end - pos);
 				}
-				out_Renamed.WriteBytes((byte[]) file.buffers[buffer++], length);
+				out_Renamed.WriteBytes((byte[]) file.GetBuffer(buffer++), length);
 				pos = nextPos;
 			}
 		}
@@ -78,47 +91,92 @@
 			file.SetLength(0);
 		}
 		
-		public override void  FlushBuffer(byte[] src, int len)
+		public override void  Close()
 		{
-			byte[] buffer;
-			int bufferPos = 0;
-			while (bufferPos != len)
-			{
-				int bufferNumber = (int) (pointer / BUFFER_SIZE);
-				int bufferOffset = (int) (pointer % BUFFER_SIZE);
-				int bytesInBuffer = BUFFER_SIZE - bufferOffset;
-				int remainInSrcBuffer = len - bufferPos;
-				int bytesToCopy = bytesInBuffer >= remainInSrcBuffer ? remainInSrcBuffer : bytesInBuffer;
-				
-				if (bufferNumber == file.buffers.Count)
-					buffer = file.AddBuffer(BUFFER_SIZE);
-				else
-					buffer = (byte[]) file.buffers[bufferNumber];
-				
-				Array.Copy(src, bufferPos, buffer, bufferOffset, bytesToCopy);
-				bufferPos += bytesToCopy;
-				pointer += bytesToCopy;
+			Flush();
+		}
+		
+		public override void  Seek(long pos)
+		{
+			// set the file length in case we seek back
+			// and flush() has not been called yet
+			SetFileLength();
+			if (pos < bufferStart || pos >= bufferStart + bufferLength)
+			{
+				currentBufferIndex = (int) (pos / BUFFER_SIZE);
+				SwitchCurrentBuffer();
 			}
 			
-			if (pointer > file.length)
-				file.SetLength(pointer);
-			
-			file.SetLastModified(System.DateTime.Now.Ticks);
+			bufferPosition = (int) (pos % BUFFER_SIZE);
 		}
 		
-		public override void  Close()
+		public override long Length()
 		{
-			base.Close();
+			return file.length;
 		}
 		
-		public override void  Seek(long pos)
+		public override void  WriteByte(byte b)
 		{
-			base.Seek(pos);
-			pointer = pos;
+			if (bufferPosition == bufferLength)
+			{
+				currentBufferIndex++;
+				SwitchCurrentBuffer();
+			}
+			currentBuffer[bufferPosition++] = b;
 		}
-		public override long Length()
+		
+		public override void  WriteBytes(byte[] b, int offset, int len)
 		{
-			return file.length;
+			while (len > 0)
+			{
+				if (bufferPosition == bufferLength)
+				{
+					currentBufferIndex++;
+					SwitchCurrentBuffer();
+				}
+				
+				int remainInBuffer = currentBuffer.Length - bufferPosition;
+				int bytesToCopy = len < remainInBuffer ? len : remainInBuffer;
+				Array.Copy(b, offset, currentBuffer, bufferPosition, bytesToCopy);
+				offset += bytesToCopy;
+				len -= bytesToCopy;
+				bufferPosition += bytesToCopy;
+			}
+		}
+		
+		private void  SwitchCurrentBuffer()
+		{
+			if (currentBufferIndex == file.NumBuffers())
+			{
+				currentBuffer = file.AddBuffer(BUFFER_SIZE);
+			}
+			else
+			{
+				currentBuffer = (byte[]) file.GetBuffer(currentBufferIndex);
+			}
+			bufferPosition = 0;
+			bufferStart = (long) BUFFER_SIZE * (long) currentBufferIndex;
+			bufferLength = currentBuffer.Length;
+		}
+		
+		private void  SetFileLength()
+		{
+			long pointer = bufferStart + bufferPosition;
+			if (pointer > file.length)
+			{
+				file.SetLength(pointer);
+			}
+		}
+		
+		public override void  Flush()
+		{
+			file.SetLastModified((System.DateTime.Now.Ticks - 621355968000000000) / 10000);
+			SetFileLength();
+		}
+		
+		public override long GetFilePointer()
+		{
+			return currentBufferIndex < 0?0:bufferStart + bufferPosition;
 		}
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SimpleFSLockFactory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/SimpleFSLockFactory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SimpleFSLockFactory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SimpleFSLockFactory.cs Tue Jun 24 19:50:12 2008
@@ -20,11 +20,32 @@
 namespace Lucene.Net.Store
 {
 	
-	/// <summary> Implements {@link LockFactory} using {@link File#createNewFile()}.  This is
-	/// currently the default LockFactory used for {@link FSDirectory} if no
-	/// LockFactory instance is otherwise provided.
+	/// <summary> <p>Implements {@link LockFactory} using {@link
+	/// File#createNewFile()}.  This is the default LockFactory
+	/// for {@link FSDirectory}.</p>
 	/// 
-	/// Note that there are known problems with this locking implementation on NFS.
+	/// <p><b>NOTE:</b> the <a target="_top"
+	/// href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/File.html#createNewFile()">javadocs
+	/// for <code>File.createNewFile</code></a> contain a vague
+	/// yet spooky warning about not using the API for file
+	/// locking.  This warning was added due to <a target="_top"
+	/// href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4676183">this
+	/// bug</a>, and in fact the only known problem with using
+	/// this API for locking is that the Lucene write lock may
+	/// not be released when the JVM exits abnormally.</p>
+	/// <p>When this happens, a {@link LockObtainFailedException}
+	/// is hit when trying to create a writer, in which case you
+	/// need to explicitly clear the lock file first.  You can
+	/// either manually remove the file, or use the {@link
+	/// Lucene.Net.Index.IndexReader#Unlock(Directory)}
+	/// API.  But, first be certain that no writer is in fact
+	/// writing to the index otherwise you can easily corrupt
+	/// your index.</p>
+	/// 
+	/// <p>If you suspect that this or any other LockFactory is
+	/// not working properly in your environment, you can easily
+	/// test it by using {@link VerifyingLockFactory}, {@link
+	/// LockVerifyServer} and {@link LockStressTest}.</p>
 	/// 
 	/// </summary>
 	/// <seealso cref="LockFactory">
@@ -40,12 +61,22 @@
 		
 		private System.IO.FileInfo lockDir;
 		
+		/// <summary> Create a SimpleFSLockFactory instance, with null (unset)
+		/// lock directory.  This is package-private and is only
+		/// used by FSDirectory when creating this LockFactory via
+		/// the System property
+		/// Lucene.Net.Store.FSDirectoryLockFactoryClass.
+		/// </summary>
+		internal SimpleFSLockFactory() : this((System.IO.FileInfo) null)
+		{
+		}
+		
 		/// <summary> Instantiate using the provided directory (as a File instance).</summary>
 		/// <param name="lockDir">where lock files should be created.
 		/// </param>
 		public SimpleFSLockFactory(System.IO.FileInfo lockDir)
 		{
-			Init(lockDir);
+			SetLockDir(lockDir);
 		}
 		
 		/// <summary> Instantiate using the provided directory name (String).</summary>
@@ -54,42 +85,15 @@
 		public SimpleFSLockFactory(System.String lockDirName)
 		{
 			lockDir = new System.IO.FileInfo(lockDirName);
-			Init(lockDir);
+			SetLockDir(lockDir);
 		}
-
-        /// <summary>
-        /// </summary>
-        internal SimpleFSLockFactory()
-        {
-            lockDir = null;
-        }
-
-        /// <summary>
-        /// Set the lock directory.  This is package-private and is
-        /// only used externally by FSDirectory when creating this
-        /// LockFactory via the System property
-        /// org.apache.lucene.store.FSDirectoryLockFactoryClass.
-        /// </summary>
-        /// <param name="lockDir"></param>
-        internal void SetLockDir(System.IO.FileInfo lockDir)
-        {
-            this.lockDir = lockDir;
-            if (lockDir != null)
-            {
-                // Ensure that lockDir exists and is a directory.
-                if (!lockDir.Exists)
-                {
-                    if (System.IO.Directory.CreateDirectory(lockDir.FullName) == null)
-                        throw new System.IO.IOException("Cannot create directory: " + lockDir.FullName);
-                }
-                else if (!new System.IO.DirectoryInfo(lockDir.FullName).Exists)
-                {
-                    throw new System.IO.IOException("Found regular file where directory expected: " + lockDir.FullName);
-                }
-            }
-        }
 		
-		protected internal virtual void  Init(System.IO.FileInfo lockDir)
+		/// <summary> Set the lock directory.  This is package-private and is
+		/// only used externally by FSDirectory when creating this
+		/// LockFactory via the System property
+		/// Lucene.Net.Store.FSDirectoryLockFactoryClass.
+		/// </summary>
+		internal virtual void  SetLockDir(System.IO.FileInfo lockDir)
 		{
 			this.lockDir = lockDir;
 		}
@@ -203,18 +207,24 @@
 		{
 			bool tmpBool;
 			if (System.IO.File.Exists(lockFile.FullName))
+				tmpBool = true;
+			else
+				tmpBool = System.IO.Directory.Exists(lockFile.FullName);
+			bool tmpBool2;
+			if (System.IO.File.Exists(lockFile.FullName))
 			{
 				System.IO.File.Delete(lockFile.FullName);
-				tmpBool = true;
+				tmpBool2 = true;
 			}
 			else if (System.IO.Directory.Exists(lockFile.FullName))
 			{
 				System.IO.Directory.Delete(lockFile.FullName);
-				tmpBool = true;
+				tmpBool2 = true;
 			}
 			else
-				tmpBool = false;
-			bool generatedAux = tmpBool;
+				tmpBool2 = false;
+			if (tmpBool && !tmpBool2)
+				throw new LockReleaseFailedException("failed to delete " + lockFile);
 		}
 		
 		public override bool IsLocked()

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SingleInstanceLockFactory.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Store/SingleInstanceLockFactory.cs?rev=671401&r1=671400&r2=671401&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SingleInstanceLockFactory.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Store/SingleInstanceLockFactory.cs Tue Jun 24 19:50:12 2008
@@ -31,7 +31,7 @@
 	/// <seealso cref="LockFactory">
 	/// </seealso>
 	
-	public class SingleInstanceLockFactory:LockFactory
+	public class SingleInstanceLockFactory : LockFactory
 	{
 		
 		private System.Collections.Hashtable locks = new System.Collections.Hashtable();
@@ -57,7 +57,7 @@
 	}
 	
 	
-	class SingleInstanceLock:Lock
+	class SingleInstanceLock : Lock
 	{
 		
 		internal System.String lockName;