Example #1
0
        /// <summary> Tries to acquire the WriteLock on this directory.
        /// this method is only valid if this IndexReader is directory owner.
        ///
        /// </summary>
        /// <throws>  IOException If WriteLock cannot be acquired. </throws>
        private void  AquireWriteLock()
        {
            if (stale)
            {
                throw new System.IO.IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
            }

            if (this.writeLock == null)
            {
                Lock writeLock = directory.MakeLock(IndexWriter.WRITE_LOCK_NAME);
                if (!writeLock.Obtain(IndexWriter.WRITE_LOCK_TIMEOUT))
                // obtain write lock
                {
                    throw new System.IO.IOException("Index locked for write: " + writeLock);
                }
                this.writeLock = writeLock;

                // we have to check whether index has changed since this reader was opened.
                // if so, this reader is no longer valid for deletion
                if (SegmentInfos.ReadCurrentVersion(directory) > segmentInfos.GetVersion())
                {
                    stale = true;
                    this.writeLock.Release();
                    this.writeLock = null;
                    throw new System.IO.IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
                }
            }
        }
Example #2
0
 /// <summary> Commit changes resulting from delete, undeleteAll, or setNorm operations
 ///
 /// </summary>
 /// <throws>  IOException </throws>
 protected internal void  Commit()
 {
     lock (this)
     {
         if (hasChanges)
         {
             if (directoryOwner)
             {
                 lock (directory)
                 {
                     // in- & inter-process sync
                     new AnonymousClassWith1(this, directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME), IndexWriter.COMMIT_LOCK_TIMEOUT).Run();
                 }
                 if (writeLock != null)
                 {
                     writeLock.Release();                             // release write lock
                     writeLock = null;
                 }
             }
             else
             {
                 DoCommit();
             }
         }
         hasChanges = false;
     }
 }
		/// <summary> Commit changes resulting from delete, undeleteAll, or
		/// setNorm operations
		/// 
		/// If an exception is hit, then either no changes or all
		/// changes will have been committed to the index
		/// (transactional semantics).
		/// </summary>
		/// <throws>  IOException if there is a low-level IO error </throws>
		protected internal override void  DoCommit()
		{
			if (hasChanges)
			{
				if (segmentInfos != null)
				{
					
					// Default deleter (for backwards compatibility) is
					// KeepOnlyLastCommitDeleter:
					IndexFileDeleter deleter = new IndexFileDeleter(directory, deletionPolicy == null ? new KeepOnlyLastCommitDeletionPolicy() : deletionPolicy, segmentInfos, null, null);
					
					// Checkpoint the state we are about to change, in
					// case we have to roll back:
					StartCommit();
					
					bool success = false;
					try
					{
						CommitChanges();
						segmentInfos.Write(directory);
						success = true;
					}
					finally
					{
						
						if (!success)
						{
							
							// Rollback changes that were made to
							// SegmentInfos but failed to get [fully]
							// committed.  This way this reader instance
							// remains consistent (matched to what's
							// actually in the index):
							RollbackCommit();
							
							// Recompute deletable files & remove them (so
							// partially written .del files, etc, are
							// removed):
							deleter.Refresh();
						}
					}
					
					// Have the deleter remove any now unreferenced
					// files due to this commit:
					deleter.Checkpoint(segmentInfos, true);
					
					if (writeLock != null)
					{
						writeLock.Release(); // release write lock
						writeLock = null;
					}
				}
				else
					CommitChanges();
			}
			hasChanges = false;
		}
Example #4
0
        /// <summary>
        /// Deletes a number of documents that conform to the specified Term-s
        /// </summary>
        /// <param name="terms">Term-s to be deleted</param>
        /// <returns>A number of documents deleted</returns>
        public int OptimizedDeleteDocuments(Term[] terms)
        {
            int n = 0;

            lock (this)
            {
                if (directoryOwner)
                {
                    AquireWriteLock();
                }

                foreach (Term term in terms)
                {
                    TermDocs docs = TermDocs(term);

                    if (docs == null)
                    {
                        continue;
                    }

                    try
                    {
                        while (docs.Next())
                        {
                            DoDelete(docs.Doc());

                            hasChanges = true;

                            n++;
                        }
                    }
                    finally
                    {
                        docs.Close();
                    }
                }

                // Release the lock ASAP if there are no changes

                if (!hasChanges &&
                    writeLock != null)
                {
                    writeLock.Release();
                    writeLock = null;
                }
            }

            return(n);
        }
Example #5
0
 /// <summary>Flushes all changes to an index and closes all associated files. </summary>
 public virtual void  Close()
 {
     lock (this)
     {
         FlushRamSegments();
         ramDirectory.Close();
         if (writeLock != null)
         {
             writeLock.Release();                     // release write lock
             writeLock = null;
         }
         if (closeDir)
         {
             directory.Close();
         }
         System.GC.SuppressFinalize(this);
     }
 }
Example #6
0
        private IndexWriter(Directory d, Analyzer a, bool create, bool closeDir)
        {
            InitBlock();
            this.closeDir = closeDir;
            directory     = d;
            analyzer      = a;

            Lock writeLock = directory.MakeLock(IndexWriter.WRITE_LOCK_NAME);

            if (!writeLock.Obtain(writeLockTimeout))
            // obtain write lock
            {
                throw new System.IO.IOException("Index locked for write: " + writeLock);
            }
            this.writeLock = writeLock;             // save it

            lock (directory)
            {
                // in- & inter-process sync
                new AnonymousClassWith(create, this, directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME), commitLockTimeout).Run();
            }
        }
Example #7
0
        /// <summary> Check whether this IndexReader still works on a current version of the index.
        /// If this is not the case you will need to re-open the IndexReader to
        /// make sure you see the latest changes made to the index.
        ///
        /// </summary>
        /// <throws>  IOException </throws>
        public virtual bool IsCurrent()
        {
            lock (directory)
            {
                // in- & inter-process sync
                Lock commitLock = directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME);

                bool locked = false;

                try
                {
                    locked = commitLock.Obtain(IndexWriter.COMMIT_LOCK_TIMEOUT);

                    return(SegmentInfos.ReadCurrentVersion(directory) == segmentInfos.GetVersion());
                }
                finally
                {
                    if (locked)
                    {
                        commitLock.Release();
                    }
                }
            }
        }
