Example #1
0
            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;
                    }
                }
            }
Example #2
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();
                }
            }
        }