-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a17af3f
commit 5d25923
Showing
33 changed files
with
1,984 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
public class BufferConsumerOptions | ||
{ | ||
public string TopicName { get; init; } = default!; | ||
|
||
public string GroupName { get; init; } = default!; | ||
|
||
public bool AutoCommit { get; init; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
public class BufferOptionsBuilder | ||
{ | ||
public BufferOptionsBuilder(IServiceCollection services) | ||
{ | ||
Services = services; | ||
} | ||
|
||
public IServiceCollection Services { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
internal class BufferQueue : IBufferQueue | ||
{ | ||
private readonly IServiceProvider _serviceProvider; | ||
|
||
public BufferQueue(IServiceProvider serviceProvider) | ||
{ | ||
_serviceProvider = serviceProvider; | ||
} | ||
|
||
public IBufferProducer<T> CreateProducer<T>(string topicName) | ||
{ | ||
ArgumentException.ThrowIfNullOrEmpty(topicName, nameof(topicName)); | ||
var queue = _serviceProvider.GetRequiredKeyedService<IBufferQueue<T>>(topicName); | ||
return queue.CreateProducer(); | ||
} | ||
|
||
public IBufferConsumer<T> CreateConsumer<T>(BufferConsumerOptions options) | ||
{ | ||
ArgumentException.ThrowIfNullOrEmpty(options.TopicName, nameof(options.TopicName)); | ||
var queue = _serviceProvider.GetRequiredKeyedService<IBufferQueue<T>>(options.TopicName); | ||
return queue.CreateConsumer(options); | ||
} | ||
|
||
public IEnumerable<IBufferConsumer<T>> CreateConsumers<T>(BufferConsumerOptions options, int consumerNumber) | ||
{ | ||
ArgumentException.ThrowIfNullOrEmpty(options.TopicName, nameof(options.TopicName)); | ||
var queue = _serviceProvider.GetRequiredKeyedService<IBufferQueue<T>>(options.TopicName); | ||
return queue.CreateConsumers(options, consumerNumber); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/Mocha.Core/Buffer/BufferServiceCollectionExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
using Mocha.Core.Buffer; | ||
|
||
namespace Microsoft.Extensions.DependencyInjection; | ||
|
||
public static class BufferServiceCollectionExtensions | ||
{ | ||
public static IServiceCollection AddBuffer( | ||
this IServiceCollection services, | ||
Action<BufferOptionsBuilder> configure) | ||
{ | ||
services.AddSingleton<IBufferQueue, BufferQueue>(); | ||
configure(new BufferOptionsBuilder(services)); | ||
return services; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
public interface IBufferConsumer<out T> | ||
{ | ||
string TopicName { get; } | ||
|
||
string GroupName { get; } | ||
|
||
IAsyncEnumerable<T> ConsumeAsync(CancellationToken cancellationToken = default); | ||
|
||
ValueTask CommitAsync(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
public interface IBufferProducer<in T> | ||
{ | ||
string TopicName { get; } | ||
|
||
ValueTask ProduceAsync(T item); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
public interface IBufferQueue | ||
{ | ||
IBufferProducer<T> CreateProducer<T>(string topicName); | ||
|
||
IBufferConsumer<T> CreateConsumer<T>(BufferConsumerOptions options); | ||
|
||
IEnumerable<IBufferConsumer<T>> CreateConsumers<T>(BufferConsumerOptions options, int consumerNumber); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
internal interface IBufferQueue<T> | ||
{ | ||
string TopicName { get; } | ||
|
||
IBufferProducer<T> CreateProducer(); | ||
|
||
IBufferConsumer<T> CreateConsumer(BufferConsumerOptions options); | ||
|
||
IEnumerable<IBufferConsumer<T>> CreateConsumers(BufferConsumerOptions options, int consumerNumber); | ||
} |
19 changes: 19 additions & 0 deletions
19
src/Mocha.Core/Buffer/Memory/BufferOptionsBuilderExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
using Mocha.Core.Buffer.Memory; | ||
|
||
namespace Mocha.Core.Buffer; | ||
|
||
public static class BufferOptionsBuilderExtensions | ||
{ | ||
public static BufferOptionsBuilder UseMemory( | ||
this BufferOptionsBuilder builder, | ||
Action<MemoryBufferOptions> configure) | ||
{ | ||
var options = new MemoryBufferOptions(builder.Services); | ||
configure(options); | ||
|
||
return builder; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Licensed to the .NET Core Community under one or more agreements. | ||
// The .NET Core Community licenses this file to you under the MIT license. | ||
|
||
namespace Mocha.Core.Buffer.Memory; | ||
|
||
internal sealed class MemoryBufferQueue<T> : IBufferQueue<T> | ||
{ | ||
private readonly MemoryBufferPartition<T>[] _partitions; | ||
private readonly int _partitionNumber; | ||
|
||
private readonly IBufferProducer<T> _producer; | ||
|
||
// Consider that the frequency of creating consumers will not be very high, | ||
// so the lock is relatively coarse-grained. | ||
private readonly object _consumersLock; | ||
private readonly Dictionary<string /* GroupName */, List<MemoryBufferConsumer<T>>> _consumers; | ||
|
||
public MemoryBufferQueue(string topicName, int partitionNumber) | ||
{ | ||
TopicName = topicName; | ||
_partitionNumber = partitionNumber; | ||
_partitions = new MemoryBufferPartition<T>[partitionNumber]; | ||
for (var i = 0; i < partitionNumber; i++) | ||
{ | ||
_partitions[i] = new MemoryBufferPartition<T>(); | ||
} | ||
|
||
_producer = new MemoryBufferProducer<T>(topicName, _partitions); | ||
|
||
_consumers = new Dictionary<string, List<MemoryBufferConsumer<T>>>(); | ||
_consumersLock = new object(); | ||
} | ||
|
||
public string TopicName { get; } | ||
|
||
public IBufferProducer<T> CreateProducer() => _producer; | ||
|
||
public IBufferConsumer<T> CreateConsumer(BufferConsumerOptions options) | ||
{ | ||
var consumers = CreateConsumers(options, 1); | ||
return consumers.Single(); | ||
} | ||
|
||
public IEnumerable<IBufferConsumer<T>> CreateConsumers(BufferConsumerOptions options, int consumerNumber) | ||
{ | ||
if (consumerNumber < 1) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(consumerNumber), | ||
"The number of consumers must be greater than 0."); | ||
} | ||
|
||
if (consumerNumber > _partitionNumber) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(consumerNumber), | ||
"The number of consumers cannot be greater than the number of partitions."); | ||
} | ||
|
||
var groupName = options.GroupName; | ||
ArgumentException.ThrowIfNullOrEmpty(groupName, nameof(options.GroupName)); | ||
|
||
lock (_consumersLock) | ||
{ | ||
if (_consumers.ContainsKey(groupName)) | ||
{ | ||
throw new InvalidOperationException($"The consumer group '{groupName}' already exists."); | ||
} | ||
|
||
var consumers = new List<MemoryBufferConsumer<T>>(); | ||
for (var i = 0; i < consumerNumber; i++) | ||
{ | ||
var consumer = new MemoryBufferConsumer<T>(options); | ||
consumers.Add(consumer); | ||
} | ||
|
||
AssignPartitions(consumers); | ||
|
||
_consumers.Add(groupName, consumers); | ||
return consumers; | ||
} | ||
} | ||
|
||
private void AssignPartitions(List<MemoryBufferConsumer<T>> consumers) | ||
{ | ||
var consumerNumber = consumers.Count; | ||
var partitionsPerConsumer = _partitionNumber / consumerNumber; | ||
var partitionsRemainder = _partitionNumber % consumerNumber; | ||
var partitionStartIndex = 0; | ||
foreach (var consumer in consumers) | ||
{ | ||
var extraPartitions = partitionsRemainder > 0 ? 1 : 0; | ||
var partitionEndIndex = partitionStartIndex | ||
+ partitionsPerConsumer | ||
+ extraPartitions; | ||
var partitions = _partitions[partitionStartIndex..partitionEndIndex]; | ||
consumer.AssignPartitions(partitions); | ||
|
||
partitionStartIndex = partitionEndIndex; | ||
|
||
if (partitionsRemainder > 0) | ||
{ | ||
partitionsRemainder--; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.