Beispiel #1
0
        /// <summary>Merges the named range of segments, replacing them in the stack with a
        /// single segment.
        /// </summary>
        private void  MergeSegments(int minSegment, int end)
        {
            System.String mergedName = NewSegmentName();
            if (infoStream != null)
            {
                infoStream.Write("merging segments");
            }
            SegmentMerger merger = new SegmentMerger(this, mergedName);

            System.Collections.ArrayList segmentsToDelete = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
            for (int i = minSegment; i < end; i++)
            {
                SegmentInfo si = segmentInfos.Info(i);
                if (infoStream != null)
                {
                    infoStream.Write(" " + si.name + " (" + si.docCount + " docs)");
                }
                IndexReader reader = SegmentReader.Get(si);
                merger.Add(reader);
                if ((reader.Directory() == this.directory) || (reader.Directory() == this.ramDirectory))
                {
                    segmentsToDelete.Add(reader);                     // queue segment for deletion
                }
            }

            int mergedDocCount = merger.Merge();

            if (infoStream != null)
            {
                infoStream.WriteLine(" into " + mergedName + " (" + mergedDocCount + " docs)");
            }

            for (int i = end - 1; i >= minSegment; i--)
            {
                // remove old infos & add new
                segmentInfos.RemoveAt(i);
            }
            segmentInfos.Add(new SegmentInfo(mergedName, mergedDocCount, directory));

            // close readers before we attempt to delete now-obsolete segments
            merger.CloseReaders();

            lock (directory)
            {
                // in- & inter-process sync
                new AnonymousClassWith3(segmentsToDelete, this, directory.MakeLock(COMMIT_LOCK_NAME), COMMIT_LOCK_TIMEOUT).Run();
            }

            if (useCompoundFile)
            {
                System.Collections.ArrayList filesToDelete = merger.CreateCompoundFile(mergedName + ".tmp");
                lock (directory)
                {
                    // in- & inter-process sync
                    new AnonymousClassWith4(mergedName, filesToDelete, this, directory.MakeLock(COMMIT_LOCK_NAME), COMMIT_LOCK_TIMEOUT).Run();
                }
            }
        }