Example #8
0
        /// <summary>
        /// Constructs a new IndexWriter per the settings given in <code>conf</code>.
        /// If you want to make "live" changes to this writer instance, use
        /// <seealso cref="#getConfig()"/>.
        ///
        /// <p>
        /// <b>NOTE:</b> after ths writer is created, the given configuration instance
        /// cannot be passed to another writer. If you intend to do so, you should
        /// <seealso cref="IndexWriterConfig#clone() clone"/> it beforehand.
        /// </summary>
        /// <param name="d">
        ///          the index directory. The index is either created or appended
        ///          according <code>conf.getOpenMode()</code>. </param>
        /// <param name="conf">
        ///          the configuration settings according to which IndexWriter should
        ///          be initialized. </param>
        /// <exception cref="IOException">
        ///           if the directory cannot be read/written to, or if it does not
        ///           exist and <code>conf.getOpenMode()</code> is
        ///           <code>OpenMode.APPEND</code> or if there is any other low-level
        ///           IO error </exception>
        public IndexWriter(Directory d, IndexWriterConfig conf)
        {
            /*if (!InstanceFieldsInitialized)
            {
                InitializeInstanceFields();
                InstanceFieldsInitialized = true;
            }*/
            readerPool = new ReaderPool(this);
            conf.SetIndexWriter(this); // prevent reuse by other instances
            Config_Renamed = new LiveIndexWriterConfig(conf);
            directory = d;
            analyzer = Config_Renamed.Analyzer;
            infoStream = Config_Renamed.InfoStream;
            mergePolicy = Config_Renamed.MergePolicy;
            mergePolicy.IndexWriter = this;
            mergeScheduler = Config_Renamed.MergeScheduler;
            Codec = Config_Renamed.Codec;

            BufferedUpdatesStream = new BufferedUpdatesStream(infoStream);
            PoolReaders = Config_Renamed.ReaderPooling;

            WriteLock = directory.MakeLock(WRITE_LOCK_NAME);

            if (!WriteLock.Obtain(Config_Renamed.WriteLockTimeout)) // obtain write lock
            {
                throw new LockObtainFailedException("Index locked for write: " + WriteLock);
            }

            bool success = false;
            try
            {
                OpenMode_e? mode = Config_Renamed.OpenMode;
                bool create;
                if (mode == OpenMode_e.CREATE)
                {
                    create = true;
                }
                else if (mode == OpenMode_e.APPEND)
                {
                    create = false;
                }
                else
                {
                    // CREATE_OR_APPEND - create only if an index does not exist
                    create = !DirectoryReader.IndexExists(directory);
                }

                // If index is too old, reading the segments will throw
                // IndexFormatTooOldException.
                segmentInfos = new SegmentInfos();

                bool initialIndexExists = true;

                if (create)
                {
                    // Try to read first.  this is to allow create
                    // against an index that's currently open for
                    // searching.  In this case we write the next
                    // segments_N file with no segments:
                    try
                    {
                        segmentInfos.Read(directory);
                        segmentInfos.Clear();
                    }
                    catch (IOException)
                    {
                        // Likely this means it's a fresh directory
                        initialIndexExists = false;
                    }

                    // Record that we have a change (zero out all
                    // segments) pending:
                    Changed();
                }
                else
                {
                    segmentInfos.Read(directory);

                    IndexCommit commit = Config_Renamed.IndexCommit;
                    if (commit != null)
                    {
                        // Swap out all segments, but, keep metadata in
                        // SegmentInfos, like version & generation, to
                        // preserve write-once.  this is important if
                        // readers are open against the future commit
                        // points.
                        if (commit.Directory != directory)
                        {
                            throw new ArgumentException(string.Format("IndexCommit's directory doesn't match my directory (mine: {0}, commit's: {1})", directory, commit.Directory));
                        }
                        SegmentInfos oldInfos = new SegmentInfos();
                        oldInfos.Read(directory, commit.SegmentsFileName);
                        segmentInfos.Replace(oldInfos);
                        Changed();
                        if (infoStream.IsEnabled("IW"))
                        {
                            infoStream.Message("IW", "init: loaded commit \"" + commit.SegmentsFileName + "\"");
                        }
                    }
                }

                RollbackSegments = segmentInfos.CreateBackupSegmentInfos();

                // start with previous field numbers, but new FieldInfos
                GlobalFieldNumberMap = FieldNumberMap;
                Config_Renamed.FlushPolicy.Init(Config_Renamed);
                DocWriter = new DocumentsWriter(this, Config_Renamed, directory);
                eventQueue = DocWriter.EventQueue();

                // Default deleter (for backwards compatibility) is
                // KeepOnlyLastCommitDeleter:
                lock (this)
                {
                    Deleter = new IndexFileDeleter(directory, Config_Renamed.DelPolicy, segmentInfos, infoStream, this, initialIndexExists);
                }

                if (Deleter.StartingCommitDeleted)
                {
                    // Deletion policy deleted the "head" commit point.
                    // We have to mark ourself as changed so that if we
                    // are closed w/o any further changes we write a new
                    // segments_N file.
                    Changed();
                }

                if (infoStream.IsEnabled("IW"))
                {
                    infoStream.Message("IW", "init: create=" + create);
                    MessageState();
                }

                success = true;
            }
            finally
            {
                if (!success)
                {
                    if (infoStream.IsEnabled("IW"))
                    {
                        infoStream.Message("IW", "init: hit exception on init; releasing write lock");
                    }
                    WriteLock.Release();
                    IOUtils.CloseWhileHandlingException(WriteLock);
                    WriteLock = null;
                }
            }
        }
Example #9
0
		private void  CloseInternal(bool waitForMerges)
		{
			
			docWriter.PauseAllThreads();
			
			try
			{
				if (infoStream != null)
					Message("now flush at close");
				
				docWriter.Close();
				
				// Only allow a new merge to be triggered if we are
				// going to wait for merges:
				if (!hitOOM)
				{
					Flush(waitForMerges, true, true);
				}
				
				if (waitForMerges)
				// Give merge scheduler last chance to run, in case
				// any pending merges are waiting:
					mergeScheduler.Merge(this);
				
				mergePolicy.Close();
				
				FinishMerges(waitForMerges);
				stopMerges = true;
				
				mergeScheduler.Close();
				
				if (infoStream != null)
					Message("now call final commit()");
				
				if (!hitOOM)
				{
					Commit(0);
				}
				
				if (infoStream != null)
					Message("at close: " + SegString());
				
				lock (this)
				{
					readerPool.Close();
					docWriter = null;
					deleter.Close();
				}
				
				if (closeDir)
					directory.Close();
				
				if (writeLock != null)
				{
					writeLock.Release(); // release write lock
					writeLock = null;
				}
				lock (this)
				{
					closed = true;
				}
			}
			catch (System.OutOfMemoryException oom)
			{
				HandleOOM(oom, "closeInternal");
			}
			finally
			{
				lock (this)
				{
					closing = false;
					System.Threading.Monitor.PulseAll(this);
					if (!closed)
					{
						if (docWriter != null)
							docWriter.ResumeAllThreads();
						if (infoStream != null)
							Message("hit exception while closing");
					}
				}
			}
		}
