Skip to content

Commit 1c9f2ac

Browse files
fix stuff, add as draft
1 parent 94483ed commit 1c9f2ac

24 files changed

+865
-658
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

src/.idea/.idea.DistributedLock/.idea/.gitignore

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/.idea/.idea.DistributedLock/.idea/.name

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/.idea/.idea.DistributedLock/.idea/encodings.xml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/.idea/.idea.DistributedLock/.idea/indexLayout.xml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/.idea/.idea.DistributedLock/.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Directory.Packages.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
<PackageVersion Include="System.Data.SqlClient" Version="4.8.6" />
2323
<PackageVersion Include="Moq" Version="4.20.70" />
2424
<PackageVersion Include="System.Threading.AccessControl" Version="8.0.0" Condition="'$(TargetFramework)' != 'net462'" />
25+
<PackageVersion Include="Testcontainers" Version="4.6.0" />
2526
<PackageVersion Include="ZooKeeperNetEx" Version="3.4.12.4" />
2627
<PackageVersion Include="IsExternalInit" Version="1.0.3" />
2728
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" Condition="'$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'net462'" />
2829
<PackageVersion Include="System.ValueTuple" Version="4.5.0" Condition="'$(TargetFramework)' == 'net462'" />
2930
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
31+
<PackageVersion Include="dotnet-etcd" Version="5.2.1" />
3032
</ItemGroup>
3133
</Project>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>netstandard2.1</TargetFrameworks>
5+
<RootNamespace>Medallion.Threading.FileSystem</RootNamespace>
6+
<GenerateDocumentationFile>True</GenerateDocumentationFile>
7+
<WarningLevel>4</WarningLevel>
8+
<LangVersion>Latest</LangVersion>
9+
<Nullable>enable</Nullable>
10+
<ImplicitUsings>enable</ImplicitUsings>
11+
</PropertyGroup>
12+
13+
<PropertyGroup>
14+
<Version>1.0.3</Version>
15+
<AssemblyVersion>1.0.0.0</AssemblyVersion>
16+
<Authors>Michael Adelson</Authors>
17+
<Description>Provides a distributed lock implementation based on etcd</Description>
18+
<Copyright>Copyright © 2020 Michael Adelson</Copyright>
19+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
20+
<PackageTags>distributed etcd lock</PackageTags>
21+
<PackageProjectUrl>https://github.com/madelson/DistributedLock</PackageProjectUrl>
22+
<RepositoryUrl>https://github.com/madelson/DistributedLock</RepositoryUrl>
23+
<FileVersion>1.0.0.0</FileVersion>
24+
<PackageReleaseNotes>See https://github.com/madelson/DistributedLock#release-notes</PackageReleaseNotes>
25+
<SignAssembly>true</SignAssembly>
26+
<AssemblyOriginatorKeyFile>..\DistributedLock.snk</AssemblyOriginatorKeyFile>
27+
</PropertyGroup>
28+
29+
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
30+
<Optimize>True</Optimize>
31+
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
32+
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
33+
<TreatSpecificWarningsAsErrors />
34+
<!-- see https://github.com/dotnet/sdk/issues/2679 -->
35+
<DebugType>embedded</DebugType>
36+
<!-- see https://mitchelsellers.com/blog/article/net-5-deterministic-builds-source-linking -->
37+
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
38+
<EmbedUntrackedSources>true</EmbedUntrackedSources>
39+
</PropertyGroup>
40+
41+
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
42+
<Optimize>False</Optimize>
43+
<NoWarn>1591</NoWarn>
44+
<DefineConstants>TRACE;DEBUG</DefineConstants>
45+
</PropertyGroup>
46+
47+
<ItemGroup>
48+
<ProjectReference Include="..\DistributedLock.Core\DistributedLock.Core.csproj" />
49+
</ItemGroup>
50+
51+
<ItemGroup>
52+
<PackageReference Include="dotnet-etcd" />
53+
<PackageReference Include="Nullable" Condition="'$(TargetFramework)' != 'netstandard2.1'">
54+
<PrivateAssets>all</PrivateAssets>
55+
</PackageReference>
56+
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All"/>
57+
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" PrivateAssets="All" />
58+
</ItemGroup>
59+
60+
<ItemGroup>
61+
<Using Remove="System.Net.Http"/>
62+
</ItemGroup>
63+
64+
<Import Project="..\FixDistributedLockCoreDependencyVersion.targets" />
65+
</Project>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using dotnet_etcd;
2+
using dotnet_etcd.interfaces;
3+
using Etcdserverpb;
4+
using Grpc.Core;
5+
using Medallion.Threading.Internal;
6+
using V3Lockpb;
7+
8+
namespace Medallion.Threading.Etcd;
9+
10+
public class EtcdClientWrapper
11+
{
12+
private readonly IEtcdClient _etcdClient;
13+
public EtcdClientWrapper(IEtcdClient etcdClient)
14+
{
15+
_etcdClient = etcdClient ?? throw new ArgumentNullException(nameof(etcdClient));
16+
}
17+
18+
public ValueTask<LeaseGrantResponse> LeaseGrantAsync(LeaseGrantRequest request, CancellationToken cancellationToken)
19+
{
20+
return SyncViaAsync.IsSynchronous
21+
? new ValueTask<LeaseGrantResponse>(this._etcdClient.LeaseGrant(request,
22+
cancellationToken: cancellationToken))
23+
: new ValueTask<LeaseGrantResponse>(
24+
this._etcdClient.LeaseGrantAsync(request, cancellationToken: cancellationToken));
25+
}
26+
27+
public Task LeaseKeepAlive(long leaseId, CancellationToken token)
28+
{
29+
return this._etcdClient.LeaseKeepAlive(leaseId, token);
30+
}
31+
32+
public async ValueTask<LockResponse> LockAsync(LockRequest lockRequest, CancellationToken cancellationToken)
33+
{
34+
// thread static var here is legit? TODO why not asynclocal??
35+
var response = SyncViaAsync.IsSynchronous
36+
? this._etcdClient.Lock(lockRequest, cancellationToken: cancellationToken)
37+
: await this._etcdClient.LockAsync(lockRequest, cancellationToken: cancellationToken).ConfigureAwait(false);
38+
39+
if (response == null)
40+
{
41+
throw new RpcException(new Status(StatusCode.Internal, "Lock failed"));
42+
}
43+
44+
return response;
45+
}
46+
47+
public async ValueTask LeaseRevokeAsync(LeaseRevokeRequest leaseRevokeRequest)
48+
{
49+
if (SyncViaAsync.IsSynchronous)
50+
{
51+
this._etcdClient.LeaseRevoke(leaseRevokeRequest);
52+
}
53+
else
54+
{
55+
await this._etcdClient.LeaseRevokeAsync(leaseRevokeRequest).ConfigureAwait(false);
56+
}
57+
}
58+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using Medallion.Threading.Internal;
2+
3+
namespace Medallion.Threading.Etcd;
4+
5+
public partial class EtcdLeaseDistributedLock
6+
{
7+
// AUTO-GENERATED
8+
9+
IDistributedSynchronizationHandle? IDistributedLock.TryAcquire(TimeSpan timeout, CancellationToken cancellationToken) =>
10+
this.TryAcquire(timeout, cancellationToken);
11+
IDistributedSynchronizationHandle IDistributedLock.Acquire(TimeSpan? timeout, CancellationToken cancellationToken) =>
12+
this.Acquire(timeout, cancellationToken);
13+
ValueTask<IDistributedSynchronizationHandle?> IDistributedLock.TryAcquireAsync(TimeSpan timeout, CancellationToken cancellationToken) =>
14+
this.TryAcquireAsync(timeout, cancellationToken).Convert(To<IDistributedSynchronizationHandle?>.ValueTask);
15+
ValueTask<IDistributedSynchronizationHandle> IDistributedLock.AcquireAsync(TimeSpan? timeout, CancellationToken cancellationToken) =>
16+
this.AcquireAsync(timeout, cancellationToken).Convert(To<IDistributedSynchronizationHandle>.ValueTask);
17+
18+
/// <summary>
19+
/// Attempts to acquire the lock synchronously. Usage:
20+
/// <code>
21+
/// using (var handle = myLock.TryAcquire(...))
22+
/// {
23+
/// if (handle != null) { /* we have the lock! */ }
24+
/// }
25+
/// // dispose releases the lock if we took it
26+
/// </code>
27+
/// </summary>
28+
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to 0</param>
29+
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
30+
/// <returns>An <see cref="EtcdLeaseDistributedLockHandle"/> which can be used to release the lock or null on failure</returns>
31+
public EtcdLeaseDistributedLockHandle? TryAcquire(TimeSpan timeout = default, CancellationToken cancellationToken = default) =>
32+
DistributedLockHelpers.TryAcquire(this, timeout, cancellationToken);
33+
34+
/// <summary>
35+
/// Acquires the lock synchronously, failing with <see cref="TimeoutException"/> if the attempt times out. Usage:
36+
/// <code>
37+
/// using (myLock.Acquire(...))
38+
/// {
39+
/// /* we have the lock! */
40+
/// }
41+
/// // dispose releases the lock
42+
/// </code>
43+
/// </summary>
44+
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to <see cref="Timeout.InfiniteTimeSpan"/></param>
45+
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
46+
/// <returns>An <see cref="EtcdLeaseDistributedLockHandle"/> which can be used to release the lock</returns>
47+
public EtcdLeaseDistributedLockHandle Acquire(TimeSpan? timeout = null, CancellationToken cancellationToken = default) =>
48+
DistributedLockHelpers.Acquire(this, timeout, cancellationToken);
49+
50+
/// <summary>
51+
/// Attempts to acquire the lock asynchronously. Usage:
52+
/// <code>
53+
/// await using (var handle = await myLock.TryAcquireAsync(...))
54+
/// {
55+
/// if (handle != null) { /* we have the lock! */ }
56+
/// }
57+
/// // dispose releases the lock if we took it
58+
/// </code>
59+
/// </summary>
60+
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to 0</param>
61+
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
62+
/// <returns>An <see cref="EtcdLeaseDistributedLockHandle"/> which can be used to release the lock or null on failure</returns>
63+
public ValueTask<EtcdLeaseDistributedLockHandle?> TryAcquireAsync(TimeSpan timeout = default, CancellationToken cancellationToken = default) =>
64+
this.As<IInternalDistributedLock<EtcdLeaseDistributedLockHandle>>().InternalTryAcquireAsync(timeout, cancellationToken);
65+
66+
/// <summary>
67+
/// Acquires the lock asynchronously, failing with <see cref="TimeoutException"/> if the attempt times out. Usage:
68+
/// <code>
69+
/// await using (await myLock.AcquireAsync(...))
70+
/// {
71+
/// /* we have the lock! */
72+
/// }
73+
/// // dispose releases the lock
74+
/// </code>
75+
/// </summary>
76+
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to <see cref="Timeout.InfiniteTimeSpan"/></param>
77+
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
78+
/// <returns>An <see cref="EtcdLeaseDistributedLockHandle"/> which can be used to release the lock</returns>
79+
public ValueTask<EtcdLeaseDistributedLockHandle> AcquireAsync(TimeSpan? timeout = null, CancellationToken cancellationToken = default) =>
80+
DistributedLockHelpers.AcquireAsync(this, timeout, cancellationToken);
81+
}

0 commit comments

Comments
 (0)