private void Run() { NativeMemory.EnsureRegistered(); int tries = 0; while (true) { (WaitCallback callback, object state)result; while (_actions.TryDequeue(out result)) { try { result.callback(result.state); } catch { // there is nothing that we _can_ do here that would be right // and there is no meaningful error handling. Ignoring this because // callers are expected to do their own exception catching } } // PERF: Entering a kernel lock even if the ManualResetEventSlim will try to avoid that doing some spin locking // is very costly. This is a hack that is allowing amortize a bit very high frequency events. The proper // way to handle requires infrastructure changes. http://issues.hibernatingrhinos.com/issue/RavenDB-8126 if (tries < 5) { // Yield execution quantum. If we are in a high-frequency event we will be able to avoid the kernel lock. Thread.Sleep(0); tries++; } else { _event.WaitHandle.WaitOne(); _event.Reset(); // Nothing we can do here, just block. tries = 0; } } }
private void BackgroundLogger() { NativeMemory.EnsureRegistered(); try { Interlocked.Increment(ref _generation); var threadStatesToRemove = new FastStack <WeakReference <LocalThreadWriterState> >(); while (_keepLogging) { try { var maxFileSize = MaxFileSizeInBytes; if (TryGetNewStreamAndApplyRetentionPolicies(maxFileSize, out var currentFile) == false) { if (_keepLogging == false) { return; } _hasEntries.Wait(1000); continue; } using (currentFile) { _readyToCompress.Set(); var sizeWritten = 0; var foundEntry = true; while (sizeWritten < maxFileSize) { if (foundEntry == false) { if (_keepLogging == false) { return; } // we don't want to have fsync here, we just // want to send it to the OS currentFile.Flush(flushToDisk: false); if (_hasEntries.IsSet == false) { // about to go to sleep, so can check if need to update offset or create new file for today logs UpdateLocalDateTimeOffset(); if (DateTime.Today != _today) { // let's create new file so its name will have today date break; } } _hasEntries.Wait(); if (_keepLogging == false) { return; } _hasEntries.Reset(); } foundEntry = false; for (var index = 0; index < _activePoolMessageEntries.Length; index++) { var messages = _activePoolMessageEntries[index]; for (var limit = 0; limit < 16; limit++) { if (messages.TryDequeue(out LogMessageEntry item) == false) { break; } foundEntry = true; sizeWritten += ActualWriteToLogTargets(item, currentFile); Debug.Assert(item.Data != null); _freePooledMessageEntries[index].Enqueue(item, 128); } } } } } catch (OutOfMemoryException) { Console.Error.WriteLine("Out of memory exception while trying to log, will avoid logging for the next 5 seconds"); DisableLogsFor(TimeSpan.FromSeconds(5)); } catch (Exception e) { var msg = e is IOException i && IsOutOfDiskSpaceException(i) ? "Couldn't create a new log file because of out of disk space! " + "Disabling the logs for 30 seconds" : "FATAL ERROR trying to log!"; Console.Error.WriteLine($"{msg}{Environment.NewLine}{e}"); DisableLogsFor(TimeSpan.FromSeconds(30)); } } } finally { _readyToCompress.Set(); if (_compressLoggingThread?.Join(1000) == false) { _tokenSource.Cancel(); } } }