Example #10
0
		private void  Init(Directory d, Analyzer a, bool create, bool closeDir, IndexDeletionPolicy deletionPolicy, bool autoCommit, int maxFieldLength, IndexingChain indexingChain, IndexCommit commit)
		{
			this.closeDir = closeDir;
			directory = d;
			analyzer = a;
			SetMessageID(defaultInfoStream);
			this.maxFieldLength = maxFieldLength;
			
			if (indexingChain == null)
				indexingChain = DocumentsWriter.DefaultIndexingChain;
			
			if (create)
			{
				// Clear the write lock in case it's leftover:
				directory.ClearLock(WRITE_LOCK_NAME);
			}
			
			Lock writeLock = directory.MakeLock(WRITE_LOCK_NAME);
			if (!writeLock.Obtain(writeLockTimeout))
			// obtain write lock
			{
				throw new LockObtainFailedException("Index locked for write: " + writeLock);
			}
			this.writeLock = writeLock; // save it

            bool success = false;
			try
			{
				if (create)
				{
					// Try to read first.  This is to allow create
					// against an index that's currently open for
					// searching.  In this case we write the next
					// segments_N file with no segments:
					bool doCommit;
					try
					{
						segmentInfos.Read(directory);
						segmentInfos.Clear();
						doCommit = false;
					}
					catch (System.IO.IOException e)
					{
						// Likely this means it's a fresh directory
						doCommit = true;
					}
					
					if (autoCommit || doCommit)
					{
						// Always commit if autoCommit=true, else only
						// commit if there is no segments file in this dir
						// already.
						segmentInfos.Commit(directory);
						SupportClass.CollectionsHelper.AddAllIfNotContains(synced, segmentInfos.Files(directory, true));
					}
					else
					{
						// Record that we have a change (zero out all
						// segments) pending:
						changeCount++;
					}
				}
				else
				{
					segmentInfos.Read(directory);
					
					if (commit != null)
					{
						// Swap out all segments, but, keep metadata in
						// SegmentInfos, like version & generation, to
						// preserve write-once.  This is important if
						// readers are open against the future commit
						// points.
						if (commit.GetDirectory() != directory)
							throw new System.ArgumentException("IndexCommit's directory doesn't match my directory");
						SegmentInfos oldInfos = new SegmentInfos();
						oldInfos.Read(directory, commit.GetSegmentsFileName());
						segmentInfos.Replace(oldInfos);
						changeCount++;
						if (infoStream != null)
							Message("init: loaded commit \"" + commit.GetSegmentsFileName() + "\"");
					}
					
					// We assume that this segments_N was previously
					// properly sync'd:
					SupportClass.CollectionsHelper.AddAllIfNotContains(synced, segmentInfos.Files(directory, true));
				}
				
				this.autoCommit = autoCommit;
				SetRollbackSegmentInfos(segmentInfos);
				
				docWriter = new DocumentsWriter(directory, this, indexingChain);
				docWriter.SetInfoStream(infoStream);
				docWriter.SetMaxFieldLength(maxFieldLength);
				
				// Default deleter (for backwards compatibility) is
				// KeepOnlyLastCommitDeleter:
				deleter = new IndexFileDeleter(directory, deletionPolicy == null?new KeepOnlyLastCommitDeletionPolicy():deletionPolicy, segmentInfos, infoStream, docWriter,synced);
				
				if (deleter.startingCommitDeleted)
				// Deletion policy deleted the "head" commit point.
				// We have to mark ourself as changed so that if we
				// are closed w/o any further changes we write a new
				// segments_N file.
					changeCount++;
				
				PushMaxBufferedDocs();
				
				if (infoStream != null)
				{
					Message("init: create=" + create);
					MessageState();
				}

                success = true;
			}
			finally
			{
                if (!success)
                {
                    if (infoStream != null)
                    {
                        Message("init: hit exception on init; releasing write lock");
                    }
                    try
                    {
                        writeLock.Release();
                    }
                    catch (Exception t)
                    {
                        // don't mask the original exception
                    }
                    writeLock = null;
                }
			}
		}
Example #11
0
        /// <summary> Commit changes resulting from delete, undeleteAll, or setNorm operations
        /// <p/>
        /// If an exception is hit, then either no changes or all changes will have been committed to the index (transactional
        /// semantics).
        /// 
        /// </summary>
        /// <throws>  IOException if there is a low-level IO error </throws>
        protected internal override void DoCommit(IDictionary<string, string> commitUserData)
        {
            if (hasChanges)
            {
                segmentInfos.UserData = commitUserData;
                // Default deleter (for backwards compatibility) is
                // KeepOnlyLastCommitDeleter:
                var deleter = new IndexFileDeleter(internalDirectory, deletionPolicy ?? new KeepOnlyLastCommitDeletionPolicy(), segmentInfos, null, null, synced);

                segmentInfos.UpdateGeneration(deleter.LastSegmentInfos);

                // Checkpoint the state we are about to change, in
                // case we have to roll back:
                StartCommit();
                
                bool success = false;
                try
                {
                    foreach (SegmentReader t in subReaders)
                    	t.Commit();

                	// Sync all files we just wrote
                    foreach(string fileName in segmentInfos.Files(internalDirectory, false))
                    {
                        if(!synced.Contains(fileName))
                        {
                            System.Diagnostics.Debug.Assert(internalDirectory.FileExists(fileName));
                            internalDirectory.Sync(fileName);
                            synced.Add(fileName);
                        }   
                    }
                    
                    segmentInfos.Commit(internalDirectory);
                    success = true;
                }
                finally
                {
                    
                    if (!success)
                    {
                        
                        // Rollback changes that were made to
                        // SegmentInfos but failed to get [fully]
                        // committed.  This way this reader instance
                        // remains consistent (matched to what's
                        // actually in the index):
                        RollbackCommit();
                        
                        // Recompute deletable files & remove them (so
                        // partially written .del files, etc, are
                        // removed):
                        deleter.Refresh();
                    }
                }
                
                // Have the deleter remove any now unreferenced
                // files due to this commit:
                deleter.Checkpoint(segmentInfos, true);
                deleter.Dispose();

                maxIndexVersion = segmentInfos.Version;
                
                if (writeLock != null)
                {
                    writeLock.Release(); // release write lock
                    writeLock = null;
                }
            }
            hasChanges = false;
        }
