/// <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 /// /// </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; }
/// <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); }
/// <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); } }
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(); } }
/// <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(); } } } }
/// <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; } } }
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"); } } } }
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; } } }
/// <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; }
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; }
/// <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; } }
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; } }
/// <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); } }
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(); } }
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; } }
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; }
/// <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; } }
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; } }
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; } }
/// <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; }
/// <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"); } } } }
/// <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; } }
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(); } } }
/// <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; }