/// <summary> /// Returns a new <see cref="ThreadState"/> iff any new state is available otherwise /// <c>null</c>. /// <para/> /// NOTE: the returned <see cref="ThreadState"/> is already locked iff non-<c>null</c>. /// </summary> /// <returns> a new <see cref="ThreadState"/> iff any new state is available otherwise /// <c>null</c> </returns> public virtual ThreadState NewThreadState() { lock (this) { if (numThreadStatesActive < threadStates.Length) { ThreadState threadState = threadStates[numThreadStatesActive]; threadState.@Lock(); // lock so nobody else will get this ThreadState bool unlock = true; try { if (threadState.IsActive) { // unreleased thread states are deactivated during DW#close() numThreadStatesActive++; // increment will publish the ThreadState Debug.Assert(threadState.dwpt == null); unlock = false; return(threadState); } // unlock since the threadstate is not active anymore - we are closed! Debug.Assert(AssertUnreleasedThreadStatesInactive()); return(null); } finally { if (unlock) { // in any case make sure we unlock if we fail threadState.Unlock(); } } } return(null); } }
public override ThreadState GetAndLock(Thread requestingThread, DocumentsWriter documentsWriter) { ThreadState threadState = null; if (NumThreadStatesActive == 0) { lock (this) { if (NumThreadStatesActive == 0) { threadState = states[0] = NewThreadState(); return(threadState); } } } Debug.Assert(NumThreadStatesActive > 0); for (int i = 0; i < maxRetry; i++) { int ord = random.Next(NumThreadStatesActive); lock (this) { threadState = states[ord]; Debug.Assert(threadState != null); } if (threadState.TryLock()) { return(threadState); } if (random.Next(20) == 0) { break; } } /* * only try to create a new threadstate if we can not lock the randomly * selected state. this is important since some tests rely on a single * threadstate in the single threaded case. Eventually it would be nice if * we would not have this limitation but for now we just make sure we only * allocate one threadstate if indexing is single threaded */ lock (this) { ThreadState newThreadState = NewThreadState(); if (newThreadState != null) // did we get a new state? { threadState = states[NumThreadStatesActive - 1] = newThreadState; //Debug.Assert(threadState.HeldByCurrentThread); return(threadState); } // if no new state is available lock the random one } Debug.Assert(threadState != null); threadState.@Lock(); return(threadState); }
internal void Abort(IndexWriter writer) { UninterruptableMonitor.Enter(this); try { if (Debugging.AssertsEnabled) { Debugging.Assert(!UninterruptableMonitor.IsEntered(writer), "IndexWriter lock should never be hold when aborting"); } bool success = false; JCG.HashSet <string> newFilesSet = new JCG.HashSet <string>(); try { deleteQueue.Clear(); if (infoStream.IsEnabled("DW")) { infoStream.Message("DW", "abort"); } int limit = perThreadPool.NumThreadStatesActive; for (int i = 0; i < limit; i++) { ThreadState perThread = perThreadPool.GetThreadState(i); perThread.@Lock(); try { AbortThreadState(perThread, newFilesSet); } finally { perThread.Unlock(); } } flushControl.AbortPendingFlushes(newFilesSet); PutEvent(new DeleteNewFilesEvent(newFilesSet)); flushControl.WaitForFlush(); success = true; } finally { if (infoStream.IsEnabled("DW")) { infoStream.Message("DW", "done abort; abortedFiles=" + string.Format(J2N.Text.StringFormatter.InvariantCulture, "{0}", newFilesSet) + " success=" + success); } } } finally { UninterruptableMonitor.Exit(this); } }
internal void LockAndAbortAll(IndexWriter indexWriter) { UninterruptableMonitor.Enter(this); try { if (Debugging.AssertsEnabled) { Debugging.Assert(indexWriter.HoldsFullFlushLock); } if (infoStream.IsEnabled("DW")) { infoStream.Message("DW", "lockAndAbortAll"); } bool success = false; try { deleteQueue.Clear(); int limit = perThreadPool.MaxThreadStates; JCG.HashSet <string> newFilesSet = new JCG.HashSet <string>(); for (int i = 0; i < limit; i++) { ThreadState perThread = perThreadPool.GetThreadState(i); perThread.@Lock(); AbortThreadState(perThread, newFilesSet); } deleteQueue.Clear(); flushControl.AbortPendingFlushes(newFilesSet); PutEvent(new DeleteNewFilesEvent(newFilesSet)); flushControl.WaitForFlush(); success = true; } finally { if (infoStream.IsEnabled("DW")) { infoStream.Message("DW", "finished lockAndAbortAll success=" + success); } if (!success) { // if something happens here we unlock all states again UnlockAllAfterAbortAll(indexWriter); } } } finally { UninterruptableMonitor.Exit(this); } }
private void CheckoutAndBlock(ThreadState perThread) { perThread.@Lock(); try { Debug.Assert(perThread.flushPending, "can not block non-pending threadstate"); Debug.Assert(fullFlush, "can not block if fullFlush == false"); DocumentsWriterPerThread dwpt; long bytes = perThread.bytesUsed; dwpt = perThreadPool.Reset(perThread, closed); numPending--; blockedFlushes.AddLast(new BlockedFlush(dwpt, bytes)); } finally { perThread.Unlock(); } }
private bool AssertActiveDeleteQueue(DocumentsWriterDeleteQueue queue) { int limit = perThreadPool.NumThreadStatesActive; for (int i = 0; i < limit; i++) { ThreadState next = perThreadPool.GetThreadState(i); next.@Lock(); try { Debug.Assert(!next.IsInitialized || next.dwpt.deleteQueue == queue, "isInitialized: " + next.IsInitialized + " numDocs: " + (next.IsInitialized ? next.dwpt.NumDocsInRAM : 0)); } finally { next.Unlock(); } } return(true); }
/// <summary> /// Deactivate all unreleased threadstates /// </summary> internal virtual void DeactivateUnreleasedStates() { lock (this) { for (int i = numThreadStatesActive; i < threadStates.Length; i++) { ThreadState threadState = threadStates[i]; threadState.@Lock(); try { threadState.Deactivate(); } finally { threadState.Unlock(); } } } }
internal void Abort(IndexWriter writer) { lock (this) { //Debug.Assert(!Thread.HoldsLock(writer), "IndexWriter lock should never be hold when aborting"); bool success = false; HashSet <string> newFilesSet = new HashSet <string>(); try { deleteQueue.Clear(); if (infoStream.IsEnabled("DW")) { infoStream.Message("DW", "abort"); } int limit = perThreadPool.NumThreadStatesActive; for (int i = 0; i < limit; i++) { ThreadState perThread = perThreadPool.GetThreadState(i); perThread.@Lock(); try { AbortThreadState(perThread, newFilesSet); } finally { perThread.Unlock(); } } flushControl.AbortPendingFlushes(newFilesSet); PutEvent(new DeleteNewFilesEvent(newFilesSet)); flushControl.WaitForFlush(); success = true; } finally { if (infoStream.IsEnabled("DW")) { infoStream.Message("DW", "done abort; abortedFiles=" + Arrays.ToString(newFilesSet) + " success=" + success); } } } }
public override ThreadState GetAndLock(Thread requestingThread, DocumentsWriter documentsWriter) { if (threadBindings.TryGetValue(requestingThread, out ThreadState threadState) && threadState.TryLock()) { return(threadState); } ThreadState minThreadState = null; /* TODO -- another thread could lock the minThreadState we just got while * we should somehow prevent this. */ // Find the state that has minimum number of threads waiting minThreadState = MinContendedThreadState(); if (minThreadState == null || minThreadState.HasQueuedThreads) { ThreadState newState = NewThreadState(); // state is already locked if non-null if (newState != null) { if (Debugging.AssertsEnabled) { Debugging.Assert(newState.IsHeldByCurrentThread); } threadBindings[requestingThread] = newState; return(newState); } else if (minThreadState == null) { /* * no new threadState available we just take the minContented one * this must return a valid thread state since we accessed the * synced context in newThreadState() above. */ minThreadState = MinContendedThreadState(); } } if (Debugging.AssertsEnabled) { Debugging.Assert(minThreadState != null, () => "ThreadState is null"); } minThreadState.@Lock(); return(minThreadState); }
private void CheckoutAndBlock(ThreadState perThread) { perThread.@Lock(); try { if (Debugging.AssertsEnabled) { Debugging.Assert(perThread.flushPending, "can not block non-pending threadstate"); Debugging.Assert(fullFlush, "can not block if fullFlush == false"); } DocumentsWriterPerThread dwpt; long bytes = perThread.bytesUsed; dwpt = DocumentsWriterPerThreadPool.Reset(perThread, closed); // LUCENENET specific - made method static per CA1822 numPending--; blockedFlushes.AddLast(new BlockedFlush(dwpt, bytes)); } finally { perThread.Unlock(); } }
/// <summary> /// Returns the number of currently deactivated <see cref="ThreadState"/> instances. /// A deactivated <see cref="ThreadState"/> should not be used for indexing anymore. /// </summary> /// <returns> the number of currently deactivated <see cref="ThreadState"/> instances. </returns> internal virtual int NumDeactivatedThreadStates() { int count = 0; for (int i = 0; i < threadStates.Length; i++) { ThreadState threadState = threadStates[i]; threadState.@Lock(); try { if (!threadState.isActive) { count++; } } finally { threadState.Unlock(); } } return(count); }
/// <summary> /// Deactivate all unreleased threadstates /// </summary> internal void DeactivateUnreleasedStates() { UninterruptableMonitor.Enter(this); try { for (int i = numThreadStatesActive; i < threadStates.Length; i++) { ThreadState threadState = threadStates[i]; threadState.@Lock(); try { threadState.Deactivate(); } finally { threadState.Unlock(); } } } finally { UninterruptableMonitor.Exit(this); } }
internal void MarkForFullFlush() { DocumentsWriterDeleteQueue flushingQueue; lock (this) { Debug.Assert(!fullFlush, "called DWFC#markForFullFlush() while full flush is still running"); Debug.Assert(fullFlushBuffer.Count == 0, "full flush buffer should be empty: " + fullFlushBuffer); fullFlush = true; flushingQueue = documentsWriter.deleteQueue; // Set a new delete queue - all subsequent DWPT will use this queue until // we do another full flush DocumentsWriterDeleteQueue newQueue = new DocumentsWriterDeleteQueue(flushingQueue.generation + 1); documentsWriter.deleteQueue = newQueue; } int limit = perThreadPool.NumThreadStatesActive; for (int i = 0; i < limit; i++) { ThreadState next = perThreadPool.GetThreadState(i); next.@Lock(); try { if (!next.IsInitialized) { if (closed && next.IsActive) { perThreadPool.DeactivateThreadState(next); } continue; } Debug.Assert(next.dwpt.deleteQueue == flushingQueue || next.dwpt.deleteQueue == documentsWriter.deleteQueue, " flushingQueue: " + flushingQueue + " currentqueue: " + documentsWriter.deleteQueue + " perThread queue: " + next.dwpt.deleteQueue + " numDocsInRam: " + next.dwpt.NumDocsInRAM); if (next.dwpt.deleteQueue != flushingQueue) { // this one is already a new DWPT continue; } AddFlushableState(next); } finally { next.Unlock(); } } lock (this) { /* make sure we move all DWPT that are where concurrently marked as * pending and moved to blocked are moved over to the flushQueue. There is * a chance that this happens since we marking DWPT for full flush without * blocking indexing.*/ PruneBlockedQueue(flushingQueue); Debug.Assert(AssertBlockedFlushes(documentsWriter.deleteQueue)); //FlushQueue.AddAll(FullFlushBuffer); foreach (var dwpt in fullFlushBuffer) { flushQueue.Enqueue(dwpt); } fullFlushBuffer.Clear(); UpdateStallState(); } Debug.Assert(AssertActiveDeleteQueue(documentsWriter.deleteQueue)); }