Example #12
0
        private void RollbackInternal()
        {
            bool success = false;

            if (infoStream.IsEnabled("IW"))
            {
                infoStream.Message("IW", "rollback");
            }

            try
            {
                lock (this)
                {
                    FinishMerges(false);
                    StopMerges = true;
                }

                if (infoStream.IsEnabled("IW"))
                {
                    infoStream.Message("IW", "rollback: done finish merges");
                }

                // Must pre-close these two, in case they increment
                // changeCount so that we can then set it to false
                // before calling closeInternal
                mergePolicy.Dispose();
                mergeScheduler.Dispose();

                BufferedUpdatesStream.Clear();
                DocWriter.Dispose(); // mark it as closed first to prevent subsequent indexing actions/flushes
                DocWriter.Abort(this); // don't sync on IW here
                lock (this)
                {
                    if (PendingCommit != null)
                    {
                        PendingCommit.RollbackCommit(directory);
                        Deleter.DecRef(PendingCommit);
                        PendingCommit = null;
                        Monitor.PulseAll(this);
                    }

                    // Don't bother saving any changes in our segmentInfos
                    readerPool.DropAll(false);

                    // Keep the same segmentInfos instance but replace all
                    // of its SegmentInfo instances.  this is so the next
                    // attempt to commit using this instance of IndexWriter
                    // will always write to a new generation ("write
                    // once").
                    segmentInfos.RollbackSegmentInfos(RollbackSegments);
                    if (infoStream.IsEnabled("IW"))
                    {
                        infoStream.Message("IW", "rollback: infos=" + SegString(segmentInfos.Segments));
                    }

                    var tpResult = TestPoint("rollback before checkpoint");
                    Debug.Assert(tpResult);

                    // Ask deleter to locate unreferenced files & remove
                    // them:
                    Deleter.Checkpoint(segmentInfos, false);
                    Deleter.Refresh();

                    LastCommitChangeCount = ChangeCount;

                    Deleter.Refresh();
                    Deleter.Dispose();

                    WriteLock.Release();
                    IOUtils.Close(WriteLock); // release write lock
                    WriteLock = null;

                    Debug.Assert(DocWriter.PerThreadPool.NumDeactivatedThreadStates() == DocWriter.PerThreadPool.MaxThreadStates, "" + DocWriter.PerThreadPool.NumDeactivatedThreadStates() + " " + DocWriter.PerThreadPool.MaxThreadStates);
                }

                success = true;
            }
            catch (System.OutOfMemoryException oom)
            {
                HandleOOM(oom, "rollbackInternal");
            }
            finally
            {
                if (!success)
                {
                    // Must not hold IW's lock while closing
                    // mergePolicy/Scheduler: this can lead to deadlock,
                    // e.g. TestIW.testThreadInterruptDeadlock
                    IOUtils.CloseWhileHandlingException(mergePolicy, mergeScheduler);
                }
                lock (this)
                {
                    if (!success)
                    {
                        // we tried to be nice about it: do the minimum

                        // don't leak a segments_N file if there is a pending commit
                        if (PendingCommit != null)
                        {
                            try
                            {
                                PendingCommit.RollbackCommit(directory);
                                Deleter.DecRef(PendingCommit);
                            }
                            catch (Exception)
                            {
                            }
                        }

                        // close all the closeables we can (but important is readerPool and writeLock to prevent leaks)
                        if (WriteLock != null)
                        {
                            WriteLock.Release();
                        }
                        IOUtils.CloseWhileHandlingException(readerPool, Deleter, WriteLock);
                        WriteLock = null;
                    }
                    closed = true;
                    Closing = false;
                }
            }
        }
        /// <summary> Commit changes resulting from delete, undeleteAll, or
        /// setNorm operations
        /// 
        /// If an exception is hit, then either no changes or all
        /// changes will have been committed to the index
        /// (transactional semantics).
        /// </summary>
        /// <throws>  IOException if there is a low-level IO error </throws>
        protected internal override void DoCommit()
        {
            if (hasChanges)
            {
                if (segmentInfos != null)
                {

                    // Default deleter (for backwards compatibility) is
                    // KeepOnlyLastCommitDeleter:
                    IndexFileDeleter deleter = new IndexFileDeleter(directory, deletionPolicy == null ? new KeepOnlyLastCommitDeletionPolicy() : deletionPolicy, segmentInfos, null, null);

                    // Checkpoint the state we are about to change, in
                    // case we have to roll back:
                    StartCommit();

                    bool success = false;
                    try
                    {
                        CommitChanges();

                        // sync all the files we just wrote
                        for (int i = 0; i < segmentInfos.Count; i++)
                        {
                            SegmentInfo info = segmentInfos.Info(i);
                            IList<string> files = info.Files();
                            for (int j = 0; j < files.Count; j++)
                            {
                                string fileName = files[j];
                                if (!synced.ContainsKey(fileName))
                                {
                                    System.Diagnostics.Debug.Assert(directory.FileExists(fileName));
                                    directory.Sync(fileName);
                                    synced[fileName] = fileName;
                                }
                            }
                        }

                        segmentInfos.Commit(directory);
                        success = true;
                    }
                    finally
                    {

                        if (!success)
                        {

                            // Rollback changes that were made to
                            // SegmentInfos but failed to get [fully]
                            // committed.  This way this reader instance
                            // remains consistent (matched to what's
                            // actually in the index):
                            RollbackCommit();

                            // Recompute deletable files & remove them (so
                            // partially written .del files, etc, are
                            // removed):
                            deleter.Refresh();
                        }
                    }

                    // Have the deleter remove any now unreferenced
                    // files due to this commit:
                    deleter.Checkpoint(segmentInfos, true);

                    if (writeLock != null)
                    {
                        writeLock.Release(); // release write lock
                        writeLock = null;
                    }
                }
                else
                    CommitChanges();
            }
            hasChanges = false;
        }
Example #14
0
 /// <summary> Commit changes resulting from delete, undeleteAll, or setNorm operations
 /// 
 /// </summary>
 /// <throws>  IOException </throws>
 protected internal void Commit()
 {
     lock (this)
     {
         if (hasChanges)
         {
             if (directoryOwner)
             {
                 lock (directory)
                 {
                     // in- & inter-process sync
                     new AnonymousClassWith1(this, directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME), IndexWriter.COMMIT_LOCK_TIMEOUT).Run();
                 }
                 if (writeLock != null)
                 {
                     writeLock.Release(); // release write lock
                     writeLock = null;
                 }
             }
             else
                 DoCommit();
         }
         hasChanges = false;
     }
 }
