You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by do...@apache.org on 2009/07/29 20:04:24 UTC

svn commit: r798995 [8/35] - in /incubator/lucene.net/trunk/C#/src: Lucene.Net/ Lucene.Net/Analysis/ Lucene.Net/Analysis/Standard/ Lucene.Net/Document/ Lucene.Net/Index/ Lucene.Net/QueryParser/ Lucene.Net/Search/ Lucene.Net/Search/Function/ Lucene.Net/...

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriter.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Index/FreqProxTermsWriter.cs?rev=798995&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriter.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriter.cs Wed Jul 29 18:04:12 2009
@@ -0,0 +1,423 @@
+/**
+ * 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.Collections.Generic;
+
+using IndexInput = Lucene.Net.Store.IndexInput;
+using IndexOutput = Lucene.Net.Store.IndexOutput;
+using UnicodeUtil = Lucene.Net.Util.UnicodeUtil;
+
+namespace Lucene.Net.Index
+{
+    internal sealed class FreqProxTermsWriter : TermsHashConsumer
+    {
+
+        internal override TermsHashConsumerPerThread addThread(TermsHashPerThread perThread)
+        {
+            return new FreqProxTermsWriterPerThread(perThread);
+        }
+
+        internal override void createPostings(RawPostingList[] postings, int start, int count)
+        {
+            int end = start + count;
+            for (int i = start; i < end; i++)
+                postings[i] = new PostingList();
+        }
+
+        private static int compareText(char[] text1, int pos1, char[] text2, int pos2)
+        {
+            while (true)
+            {
+                char c1 = text1[pos1++];
+                char c2 = text2[pos2++];
+                if (c1 != c2)
+                {
+                    if (0xffff == c2)
+                        return 1;
+                    else if (0xffff == c1)
+                        return -1;
+                    else
+                        return c1 - c2;
+                }
+                else if (0xffff == c1)
+                    return 0;
+            }
+        }
+
+        internal override void closeDocStore(DocumentsWriter.FlushState state) { }
+        internal override void Abort() { }
+
+
+        // TODO: would be nice to factor out morme of this, eg the
+        // FreqProxFieldMergeState, and code to visit all Fields
+        // under the same FieldInfo together, up into TermsHash*.
+        // Other writers would presumably share alot of this...
+
+        internal override void flush(IDictionary<object, object> threadsAndFields, DocumentsWriter.FlushState state)
+        {
+
+            // Gather all FieldData's that have postings, across all
+            // ThreadStates
+            List<object> allFields = new List<object>();
+
+            IEnumerator<KeyValuePair<object, object>> it = threadsAndFields.GetEnumerator();
+            while (it.MoveNext())
+            {
+
+                KeyValuePair<object, object> entry = (KeyValuePair<object, object>)it.Current;
+
+                ICollection<object> fields = (ICollection<object>)entry.Value;
+
+                IEnumerator<object> fieldsIt = fields.GetEnumerator();
+
+                while (fieldsIt.MoveNext())
+                {
+                    FreqProxTermsWriterPerField perField = (FreqProxTermsWriterPerField)fieldsIt.Current;
+                    if (perField.termsHashPerField.numPostings > 0)
+                        allFields.Add(perField);
+                }
+            }
+
+            // Sort by field name
+            allFields.Sort();
+            int numAllFields = allFields.Count;
+
+            TermInfosWriter termsOut = new TermInfosWriter(state.directory,
+                                                                 state.segmentName,
+                                                                 fieldInfos,
+                                                                 state.docWriter.writer.GetTermIndexInterval());
+
+            IndexOutput freqOut = state.directory.CreateOutput(state.SegmentFileName(IndexFileNames.FREQ_EXTENSION));
+            IndexOutput proxOut;
+
+            if (fieldInfos.HasProx())
+                proxOut = state.directory.CreateOutput(state.SegmentFileName(IndexFileNames.PROX_EXTENSION));
+            else
+                proxOut = null;
+
+            DefaultSkipListWriter skipListWriter = new DefaultSkipListWriter(termsOut.skipInterval,
+                                                                                   termsOut.maxSkipLevels,
+                                                                                   state.numDocsInRAM, freqOut, proxOut);
+
+            int start = 0;
+            while (start < numAllFields)
+            {
+                FieldInfo fieldInfo = ((FreqProxTermsWriterPerField)allFields[start]).fieldInfo;
+                string fieldName = fieldInfo.name;
+
+                int end = start + 1;
+                while (end < numAllFields && ((FreqProxTermsWriterPerField)allFields[end]).fieldInfo.name.Equals(fieldName))
+                    end++;
+
+                FreqProxTermsWriterPerField[] fields = new FreqProxTermsWriterPerField[end - start];
+                for (int i = start; i < end; i++)
+                {
+                    fields[i - start] = (FreqProxTermsWriterPerField)allFields[i];
+
+                    // Aggregate the storePayload as seen by the same
+                    // field across multiple threads
+                    fieldInfo.storePayloads |= fields[i - start].hasPayloads;
+                }
+
+                // If this field has postings then add them to the
+                // segment
+                AppendPostings(state, fields, termsOut, freqOut, proxOut, skipListWriter);
+
+                for (int i = 0; i < fields.Length; i++)
+                {
+                    TermsHashPerField perField = fields[i].termsHashPerField;
+                    int numPostings = perField.numPostings;
+                    perField.reset();
+                    perField.shrinkHash(numPostings);
+                    fields[i].reset();
+                }
+
+                start = end;
+            }
+
+            it = threadsAndFields.GetEnumerator();
+            while (it.MoveNext())
+            {
+                KeyValuePair<object, object> entry = (KeyValuePair<object, object>)it.Current;
+                FreqProxTermsWriterPerThread perThread = (FreqProxTermsWriterPerThread)entry.Key;
+                perThread.termsHashPerThread.reset(true);
+            }
+
+            freqOut.Close();
+            if (proxOut != null)
+            {
+                state.flushedFiles[state.SegmentFileName(IndexFileNames.PROX_EXTENSION)] = state.SegmentFileName(IndexFileNames.PROX_EXTENSION);
+                proxOut.Close();
+            }
+            termsOut.Close();
+
+            // Record all files we have flushed
+            state.flushedFiles[state.SegmentFileName(IndexFileNames.FIELD_INFOS_EXTENSION)] = state.SegmentFileName(IndexFileNames.FIELD_INFOS_EXTENSION);
+            state.flushedFiles[state.SegmentFileName(IndexFileNames.FREQ_EXTENSION)] = state.SegmentFileName(IndexFileNames.FREQ_EXTENSION);
+            state.flushedFiles[state.SegmentFileName(IndexFileNames.TERMS_EXTENSION)] = state.SegmentFileName(IndexFileNames.TERMS_EXTENSION);
+            state.flushedFiles[state.SegmentFileName(IndexFileNames.TERMS_INDEX_EXTENSION)] = state.SegmentFileName(IndexFileNames.TERMS_INDEX_EXTENSION);
+        }
+
+        byte[] copyByteBuffer = new byte[4096];
+
+        /** Copy numBytes from srcIn to destIn */
+        void copyBytes(IndexInput srcIn, IndexOutput destIn, long numBytes)
+        {
+            // TODO: we could do this more efficiently (save a copy)
+            // because it's always from a ByteSliceReader ->
+            // IndexOutput
+            while (numBytes > 0)
+            {
+                int chunk;
+                if (numBytes > 4096)
+                    chunk = 4096;
+                else
+                    chunk = (int)numBytes;
+                srcIn.ReadBytes(copyByteBuffer, 0, chunk);
+                destIn.WriteBytes(copyByteBuffer, 0, chunk);
+                numBytes -= chunk;
+            }
+        }
+
+        /* Walk through all unique text tokens (Posting
+         * instances) found in this field and serialize them
+         * into a single RAM segment. */
+        void AppendPostings(DocumentsWriter.FlushState flushState,
+                            FreqProxTermsWriterPerField[] fields,
+                            TermInfosWriter termsOut,
+                            IndexOutput freqOut,
+                            IndexOutput proxOut,
+                            DefaultSkipListWriter skipListWriter)
+        {
+
+            int fieldNumber = fields[0].fieldInfo.number;
+            int numFields = fields.Length;
+
+            FreqProxFieldMergeState[] mergeStates = new FreqProxFieldMergeState[numFields];
+
+            for (int i = 0; i < numFields; i++)
+            {
+                FreqProxFieldMergeState fms = mergeStates[i] = new FreqProxFieldMergeState(fields[i]);
+
+                System.Diagnostics.Debug.Assert(fms.field.fieldInfo == fields[0].fieldInfo);
+
+                // Should always be true
+                bool result = fms.nextTerm();
+                System.Diagnostics.Debug.Assert(result);
+            }
+
+            int skipInterval = termsOut.skipInterval;
+            bool currentFieldOmitTf = fields[0].fieldInfo.omitTf;
+
+            // If current field omits tf then it cannot store
+            // payloads.  We silently drop the payloads in this case:
+            bool currentFieldStorePayloads = currentFieldOmitTf ? false : fields[0].fieldInfo.storePayloads;
+
+            FreqProxFieldMergeState[] termStates = new FreqProxFieldMergeState[numFields];
+
+            while (numFields > 0)
+            {
+
+                // Get the next term to merge
+                termStates[0] = mergeStates[0];
+                int numToMerge = 1;
+
+                for (int i = 1; i < numFields; i++)
+                {
+                    char[] text = mergeStates[i].text;
+                    int textOffset = mergeStates[i].textOffset;
+                    int cmp = compareText(text, textOffset, termStates[0].text, termStates[0].textOffset);
+
+                    if (cmp < 0)
+                    {
+                        termStates[0] = mergeStates[i];
+                        numToMerge = 1;
+                    }
+                    else if (cmp == 0)
+                        termStates[numToMerge++] = mergeStates[i];
+                }
+
+                int df = 0;
+                int lastPayloadLength = -1;
+
+                int lastDoc = 0;
+
+                char[] text_Renamed = termStates[0].text;
+                int start = termStates[0].textOffset;
+
+                long freqPointer = freqOut.GetFilePointer();
+                long proxPointer;
+                if (proxOut != null)
+                    proxPointer = proxOut.GetFilePointer();
+                else
+                    proxPointer = 0;
+
+                skipListWriter.ResetSkip();
+
+                // Now termStates has numToMerge FieldMergeStates
+                // which all share the same term.  Now we must
+                // interleave the docID streams.
+                while (numToMerge > 0)
+                {
+
+                    if ((++df % skipInterval) == 0)
+                    {
+                        skipListWriter.SetSkipData(lastDoc, currentFieldStorePayloads, lastPayloadLength);
+                        skipListWriter.BufferSkip(df);
+                    }
+
+                    FreqProxFieldMergeState minState = termStates[0];
+                    for (int i = 1; i < numToMerge; i++)
+                        if (termStates[i].docID < minState.docID)
+                            minState = termStates[i];
+
+                    int doc = minState.docID;
+                    int termDocFreq = minState.termFreq;
+
+                    System.Diagnostics.Debug.Assert(doc < flushState.numDocsInRAM);
+                    System.Diagnostics.Debug.Assert(doc > lastDoc || df == 1);
+
+                    ByteSliceReader prox = minState.prox;
+
+                    // Carefully copy over the prox + payload info,
+                    // changing the format to match Lucene's segment
+                    // format.
+                    if (!currentFieldOmitTf)
+                    {
+                        // omitTf == false so we do write positions & payload          
+                        System.Diagnostics.Debug.Assert(proxOut != null);
+                        for (int j = 0; j < termDocFreq; j++)
+                        {
+                            int code = prox.ReadVInt();
+                            if (currentFieldStorePayloads)
+                            {
+                                int payloadLength;
+                                if ((code & 1) != 0)
+                                {
+                                    // This position has a payload
+                                    payloadLength = prox.ReadVInt();
+                                }
+                                else
+                                    payloadLength = 0;
+                                if (payloadLength != lastPayloadLength)
+                                {
+                                    proxOut.WriteVInt(code | 1);
+                                    proxOut.WriteVInt(payloadLength);
+                                    lastPayloadLength = payloadLength;
+                                }
+                                else
+                                    proxOut.WriteVInt(code & (~1));
+                                if (payloadLength > 0)
+                                    copyBytes(prox, proxOut, payloadLength);
+                            }
+                            else
+                            {
+                                System.Diagnostics.Debug.Assert(0 == (code & 1));
+                                proxOut.WriteVInt(code >> 1);
+                            }
+                        } //End for
+
+                        int newDocCode = (doc - lastDoc) << 1;
+
+                        if (1 == termDocFreq)
+                        {
+                            freqOut.WriteVInt(newDocCode | 1);
+                        }
+                        else
+                        {
+                            freqOut.WriteVInt(newDocCode);
+                            freqOut.WriteVInt(termDocFreq);
+                        }
+                    }
+                    else
+                    {
+                        // omitTf==true: we store only the docs, without
+                        // term freq, positions, payloads
+                        freqOut.WriteVInt(doc - lastDoc);
+                    }
+
+                    lastDoc = doc;
+
+                    if (!minState.nextDoc())
+                    {
+
+                        // Remove from termStates
+                        int upto = 0;
+                        for (int i = 0; i < numToMerge; i++)
+                            if (termStates[i] != minState)
+                                termStates[upto++] = termStates[i];
+                        numToMerge--;
+                        System.Diagnostics.Debug.Assert(upto == numToMerge);
+
+                        // Advance this state to the next term
+
+                        if (!minState.nextTerm())
+                        {
+                            // OK, no more terms, so remove from mergeStates
+                            // as well
+                            upto = 0;
+                            for (int i = 0; i < numFields; i++)
+                                if (mergeStates[i] != minState)
+                                    mergeStates[upto++] = mergeStates[i];
+                            numFields--;
+                            System.Diagnostics.Debug.Assert(upto == numFields);
+                        }
+                    }
+                }
+
+                System.Diagnostics.Debug.Assert(df > 0);
+
+                // Done merging this term
+
+                long skipPointer = skipListWriter.WriteSkip(freqOut);
+
+                // Write term
+                termInfo.Set(df, freqPointer, proxPointer, (int)(skipPointer - freqPointer));
+
+                // TODO: we could do this incrementally
+                UnicodeUtil.UTF16toUTF8(text_Renamed, start, termsUTF8);
+
+                // TODO: we could save O(n) re-scan of the term by
+                // computing the shared prefix with the last term
+                // while during the UTF8 encoding
+                termsOut.Add(fieldNumber,
+                             termsUTF8.result,
+                             termsUTF8.length,
+                             termInfo);
+            }
+        }
+
+        private readonly TermInfo termInfo = new TermInfo(); // minimize consing
+
+        internal readonly UnicodeUtil.UTF8Result termsUTF8 = new UnicodeUtil.UTF8Result();
+
+        void files(ICollection<object> files) { }
+
+        internal sealed class PostingList : RawPostingList
+        {
+            internal int docFreq;                                    // # times this term occurs in the current doc
+            internal int lastDocID;                                  // Last docID where this term occurred
+            internal int lastDocCode;                                // Code for prior doc
+            internal int lastPosition;                               // Last position where this term occurred
+        }
+
+        internal override int bytesPerPosting()
+        {
+            return RawPostingList.BYTES_SIZE + 4 * DocumentsWriter.INT_NUM_BYTE;
+        }
+    }
+}

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriterPerField.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Index/FreqProxTermsWriterPerField.cs?rev=798995&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriterPerField.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriterPerField.cs Wed Jul 29 18:04:12 2009
@@ -0,0 +1,165 @@
+/**
+ * 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 Fieldable = Lucene.Net.Documents.Fieldable;
+using Token = Lucene.Net.Analysis.Token;
+
+namespace Lucene.Net.Index
+{
+    // TODO: break into separate freq and prox writers as
+    // codecs; make separate container (tii/tis/skip/*) that can
+    // be configured as any number of files 1..N
+    internal sealed class FreqProxTermsWriterPerField : TermsHashConsumerPerField, System.IComparable
+    {
+        internal readonly FreqProxTermsWriterPerThread perThread;
+        internal readonly TermsHashPerField termsHashPerField;
+        internal readonly FieldInfo fieldInfo;
+        internal readonly DocumentsWriter.DocState docState;
+        internal readonly DocInverter.FieldInvertState fieldState;
+        internal bool omitTf;
+
+        public FreqProxTermsWriterPerField(TermsHashPerField termsHashPerField, FreqProxTermsWriterPerThread perThread, FieldInfo fieldInfo)
+        {
+            this.termsHashPerField = termsHashPerField;
+            this.perThread = perThread;
+            this.fieldInfo = fieldInfo;
+            docState = termsHashPerField.docState;
+            fieldState = termsHashPerField.fieldState;
+            omitTf = fieldInfo.omitTf;
+        }
+
+        internal override int getStreamCount()
+        {
+            if (fieldInfo.omitTf)
+                return 1;
+            else
+                return 2;
+        }
+
+        internal override void finish() { }
+
+        internal bool hasPayloads;
+
+        internal override void skippingLongTerm(Token t) { }
+
+        public int CompareTo(object other0)
+        {
+            FreqProxTermsWriterPerField other = (FreqProxTermsWriterPerField)other0;
+            return string.CompareOrdinal(fieldInfo.name, other.fieldInfo.name);
+        }
+
+        internal void reset()
+        {
+            // Record, up front, whether our in-RAM format will be
+            // with or without term freqs:
+            omitTf = fieldInfo.omitTf;
+        }
+
+        internal override bool start(Fieldable[] fields, int count)
+        {
+            for (int i = 0; i < count; i++)
+                if (fields[i].IsIndexed())
+                    return true;
+            return false;
+        }
+
+        internal void writeProx(Token t, FreqProxTermsWriter.PostingList p, int proxCode)
+        {
+            Payload payload = t.GetPayload();
+            if (payload != null && payload.length > 0)
+            {
+                termsHashPerField.writeVInt(1, (proxCode << 1) | 1);
+                termsHashPerField.writeVInt(1, payload.length);
+                termsHashPerField.writeBytes(1, payload.data, payload.offset, payload.length);
+                hasPayloads = true;
+            }
+            else
+                termsHashPerField.writeVInt(1, proxCode << 1);
+            p.lastPosition = fieldState.position;
+        }
+
+        internal override void newTerm(Token t, RawPostingList p0)
+        {
+            // First time we're seeing this term since the last
+            // flush
+            System.Diagnostics.Debug.Assert(docState.TestPoint("FreqProxTermsWriterPerField.newTerm start"));
+            FreqProxTermsWriter.PostingList p = (FreqProxTermsWriter.PostingList)p0;
+            p.lastDocID = docState.docID;
+            if (omitTf)
+            {
+                p.lastDocCode = docState.docID;
+            }
+            else
+            {
+                p.lastDocCode = docState.docID << 1;
+                p.docFreq = 1;
+                writeProx(t, p, fieldState.position);
+            }
+        }
+
+        internal override void addTerm(Token t, RawPostingList p0)
+        {
+
+            System.Diagnostics.Debug.Assert(docState.TestPoint("FreqProxTermsWriterPerField.addTerm start"));
+
+            FreqProxTermsWriter.PostingList p = (FreqProxTermsWriter.PostingList)p0;
+
+            System.Diagnostics.Debug.Assert(omitTf || p.docFreq > 0);
+
+            if (omitTf)
+            {
+                if (docState.docID != p.lastDocID)
+                {
+                    System.Diagnostics.Debug.Assert(docState.docID > p.lastDocID);
+                    termsHashPerField.writeVInt(0, p.lastDocCode);
+                    p.lastDocCode = docState.docID - p.lastDocID;
+                    p.lastDocID = docState.docID;
+                }
+            }
+            else
+            {
+                if (docState.docID != p.lastDocID)
+                {
+                    System.Diagnostics.Debug.Assert(docState.docID > p.lastDocID);
+                    // Term not yet seen in the current doc but previously
+                    // seen in other doc(s) since the last flush
+
+                    // Now that we know doc freq for previous doc,
+                    // write it & lastDocCode
+                    if (1 == p.docFreq)
+                        termsHashPerField.writeVInt(0, p.lastDocCode | 1);
+                    else
+                    {
+                        termsHashPerField.writeVInt(0, p.lastDocCode);
+                        termsHashPerField.writeVInt(0, p.docFreq);
+                    }
+                    p.docFreq = 1;
+                    p.lastDocCode = (docState.docID - p.lastDocID) << 1;
+                    p.lastDocID = docState.docID;
+                    writeProx(t, p, fieldState.position);
+                }
+                else
+                {
+                    p.docFreq++;
+                    writeProx(t, p, fieldState.position - p.lastPosition);
+                }
+            }
+        }
+
+        public void abort() { }
+    }
+}
\ No newline at end of file

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriterPerThread.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Index/FreqProxTermsWriterPerThread.cs?rev=798995&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriterPerThread.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/FreqProxTermsWriterPerThread.cs Wed Jul 29 18:04:12 2009
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+namespace Lucene.Net.Index
+{
+    internal sealed class FreqProxTermsWriterPerThread : TermsHashConsumerPerThread
+    {
+        internal readonly TermsHashPerThread termsHashPerThread;
+        internal readonly DocumentsWriter.DocState docState;
+
+        public FreqProxTermsWriterPerThread(TermsHashPerThread perThread)
+        {
+            docState = perThread.docState;
+            termsHashPerThread = perThread;
+        }
+
+        public override TermsHashConsumerPerField addField(TermsHashPerField termsHashPerField, FieldInfo fieldInfo)
+        {
+            return new FreqProxTermsWriterPerField(termsHashPerField, this, fieldInfo);
+        }
+
+        internal override void startDocument()
+        {
+        }
+
+        internal override DocumentsWriter.DocWriter finishDocument()
+        {
+            return null;
+        }
+
+        public override void abort() { }
+    }
+}

Added: incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexCommit.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Index/IndexCommit.cs?rev=798995&view=auto
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexCommit.cs (added)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexCommit.cs Wed Jul 29 18:04:12 2009
@@ -0,0 +1,117 @@
+/**
+ * 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 Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Index
+{
+    /// <summary>
+    /// Deprecated.  Please subclass Indexcommit class instead.
+    /// </summary>
+    public abstract class IndexCommit : IndexCommitPoint
+    {
+
+        /**
+         * Get the segments file (<code>segments_N</code>) associated 
+         * with this commit point.
+         */
+        public abstract string GetSegmentsFileName();
+
+        /**
+         * Returns all index files referenced by this commit point.
+         */
+        public abstract System.Collections.Generic.ICollection<string> GetFileNames();
+
+        /**
+         * Returns the {@link Directory} for the index.
+         */
+        public abstract Directory GetDirectory();
+
+        /**
+         * Delete this commit point.  This only applies when using
+         * the commit point in the context of IndexWriter's
+         * IndexDeletionPolicy.
+         * <p>
+         * Upon calling this, the writer is notified that this commit 
+         * point should be deleted. 
+         * <p>
+         * Decision that a commit-point should be deleted is taken by the {@link IndexDeletionPolicy} in effect
+         * and therefore this should only be called by its {@link IndexDeletionPolicy#onInit onInit()} or 
+         * {@link IndexDeletionPolicy#onCommit onCommit()} methods.
+        */
+        public virtual void Delete()
+        {
+            throw new System.Exception("This IndexCommit does not support this method.");
+        }
+
+        public virtual bool IsDeleted()
+        {
+            throw new System.Exception("This IndexCommit does not support this method.");
+        }
+
+        /**
+         * Returns true if this commit is an optimized index.
+         */
+        public virtual bool IsOptimized()
+        {
+            throw new System.Exception("This IndexCommit does not support this method.");
+        }
+
+        /**
+         * Two IndexCommits are equal if both their Directory and versions are equal.
+         */
+        public override bool Equals(object other)
+        {
+            if (other is IndexCommit)
+            {
+                IndexCommit otherCommit = (IndexCommit)other;
+                return otherCommit.GetDirectory().Equals(GetDirectory()) && otherCommit.GetVersion() == GetVersion();
+            }
+            else
+                return false;
+        }
+
+        public override int GetHashCode()
+        {
+            return GetDirectory().GetHashCode() + GetSegmentsFileName().GetHashCode();
+        }
+
+        /** Returns the version for this IndexCommit.  This is the
+            same value that {@link IndexReader#getVersion} would
+            return if it were opened on this commit. */
+        public virtual long GetVersion()
+        {
+            throw new System.Exception("This IndexCommit does not support this method.");
+        }
+
+        /** Returns the generation (the _N in segments_N) for this
+            IndexCommit */
+        public virtual long GetGeneration()
+        {
+            throw new System.Exception("This IndexCommit does not support this method.");
+        }
+
+        /** Convenience method that returns the last modified time
+         *  of the segments_N file corresponding to this index
+         *  commit, equivalent to
+         *  getDirectory().fileModified(getSegmentsFileName()). */
+        public long GetTimestamp()
+        {
+            return GetDirectory().FileModified(GetSegmentsFileName());
+        }
+    }
+}

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexCommitPoint.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Index/IndexCommitPoint.cs?rev=798995&r1=798994&r2=798995&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexCommitPoint.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexCommitPoint.cs Wed Jul 29 18:04:12 2009
@@ -29,7 +29,6 @@
 /// index commit point would have a larger N.
 /// </summary>
 
