Skip to content

Commit

Permalink
Multihreading fix for regex, #26
Browse files Browse the repository at this point in the history
  • Loading branch information
daningalla committed Jul 11, 2023
1 parent 579e249 commit 383f233
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
13 changes: 9 additions & 4 deletions bug-repro/MultiThreaded/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
using Microsoft.Extensions.Logging;
using Vertical.SpectreLogger;

const int threadCount = 25;
const int logsPerThread = 150;
const int delayMs = 250;

var loggerFactory = LoggerFactory.Create(builder => builder.AddSpectreConsole());
var logger = loggerFactory.CreateLogger("Test");
var threads = Enumerable.Range(0, 25).Select(i =>
var threads = Enumerable.Range(0, threadCount).Select(i =>
Task.Run(async () =>
{
await Task.Delay(250);
for (var c = 0; c < 25; c++)
await Task.Delay(delayMs);
for (var c = 0; c < logsPerThread; c++)
{
if (c % 25 == 0)
if (c % 5 == 0)
{
try
{
Expand Down
47 changes: 30 additions & 17 deletions src/Templates/TemplateSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,25 @@ internal TemplateSegment(
Source = source;
StartIndex = startIndex;
Length = length;
IsTemplate = match?.Success ?? false;
Value = match?.Value ?? Source.Substring(startIndex, length);
var groups = match?.Groups;

// Force the regular expression's materialization of internal data - prevents issues
// with multi-threaded logging where the RegEx has deferred evaluation.
var _ = match?.Groups;
if (groups == null)
return;

HasDestructureSpecifier = groups[DestructuringGroup].Success;
InnerTemplate = groups[InnerTemplateGroup].Value;
Key = groups[KeyGroup].Value;
ControlCode = groups[ControlGroup].Value;
ControlCodeMatched = groups[ControlGroup].Success;
CompositeFormatSpan = groups[CompositeFormatSpanGroup].Value;
AlignmentSpan = groups[WidthSpanGroup].Value;
Alignment = int.TryParse(groups[WidthValueGroup].Value, out var i)
? i
: null;
FormatSpan = groups[FormatSpanGroup].Value;
Format = groups[FormatValueGroup].Value;
}

/// <summary>
Expand All @@ -86,64 +101,62 @@ internal TemplateSegment(
/// <summary>
/// Gets whether the segment is a template.
/// </summary>
public bool IsTemplate => Match?.Success == true;
public bool IsTemplate { get; }

/// <summary>
/// Gets the segment value.
/// </summary>
public string Value => Match?.Value ?? Source.Substring(StartIndex, Length);
public string Value { get; }

/// <summary>
/// Gets whether the destructure operator was specified.
/// </summary>
public bool HasDestructureSpecifier => Match?.Groups[DestructuringGroup].Success == true;
public bool HasDestructureSpecifier { get; }

/// <summary>
/// Gets the inner content of the template with the braces removed.
/// </summary>
public string? InnerTemplate => Match?.Groups[InnerTemplateGroup].Value;
public string? InnerTemplate { get; }

/// <summary>
/// Gets the template key.
/// </summary>
public string? Key => Match?.Groups[KeyGroup].Value;
public string? Key { get; }

/// <summary>
/// Gets the template control code.
/// </summary>
public string? ControlCode => Match?.Groups[ControlGroup].Value;
public string? ControlCode { get; }

/// <summary>
/// Gets whether the control code group was matched.
/// </summary>
public bool ControlCodeMatched => Match?.Groups[ControlGroup].Success == true;
public bool ControlCodeMatched { get; }

/// <summary>
/// Gets the format group value.
/// </summary>
public string? CompositeFormatSpan => Match?.Groups[CompositeFormatSpanGroup].Value;
public string? CompositeFormatSpan { get; }

/// <summary>
/// Gets the width span.
/// </summary>
public string? AlignmentSpan => Match?.Groups[WidthSpanGroup].Value;
public string? AlignmentSpan { get; }

/// <summary>
/// Gets the formatted width value, or null if the value is not available.
/// </summary>
public int? Alignment => int.TryParse(Match?.Groups[WidthValueGroup].Value, out var i)
? i
: null;
public int? Alignment { get; }

/// <summary>
/// Gets the format span.
/// </summary>
public string? FormatSpan => Match?.Groups[FormatSpanGroup].Value;
public string? FormatSpan { get; }

/// <summary>
/// Gets the format value.
/// </summary>
public string? Format => Match?.Groups[FormatValueGroup].Value;
public string? Format { get; }

/// <summary>
/// Gets the complete source string.
Expand Down

0 comments on commit 383f233

Please sign in to comment.