Example #15
0
        private void Init(Directory d, Analyzer a, bool create, bool closeDir, IndexDeletionPolicy deletionPolicy, bool autoCommit, int maxFieldLength)
        {
            this.closeDir = closeDir;
            directory = d;
            analyzer = a;
            SetMessageID(defaultInfoStream);
            this.maxFieldLength = maxFieldLength;

            if (create)
            {
                // Clear the write lock in case it's leftover:
                directory.ClearLock(WRITE_LOCK_NAME);
            }

            Lock writeLock = directory.MakeLock(WRITE_LOCK_NAME);
            if (!writeLock.Obtain(writeLockTimeout))
            // obtain write lock
            {
                throw new LockObtainFailedException("Index locked for write: " + writeLock);
            }
            this.writeLock = writeLock; // save it

            try
            {
                if (create)
                {
                    // Try to read first.  This is to allow create
                    // against an index that's currently open for
                    // searching.  In this case we write the next
                    // segments_N file with no segments:
                    try
                    {
                        segmentInfos.Read(directory);
                        segmentInfos.Clear();
                    }
                    catch (System.IO.IOException)
                    {
                        // Likely this means it's a fresh directory
                    }
                    segmentInfos.Commit(directory);
                }
                else
                {
                    segmentInfos.Read(directory);

                    // We assume that this segments_N was previously
                    // properly sync'd:
                    for (int i = 0; i < segmentInfos.Count; i++)
                    {
                        SegmentInfo info = segmentInfos.Info(i);
                        List<string> files = info.Files();
                        for (int j = 0; j < files.Count; j++)
                            synced[files[j]] = files[j];
                    }
                }

                this.autoCommit = autoCommit;
                SetRollbackSegmentInfos(segmentInfos);

                docWriter = new DocumentsWriter(directory, this);
                docWriter.SetInfoStream(infoStream);
                docWriter.SetMaxFieldLength(maxFieldLength);

                // Default deleter (for backwards compatibility) is
                // KeepOnlyLastCommitDeleter:
                deleter = new IndexFileDeleter(directory, deletionPolicy == null ? new KeepOnlyLastCommitDeletionPolicy() : deletionPolicy, segmentInfos, infoStream, docWriter);

                PushMaxBufferedDocs();

                if (infoStream != null)
                {
                    Message("init: create=" + create);
                    MessageState();
                }
            }
            catch (System.IO.IOException e)
            {
                this.writeLock.Release();
                this.writeLock = null;
                throw e;
            }
        }
Example #16
0
		/// <summary>Flushes all changes to an index and closes all associated files. </summary>
		public virtual void  Close()
		{
			lock (this)
			{
				FlushRamSegments();
				ramDirectory.Close();
				if (writeLock != null)
				{
					writeLock.Release(); // release write lock
					writeLock = null;
				}
				if (closeDir)
					directory.Close();
                System.GC.SuppressFinalize(this);
            }
		}
Example #17
0
		private IndexWriter(Directory d, Analyzer a, bool create, bool closeDir)
		{
			InitBlock();
			this.closeDir = closeDir;
			directory = d;
			analyzer = a;
			
			Lock writeLock = directory.MakeLock(IndexWriter.WRITE_LOCK_NAME);
			if (!writeLock.Obtain(WRITE_LOCK_TIMEOUT))
			// obtain write lock
			{
				throw new System.IO.IOException("Index locked for write: " + writeLock);
			}
			this.writeLock = writeLock; // save it
			
			lock (directory)
			{
				// in- & inter-process sync
				new AnonymousClassWith(create, this, directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME), COMMIT_LOCK_TIMEOUT).Run();
			}
		}
Example #18
0
		private void  Init(Directory d, Analyzer a, bool create, bool closeDir, IndexDeletionPolicy deletionPolicy, bool autoCommit)
		{
			this.closeDir = closeDir;
			directory = d;
			analyzer = a;
			this.infoStream = defaultInfoStream;
			SetMessageID();
			
			if (create)
			{
				// Clear the write lock in case it's leftover:
				directory.ClearLock(IndexWriter.WRITE_LOCK_NAME);
			}
			
			Lock writeLock = directory.MakeLock(IndexWriter.WRITE_LOCK_NAME);
			if (!writeLock.Obtain(writeLockTimeout))
			// obtain write lock
			{
				throw new LockObtainFailedException("Index locked for write: " + writeLock);
			}
			this.writeLock = writeLock; // save it
			
			try
			{
				if (create)
				{
					// Try to read first.  This is to allow create
					// against an index that's currently open for
					// searching.  In this case we write the next
					// segments_N file with no segments:
					try
					{
						segmentInfos.Read(directory);
						segmentInfos.Clear();
					}
					catch (System.IO.IOException e)
					{
						// Likely this means it's a fresh directory
					}
					segmentInfos.Write(directory);
				}
				else
				{
					segmentInfos.Read(directory);
				}
				
				this.autoCommit = autoCommit;
				if (!autoCommit)
				{
					rollbackSegmentInfos = (SegmentInfos) segmentInfos.Clone();
				}
				
				docWriter = new DocumentsWriter(directory, this);
				docWriter.SetInfoStream(infoStream);
				
				// Default deleter (for backwards compatibility) is
				// KeepOnlyLastCommitDeleter:
				deleter = new IndexFileDeleter(directory, deletionPolicy == null ? new KeepOnlyLastCommitDeletionPolicy() : deletionPolicy, segmentInfos, infoStream, docWriter);
				
				PushMaxBufferedDocs();
				
				if (infoStream != null)
				{
					Message("init: create=" + create);
					MessageState();
				}
			}
			catch (System.IO.IOException e)
			{
				this.writeLock.Release();
				this.writeLock = null;
				throw e;
			}
		}