-using System;
 
 namespace Lucene.Net.Index
 {
@@ -40,10 +39,10 @@
 		/// <summary> Get the segments file (<code>segments_N</code>) associated 
 		/// with this commit point.
 		/// </summary>
-		System.String GetSegmentsFileName();
+		string GetSegmentsFileName();
 		
 		/// <summary> Returns all index files referenced by this commit point.</summary>
-		System.Collections.ICollection GetFileNames();
+		System.Collections.Generic.ICollection<string> GetFileNames();
 		
 		/// <summary> Delete this commit point.
 		/// <p>
@@ -54,6 +53,6 @@
 		/// and therefore this should only be called by its {@link IndexDeletionPolicy#onInit onInit()} or 
 		/// {@link IndexDeletionPolicy#onCommit onCommit()} methods.
 		/// </summary>
-		void  Delete();
+		void Delete();
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexDeletionPolicy.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Index/IndexDeletionPolicy.cs?rev=798995&r1=798994&r2=798995&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexDeletionPolicy.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexDeletionPolicy.cs Wed Jul 29 18:04:12 2009
@@ -15,17 +15,17 @@
  * limitations under the License.
  */
 
-using System;
+using System.Collections.Generic;
 
 namespace Lucene.Net.Index
 {
 	
-	/// <summary> <p>Expert: policy for deletion of stale {@link IndexCommitPoint index commits}. 
+	/// <summary> <p>Expert: policy for deletion of stale {@link IndexCommit index commits}. 
 	/// 
 	/// <p>Implement this interface, and pass it to one
 	/// of the {@link IndexWriter} or {@link IndexReader}
 	/// constructors, to customize when older
-	/// {@link IndexCommitPoint point-in-time commits}
+	/// {@link IndexCommit point-in-time commits}
 	/// are deleted from the index directory.  The default deletion policy
 	/// is {@link KeepOnlyLastCommitDeletionPolicy}, which always
 	/// removes old commits as soon as a new commit is done (this
@@ -57,8 +57,8 @@
 		/// <p>The writer locates all index commits present in the 
 		/// index directory and calls this method.  The policy may 
 		/// choose to delete some of the commit points, doing so by
-		/// calling method {@link IndexCommitPoint#delete delete()} 
-		/// of {@link IndexCommitPoint}.</p>
+		/// calling method {@link IndexCommit#delete delete()} 
+		/// of {@link IndexCommit}.</p>
 		/// 
 		/// <p><u>Note:</u> the last CommitPoint is the most recent one,
 		/// i.e. the "front index state". Be careful not to delete it,
@@ -67,18 +67,18 @@
 		/// 
 		/// </summary>
 		/// <param name="commits">List of current 
-		/// {@link IndexCommitPoint point-in-time commits},
+		/// {@link IndexCommit point-in-time commits},
 		/// sorted by age (the 0th one is the oldest commit).
 		/// </param>
-		void  OnInit(System.Collections.IList commits);
+		void  OnInit(List<IndexCommitPoint> commits);
 		
 		/// <summary> <p>This is called each time the writer completed a commit.
 		/// This gives the policy a chance to remove old commit points
 		/// with each commit.</p>
 		/// 
 		/// <p>The policy may now choose to delete old commit points 
-		/// by calling method {@link IndexCommitPoint#delete delete()} 
-		/// of {@link IndexCommitPoint}.</p>
+		/// by calling method {@link IndexCommit#delete delete()} 
+		/// of {@link IndexCommit}.</p>
 		/// 
 		/// <p>If writer has <code>autoCommit = true</code> then
 		/// this method will in general be called many times during
@@ -94,9 +94,9 @@
 		/// you can afford to lose the index content while doing that.
 		/// 
 		/// </summary>
-		/// <param name="commits">List of {@link IndexCommitPoint},
+		/// <param name="commits">List of {@link IndexCommit},
 		/// sorted by age (the 0th one is the oldest commit).
 		/// </param>
-		void  OnCommit(System.Collections.IList commits);
+		void  OnCommit(List<IndexCommitPoint> commits);
 	}
 }
