19 using System.Collections.Generic;
20 using Lucene.Net.Support;
23 namespace Lucene.Net.Index
69 private IList<string> deletable;
74 private IDictionary<string, RefCount> refCounts =
new HashMap<string, RefCount>();
81 private List<CommitPoint> commits =
new List<CommitPoint>();
85 private List<ICollection<string>> lastFiles =
new List<ICollection<string>>();
88 private List<CommitPoint> commitsToDelete =
new List<CommitPoint>();
90 private System.IO.StreamWriter infoStream;
95 internal bool startingCommitDeleted;
98 private HashSet<string> synced;
103 public static bool VERBOSE_REF_COUNTS =
false;
105 internal void SetInfoStream(System.IO.StreamWriter infoStream)
107 this.infoStream = infoStream;
108 if (infoStream != null)
110 Message(
"setInfoStream deletionPolicy=" + policy);
114 private void Message(System.String message)
116 infoStream.WriteLine(
"IFD [" +
new DateTime().ToString() +
"; " +
ThreadClass.
Current().
Name +
"]: " + message);
129 this.docWriter = docWriter;
130 this.infoStream = infoStream;
131 this.synced = synced;
133 if (infoStream != null)
135 Message(
"init: current segments file is \"" + segmentInfos.
GetCurrentSegmentFileName() +
"\"; deletionPolicy=" + policy);
138 this.policy = policy;
139 this.directory = directory;
146 System.String[] files = directory.ListAll();
148 CommitPoint currentCommitPoint = null;
150 for (
int i = 0; i < files.Length; i++)
153 System.String fileName = files[i];
159 GetRefCount(fileName);
167 if (infoStream != null)
169 Message(
"init: load commit \"" + fileName +
"\"");
174 sis.
Read(directory, fileName);
176 catch (System.IO.FileNotFoundException)
185 if (infoStream != null)
187 Message(
"init: hit FileNotFoundException when loading commit \"" + fileName +
"\"; skipping this commit point");
191 catch (System.IO.IOException)
207 CommitPoint commitPoint =
new CommitPoint(
this, commitsToDelete, directory, sis);
210 currentCommitPoint = commitPoint;
212 commits.Add(commitPoint);
215 if (lastSegmentInfos == null || sis.
Generation > lastSegmentInfos.Generation)
217 lastSegmentInfos = sis;
224 if (currentCommitPoint == null)
238 catch (System.IO.IOException)
242 if (infoStream != null)
244 currentCommitPoint =
new CommitPoint(
this, commitsToDelete, directory, sis);
245 commits.Add(currentCommitPoint);
255 foreach(KeyValuePair<string, RefCount> entry
in refCounts)
257 string fileName = entry.Key;
258 RefCount rc = refCounts[fileName];
261 if (infoStream != null)
263 Message(
"init: removing unreferenced file \"" + fileName +
"\"");
265 DeleteFile(fileName);
271 policy.OnInit(commits);
275 Checkpoint(segmentInfos,
false);
277 startingCommitDeleted = currentCommitPoint.IsDeleted;
284 get {
return lastSegmentInfos; }
290 private void DeleteCommits()
293 int size = commitsToDelete.Count;
300 for (
int i = 0; i < size; i++)
302 CommitPoint commit = commitsToDelete[i];
303 if (infoStream != null)
305 Message(
"deleteCommits: now decRef commit \"" + commit.SegmentsFileName +
"\"");
307 foreach(
string file
in commit.files)
312 commitsToDelete.Clear();
315 size = commits.Count;
318 while (readFrom < size)
320 CommitPoint commit = commits[readFrom];
323 if (writeTo != readFrom)
325 commits[writeTo] = commits[readFrom];
332 while (size > writeTo)
334 commits.RemoveAt(size - 1);
347 public void Refresh(System.String segmentName)
349 System.String[] files = directory.ListAll();
351 System.String segmentPrefix1;
352 System.String segmentPrefix2;
353 if (segmentName != null)
355 segmentPrefix1 = segmentName +
".";
356 segmentPrefix2 = segmentName +
"_";
360 segmentPrefix1 = null;
361 segmentPrefix2 = null;
364 for (
int i = 0; i < files.Length; i++)
366 System.String fileName = files[i];
367 if (filter.
Accept(null, fileName) && (segmentName == null || fileName.StartsWith(segmentPrefix1) || fileName.StartsWith(segmentPrefix2)) && !refCounts.ContainsKey(fileName) && !fileName.Equals(
IndexFileNames.
SEGMENTS_GEN))
370 if (infoStream != null)
372 Message(
"refresh [prefix=" + segmentName +
"]: removing newly created unreferenced file \"" + fileName +
"\"");
374 DeleteFile(fileName);
379 public void Refresh()
384 public void Dispose()
388 int size = lastFiles.Count;
391 for (
int i = 0; i < size; i++)
392 DecRef(lastFiles[i]);
396 DeletePendingFiles();
399 private void DeletePendingFiles()
401 if (deletable != null)
403 IList<string> oldDeletable = deletable;
405 int size = oldDeletable.Count;
406 for (
int i = 0; i < size; i++)
408 if (infoStream != null)
410 Message(
"delete pending file " + oldDeletable[i]);
412 DeleteFile(oldDeletable[i]);
439 if (infoStream != null)
441 Message(
"now checkpoint \"" + segmentInfos.
GetCurrentSegmentFileName() +
"\" [" + segmentInfos.Count +
" segments " +
"; isCommit = " + isCommit +
"]");
446 DeletePendingFiles();
449 IncRef(segmentInfos, isCommit);
454 commits.Add(
new CommitPoint(
this, commitsToDelete, directory, segmentInfos));
457 policy.OnCommit(commits);
465 IList<string> docWriterFiles;
466 if (docWriter != null)
468 docWriterFiles = docWriter.OpenFiles();
469 if (docWriterFiles != null)
473 IncRef(docWriterFiles);
476 docWriterFiles = null;
479 int size = lastFiles.Count;
482 for (
int i = 0; i < size; i++)
483 DecRef(lastFiles[i]);
488 lastFiles.Add(segmentInfos.
Files(directory,
false));
490 if (docWriterFiles != null)
492 lastFiles.Add(docWriterFiles);
497 internal void IncRef(
SegmentInfos segmentInfos,
bool isCommit)
501 foreach(
string fileName
in segmentInfos.
Files(directory, isCommit))
507 internal void IncRef(ICollection<string> files)
509 foreach(
string file
in files)
515 internal void IncRef(
string fileName)
517 RefCount rc = GetRefCount(fileName);
518 if (infoStream != null && VERBOSE_REF_COUNTS)
520 Message(
" IncRef \"" + fileName +
"\": pre-incr count is " + rc.count);
525 internal void DecRef(ICollection<string> files)
527 foreach(
string file
in files)
533 internal void DecRef(System.String fileName)
535 RefCount rc = GetRefCount(fileName);
536 if (infoStream != null && VERBOSE_REF_COUNTS)
538 Message(
" DecRef \"" + fileName +
"\": pre-decr count is " + rc.count);
540 if (0 == rc.DecRef())
544 DeleteFile(fileName);
545 refCounts.Remove(fileName);
547 if (synced != null) {
550 synced.Remove(fileName);
556 internal void DecRef(SegmentInfos segmentInfos)
558 foreach(
string file
in segmentInfos.Files(directory,
false))
564 public bool Exists(String fileName)
566 if (!refCounts.ContainsKey(fileName))
572 return GetRefCount(fileName).count > 0;
576 private RefCount GetRefCount(System.String fileName)
579 if (!refCounts.ContainsKey(fileName))
581 rc =
new RefCount(fileName);
582 refCounts[fileName] = rc;
586 rc = refCounts[fileName];
591 internal void DeleteFiles(System.Collections.Generic.IList<
string> files)
593 foreach(
string file
in files)
600 internal void DeleteNewFiles(System.Collections.Generic.ICollection<
string> files)
602 foreach(
string fileName
in files)
604 if (!refCounts.ContainsKey(fileName))
606 if (infoStream != null)
608 Message(
"delete new file \"" + fileName +
"\"");
610 DeleteFile(fileName);
615 internal void DeleteFile(System.String fileName)
619 if (infoStream != null)
621 Message(
"delete \"" + fileName +
"\"");
623 directory.DeleteFile(fileName);
625 catch (System.IO.IOException e)
628 if (directory.FileExists(fileName))
638 if (infoStream != null)
640 Message(
"IndexFileDeleter: unable to remove file \"" + fileName +
"\": " + e.ToString() +
"; Will re-try later.");
642 if (deletable == null)
644 deletable =
new List<string>();
646 deletable.Add(fileName);
652 sealed
private class RefCount
656 internal System.String fileName;
657 internal bool initDone;
658 internal RefCount(System.String fileName)
660 this.fileName = fileName;
673 System.Diagnostics.Debug.Assert(count > 0,
"RefCount is 0 pre-increment for file " + fileName);
680 System.Diagnostics.Debug.Assert(count > 0,
"RefCount is 0 pre-decrement for file " + fileName);
691 sealed
private class CommitPoint:IndexCommit, System.IComparable<CommitPoint>
693 private void InitBlock(IndexFileDeleter enclosingInstance)
695 this.enclosingInstance = enclosingInstance;
697 private IndexFileDeleter enclosingInstance;
698 public IndexFileDeleter Enclosing_Instance
702 return enclosingInstance;
708 internal ICollection<string> files;
709 internal string segmentsFileName;
710 internal bool deleted;
712 internal ICollection<CommitPoint> commitsToDelete;
713 internal long version;
714 internal long generation;
715 internal bool isOptimized;
716 internal IDictionary<string, string> userData;
718 public CommitPoint(IndexFileDeleter enclosingInstance, ICollection<CommitPoint> commitsToDelete,
Directory directory, SegmentInfos segmentInfos)
720 InitBlock(enclosingInstance);
721 this.directory = directory;
722 this.commitsToDelete = commitsToDelete;
723 userData = segmentInfos.UserData;
724 segmentsFileName = segmentInfos.GetCurrentSegmentFileName();
725 version = segmentInfos.Version;
726 generation = segmentInfos.Generation;
727 files = segmentInfos.Files(directory,
true);
728 gen = segmentInfos.Generation;
729 isOptimized = segmentInfos.Count == 1 && !segmentInfos.Info(0).HasDeletions();
731 System.Diagnostics.Debug.Assert(!segmentInfos.HasExternalSegments(directory));
734 public override string ToString()
736 return "IndexFileDeleter.CommitPoint(" + segmentsFileName +
")";
739 public override bool IsOptimized
741 get {
return isOptimized; }
744 public override string SegmentsFileName
746 get {
return segmentsFileName; }
749 public override ICollection<string> FileNames
751 get {
return files; }
756 get {
return directory; }
761 get {
return version; }
764 public override long Generation
766 get {
return generation; }
769 public override IDictionary<string, string> UserData
771 get {
return userData; }
777 public override void Delete()
782 Enclosing_Instance.commitsToDelete.Add(
this);
786 public override bool IsDeleted
788 get {
return deleted; }
791 public int CompareTo(CommitPoint commit)
793 if (gen < commit.gen)
797 else if (gen > commit.gen)