Example #19
0
		private void  CloseInternal(bool waitForMerges)
		{
			try
			{
				if (infoStream != null)
					Message("now flush at close");
				
				docWriter.Close();
				
				// Only allow a new merge to be triggered if we are
				// going to wait for merges:
				Flush(waitForMerges, true);

                if (waitForMerges)
                    // Give merge scheduler last chance to run, in case
                    // any pending merges are waiting
                    mergeScheduler.Merge(this);
				
				mergePolicy.Close();
				
				FinishMerges(waitForMerges);
				
				mergeScheduler.Close();
				
				lock (this)
				{
					if (commitPending)
					{
						bool success = false;
						try
						{
							segmentInfos.Write(directory); // now commit changes
							success = true;
						}
						finally
						{
							if (!success)
							{
								if (infoStream != null)
									Message("hit exception committing segments file during close");
								DeletePartialSegmentsFile();
							}
						}
						if (infoStream != null)
							Message("close: wrote segments file \"" + segmentInfos.GetCurrentSegmentFileName() + "\"");
						
						deleter.Checkpoint(segmentInfos, true);
						
						commitPending = false;
						rollbackSegmentInfos = null;
					}
					
					if (infoStream != null)
						Message("at close: " + SegString());
					
					docWriter = null;
					
					deleter.Close();
				}
				
				if (closeDir)
					directory.Close();
				
				if (writeLock != null)
				{
					writeLock.Release(); // release write lock
					writeLock = null;
				}
				closed = true;
			}
            catch (OutOfMemoryException oom) 
            {
                hitOOM = true;
                throw oom;
            }
			finally
			{
				lock (this)
				{
                    if (!closed)
                    {
                        closing = false;
                        if (infoStream != null)
                            Message("hit exception while closing");
                    }
					System.Threading.Monitor.PulseAll(this);
				}
			}
		}
        /// <summary> Commit changes resulting from delete, undeleteAll, or
        /// setNorm operations
        ///
        /// If an exception is hit, then either no changes or all
        /// changes will have been committed to the index
        /// (transactional semantics).
        /// </summary>
        /// <throws>  IOException if there is a low-level IO error </throws>
        protected internal override void DoCommit()
        {
            if (hasChanges)
            {
                if (segmentInfos != null)
                {
                    // Default deleter (for backwards compatibility) is
                    // KeepOnlyLastCommitDeleter:
                    IndexFileDeleter deleter = new IndexFileDeleter(directory, deletionPolicy == null ? new KeepOnlyLastCommitDeletionPolicy() : deletionPolicy, segmentInfos, null, null);

                    // Checkpoint the state we are about to change, in
                    // case we have to roll back:
                    StartCommit();

                    bool success = false;
                    try
                    {
                        CommitChanges();

                        // sync all the files we just wrote
                        for (int i = 0; i < segmentInfos.Count; i++)
                        {
                            SegmentInfo    info  = segmentInfos.Info(i);
                            IList <string> files = info.Files();
                            for (int j = 0; j < files.Count; j++)
                            {
                                string fileName = files[j];
                                if (!synced.ContainsKey(fileName))
                                {
                                    System.Diagnostics.Debug.Assert(directory.FileExists(fileName));
                                    directory.Sync(fileName);
                                    synced[fileName] = fileName;
                                }
                            }
                        }

                        segmentInfos.Commit(directory);
                        success = true;
                    }
                    finally
                    {
                        if (!success)
                        {
                            // Rollback changes that were made to
                            // SegmentInfos but failed to get [fully]
                            // committed.  This way this reader instance
                            // remains consistent (matched to what's
                            // actually in the index):
                            RollbackCommit();

                            // Recompute deletable files & remove them (so
                            // partially written .del files, etc, are
                            // removed):
                            deleter.Refresh();
                        }
                    }

                    // Have the deleter remove any now unreferenced
                    // files due to this commit:
                    deleter.Checkpoint(segmentInfos, true);

                    if (writeLock != null)
                    {
                        writeLock.Release(); // release write lock
                        writeLock = null;
                    }
                }
                else
                {
                    CommitChanges();
                }
            }
            hasChanges = false;
        }
Example #21
0
		/// <summary> Commit changes resulting from delete, undeleteAll, or
		/// setNorm operations
		/// 
		/// If an exception is hit, then either no changes or all
		/// changes will have been committed to the index
		/// (transactional semantics).
		/// 
		/// </summary>
		/// <throws>  IOException </throws>
		public void  Commit()
		{
			lock (this)
			{
				if (hasChanges)
				{
					if (deleter == null)
					{
						// In the MultiReader case, we share this deleter
						// across all SegmentReaders:
						SetDeleter(new IndexFileDeleter(segmentInfos, directory));
					}
					if (directoryOwner)
					{
						
						// Should not be necessary: no prior commit should
						// have left pending files, so just defensive:
						deleter.ClearPendingFiles();
						
						System.String oldInfoFileName = segmentInfos.GetCurrentSegmentFileName();
						System.String nextSegmentsFileName = segmentInfos.GetNextSegmentFileName();
						
						// Checkpoint the state we are about to change, in
						// case we have to roll back:
						StartCommit();
						
						bool success = false;
						try
						{
							DoCommit();
							segmentInfos.Write(directory);
							success = true;
						}
						finally
						{
							
							if (!success)
							{
								
								// Rollback changes that were made to
								// SegmentInfos but failed to get [fully]
								// committed.  This way this reader instance
								// remains consistent (matched to what's
								// actually in the index):
								RollbackCommit();
								
								// Erase any pending files that we were going to delete:
								deleter.ClearPendingFiles();
								
								// Remove possibly partially written next
								// segments file:
								deleter.DeleteFile(nextSegmentsFileName);
								
								// Recompute deletable files & remove them (so
								// partially written .del files, etc, are
								// removed):
								deleter.FindDeletableFiles();
								deleter.DeleteFiles();
							}
						}
						
						// Attempt to delete all files we just obsoleted:
						deleter.DeleteFile(oldInfoFileName);
						deleter.CommitPendingFiles();
						
						if (writeLock != null)
						{
							writeLock.Release(); // release write lock
							writeLock = null;
						}
					}
					else
						DoCommit();
				}
				hasChanges = false;
			}
		}
Example #22
0
		private void  Init(Directory d, Analyzer a, bool create, bool closeDir)
		{
			this.closeDir = closeDir;
			directory = d;
			analyzer = a;
			
			if (create)
			{
				// Clear the write lock in case it's leftover:
				directory.ClearLock(IndexWriter.WRITE_LOCK_NAME);
			}
			
			Lock writeLock = directory.MakeLock(IndexWriter.WRITE_LOCK_NAME);
			if (!writeLock.Obtain(writeLockTimeout))
			// obtain write lock
			{
				throw new System.IO.IOException("Index locked for write: " + writeLock);
			}
			this.writeLock = writeLock; // save it
			
			try
			{
				if (create)
				{
					// Try to read first. This is to allow create
					// against an index that's currently open for
					// searching. In this case we write the next
					// segments_N file with no segments:
					try
					{
						segmentInfos.Read(directory);
						segmentInfos.Clear();
					}
					catch (System.IO.IOException e)
					{
						// Likely this means it's a fresh directory
					}
					segmentInfos.Write(directory);
				}
				else
				{
					segmentInfos.Read(directory);
				}
				
				// Create a deleter to keep track of which files can
				// be deleted:
				deleter = new IndexFileDeleter(segmentInfos, directory);
				deleter.SetInfoStream(infoStream);
				deleter.FindDeletableFiles();
				deleter.DeleteFiles();
			}
			catch (System.IO.IOException e)
			{
				this.writeLock.Release();
				this.writeLock = null;
				throw e;
			}
		}
