-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #105 from madelson/mysql
2.2 release (MySQL support)
- Loading branch information
Showing
38 changed files
with
1,169 additions
and
50 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
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,3 @@ | ||
using System.Runtime.CompilerServices; | ||
|
||
[assembly: InternalsVisibleTo("DistributedLock.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fd3af56ccc8ed94fffe25bfd651e6a5674f8f20a76d37de800dd0f7380e04f0fde2da6fa200380b14fe398605b6f470c87e5e0a0bf39ae871f07536a4994aa7a0057c4d3bcedc8fef3eecb0c88c2024a1b3289305c2393acd9fb9f9a42d0bd7826738ce864d507575ea3a1fe1746ab19823303269f79379d767949807f494be8")] |
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,55 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFrameworks>netstandard2.0;netstandard2.1;net461</TargetFrameworks> | ||
<RootNamespace>Medallion.Threading.MySql</RootNamespace> | ||
<GenerateDocumentationFile>True</GenerateDocumentationFile> | ||
<WarningLevel>4</WarningLevel> | ||
<LangVersion>Latest</LangVersion> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<Version>1.0.0</Version> | ||
<AssemblyVersion>1.0.0.0</AssemblyVersion> | ||
<Authors>Michael Adelson</Authors> | ||
<Description>Provides a distributed lock implementation based on MySql</Description> | ||
<Copyright>Copyright © 2021 Michael Adelson</Copyright> | ||
<PackageLicenseExpression>MIT</PackageLicenseExpression> | ||
<PackageTags>distributed lock async mutex sql mysql</PackageTags> | ||
<PackageProjectUrl>https://github.com/madelson/DistributedLock</PackageProjectUrl> | ||
<RepositoryUrl>https://github.com/madelson/DistributedLock</RepositoryUrl> | ||
<FileVersion>1.0.0.0</FileVersion> | ||
<PackageReleaseNotes>See https://github.com/madelson/DistributedLock#release-notes</PackageReleaseNotes> | ||
<SignAssembly>true</SignAssembly> | ||
<AssemblyOriginatorKeyFile>..\DistributedLock.snk</AssemblyOriginatorKeyFile> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> | ||
<Optimize>True</Optimize> | ||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> | ||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors> | ||
<TreatSpecificWarningsAsErrors /> | ||
<!-- see https://github.com/dotnet/sdk/issues/2679 --> | ||
<DebugType>embedded</DebugType> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"> | ||
<Optimize>False</Optimize> | ||
<NoWarn>1591</NoWarn> | ||
<DefineConstants>TRACE;DEBUG</DefineConstants> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<!-- Used as the default over MySql.Data because of better licensing --> | ||
<PackageReference Include="MySqlConnector" Version="1.3.11" /> | ||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\DistributedLock.Core\DistributedLock.Core.csproj" /> | ||
</ItemGroup> | ||
|
||
<Import Project="..\CopyPackageToPublishDirectory.targets" /> | ||
<Import Project="..\FixDistributedLockCoreDependencyVersion.targets" /> | ||
</Project> |
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,76 @@ | ||
using Medallion.Threading.Internal; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using System.Threading; | ||
|
||
namespace Medallion.Threading.MySql | ||
{ | ||
/// <summary> | ||
/// Specifies options for connecting to and locking against a MySQL database | ||
/// </summary> | ||
public sealed class MySqlConnectionOptionsBuilder | ||
{ | ||
private TimeoutValue? _keepaliveCadence; | ||
private bool? _useMultiplexing; | ||
|
||
internal MySqlConnectionOptionsBuilder() { } | ||
|
||
/// <summary> | ||
/// MySQL's wait_timeout system variable determines how long the server will allow a connection to be idle before killing it. | ||
/// For more information, see https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_wait_timeout. | ||
/// | ||
/// To prevent this, this option sets the cadence at which we run a no-op "keepalive" query on a connection that is holding a lock. | ||
/// | ||
/// Because MySQL's default for this setting is 8 hours, the default <paramref name="keepaliveCadence"/> is 3.5 hours. | ||
/// | ||
/// Setting a value of <see cref="Timeout.InfiniteTimeSpan"/> disables keepalive. | ||
/// </summary> | ||
public MySqlConnectionOptionsBuilder KeepaliveCadence(TimeSpan keepaliveCadence) | ||
{ | ||
this._keepaliveCadence = new TimeoutValue(keepaliveCadence, nameof(keepaliveCadence)); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This mode takes advantage of the fact that while "holding" a lock (or other synchronization primitive) | ||
/// a connection is essentially idle. Thus, rather than creating a new connection for each held lock it is | ||
/// often possible to multiplex a shared connection so that that connection can hold multiple locks at the same time. | ||
/// | ||
/// Multiplexing is on by default. | ||
/// | ||
/// This is implemented in such a way that releasing a lock held on such a connection will never be blocked by an | ||
/// Acquire() call that is waiting to acquire a lock on that same connection. For this reason, the multiplexing | ||
/// strategy is "optimistic": if the lock can't be acquired instantaneously on the shared connection, a new (shareable) | ||
/// connection will be allocated. | ||
/// | ||
/// This option can improve performance and avoid connection pool starvation in high-load scenarios. It is also | ||
/// particularly applicable to cases where <see cref="IDistributedLock.TryAcquire(TimeSpan, System.Threading.CancellationToken)"/> | ||
/// semantics are used with a zero-length timeout. | ||
/// </summary> | ||
public MySqlConnectionOptionsBuilder UseMultiplexing(bool useMultiplexing = true) | ||
{ | ||
this._useMultiplexing = useMultiplexing; | ||
return this; | ||
} | ||
|
||
internal static (TimeoutValue keepaliveCadence, bool useMultiplexing) GetOptions(Action<MySqlConnectionOptionsBuilder>? optionsBuilder) | ||
{ | ||
MySqlConnectionOptionsBuilder? options; | ||
if (optionsBuilder != null) | ||
{ | ||
options = new MySqlConnectionOptionsBuilder(); | ||
optionsBuilder(options); | ||
} | ||
else | ||
{ | ||
options = null; | ||
} | ||
|
||
var keepaliveCadence = options?._keepaliveCadence ?? TimeSpan.FromHours(3.5); | ||
var useMultiplexing = options?._useMultiplexing ?? true; | ||
|
||
return (keepaliveCadence, useMultiplexing); | ||
} | ||
} | ||
} |
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,49 @@ | ||
using Medallion.Threading.Internal.Data; | ||
using MySqlConnector; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Data; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Medallion.Threading.MySql | ||
{ | ||
internal class MySqlDatabaseConnection : DatabaseConnection | ||
{ | ||
public MySqlDatabaseConnection(IDbConnection connection) | ||
: base(connection, isExternallyOwned: true) | ||
{ | ||
} | ||
|
||
public MySqlDatabaseConnection(IDbTransaction transaction) | ||
: base(transaction, isExternallyOwned: true) | ||
{ | ||
} | ||
|
||
public MySqlDatabaseConnection(string connectionString) | ||
: base(new MySqlConnection(connectionString), isExternallyOwned: false) | ||
{ | ||
} | ||
|
||
// Seems like this only helps when executing a statement multiple times on the | ||
// same connection (unclear since there's limited documentation) | ||
public override bool ShouldPrepareCommands => false; | ||
|
||
public override bool IsCommandCancellationException(Exception exception) | ||
{ | ||
// see https://mysqlconnector.net/overview/command-cancellation/ | ||
return exception is MySqlException ex && ex.ErrorCode == MySqlErrorCode.QueryInterrupted; | ||
} | ||
|
||
public override async Task SleepAsync(TimeSpan sleepTime, CancellationToken cancellationToken, Func<DatabaseCommand, CancellationToken, ValueTask<int>> executor) | ||
{ | ||
using var sleepCommand = this.CreateCommand(); | ||
sleepCommand.SetCommandText("SELECT SLEEP(@durationSeconds)"); | ||
sleepCommand.AddParameter("durationSeconds", sleepTime.TotalSeconds); | ||
sleepCommand.SetTimeout(sleepTime); | ||
|
||
await executor(sleepCommand, cancellationToken).ConfigureAwait(false); | ||
} | ||
} | ||
} |
Oops, something went wrong.