Beispiel #2
0
		/// <summary> Merges the named range of segments, replacing them in the stack with a
		/// single segment.
		/// </summary>
		private int MergeSegments(SegmentInfos sourceSegments, int minSegment, int end)
		{
			
			// We may be called solely because there are deletes
			// pending, in which case doMerge is false:
			bool doMerge = end > 0;
			System.String mergedName = NewSegmentName();
			SegmentMerger merger = null;
			
			System.Collections.ArrayList segmentsToDelete = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
			
			System.String segmentsInfosFileName = segmentInfos.GetCurrentSegmentFileName();
			System.String nextSegmentsFileName = segmentInfos.GetNextSegmentFileName();
			
			SegmentInfo newSegment = null;
			
			int mergedDocCount = 0;
			
			// This is try/finally to make sure merger's readers are closed:
			try
			{
				
				if (doMerge)
				{
					if (infoStream != null)
						infoStream.Write("merging segments");
					merger = new SegmentMerger(this, mergedName);
					
					for (int i = minSegment; i < end; i++)
					{
						SegmentInfo si = sourceSegments.Info(i);
						if (infoStream != null)
							infoStream.Write(" " + si.name + " (" + si.docCount + " docs)");
						IndexReader reader = SegmentReader.Get(si); // no need to
						// set deleter
						// (yet)
						merger.Add(reader);
						if ((reader.Directory() == this.directory) || (reader.Directory() == this.ramDirectory))
							segmentsToDelete.Add(reader); // queue segment
						// for deletion
					}
				}
				
				SegmentInfos rollback = null;
				bool success = false;
				
				// This is try/finally to rollback our internal state
				// if we hit exception when doing the merge:
				try
				{
					
					if (doMerge)
					{
						mergedDocCount = merger.Merge();
						
						if (infoStream != null)
						{
							infoStream.WriteLine(" into " + mergedName + " (" + mergedDocCount + " docs)");
						}
						
						newSegment = new SegmentInfo(mergedName, mergedDocCount, directory, false, true);
					}
					
					if (!inTransaction && (sourceSegments != ramSegmentInfos || bufferedDeleteTerms.Count > 0))
					{
						// Now save the SegmentInfo instances that
						// we are replacing:
						rollback = (SegmentInfos) segmentInfos.Clone();
					}
					
					if (doMerge)
					{
						if (sourceSegments == ramSegmentInfos)
						{
							segmentInfos.Add(newSegment);
						}
						else
						{
							for (int i = end - 1; i > minSegment; i--)
							// remove old infos & add new
								sourceSegments.RemoveAt(i);
							
							segmentInfos[minSegment] = newSegment;
						}
					}
					
					if (sourceSegments == ramSegmentInfos)
					{
						// Should not be necessary: no prior commit should
						// have left pending files, so just defensive:
						deleter.ClearPendingFiles();
						MaybeApplyDeletes(doMerge);
						DoAfterFlush();
					}
					
					if (!inTransaction)
					{
						segmentInfos.Write(directory); // commit before deleting
					}
					else
					{
						commitPending = true;
					}
					
					success = true;
				}
				finally
				{
					
					if (success)
					{
						// The non-ram-segments case is already committed
						// (above), so all the remains for ram segments case
						// is to clear the ram segments:
						if (sourceSegments == ramSegmentInfos)
						{
							ramSegmentInfos.Clear();
						}
					}
					else if (!inTransaction)
					{
						
						// Must rollback so our state matches index:
						
						if (sourceSegments == ramSegmentInfos && 0 == bufferedDeleteTerms.Count)
						{
							// Simple case: newSegment may or may not have
							// been added to the end of our segment infos,
							// so just check & remove if so:
							if (newSegment != null && segmentInfos.Count > 0 && segmentInfos.Info(segmentInfos.Count - 1) == newSegment)
							{
								segmentInfos.RemoveAt(segmentInfos.Count - 1);
							}
						}
						else if (rollback != null)
						{
							// Rollback the individual SegmentInfo
							// instances, but keep original SegmentInfos
							// instance (so we don't try to write again the
							// same segments_N file -- write once):
							segmentInfos.Clear();
							segmentInfos.AddRange(rollback);
						}
						
						// Erase any pending files that we were going to delete:
						// i.e. old del files added by SegmentReader.doCommit()
						deleter.ClearPendingFiles();
						
						// Delete any partially created files:
						deleter.DeleteFile(nextSegmentsFileName);
						deleter.FindDeletableFiles();
						deleter.DeleteFiles();
					}
				}
			}
			finally
			{
				// close readers before we attempt to delete now-obsolete segments
				if (doMerge)
					merger.CloseReaders();
			}
			
			if (!inTransaction)
			{
				// Attempt to delete all files we just obsoleted:
				deleter.DeleteFile(segmentsInfosFileName); // delete old segments_N
				// file
				deleter.DeleteSegments(segmentsToDelete); // delete now-unused
				// segments
				// Includes the old del files
				deleter.CommitPendingFiles();
			}
			else
			{
				deleter.AddPendingFile(segmentsInfosFileName); // delete old
				// segments_N file
				deleter.DeleteSegments(segmentsToDelete, protectedSegments); // delete
				// now-unused
				// segments
			}
			
			if (useCompoundFile && doMerge)
			{
				
				segmentsInfosFileName = nextSegmentsFileName;
				nextSegmentsFileName = segmentInfos.GetNextSegmentFileName();
				
				System.Collections.ArrayList filesToDelete;
				
				bool success = false;
				
				try
				{
					
					filesToDelete = merger.CreateCompoundFile(mergedName + ".cfs");
					newSegment.SetUseCompoundFile(true);
					if (!inTransaction)
					{
						segmentInfos.Write(directory); // commit again so readers
						// know we've switched this
						// segment to a compound
						// file
					}
					success = true;
				}
				finally
				{
					if (!success && !inTransaction)
					{
						// Must rollback:
						newSegment.SetUseCompoundFile(false);
						deleter.DeleteFile(mergedName + ".cfs");
						deleter.DeleteFile(nextSegmentsFileName);
					}
				}
				
				if (!inTransaction)
				{
					deleter.DeleteFile(segmentsInfosFileName); // delete old
					// segments_N file
				}
				
				// We can delete these segments whether or not we are
				// in a transaction because we had just written them
				// above so they can't need protection by the
				// transaction:
				deleter.DeleteFiles(filesToDelete); // delete now-unused segments
			}
			
			return mergedDocCount;
		}