Example #23
0
 public override IndexReader Clone(bool openReadOnly)
 {
     lock (this)
     {
         DirectoryReader newReader = DoReopen((SegmentInfos) segmentInfos.Clone(), true, openReadOnly);
         
         if (this != newReader)
         {
             newReader.deletionPolicy = deletionPolicy;
         }
         newReader.writer = writer;
         // If we're cloning a non-readOnly reader, move the
         // writeLock (if there is one) to the new reader:
         if (!openReadOnly && writeLock != null)
         {
             // In near real-time search, reader is always readonly
             System.Diagnostics.Debug.Assert(writer == null);
             newReader.writeLock = writeLock;
             newReader.hasChanges = hasChanges;
             newReader.hasDeletions = hasDeletions;
             writeLock = null;
             hasChanges = false;
         }
         
         return newReader;
     }
 }
Example #24
0
        /// <summary>
        /// Deletes a number of documents that conform to the specified Term-s
        /// </summary>
        /// <param name="terms">Term-s to be deleted</param>
        /// <returns>A number of documents deleted</returns>
        public int OptimizedDeleteDocuments(Term[] terms)
        {
            int n = 0;

            lock (this)
            {
                if (directoryOwner)
                {
                    AquireWriteLock();
                }

                foreach (Term term in terms)
                {
                    TermDocs docs = TermDocs(term);

                    if (docs == null)
                    {
                        continue;
                    }

                    try
                    {
                        while (docs.Next())
                        {
                            DoDelete(docs.Doc());

                            hasChanges = true;

                            n++;
                        }
                    }
                    finally
                    {
                        docs.Close();
                    }
                }

                // Release the lock ASAP if there are no changes

                if (!hasChanges &&
                    writeLock != null)
                {
                    writeLock.Release();
                    writeLock = null;
                }
            }

            return n;
        }
Example #25
0
 /// <summary> Tries to acquire the WriteLock on this directory. this method is only valid if this IndexReader is directory
 /// owner.
 /// 
 /// </summary>
 /// <throws>  StaleReaderException  if the index has changed since this reader was opened </throws>
 /// <throws>  CorruptIndexException if the index is corrupt </throws>
 /// <throws>  Lucene.Net.Store.LockObtainFailedException </throws>
 /// <summary>                               if another writer has this index open (<c>write.lock</c> could not be
 /// obtained)
 /// </summary>
 /// <throws>  IOException           if there is a low-level IO error </throws>
 protected internal override void  AcquireWriteLock()
 {
     
     if (readOnly)
     {
         // NOTE: we should not reach this code w/ the core
         // IndexReader classes; however, an external subclass
         // of IndexReader could reach this.
         ReadOnlySegmentReader.NoWrite();
     }
     
     if (segmentInfos != null)
     {
         EnsureOpen();
         if (stale)
             throw new StaleReaderException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
         
         if (this.writeLock == null)
         {
             Lock writeLock = internalDirectory.MakeLock(IndexWriter.WRITE_LOCK_NAME);
             if (!writeLock.Obtain(IndexWriter.WRITE_LOCK_TIMEOUT))
             // obtain write lock
             {
                 throw new LockObtainFailedException("Index locked for write: " + writeLock);
             }
             this.writeLock = writeLock;
             
             // we have to check whether index has changed since this reader was opened.
             // if so, this reader is no longer valid for
             // deletion
             if (SegmentInfos.ReadCurrentVersion(internalDirectory) > maxIndexVersion)
             {
                 stale = true;
                 this.writeLock.Release();
                 this.writeLock = null;
                 throw new StaleReaderException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
             }
         }
     }
 }
Example #26
0
        /// <summary> Commit changes resulting from delete, undeleteAll, or
        /// setNorm operations
        ///
        /// If an exception is hit, then either no changes or all
        /// changes will have been committed to the index
        /// (transactional semantics).
        ///
        /// </summary>
        /// <throws>  IOException </throws>
        public void  Commit()
        {
            lock (this)
            {
                if (hasChanges)
                {
                    if (deleter == null)
                    {
                        // In the MultiReader case, we share this deleter
                        // across all SegmentReaders:
                        SetDeleter(new IndexFileDeleter(segmentInfos, directory));
                    }
                    if (directoryOwner)
                    {
                        // Should not be necessary: no prior commit should
                        // have left pending files, so just defensive:
                        deleter.ClearPendingFiles();

                        System.String oldInfoFileName      = segmentInfos.GetCurrentSegmentFileName();
                        System.String nextSegmentsFileName = segmentInfos.GetNextSegmentFileName();

                        // Checkpoint the state we are about to change, in
                        // case we have to roll back:
                        StartCommit();

                        bool success = false;
                        try
                        {
                            DoCommit();
                            segmentInfos.Write(directory);
                            success = true;
                        }
                        finally
                        {
                            if (!success)
                            {
                                // Rollback changes that were made to
                                // SegmentInfos but failed to get [fully]
                                // committed.  This way this reader instance
                                // remains consistent (matched to what's
                                // actually in the index):
                                RollbackCommit();

                                // Erase any pending files that we were going to delete:
                                deleter.ClearPendingFiles();

                                // Remove possibly partially written next
                                // segments file:
                                deleter.DeleteFile(nextSegmentsFileName);

                                // Recompute deletable files & remove them (so
                                // partially written .del files, etc, are
                                // removed):
                                deleter.FindDeletableFiles();
                                deleter.DeleteFiles();
                            }
                        }

                        // Attempt to delete all files we just obsoleted:
                        deleter.DeleteFile(oldInfoFileName);
                        deleter.CommitPendingFiles();

                        if (writeLock != null)
                        {
                            writeLock.Release();                             // release write lock
                            writeLock = null;
                        }
                    }
                    else
                    {
                        DoCommit();
                    }
                }
                hasChanges = false;
            }
        }
