Skip to content

Commit

Permalink
Introduce ObjectPool and use it for ResilienceContext pooling (#1111)
Browse files Browse the repository at this point in the history
  • Loading branch information
martintmk authored Apr 12, 2023
1 parent a058852 commit 5e19d1d
Show file tree
Hide file tree
Showing 26 changed files with 235 additions and 63 deletions.
54 changes: 27 additions & 27 deletions src/Polly.Core.Benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,44 @@ LaunchCount=2 WarmupCount=10

## PIPELINES

| Method | Components | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|------------------- |----------- |------------:|----------:|----------:|------:|--------:|-------:|----------:|------------:|
| ExecutePipeline_V7 | 1 | 71.29 ns | 1.309 ns | 1.959 ns | 1.00 | 0.00 | 0.0362 | 304 B | 1.00 |
| ExecutePipeline_V8 | 1 | 92.93 ns | 1.398 ns | 2.049 ns | 1.30 | 0.05 | 0.0181 | 152 B | 0.50 |
| | | | | | | | | | |
| ExecutePipeline_V7 | 2 | 164.39 ns | 5.294 ns | 7.592 ns | 1.00 | 0.00 | 0.0658 | 552 B | 1.00 |
| ExecutePipeline_V8 | 2 | 126.74 ns | 1.198 ns | 1.755 ns | 0.77 | 0.04 | 0.0181 | 152 B | 0.28 |
| | | | | | | | | | |
| ExecutePipeline_V7 | 5 | 540.07 ns | 16.941 ns | 24.832 ns | 1.00 | 0.00 | 0.1545 | 1296 B | 1.00 |
| ExecutePipeline_V8 | 5 | 257.13 ns | 2.748 ns | 4.114 ns | 0.48 | 0.03 | 0.0181 | 152 B | 0.12 |
| | | | | | | | | | |
| ExecutePipeline_V7 | 10 | 1,111.72 ns | 16.405 ns | 23.527 ns | 1.00 | 0.00 | 0.3014 | 2536 B | 1.00 |
| ExecutePipeline_V8 | 10 | 467.93 ns | 6.546 ns | 9.388 ns | 0.42 | 0.01 | 0.0181 | 152 B | 0.06 |
| Method | Components | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|------------------- |----------- |------------:|----------:|-----------:|------------:|------:|--------:|-------:|----------:|------------:|
| ExecutePipeline_V7 | 1 | 74.78 ns | 1.555 ns | 2.279 ns | 75.63 ns | 1.00 | 0.00 | 0.0362 | 304 B | 1.00 |
| ExecutePipeline_V8 | 1 | 85.69 ns | 0.500 ns | 0.732 ns | 85.36 ns | 1.15 | 0.04 | - | - | 0.00 |
| | | | | | | | | | | |
| ExecutePipeline_V7 | 2 | 165.37 ns | 1.157 ns | 1.732 ns | 165.59 ns | 1.00 | 0.00 | 0.0658 | 552 B | 1.00 |
| ExecutePipeline_V8 | 2 | 119.10 ns | 0.653 ns | 0.915 ns | 119.63 ns | 0.72 | 0.01 | - | - | 0.00 |
| | | | | | | | | | | |
| ExecutePipeline_V7 | 5 | 533.97 ns | 7.327 ns | 10.967 ns | 536.79 ns | 1.00 | 0.00 | 0.1545 | 1296 B | 1.00 |
| ExecutePipeline_V8 | 5 | 227.69 ns | 1.236 ns | 1.812 ns | 227.72 ns | 0.43 | 0.01 | - | - | 0.00 |
| | | | | | | | | | | |
| ExecutePipeline_V7 | 10 | 1,191.41 ns | 35.512 ns | 53.152 ns | 1,192.79 ns | 1.00 | 0.00 | 0.3014 | 2536 B | 1.00 |
| ExecutePipeline_V8 | 10 | 557.95 ns | 76.434 ns | 112.036 ns | 505.58 ns | 0.47 | 0.09 | - | - | 0.00 |

## TIMEOUT

| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|------------------ |---------:|--------:|---------:|------:|--------:|-------:|----------:|------------:|
| ExecuteTimeout_V7 | 287.1 ns | 9.20 ns | 12.59 ns | 1.00 | 0.00 | 0.0868 | 728 B | 1.00 |
| ExecuteTimeout_V8 | 272.9 ns | 3.16 ns | 4.54 ns | 0.95 | 0.04 | 0.0439 | 368 B | 0.51 |
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|------------------ |---------:|--------:|--------:|------:|--------:|-------:|----------:|------------:|
| ExecuteTimeout_V7 | 281.5 ns | 5.76 ns | 8.08 ns | 1.00 | 0.00 | 0.0868 | 728 B | 1.00 |
| ExecuteTimeout_V8 | 268.9 ns | 3.86 ns | 5.53 ns | 0.96 | 0.04 | 0.0257 | 216 B | 0.30 |

## RETRY

| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------- |---------:|--------:|--------:|------:|--------:|-------:|----------:|------------:|
| ExecuteRetry_V7 | 162.5 ns | 2.33 ns | 3.34 ns | 1.00 | 0.00 | 0.0687 | 576 B | 1.00 |
| ExecuteRetry_V8 | 152.3 ns | 1.31 ns | 1.93 ns | 0.94 | 0.02 | 0.0181 | 152 B | 0.26 |
| ExecuteRetry_V7 | 169.8 ns | 4.98 ns | 6.98 ns | 1.00 | 0.00 | 0.0687 | 576 B | 1.00 |
| ExecuteRetry_V8 | 144.9 ns | 2.35 ns | 3.52 ns | 0.85 | 0.04 | - | - | 0.00 |

## RATE LIMITER

| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------- |---------:|--------:|--------:|------:|--------:|-------:|----------:|------------:|
| ExecuteRateLimiter_V7 | 173.8 ns | 2.33 ns | 3.48 ns | 1.00 | 0.00 | 0.0448 | 376 B | 1.00 |
| ExecuteRateLimiter_V8 | 207.9 ns | 2.06 ns | 2.89 ns | 1.19 | 0.03 | 0.0229 | 192 B | 0.51 |
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|---------------------- |---------:|---------:|---------:|------:|--------:|-------:|----------:|------------:|
| ExecuteRateLimiter_V7 | 190.8 ns | 10.01 ns | 14.98 ns | 1.00 | 0.00 | 0.0448 | 376 B | 1.00 |
| ExecuteRateLimiter_V8 | 199.6 ns | 2.54 ns | 3.64 ns | 1.05 | 0.09 | 0.0048 | 40 B | 0.11 |

## STRATEGY PIPELINE (TIMEOUT + RETRY + TIMEOUT + RATE LIMITER)

| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|--------------------------- |---------:|----------:|----------:|---------:|------:|--------:|-------:|----------:|------------:|
| ExecuteStrategyPipeline_V7 | 1.207 us | 0.0201 us | 0.0295 us | 1.202 us | 1.00 | 0.00 | 0.2861 | 2400 B | 1.00 |
| ExecuteStrategyPipeline_V8 | 1.117 us | 0.0297 us | 0.0407 us | 1.118 us | 0.93 | 0.05 | 0.0935 | 792 B | 0.33 |
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|--------------------------- |---------:|----------:|----------:|------:|--------:|-------:|----------:|------------:|
| ExecuteStrategyPipeline_V7 | 1.321 us | 0.0355 us | 0.0520 us | 1.00 | 0.00 | 0.2861 | 2400 B | 1.00 |
| ExecuteStrategyPipeline_V8 | 1.126 us | 0.0193 us | 0.0283 us | 0.85 | 0.03 | 0.0763 | 640 B | 0.27 |
4 changes: 2 additions & 2 deletions src/Polly.Core.Tests/ExecutionRejectedExceptionTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Polly.Core.Tests.Timeout;
namespace Polly.Core.Tests;

public class ExecutionRejectedExceptionTests
{
[Fact]
public void Ctor_Ok()
{
new CustomException().Message.Should().Be("Exception of type 'Polly.Core.Tests.Timeout.ExecutionRejectedExceptionTests+CustomException' was thrown.");
new CustomException().Message.Should().Be("Exception of type 'Polly.Core.Tests.ExecutionRejectedExceptionTests+CustomException' was thrown.");
new CustomException("Dummy").Message.Should().Be("Dummy");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using System;

namespace Polly.Core.Tests.Utils;
namespace Polly.Core.Tests.Helpers;

/// <summary>
/// Utility that serializes and deserializes the exceptions using the binary formatter.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Moq;
using Polly.Utils;

namespace Polly.Core.Tests.Utils;
namespace Polly.Core.Tests.Helpers;

internal class FakeTimeProvider : Mock<TimeProvider>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Polly.Strategy;

namespace Polly.Core.Tests.Utils;
namespace Polly.Core.Tests.Helpers;

public class TestArguments : IResilienceArguments
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Polly.Core.Tests.Utils;
namespace Polly.Core.Tests.Helpers;

public class TestResilienceStrategy : ResilienceStrategy
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Polly.Core.Tests.Utils;
namespace Polly.Core.Tests.Helpers;

#pragma warning disable CA1031 // Do not catch general exception types

Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Core.Tests/Polly.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
</ItemGroup>

<ItemGroup>
<Using Include="Polly.Core.Tests.Utils" />
<Using Include="Polly.Core.Tests.Helpers" />
</ItemGroup>
</Project>
3 changes: 0 additions & 3 deletions src/Polly.Core.Tests/Registry/StrategyId.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using System;
using System.Collections.Generic;

namespace Polly.Core.Tests.Registry;

public record StrategyId(Type Type, string BuilderName, string InstanceName = "")
Expand Down
10 changes: 10 additions & 0 deletions src/Polly.Core.Tests/ResilienceContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ public void Get_EnsureDefaults()
AssertDefaults(context);
}

[Fact]
public void Get_EnsurePooled()
{
var context = ResilienceContext.Get();

ResilienceContext.Return(context);

ResilienceContext.Get().Should().BeSameAs(context);
}

[Fact]
public void Return_Null_Throws()
{
Expand Down
3 changes: 0 additions & 3 deletions src/Polly.Core.Tests/Retry/RetryDelayGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
using System;
using System.Threading.Tasks;
using Polly.Retry;
using Polly.Strategy;
using Xunit;

namespace Polly.Core.Tests.Retry;

Expand Down
1 change: 0 additions & 1 deletion src/Polly.Core.Tests/Retry/RetryHelperTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using Polly.Retry;

namespace Polly.Core.Tests.Retry;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.ComponentModel.DataAnnotations;
using Polly.Builder;
using Polly.Retry;
using Xunit;

namespace Polly.Core.Tests.Retry;

Expand Down
2 changes: 0 additions & 2 deletions src/Polly.Core.Tests/Strategy/OutcomeEventTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System;
using System.Threading.Tasks;
using Polly.Strategy;

namespace Polly.Core.Tests.Strategy;
Expand Down
2 changes: 0 additions & 2 deletions src/Polly.Core.Tests/Strategy/OutcomeGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System;
using System.Threading.Tasks;
using Polly.Strategy;

namespace Polly.Core.Tests.Strategy;
Expand Down
2 changes: 0 additions & 2 deletions src/Polly.Core.Tests/Strategy/OutcomePredicateTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System;
using System.Threading.Tasks;
using Polly.Strategy;

namespace Polly.Core.Tests.Strategy;
Expand Down
1 change: 0 additions & 1 deletion src/Polly.Core.Tests/Strategy/OutcomeTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using Polly.Strategy;

namespace Polly.Core.Tests.Strategy;
Expand Down
6 changes: 3 additions & 3 deletions src/Polly.Core.Tests/Strategy/SimpleEventTests.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using Polly.Strategy;

namespace Polly.Core.Tests.Timeout;
namespace Polly.Core.Tests.Strategy;

public class SimpleEventTests
{
[Fact]
public async Task Add_EnsureOrdering()
{
var ev = new DummyEvent();
List<int> raisedEvents = new List<int>();
var raisedEvents = new List<int>();

ev.Add(() => raisedEvents.Add(1));
ev.Add(args => raisedEvents.Add(2));
Expand Down Expand Up @@ -41,7 +41,7 @@ public async Task CreateHandler_Ok(int count)
var ev = new DummyEvent();
var events = new List<int>();

for (int i = 0; i < count; i++)
for (var i = 0; i < count; i++)
{
ev.Add(() => events.Add(i));
}
Expand Down
1 change: 0 additions & 1 deletion src/Polly.Core.Tests/Timeout/TimeoutAttributeTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.ComponentModel.DataAnnotations;
using Polly.Timeout;

namespace Polly.Core.Tests.Timeout;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.ComponentModel.DataAnnotations;
using Polly.Timeout;
using Polly.Utils;
using Xunit;

namespace Polly.Core.Tests.Timeout;

Expand Down
2 changes: 0 additions & 2 deletions src/Polly.Core.Tests/Timeout/TimeoutUtilTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using Polly.Timeout;
using Xunit;

namespace Polly.Core.Tests.Timeout;
public class TimeoutUtilTests
Expand Down
111 changes: 111 additions & 0 deletions src/Polly.Core.Tests/Utils/ObjectPoolTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using Polly.Utils;

namespace Polly.Core.Tests.Utils;

public class ObjectPoolTests
{
[Fact]
public void GetAnd_ReturnObject_SameInstance()
{
// Arrange
var pool = new ObjectPool<object>(() => new object(), _ => true);

var obj1 = pool.Get();
pool.Return(obj1);

// Act
var obj2 = pool.Get();

// Assert
Assert.Same(obj1, obj2);
}

[Fact]
public void MaxCapacity_Ok()
{
ObjectPool<object>.MaxCapacity.Should().Be((Environment.ProcessorCount * 2) - 1);
}

[Fact]
public void MaxCapacity_Respected()
{
// Arrange
var pool = new ObjectPool<object>(() => new object(), _ => true);
var items1 = GetStoreReturn(pool);

// Act
var items2 = GetStoreReturn(pool);

// Assert
items1.Should().BeEquivalentTo(items2);
}

[Fact]
public void MaxCapacityOverflow_Respected()
{
// Arrange
var count = ObjectPool<object>.MaxCapacity + 10;
var pool = new ObjectPool<object>(() => new object(), _ => true);
var items1 = GetStoreReturn(pool, count);

// Act
var items2 = GetStoreReturn(pool, count);

// Assert
items1.Last().Should().NotBeSameAs(items2.Last());
}

[Fact]
public void CreatedByPolicy()
{
// Arrange
var policy = new ListPolicy();
var pool = new ObjectPool<List<int>>(ListPolicy.Create, ListPolicy.Return);

// Act
var list = pool.Get();

// Assert
Assert.Equal(17, list.Capacity);
}

[Fact]
public void Return_RejectedByPolicy()
{
// Arrange
var policy = new ListPolicy();
var pool = new ObjectPool<List<int>>(ListPolicy.Create, ListPolicy.Return);
var list1 = pool.Get();
list1.Capacity = 20;

// Act
pool.Return(list1);
var list2 = pool.Get();

// Assert
Assert.NotSame(list1, list2);
}

private static List<object> GetStoreReturn(ObjectPool<object> pool, int? count = null)
{
var items = new List<object>();
for (int i = 0; i < (count ?? ObjectPool<object>.MaxCapacity); i++)
{
items.Add(pool.Get());
}

foreach (var item in items)
{
pool.Return(item);
}

return items;
}

private class ListPolicy
{
public static List<int> Create() => new(17);

public static bool Return(List<int> obj) => obj.Capacity == 17;
}
}
1 change: 0 additions & 1 deletion src/Polly.Core.Tests/Utils/TimeSpanAttributeTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.ComponentModel.DataAnnotations;

namespace Polly.Core.Tests.Utils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Polly.Core.Tests.Utils;

public class ValidationContextExtensions
public class ValidationContextExtensionsTests
{
[Fact]
public void GetMemberName_Ok()
Expand Down
Loading

0 comments on commit 5e19d1d

Please sign in to comment.