\ No newline at end of file

Modified: incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexFileDeleter.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/trunk/C%23/src/Lucene.Net/Index/IndexFileDeleter.cs?rev=798995&r1=798994&r2=798995&view=diff
==============================================================================
--- incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexFileDeleter.cs (original)
+++ incubator/lucene.net/trunk/C#/src/Lucene.Net/Index/IndexFileDeleter.cs Wed Jul 29 18:04:12 2009
@@ -15,710 +15,753 @@
  * limitations under the License.
  */
 
-using System;
+using System.Collections.Generic;
 
 using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Index
 {
-	
-	/*
-	* This class keeps track of each SegmentInfos instance that
-	* is still "live", either because it corresponds to a 
-	* segments_N file in the Directory (a "commit", i.e. a 
-	* committed SegmentInfos) or because it's the in-memory SegmentInfos 
-	* that a writer is actively updating but has not yet committed 
-	* (currently this only applies when autoCommit=false in IndexWriter).
-	* This class uses simple reference counting to map the live
-	* SegmentInfos instances to individual files in the Directory. 
-	* 
-	* The same directory file may be referenced by more than
-	* one IndexCommitPoints, i.e. more than one SegmentInfos.
-	* Therefore we count how many commits reference each file.
-	* When all the commits referencing a certain file have been
-	* deleted, the refcount for that file becomes zero, and the
-	* file is deleted.
-	*
-	* A separate deletion policy interface
-	* (IndexDeletionPolicy) is consulted on creation (onInit)
-	* and once per commit (onCommit), to decide when a commit
-	* should be removed.
-	* 
-	* It is the business of the IndexDeletionPolicy to choose
-	* when to delete commit points.  The actual mechanics of
-	* file deletion, retrying, etc, derived from the deletion
-	* of commit points is the business of the IndexFileDeleter.
-	* 
-	* The current default deletion policy is {@link
-	* KeepOnlyLastCommitDeletionPolicy}, which removes all
-	* prior commits when a new commit has completed.  This
-	* matches the behavior before 2.2.
-	*
-	* Note that you must hold the write.lock before
-	* instantiating this class.  It opens segments_N file(s)
-	* directly with no retry logic.
-	*/
-	
-	sealed public class IndexFileDeleter
-	{
-		
-		/* Files that we tried to delete but failed (likely
-		* because they are open and we are running on Windows),
-		* so we will retry them again later: */
-		private System.Collections.IList deletable;
-		
-		/* Reference count for all files in the index.  
-		* Counts how many existing commits reference a file.
-		* Maps String to RefCount (class below) instances: */
-		private System.Collections.IDictionary refCounts = new System.Collections.Hashtable();
-		
-		/* Holds all commits (segments_N) currently in the index.
-		* This will have just 1 commit if you are using the
-		* default delete policy (KeepOnlyLastCommitDeletionPolicy).
-		* Other policies may leave commit points live for longer
-		* in which case this list would be longer than 1: */
-		private System.Collections.ArrayList commits = new System.Collections.ArrayList();
-		
-		/* Holds files we had incref'd from the previous
-		* non-commit checkpoint: */
-		private System.Collections.IList lastFiles = new System.Collections.ArrayList();
-		
-		/* Commits that the IndexDeletionPolicy have decided to delete: */
-		private System.Collections.IList commitsToDelete = new System.Collections.ArrayList();
+
+    /*
+     * This class keeps track of each SegmentInfos instance that
+     * is still "live", either because it corresponds to a
+     * segments_N file in the Directory (a "commit", i.e. a
+     * committed SegmentInfos) or because it's an in-memory
+     * SegmentInfos that a writer is actively updating but has
+     * not yet committed.  This class uses simple reference
+     * counting to map the live SegmentInfos instances to
+     * individual files in the Directory.
+     *
+     * When autoCommit=true, IndexWriter currently commits only
+     * on completion of a merge (though this may change with
+     * time: it is not a guarantee).  When autoCommit=false,
+     * IndexWriter only commits when it is closed.  Regardless
+     * of autoCommit, the user may call IndexWriter.commit() to
+     * force a blocking commit.
+     * 
+     * The same directory file may be referenced by more than
+     * one IndexCommit, i.e. more than one SegmentInfos.
+     * Therefore we count how many commits reference each file.
+     * When all the commits referencing a certain file have been
+     * deleted, the refcount for that file becomes zero, and the
+     * file is deleted.
+     *
+     * A separate deletion policy interface
+     * (IndexDeletionPolicy) is consulted on creation (onInit)
+     * and once per commit (onCommit), to decide when a commit
+     * should be removed.
+     * 
+     * It is the business of the IndexDeletionPolicy to choose
+     * when to delete commit points.  The actual mechanics of
+     * file deletion, retrying, etc, derived from the deletion
+     * of commit points is the business of the IndexFileDeleter.
+     * 
+     * The current default deletion policy is {@link
+     * KeepOnlyLastCommitDeletionPolicy}, which removes all
+     * prior commits when a new commit has completed.  This
+     * matches the behavior before 2.2.
+     *
+     * Note that you must hold the write.lock before
+     * instantiating this class.  It opens segments_N file(s)
+     * directly with no retry logic.
+     */
+    sealed public class IndexFileDeleter
+    {
+        /* Files that we tried to delete but failed (likely
+        * because they are open and we are running on Windows),
+        * so we will retry them again later: */
+        private List<string> deletable;
+
+        /* Reference count for all files in the index.  
+        * Counts how many existing commits reference a file.
+        * Maps string to RefCount (class below) instances: */
+        private Dictionary<string,RefCount> refCounts = new Dictionary<string,RefCount>();
+
+        /* Holds all commits (segments_N) currently in the index.
+        * This will have just 1 commit if you are using the
+        * default delete policy (KeepOnlyLastCommitDeletionPolicy).
+        * Other policies may leave commit points live for longer
+        * in which case this list would be longer than 1: */
+        private List<IndexCommitPoint> commits = new List<IndexCommitPoint>();
+
+        /* Holds files we had incref'd from the previous
+        * non-commit checkpoint: */
+        private List<string> lastFiles = new List<string>();
+
+        /* Commits that the IndexDeletionPolicy have decided to delete: */
+        private List<IndexCommitPoint> commitsToDelete = new List<IndexCommitPoint>();
 
         private System.IO.TextWriter infoStream;
-		private Directory directory;
-		private IndexDeletionPolicy policy;
-		private DocumentsWriter docWriter;
-		
-		/// <summary>Change to true to see details of reference counts when
-		/// infoStream != null 
-		/// </summary>
-		public static bool VERBOSE_REF_COUNTS = false;
-		
-		internal void  SetInfoStream(System.IO.TextWriter infoStream)
-		{
-			this.infoStream = infoStream;
-			if (infoStream != null)
-			{
-				Message("setInfoStream deletionPolicy=" + policy);
-			}
-		}
-		
-		private void  Message(System.String message)
-		{
-			infoStream.WriteLine("IFD [" + SupportClass.ThreadClass.Current().Name + "]: " + message);
-		}
-		
-		/// <summary> Initialize the deleter: find all previous commits in
-		/// the Directory, incref the files they reference, call
-		/// the policy to let it delete commits.  The incoming
-		/// segmentInfos must have been loaded from a commit point
-		/// and not yet modified.  This will remove any files not
-		/// referenced by any of the commits.
-		/// </summary>
-		/// <throws>  CorruptIndexException if the index is corrupt </throws>
-		/// <throws>  IOException if there is a low-level IO error </throws>
-		public IndexFileDeleter(Directory directory, IndexDeletionPolicy policy, SegmentInfos segmentInfos, System.IO.TextWriter infoStream, DocumentsWriter docWriter)
-		{
-			
-			this.docWriter = docWriter;
-			this.infoStream = infoStream;
-			
-			if (infoStream != null)
-			{
-				Message("init: current segments file is \"" + segmentInfos.GetCurrentSegmentFileName() + "\"; deletionPolicy=" + policy);
-			}
-			
-			this.policy = policy;
-			this.directory = directory;
-			
-			// First pass: walk the files and initialize our ref
-			// counts:
-			long currentGen = segmentInfos.GetGeneration();
-			IndexFileNameFilter filter = IndexFileNameFilter.GetFilter();
-			
-			System.String[] files = directory.List();
-			if (files == null)
-			{
-				throw new System.IO.IOException("cannot read directory " + directory + ": list() returned null");
-			}
-			
-			CommitPoint currentCommitPoint = null;
-			
-			for (int i = 0; i < files.Length; i++)
-			{
-				
-				System.String fileName = files[i];
-				
-				if (filter.Accept(null, fileName) && !fileName.Equals(IndexFileNames.SEGMENTS_GEN))
-				{
-					
-					// Add this file to refCounts with initial count 0:
-					GetRefCount(fileName);
-					
-					if (fileName.StartsWith(IndexFileNames.SEGMENTS))
-					{
-						
-						// This is a commit (segments or segments_N), and
-						// it's valid (<= the max gen).  Load it, then
-						// incref all files it refers to:
-						if (SegmentInfos.GenerationFromSegmentsFileName(fileName) <= currentGen)
-						{
-							if (infoStream != null)
-							{
-								Message("init: load commit \"" + fileName + "\"");
-							}
-							SegmentInfos sis = new SegmentInfos();
-							try
-							{
-								sis.Read(directory, fileName);
-							}
-							catch (System.IO.FileNotFoundException e)
-							{
-								// LUCENE-948: on NFS (and maybe others), if
-								// you have writers switching back and forth
-								// between machines, it's very likely that the
-								// dir listing will be stale and will claim a
-								// file segments_X exists when in fact it
-								// doesn't.  So, we catch this and handle it
-								// as if the file does not exist
-								if (infoStream != null)
-								{
-									Message("init: hit FileNotFoundException when loading commit \"" + fileName + "\"; skipping this commit point");
-								}
-								sis = null;
-							}
-							if (sis != null)
-							{
-								CommitPoint commitPoint = new CommitPoint(this, sis);
-								if (sis.GetGeneration() == segmentInfos.GetGeneration())
-								{
-									currentCommitPoint = commitPoint;
-								}
-								commits.Add(commitPoint);
-								IncRef(sis, true);
-							}
-						}
-					}
-				}
-			}
-			
-			if (currentCommitPoint == null)
-			{
-				// We did not in fact see the segments_N file
-				// corresponding to the segmentInfos that was passed
-				// in.  Yet, it must exist, because our caller holds
-				// the write lock.  This can happen when the directory
-				// listing was stale (eg when index accessed via NFS
-				// client with stale directory listing cache).  So we
-				// try now to explicitly open this commit point:
-				SegmentInfos sis = new SegmentInfos();
-				try
-				{
-					sis.Read(directory, segmentInfos.GetCurrentSegmentFileName());
-				}
-				catch (System.IO.IOException e)
-				{
-					throw new CorruptIndexException("failed to locate current segments_N file");
-				}
-				if (infoStream != null)
-					Message("forced open of current segments file " + segmentInfos.GetCurrentSegmentFileName());
-				currentCommitPoint = new CommitPoint(this, sis);
-				commits.Add(currentCommitPoint);
-				IncRef(sis, true);
-			}
-			
-			// We keep commits list in sorted order (oldest to newest):
-			commits.Sort();
-			
-			// Now delete anything with ref count at 0.  These are
-			// presumably abandoned files eg due to crash of
-			// IndexWriter.
-			System.Collections.IEnumerator it = refCounts.Keys.GetEnumerator();
-			while (it.MoveNext())
-			{
-				System.String fileName = (System.String) it.Current;
-				RefCount rc = (RefCount) refCounts[fileName];
-				if (0 == rc.count)
-				{
-					if (infoStream != null)
-					{
-						Message("init: removing unreferenced file \"" + fileName + "\"");
-					}
-					DeleteFile(fileName);
-				}
-			}
-			
-			// Finally, give policy a chance to remove things on
-			// startup:
-			policy.OnInit(commits);
-			
-			// It's OK for the onInit to remove the current commit
-			// point; we just have to checkpoint our in-memory
-			// SegmentInfos to protect those files that it uses:
-			if (currentCommitPoint.deleted)
-			{
-				Checkpoint(segmentInfos, false);
-			}
-			
-			DeleteCommits();
-		}
-		
-		/// <summary> Remove the CommitPoints in the commitsToDelete List by
-		/// DecRef'ing all files from each SegmentInfos.
-		/// </summary>
-		private void  DeleteCommits()
-		{
-			
-			int size = commitsToDelete.Count;
-			
-			if (size > 0)
-			{
-				
-				// First decref all files that had been referred to by
-				// the now-deleted commits:
-				for (int i = 0; i < size; i++)
-				{
-					CommitPoint commit = (CommitPoint) commitsToDelete[i];
-					if (infoStream != null)
-					{
-						Message("deleteCommits: now remove commit \"" + commit.GetSegmentsFileName() + "\"");
-					}
-					int size2 = commit.files.Count;
-					for (int j = 0; j < size2; j++)
-					{
-						DecRef((System.String) commit.files[j]);
-					}
-				}
-				commitsToDelete.Clear();
-				
-				// Now compact commits to remove deleted ones (preserving the sort):
-				size = commits.Count;
-				int readFrom = 0;
-				int writeTo = 0;
-				while (readFrom < size)
-				{
-					CommitPoint commit = (CommitPoint) commits[readFrom];
-					if (!commit.deleted)
-					{
-						if (writeTo != readFrom)
-						{
-							commits[writeTo] = commits[readFrom];
-						}
-						writeTo++;
-					}
-					readFrom++;
-				}
-				
-				while (size > writeTo)
-				{
-					commits.RemoveAt(size - 1);
-					size--;
-				}
-			}
-		}
-		
-		/// <summary> Writer calls this when it has hit an error and had to
-		/// roll back, to tell us that there may now be
-		/// unreferenced files in the filesystem.  So we re-list
-		/// the filesystem and delete such files.  If segmentName
-		/// is non-null, we will only delete files corresponding to
-		/// that segment.
-		/// </summary>
-		public void  Refresh(System.String segmentName)
-		{
-			System.String[] files = directory.List();
-			if (files == null)
-			{
-				throw new System.IO.IOException("cannot read directory " + directory + ": list() returned null");
-			}
-			IndexFileNameFilter filter = IndexFileNameFilter.GetFilter();
-			System.String segmentPrefix1;
-			System.String segmentPrefix2;
-			if (segmentName != null)
-			{
-				segmentPrefix1 = segmentName + ".";
-				segmentPrefix2 = segmentName + "_";
-			}
-			else
-			{
-				segmentPrefix1 = null;
-				segmentPrefix2 = null;
-			}
-			
-			for (int i = 0; i < files.Length; i++)
-			{
-				System.String fileName = files[i];
-				if (filter.Accept(null, fileName) && (segmentName == null || fileName.StartsWith(segmentPrefix1) || fileName.StartsWith(segmentPrefix2)) && !refCounts.Contains(fileName) && !fileName.Equals(IndexFileNames.SEGMENTS_GEN))
-				{
-					// Unreferenced file, so remove it
-					if (infoStream != null)
-					{
-						Message("refresh [prefix=" + segmentName + "]: removing newly created unreferenced file \"" + fileName + "\"");
-					}
-					DeleteFile(fileName);
-				}
-			}
-		}
-		
-		public void  Refresh()
-		{
-			Refresh(null);
-		}
-		
-		public void  Close()
-		{
-			DeletePendingFiles();
-		}
-		
-		private void  DeletePendingFiles()
-		{
-			if (deletable != null)
-			{
-				System.Collections.IList oldDeletable = deletable;
-				deletable = null;
-				int size = oldDeletable.Count;
-				for (int i = 0; i < size; i++)
-				{
-					if (infoStream != null)
-					{
-						Message("delete pending file " + oldDeletable[i]);
-					}
-					DeleteFile((System.String) oldDeletable[i]);
-				}
-			}
-		}
-		
-		/// <summary> For definition of "check point" see IndexWriter comments:
-		/// "Clarification: Check Points (and commits)".
-		/// 
-		/// Writer calls this when it has made a "consistent
-		/// change" to the index, meaning new files are written to
-		/// the index and the in-memory SegmentInfos have been
-		/// modified to point to those files.
-		/// 
-		/// This may or may not be a commit (segments_N may or may
-		/// not have been written).
-		/// 
-		/// We simply incref the files referenced by the new
-		/// SegmentInfos and decref the files we had previously
-		/// seen (if any).
-		/// 
-		/// If this is a commit, we also call the policy to give it
-		/// a chance to remove other commits.  If any commits are
-		/// removed, we decref their files as well.
-		/// </summary>
-		public void  Checkpoint(SegmentInfos segmentInfos, bool isCommit)
-		{
-			
-			if (infoStream != null)
-			{
-				Message("now checkpoint \"" + segmentInfos.GetCurrentSegmentFileName() + "\" [" + segmentInfos.Count + " segments " + "; isCommit = " + isCommit + "]");
-			}
-			
-			// Try again now to delete any previously un-deletable
-			// files (because they were in use, on Windows):
-			DeletePendingFiles();
-			
-			// Incref the files:
-			IncRef(segmentInfos, isCommit);
-			System.Collections.IList docWriterFiles;
-			if (docWriter != null)
-			{
-				docWriterFiles = docWriter.Files();
-				if (docWriterFiles != null)
-					IncRef(docWriterFiles);
-			}
-			else
-				docWriterFiles = null;
-			
-			if (isCommit)
-			{
-				// Append to our commits list:
-				commits.Add(new CommitPoint(this, segmentInfos));
-				
-				// Tell policy so it can remove commits:
-				policy.OnCommit(commits);
-				
-				// Decref files for commits that were deleted by the policy:
-				DeleteCommits();
-			}
-			
-			// DecRef old files from the last checkpoint, if any:
-			int size = lastFiles.Count;
-			if (size > 0)
-			{
-				for (int i = 0; i < size; i++)
-					DecRef((System.Collections.IList) lastFiles[i]);
-				lastFiles.Clear();
-			}
-			
-			if (!isCommit)
-			{
-				// Save files so we can decr on next checkpoint/commit:
-				size = segmentInfos.Count;
-				for (int i = 0; i < size; i++)
-				{
-					SegmentInfo segmentInfo = segmentInfos.Info(i);
-					if (segmentInfo.dir == directory)
-					{
-						lastFiles.Add(segmentInfo.Files());
-					}
-				}
-			}
-			if (docWriterFiles != null)
-				lastFiles.Add(docWriterFiles);
-		}
-		
-		internal void  IncRef(SegmentInfos segmentInfos, bool isCommit)
-		{
-			int size = segmentInfos.Count;
-			for (int i = 0; i < size; i++)
-			{
-				SegmentInfo segmentInfo = segmentInfos.Info(i);
-				if (segmentInfo.dir == directory)
-				{
-					IncRef(segmentInfo.Files());
-				}
-			}
-			
-			if (isCommit)
-			{
-				// Since this is a commit point, also incref its
-				// segments_N file:
-				GetRefCount(segmentInfos.GetCurrentSegmentFileName()).IncRef();
-			}
-		}
-		
-		internal void  IncRef(System.Collections.IList files)
-		{
-			int size = files.Count;
-			for (int i = 0; i < size; i++)
-			{
-				System.String fileName = (System.String) files[i];
-				RefCount rc = GetRefCount(fileName);
-				if (infoStream != null && VERBOSE_REF_COUNTS)
-				{
-					Message("  IncRef \"" + fileName + "\": pre-incr count is " + rc.count);
-				}
-				rc.IncRef();
-			}
-		}
-		
-		internal void  DecRef(System.Collections.IList files)
-		{
-			int size = files.Count;
-			for (int i = 0; i < size; i++)
-			{
-				DecRef((System.String) files[i]);
-			}
-		}
-		
-		private void  DecRef(System.String fileName)
-		{
-			RefCount rc = GetRefCount(fileName);
-			if (infoStream != null && VERBOSE_REF_COUNTS)
-			{
-				Message("  DecRef \"" + fileName + "\": pre-decr count is " + rc.count);
-			}
-			if (0 == rc.DecRef())
-			{
-				// This file is no longer referenced by any past
-				// commit points nor by the in-memory SegmentInfos:
-				DeleteFile(fileName);
-				refCounts.Remove(fileName);
-			}
-		}
-		
-		internal void  DecRef(SegmentInfos segmentInfos)
-		{
-			int size = segmentInfos.Count;
-			for (int i = 0; i < size; i++)
-			{
-				SegmentInfo segmentInfo = segmentInfos.Info(i);
-				if (segmentInfo.dir == directory)
-				{
-					DecRef(segmentInfo.Files());
-				}
-			}
-		}
-		
-		private RefCount GetRefCount(System.String fileName)
-		{
-			RefCount rc;
-			if (!refCounts.Contains(fileName))
-			{
-				rc = new RefCount();
-				refCounts[fileName] = rc;
-			}
-			else
-			{
-				rc = (RefCount) refCounts[fileName];
-			}
-			return rc;
-		}
-		
-		internal void  DeleteFiles(System.Collections.IList files)
-		{
-			int size = files.Count;
-			for (int i = 0; i < size; i++)
-				DeleteFile((System.String) files[i]);
-		}
-		
-		/// <summary>Delets the specified files, but only if they are new
-		/// (have not yet been incref'd). 
-		/// </summary>
-		internal void  DeleteNewFiles(System.Collections.IList files)
-		{
-			int size = files.Count;
-			for (int i = 0; i < size; i++)
-				if (!refCounts.Contains(files[i]))
-					DeleteFile((System.String) files[i]);
-		}
-		
-		internal void  DeleteFile(System.String fileName)
-		{
-			try
-			{
-				if (infoStream != null)
-				{
-					Message("delete \"" + fileName + "\"");
-				}
-				directory.DeleteFile(fileName);
-			}
-			catch (System.IO.IOException e)
-			{
-				// if delete fails
-				if (directory.FileExists(fileName))
-				{
-					
-					// Some operating systems (e.g. Windows) don't
-					// permit a file to be deleted while it is opened
-					// for read (e.g. by another process or thread). So
-					// we assume that when a delete fails it is because
-					// the file is open in another process, and queue
-					// the file for subsequent deletion.
-					
-					if (infoStream != null)
-					{
-						Message("IndexFileDeleter: unable to remove file \"" + fileName + "\": " + e.ToString() + "; Will re-try later.");
-					}
-					if (deletable == null)
-					{
-						deletable = new System.Collections.ArrayList();
-					}
-					deletable.Add(fileName); // add to deletable
-				}
-			}
-		}
-		
-		/// <summary> Tracks the reference count for a single index file:</summary>
-		sealed private class RefCount
-		{
-			
-			internal int count;
-			
-			public int IncRef()
-			{
-				return ++count;
-			}
-			
-			public int DecRef()
-			{
-				System.Diagnostics.Debug.Assert(count > 0);
-				return --count;
-			}
-		}
-		
-		/// <summary> Holds details for each commit point.  This class is
-		/// also passed to the deletion policy.  Note: this class
-		/// has a natural ordering that is inconsistent with
-		/// equals.
-		/// </summary>
-		
-		sealed private class CommitPoint : System.IComparable, IndexCommitPoint
-		{
-			private void  InitBlock(IndexFileDeleter enclosingInstance)
-			{
-				this.enclosingInstance = enclosingInstance;
-			}
-			private IndexFileDeleter enclosingInstance;
-			public IndexFileDeleter Enclosing_Instance
-			{
-				get
-				{
-					return enclosingInstance;
-				}
-				
-			}
-			
-			internal long gen;
-			internal System.Collections.IList files;
-			internal System.String segmentsFileName;
-			internal bool deleted;
-			
-			public CommitPoint(IndexFileDeleter enclosingInstance, SegmentInfos segmentInfos)
-			{
-				InitBlock(enclosingInstance);
-				segmentsFileName = segmentInfos.GetCurrentSegmentFileName();
-				int size = segmentInfos.Count;
-				files = new System.Collections.ArrayList(size);
-				files.Add(segmentsFileName);
-				gen = segmentInfos.GetGeneration();
-				for (int i = 0; i < size; i++)
-				{
-					SegmentInfo segmentInfo = segmentInfos.Info(i);
-					if (segmentInfo.dir == Enclosing_Instance.directory)
-					{
-                        System.Collections.IEnumerator filesEnum = segmentInfo.Files().GetEnumerator();
-                        while (filesEnum.MoveNext())
+        private Directory directory;
+        private IndexDeletionPolicy policy;
+        private DocumentsWriter docWriter;
+
+        /// <summary>Change to true to see details of reference counts when
+        /// infoStream != null 
+        /// </summary>
+        public static bool VERBOSE_REF_COUNTS = false;
+
+        internal void SetInfoStream(System.IO.TextWriter infoStream)
+        {
+            this.infoStream = infoStream;
+            if (infoStream != null)
+            {
+                Message("setInfoStream deletionPolicy=" + policy);
+            }
+        }
+
+        private void Message(string message)
+        {
+            infoStream.WriteLine("IFD [" + SupportClass.ThreadClass.Current().Name + "]: " + message);
+        }
+
+        /// <summary> Initialize the deleter: find all previous commits in
+        /// the Directory, incref the files they reference, call
+        /// the policy to let it delete commits.  The incoming
+        /// segmentInfos must have been loaded from a commit point
+        /// and not yet modified.  This will remove any files not
+        /// referenced by any of the commits.
+        /// </summary>
+        /// <throws>  CorruptIndexException if the index is corrupt </throws>
+        /// <throws>  IOException if there is a low-level IO error </throws>
+        public IndexFileDeleter(Directory directory, IndexDeletionPolicy policy, SegmentInfos segmentInfos, System.IO.TextWriter infoStream, DocumentsWriter docWriter)
+        {
+
+            this.docWriter = docWriter;
+            this.infoStream = infoStream;
+
+            if (infoStream != null)
+            {
+                Message("init: current segments file is \"" + segmentInfos.GetCurrentSegmentFileName() + "\"; deletionPolicy=" + policy);
+            }
+
+            this.policy = policy;
+            this.directory = directory;
+
+            // First pass: walk the files and initialize our ref
+            // counts:
+            long currentGen = segmentInfos.GetGeneration();
+            IndexFileNameFilter filter = IndexFileNameFilter.GetFilter();
+
+            string[] files = directory.List();
+            if (files == null)
+            {
+                throw new System.IO.IOException("cannot read directory " + directory + ": list() returned null");
+            }
+
+            CommitPoint currentCommitPoint = null;
+
+            for (int i = 0; i < files.Length; i++)
+            {
+
+                string fileName = files[i];
+
+                if (filter.Accept(null, fileName) && !fileName.Equals(IndexFileNames.SEGMENTS_GEN))
+                {
+
+                    // Add this file to refCounts with initial count 0:
+                    GetRefCount(fileName);
+
+                    if (fileName.StartsWith(IndexFileNames.SEGMENTS))
+                    {
+
+                        // This is a commit (segments or segments_N), and
+                        // it's valid (<= the max gen).  Load it, then
+                        // incref all files it refers to:
+                        if (SegmentInfos.GenerationFromSegmentsFileName(fileName) <= currentGen)
                         {
-                            files.Add(filesEnum.Current);
+                            if (infoStream != null)
+                            {
+                                Message("init: load commit \"" + fileName + "\"");
+                            }
+                            SegmentInfos sis = new SegmentInfos();
+                            try
+                            {
+                                sis.Read(directory, fileName);
+                            }
+                            catch (System.IO.FileNotFoundException)
+                            {
+                                // LUCENE-948: on NFS (and maybe others), if
+                                // you have writers switching back and forth
+                                // between machines, it's very likely that the
+                                // dir listing will be stale and will claim a
+                                // file segments_X exists when in fact it
+                                // doesn't.  So, we catch this and handle it
+                                // as if the file does not exist
+                                if (infoStream != null)
+                                {
+                                    Message("init: hit FileNotFoundException when loading commit \"" + fileName + "\"; skipping this commit point");
+                                }
+                                sis = null;
+                            }
+                            if (sis != null)
+                            {
+                                CommitPoint commitPoint = new CommitPoint(this, commitsToDelete, directory, sis);
+                                if (sis.GetGeneration() == segmentInfos.GetGeneration())
+                                {
+                                    currentCommitPoint = commitPoint;
+                                }
+                                commits.Add(commitPoint);
+                                IncRef(sis, true);
+                            }
                         }
-					}
-				}
-			}
-			
-			/// <summary> Get the segments_N file for this commit point.</summary>
-			public System.String GetSegmentsFileName()
-			{
-				return segmentsFileName;
-			}
-			
-			public System.Collections.ICollection GetFileNames()
-			{
-				return System.Collections.ArrayList.ReadOnly(new System.Collections.ArrayList(files));
-			}
-			
-			/// <summary> Called only be the deletion policy, to remove this
-			/// commit point from the index.
-			/// </summary>
-			public void  Delete()
-			{
-				if (!deleted)
-				{
-					deleted = true;
-					Enclosing_Instance.commitsToDelete.Add(this);
-				}
-			}
-			
-			public int CompareTo(System.Object obj)
-			{
-				CommitPoint commit = (CommitPoint) obj;
-				if (gen < commit.gen)
-				{
-					return - 1;
-				}
-				else if (gen > commit.gen)
-				{
-					return 1;
-				}
-				else
-				{
-					return 0;
-				}
-			}
-		}
-	}
+                    }
+                }
+            }
+
+            if (currentCommitPoint == null)
+            {
+                // We did not in fact see the segments_N file
+                // corresponding to the segmentInfos that was passed
+                // in.  Yet, it must exist, because our caller holds
+                // the write lock.  This can happen when the directory
+                // listing was stale (eg when index accessed via NFS
+                // client with stale directory listing cache).  So we
+                // try now to explicitly open this commit point:
+                SegmentInfos sis = new SegmentInfos();
+                try
+                {
+                    sis.Read(directory, segmentInfos.GetCurrentSegmentFileName());
+                }
+                catch (System.IO.IOException)
+                {
+                    throw new CorruptIndexException("failed to locate current segments_N file");
+                }
+                if (infoStream != null)
+                    Message("forced open of current segments file " + segmentInfos.GetCurrentSegmentFileName());
+                currentCommitPoint = new CommitPoint(this, commitsToDelete, directory, sis);
+                commits.Add(currentCommitPoint);
+                IncRef(sis, true);
+            }
+
+            // We keep commits list in sorted order (oldest to newest):
+            commits.Sort();
+
+            // Now delete anything with ref count at 0.  These are
+            // presumably abandoned files eg due to crash of
+            // IndexWriter.
+            IEnumerator<KeyValuePair<string,RefCount>> it = refCounts.GetEnumerator();
+            while (it.MoveNext())
+            {
+                string fileName = it.Current.Key;
+                RefCount rc = it.Current.Value;
+                if (0 == rc.count)
+                {
+                    if (infoStream != null)
+                    {
+                        Message("init: removing unreferenced file \"" + fileName + "\"");
+                    }
+                    DeleteFile(fileName);
+                }
+            }
+
+            // Finally, give policy a chance to remove things on
+            // startup:
+            policy.OnInit(commits);
+
+            // It's OK for the onInit to remove the current commit
+            // point; we just have to checkpoint our in-memory
+            // SegmentInfos to protect those files that it uses:
+            if (currentCommitPoint.deleted)
+            {
+                Checkpoint(segmentInfos, false);
+            }
+
+            DeleteCommits();
+        }
+
+        /// <summary> Remove the CommitPoints in the commitsToDelete List by
+        /// DecRef'ing all files from each SegmentInfos.
+        /// </summary>
+        private void DeleteCommits()
+        {
+
+            int size = commitsToDelete.Count;
+
+            if (size > 0)
+            {
+
+                // First decref all files that had been referred to by
+                // the now-deleted commits:
+                for (int i = 0; i < size; i++)
+                {
+                    CommitPoint commit = (CommitPoint)commitsToDelete[i];
+                    if (infoStream != null)
+                    {
+                        Message("deleteCommits: now decRef commit \"" + commit.GetSegmentsFileName() + "\"");
+                    }
+                    int size2 = commit.files.Count;
+                    for (int j = 0; j < size2; j++)
+                    {
+                        DecRef((string)commit.files[j]);
+                    }
+                }
+                commitsToDelete.Clear();
+
+                // Now compact commits to remove deleted ones (preserving the sort):
+                size = commits.Count;
+                int readFrom = 0;
+                int writeTo = 0;
+                while (readFrom < size)
+                {
+                    CommitPoint commit = (CommitPoint) commits[readFrom];
+                    if (!commit.deleted)
+                    {
+                        if (writeTo != readFrom)
+                        {
+                            commits[writeTo] = commits[readFrom];
+                        }
+                        writeTo++;
+                    }
+                    readFrom++;
+                }
+
+                while (size > writeTo)
+                {
+                    commits.RemoveAt(size - 1);
+                    size--;
+                }
+            }
+        }
+
+        /// <summary> Writer calls this when it has hit an error and had to
+        /// roll back, to tell us that there may now be
+        /// unreferenced files in the filesystem.  So we re-list
+        /// the filesystem and delete such files.  If segmentName
+        /// is non-null, we will only delete files corresponding to
+        /// that segment.
+        /// </summary>
+        public void Refresh(string segmentName)
+        {
+            string[] files = directory.List();
+            if (files == null)
+            {
+                throw new System.IO.IOException("cannot read directory " + directory + ": list() returned null");
+            }
+            IndexFileNameFilter filter = IndexFileNameFilter.GetFilter();
+            string segmentPrefix1;
+            string segmentPrefix2;
+            if (segmentName != null)
+            {
+                segmentPrefix1 = segmentName + ".";
+                segmentPrefix2 = segmentName + "_";
+            }
+            else
+            {
+                segmentPrefix1 = null;
+                segmentPrefix2 = null;
+            }
+
+            for (int i = 0; i < files.Length; i++)
+            {
+                string fileName = files[i];
+                if (filter.Accept(null, fileName) && (segmentName == null || fileName.StartsWith(segmentPrefix1) || fileName.StartsWith(segmentPrefix2)) && !refCounts.ContainsKey(fileName) && !fileName.Equals(IndexFileNames.SEGMENTS_GEN))
+                {
+                    // Unreferenced file, so remove it
+                    if (infoStream != null)
+                    {
+                        Message("refresh [prefix=" + segmentName + "]: removing newly created unreferenced file \"" + fileName + "\"");
+                    }
+                    DeleteFile(fileName);
+                }
+            }
+        }
+
+        public void Refresh()
+        {
+            Refresh(null);
+        }
+
+        public void Close()
+        {
+            DeletePendingFiles();
+        }
+
+        private void DeletePendingFiles()
+        {
+            if (deletable != null)
+            {
+                System.Collections.IList oldDeletable = deletable;
+                deletable = null;
+                int size = oldDeletable.Count;
+                for (int i = 0; i < size; i++)
+                {
+                    if (infoStream != null)
+                    {
+                        Message("delete pending file " + oldDeletable[i]);
+                    }
+                    DeleteFile((string)oldDeletable[i]);
+                }
+            }
+        }
+
+        /// <summary> For definition of "check point" see IndexWriter comments:
+        /// "Clarification: Check Points (and commits)".
+        /// 
+        /// Writer calls this when it has made a "consistent
+        /// change" to the index, meaning new files are written to
+        /// the index and the in-memory SegmentInfos have been
+        /// modified to point to those files.
+        /// 
+        /// This may or may not be a commit (segments_N may or may
+        /// not have been written).
+        /// 
+        /// We simply incref the files referenced by the new
+        /// SegmentInfos and decref the files we had previously
+        /// seen (if any).
+        /// 
+        /// If this is a commit, we also call the policy to give it
+        /// a chance to remove other commits.  If any commits are
+        /// removed, we decref their files as well.
+        /// </summary>
+        public void Checkpoint(SegmentInfos segmentInfos, bool isCommit)
+        {
+
+            if (infoStream != null)
+            {
+                Message("now checkpoint \"" + segmentInfos.GetCurrentSegmentFileName() + "\" [" + segmentInfos.Count + " segments " + "; isCommit = " + isCommit + "]");
+            }
+
+            // Try again now to delete any previously un-deletable
+            // files (because they were in use, on Windows):
+            DeletePendingFiles();
+
+            // Incref the files:
+            IncRef(segmentInfos, isCommit);
+
+            if (isCommit)
+            {
+                // append to our commits list
+                commits.Add(new CommitPoint(this, commitsToDelete, directory, segmentInfos));
+
+                // tell policy so it can remove commits
+                policy.OnCommit(commits);
+
+                // decref files for commits that were deleted by the policy
+                DeleteCommits();
+            }
+            else
+            {
+
+                List<string> docWriterFiles;
+                if (docWriter != null)
+                {
+                    docWriterFiles = docWriter.OpenFiles();
+                    if (docWriterFiles != null)
+                        // we must incRef these files before decRef'ing
+                        // last files to make sure we don't accidentally 
+                        // delete them
+                        IncRef(docWriterFiles);
+                }
+                else
+                    docWriterFiles = null;
+
+                // DecRef old files from the last checkpoint, if any:
+                int size = lastFiles.Count;
+                if (size > 0)
+                {
+                    for (int i = 0; i < size; i++)
+                        DecRef(lastFiles[i]);
+                    lastFiles.Clear();
+                }
+
+                // Save files so we can decr on next checkpoint/commit:
+                size = segmentInfos.Count;
+                for (int i = 0; i < size; i++)
+                {
+                    SegmentInfo segmentInfo = segmentInfos.Info(i);
+                    if (segmentInfo.dir == directory)
+                    {
+                        SupportClass.CollectionsSupport.AddAll(segmentInfo.Files(), lastFiles);
+                    }
+                }
+
+                if (docWriterFiles != null)
+                    SupportClass.CollectionsSupport.AddAll(docWriterFiles, lastFiles);
+            }
+        }
+
+        internal void IncRef(SegmentInfos segmentInfos, bool isCommit)
+        {
+            int size = segmentInfos.Count;
+            for (int i = 0; i < size; i++)
+            {
+                SegmentInfo segmentInfo = segmentInfos.Info(i);
+                if (segmentInfo.dir == directory)
+                {
+                    IncRef(segmentInfo.Files());
+                }
+            }
+
+            if (isCommit)
+            {
+                // Since this is a commit point, also incref its
+                // segments_N file:
+                GetRefCount(segmentInfos.GetCurrentSegmentFileName()).IncRef();
+            }
+        }
+
+        internal void IncRef(System.Collections.Generic.IList<string> files)
+        {
+            int size = files.Count;
+            for (int i = 0; i < size; i++)
+            {
+                string fileName = files[i];
+                RefCount rc = GetRefCount(fileName);
+                if (infoStream != null && VERBOSE_REF_COUNTS)
+                {
+                    Message("  IncRef \"" + fileName + "\": pre-incr count is " + rc.count);
+                }
+                rc.IncRef();
+            }
+        }
+
+        internal void DecRef(System.Collections.Generic.IList<string> files)
+        {
+            int size = files.Count;
+            for (int i = 0; i < size; i++)
+            {
+                DecRef(files[i]);
+            }
+        }
+
+        internal void DecRef(string fileName)
+        {
+            RefCount rc = GetRefCount(fileName);
+            if (infoStream != null && VERBOSE_REF_COUNTS)
+            {
+                Message("  DecRef \"" + fileName + "\": pre-decr count is " + rc.count);
+            }
+            if (0 == rc.DecRef())
+            {
+                // This file is no longer referenced by any past
+                // commit points nor by the in-memory SegmentInfos:
+                DeleteFile(fileName);
+                refCounts.Remove(fileName);
+            }
+        }
+
+        internal void DecRef(SegmentInfos segmentInfos)
+        {
+            int size = segmentInfos.Count;
+            for (int i = 0; i < size; i++)
+            {
+                SegmentInfo segmentInfo = segmentInfos.Info(i);
+                if (segmentInfo.dir == directory)
+                {
+                    DecRef(segmentInfo.Files());
+                }
+            }
+        }
+
+        private RefCount GetRefCount(string fileName)
+        {
+            RefCount rc;
+            if (!refCounts.ContainsKey(fileName))
+            {
+                rc = new RefCount();
+                refCounts[fileName] = rc;
+            }
+            else
+            {
+                rc = refCounts[fileName];
+            }
+            return rc;
+        }
+
+        internal void DeleteFiles(List<string> files)
+        {
+            int size = files.Count;
+            for (int i = 0; i < size; i++)
+                DeleteFile(files[i]);
+        }
+
+        /// <summary>Delets the specified files, but only if they are new
+        /// (have not yet been incref'd). 
+        /// </summary>
+        internal void DeleteNewFiles(ICollection<string> files)
+        {
+            IEnumerator<string> enumerator = files.GetEnumerator();
+            while (enumerator.MoveNext())
+            {
+                string fileName = enumerator.Current;
+                if (!refCounts.ContainsKey(fileName))
+                    DeleteFile(fileName);
+            }
+        }
+
+        internal void DeleteFile(string fileName)
+        {
+            try
+            {
+                if (infoStream != null)
+                {
+                    Message("delete \"" + fileName + "\"");
+                }
+                directory.DeleteFile(fileName);
+            }
+            catch (System.IO.IOException e)
+            {
+                // if delete fails
+                if (directory.FileExists(fileName))
+                {
+
+                    // Some operating systems (e.g. Windows) don't
+                    // permit a file to be deleted while it is opened
+                    // for read (e.g. by another process or thread). So
+                    // we assume that when a delete fails it is because
+                    // the file is open in another process, and queue
+                    // the file for subsequent deletion.
+
+                    if (infoStream != null)
+                    {
+                        Message("IndexFileDeleter: unable to remove file \"" + fileName + "\": " + e.ToString() + "; Will re-try later.");
+                    }
+                    if (deletable == null)
+                    {
+                        deletable = new List<string>();
+                    }
+                    deletable.Add(fileName); // add to deletable
+                }
+            }
+        }
+
+        /// <summary> Tracks the reference count for a single index file:</summary>
+        sealed private class RefCount
+        {
+
+            internal int count;
+
+            public int IncRef()
+            {
+                return ++count;
+            }
+
+            public int DecRef()
+            {
+                System.Diagnostics.Debug.Assert(count > 0);
+                return --count;
+            }
+        }
+
+        /// <summary> Holds details for each commit point.  This class is
+        /// also passed to the deletion policy.  Note: this class
+        /// has a natural ordering that is inconsistent with
+        /// equals.
+        /// </summary>
+
+        sealed private class CommitPoint : IndexCommit, System.IComparable
+        {
+            private void InitBlock(IndexFileDeleter enclosingInstance)
+            {
+                this.enclosingInstance = enclosingInstance;
+            }
+            private IndexFileDeleter enclosingInstance;
+            public IndexFileDeleter Enclosing_Instance
+            {
+                get
+                {
+                    return enclosingInstance;
+                }
+
+            }
+
+            internal long gen;
+            internal List<string> files;
+            internal string segmentsFileName;
+            internal bool deleted;
+            internal Directory directory;
+            internal ICollection<IndexCommitPoint> commitsToDelete;
+            internal long version;
+            internal long generation;
+            internal readonly bool isOptimized;
+
+            public CommitPoint(IndexFileDeleter enclosingInstance, ICollection<IndexCommitPoint> commitsToDelete, Directory directory, SegmentInfos segmentInfos)
+            {
+                InitBlock(enclosingInstance);
+                this.directory = directory;
+                this.commitsToDelete = commitsToDelete;
+                segmentsFileName = segmentInfos.GetCurrentSegmentFileName();
+                version = segmentInfos.GetVersion();
+                generation = segmentInfos.GetGeneration();
+                int size = segmentInfos.Count;
+                files = new List<string>(size);
+                files.Add(segmentsFileName);
+                gen = segmentInfos.GetGeneration();
+                for (int i = 0; i < size; i++)
+                {
+                    SegmentInfo segmentInfo = segmentInfos.Info(i);
+                    if (segmentInfo.dir == Enclosing_Instance.directory)
+                    {
+                        SupportClass.CollectionsSupport.AddAll(segmentInfo.Files(), files);
+                    }
+                }
+                isOptimized = segmentInfos.Count == 1 && !segmentInfos.Info(0).HasDeletions();
+            }
+
+            public override bool IsOptimized()
+            {
+                return isOptimized;
+            }
+
+            public override string GetSegmentsFileName()
+            {
+                return segmentsFileName;
+            }
+
+            public override ICollection<string> GetFileNames()
+            {
+                return files.AsReadOnly();
+            }
+
+            public override Directory GetDirectory()
+            {
+                return directory;
+            }
+
+            public override long GetVersion()
+            {
+                return version;
+            }
+
+            public override long GetGeneration()
+            {
+                return generation;
+            }
+
+            /// <summary> Called only be the deletion policy, to remove this
+            /// commit point from the index.
+            /// </summary>
+            public override void Delete()
+            {
+                if (!deleted)
+                {
+                    deleted = true;
+                    Enclosing_Instance.commitsToDelete.Add(this);
+                }
+            }
+
+            public override bool IsDeleted()
+            {
+                return deleted;
+            }
+
+            public int CompareTo(object obj)
+            {
+                CommitPoint commit = (CommitPoint)obj;
+                if (gen < commit.gen)
+                {
+                    return -1;
+                }
+                else if (gen > commit.gen)
+                {
+                    return 1;
+                }
+                else
+                {
+                    return 0;
+                }
+            }
+        }
+    }
 }
\ No newline at end of file