Example #27
0
        private void CloseInternal(bool waitForMerges, bool doFlush)
        {
            bool interrupted = false;
            try
            {
                if (PendingCommit != null)
                {
                    throw new InvalidOperationException("cannot close: prepareCommit was already called with no corresponding call to commit");
                }

                if (infoStream.IsEnabled("IW"))
                {
                    infoStream.Message("IW", "now flush at close waitForMerges=" + waitForMerges);
                }

                DocWriter.Dispose();

                try
                {
                    // Only allow a new merge to be triggered if we are
                    // going to wait for merges:
                    if (doFlush)
                    {
                        Flush(waitForMerges, true);
                    }
                    else
                    {
                        DocWriter.Abort(this); // already closed -- never sync on IW
                    }
                }
                finally
                {
                    try
                    {
                        // clean up merge scheduler in all cases, although flushing may have failed:
                        //interrupted = Thread.Interrupted();
                        //LUCENE TO-DO
                        interrupted = false;

                        if (waitForMerges)
                        {
                            try
                            {
                                // Give merge scheduler last chance to run, in case
                                // any pending merges are waiting:
                                mergeScheduler.Merge(this, MergeTrigger.CLOSING, false);
                            }
                            catch (ThreadInterruptedException)
                            {
                                // ignore any interruption, does not matter
                                interrupted = true;
                                if (infoStream.IsEnabled("IW"))
                                {
                                    infoStream.Message("IW", "interrupted while waiting for final merges");
                                }
                            }
                        }

                        lock (this)
                        {
                            for (; ; )
                            {
                                try
                                {
                                    FinishMerges(waitForMerges && !interrupted);
                                    break;
                                }
                                catch (ThreadInterruptedException)
                                {
                                    // by setting the interrupted status, the
                                    // next call to finishMerges will pass false,
                                    // so it will not wait
                                    interrupted = true;
                                    if (infoStream.IsEnabled("IW"))
                                    {
                                        infoStream.Message("IW", "interrupted while waiting for merges to finish");
                                    }
                                }
                            }
                            StopMerges = true;
                        }
                    }
                    finally
                    {
                        // shutdown policy, scheduler and all threads (this call is not interruptible):
                        IOUtils.CloseWhileHandlingException(mergePolicy, mergeScheduler);
                    }
                }

                if (infoStream.IsEnabled("IW"))
                {
                    infoStream.Message("IW", "now call final commit()");
                }

                if (doFlush)
                {
                    CommitInternal();
                }
                ProcessEvents(false, true);
                lock (this)
                {
                    // commitInternal calls ReaderPool.commit, which
                    // writes any pending liveDocs from ReaderPool, so
                    // it's safe to drop all readers now:
                    readerPool.DropAll(true);
                    Deleter.Dispose();
                }

                if (infoStream.IsEnabled("IW"))
                {
                    infoStream.Message("IW", "at close: " + SegString());
                }

                if (WriteLock != null)
                {
                    WriteLock.Release(); // release write lock
                    WriteLock.Dispose();
                    WriteLock = null;
                }
                lock (this)
                {
                    closed = true;
                }
                Debug.Assert(DocWriter.PerThreadPool.NumDeactivatedThreadStates() == DocWriter.PerThreadPool.MaxThreadStates, "" + DocWriter.PerThreadPool.NumDeactivatedThreadStates() + " " + DocWriter.PerThreadPool.MaxThreadStates);
            }
            catch (System.OutOfMemoryException oom)
            {
                HandleOOM(oom, "closeInternal");
            }
            finally
            {
                lock (this)
                {
                    Closing = false;
                    Monitor.PulseAll(this);
                    if (!closed)
                    {
                        if (infoStream.IsEnabled("IW"))
                        {
                            infoStream.Message("IW", "hit exception while closing");
                        }
                    }
                }
                // finally, restore interrupt status:
                if (interrupted)
                {
                    Thread.CurrentThread.Interrupt();
                }
            }
        }
Example #28
0
        /// <summary> Tries to acquire the WriteLock on this directory.
        /// this method is only valid if this IndexReader is directory owner.
        /// 
        /// </summary>
        /// <throws>  IOException If WriteLock cannot be acquired. </throws>
        private void AquireWriteLock()
        {
            if (stale)
                throw new System.IO.IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");

            if (this.writeLock == null)
            {
                Lock writeLock = directory.MakeLock(IndexWriter.WRITE_LOCK_NAME);
                if (!writeLock.Obtain(IndexWriter.WRITE_LOCK_TIMEOUT))
                // obtain write lock
                {
                    throw new System.IO.IOException("Index locked for write: " + writeLock);
                }
                this.writeLock = writeLock;

                // we have to check whether index has changed since this reader was opened.
                // if so, this reader is no longer valid for deletion
                if (SegmentInfos.ReadCurrentVersion(directory) > segmentInfos.GetVersion())
                {
                    stale = true;
                    this.writeLock.Release();
                    this.writeLock = null;
                    throw new System.IO.IOException("IndexReader out of date and no longer valid for delete, undelete, or setNorm operations");
                }
            }
        }
        /// <summary> Commit changes resulting from delete, undeleteAll, or setNorm operations
        /// <p/>
        /// If an exception is hit, then either no changes or all changes will have been committed to the index (transactional
        /// semantics).
        /// 
        /// </summary>
        /// <throws>  IOException if there is a low-level IO error </throws>
        protected internal override void DoCommit(System.Collections.IDictionary commitUserData)
        {
            if (hasChanges)
            {
                segmentInfos.SetUserData(commitUserData);
                // Default deleter (for backwards compatibility) is
                // KeepOnlyLastCommitDeleter:
                IndexFileDeleter deleter = new IndexFileDeleter(directory, deletionPolicy == null?new KeepOnlyLastCommitDeletionPolicy():deletionPolicy, segmentInfos, null, null);

                // Checkpoint the state we are about to change, in
                // case we have to roll back:
                StartCommit();

                bool success = false;
                try
                {
                    for (int i = 0; i < subReaders.Length; i++)
                        subReaders[i].Commit();

                    // Sync all files we just wrote
                    System.Collections.IEnumerator it = segmentInfos.Files(directory, false).GetEnumerator();
                    while (it.MoveNext())
                    {
                        System.String fileName = (string)((System.Collections.DictionaryEntry) it.Current).Value;
                        if (!synced.Contains(fileName))
                        {
                            System.Diagnostics.Debug.Assert(directory.FileExists(fileName));
                            directory.Sync(fileName);
                            SupportClass.CollectionsHelper.AddIfNotContains(synced, fileName);
                        }
                    }

                    segmentInfos.Commit(directory);
                    success = true;
                }
                finally
                {

                    if (!success)
                    {

                        // Rollback changes that were made to
                        // SegmentInfos but failed to get [fully]
                        // committed.  This way this reader instance
                        // remains consistent (matched to what's
                        // actually in the index):
                        RollbackCommit();

                        // Recompute deletable files & remove them (so
                        // partially written .del files, etc, are
                        // removed):
                        deleter.Refresh();
                    }
                }

                // Have the deleter remove any now unreferenced
                // files due to this commit:
                deleter.Checkpoint(segmentInfos, true);
                deleter.Close();

                if (writeLock != null)
                {
                    writeLock.Release(); // release write lock
                    writeLock = null;
                }
            }
            hasChanges = false;
        }