-
Notifications
You must be signed in to change notification settings - Fork 241
Feature Request:GBase8s DB #258 add support GBase8s DB #267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
617206652
wants to merge
2
commits into
madelson:master
Choose a base branch
from
617206652:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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,67 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFrameworks>netstandard2.1;net472</TargetFrameworks> | ||
| <RootNamespace>Medallion.Threading.GBase</RootNamespace> | ||
| <GenerateDocumentationFile>True</GenerateDocumentationFile> | ||
| <WarningLevel>4</WarningLevel> | ||
| <LangVersion>Latest</LangVersion> | ||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|
|
||
| <PropertyGroup> | ||
| <Version>2.7.0.2</Version> | ||
| <AssemblyVersion>1.0.0.0</AssemblyVersion> | ||
| <Authors>Michael Adelson</Authors> | ||
| <Description>Provides a distributed lock implementation based on GBase Database</Description> | ||
| <Copyright>Copyright © 2021 Michael Adelson</Copyright> | ||
| <PackageLicenseExpression>MIT</PackageLicenseExpression> | ||
| <PackageTags>distributed lock async mutex reader writer sql GBase</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> | ||
| <!-- see https://mitchelsellers.com/blog/article/net-5-deterministic-builds-source-linking --> | ||
| <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> | ||
| <EmbedUntrackedSources>true</EmbedUntrackedSources> | ||
| </PropertyGroup> | ||
|
|
||
| <PropertyGroup Condition="'$(Configuration)' == 'Debug'"> | ||
| <Optimize>False</Optimize> | ||
| <NoWarn>1591</NoWarn> | ||
| <DefineConstants>TRACE;DEBUG</DefineConstants> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="GeneralData.GBase8s.DataProvider" /> | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove |
||
| <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" /> | ||
| <PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" PrivateAssets="All" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\DistributedLock.Core\DistributedLock.Core.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <Using Remove="System.Net.Http" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <Content Include="..\..\..\..\GeneralData.EntityFrameworkCore.GBase.DataProvider.dll" PackagePath="lib\netstandard2.1"> | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not be included |
||
| <Pack>true</Pack> | ||
| <PackageCopyToOutput>true</PackageCopyToOutput> | ||
| </Content> | ||
| </ItemGroup> | ||
| <Import Project="..\FixDistributedLockCoreDependencyVersion.targets" /> | ||
| </Project> | ||
68 changes: 68 additions & 0 deletions
68
src/DistributedLock.GBase/GBaseConnectionOptionsBuilder.cs
This file contains hidden or 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,68 @@ | ||
| using Medallion.Threading.Internal; | ||
|
|
||
| namespace Medallion.Threading.GBase; | ||
|
|
||
| /// <summary> | ||
| /// Specifies options for connecting to and locking against an GBase database | ||
| /// </summary> | ||
| public sealed class GBaseConnectionOptionsBuilder | ||
| { | ||
| private TimeoutValue? _keepaliveCadence; | ||
| private bool? _useMultiplexing; | ||
|
|
||
| internal GBaseConnectionOptionsBuilder() { } | ||
|
|
||
| /// <summary> | ||
| /// GBase does not kill idle connections by default, so by default keepalive is disabled (set to <see cref="Timeout.InfiniteTimeSpan"/>). | ||
| /// | ||
| /// However, if you are using the IDLE_TIME setting in GBase or if your network is dropping connections that are idle holding locks for | ||
| /// a long time, you can set a value for keepalive to prevent this from happening. | ||
| /// | ||
| /// </summary> | ||
| public GBaseConnectionOptionsBuilder 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 GBaseConnectionOptionsBuilder UseMultiplexing(bool useMultiplexing = true) | ||
| { | ||
| this._useMultiplexing = useMultiplexing; | ||
| return this; | ||
| } | ||
|
|
||
| internal static (TimeoutValue keepaliveCadence, bool useMultiplexing) GetOptions(Action<GBaseConnectionOptionsBuilder>? optionsBuilder) | ||
| { | ||
| GBaseConnectionOptionsBuilder? options; | ||
| if (optionsBuilder != null) | ||
| { | ||
| options = new GBaseConnectionOptionsBuilder(); | ||
| optionsBuilder(options); | ||
| } | ||
| else | ||
| { | ||
| options = null; | ||
| } | ||
|
|
||
| var keepaliveCadence = options?._keepaliveCadence ?? Timeout.InfiniteTimeSpan; | ||
| var useMultiplexing = options?._useMultiplexing ?? true; | ||
|
|
||
| return (keepaliveCadence, useMultiplexing); | ||
| } | ||
| } |
This file contains hidden or 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,80 @@ | ||
| using GBS.Data.GBasedbt; | ||
| using Medallion.Threading.Internal.Data; | ||
| using System.Data; | ||
|
|
||
| namespace Medallion.Threading.GBase; | ||
|
|
||
| internal class GBaseDatabaseConnection : DatabaseConnection | ||
| { | ||
| public const string ApplicationNameIndicatorPrefix = "__DistributedLock.ApplicationName="; | ||
|
|
||
| // see SleepAsync() for why we need this | ||
| private readonly IDbConnection _innerConnection; | ||
|
|
||
| public GBaseDatabaseConnection(IDbConnection connection) | ||
| : this(connection, isExternallyOwned: true) | ||
| { | ||
| } | ||
|
|
||
| public GBaseDatabaseConnection(IDbTransaction transaction) | ||
| : base(transaction, isExternallyOwned: true) | ||
| { | ||
| this._innerConnection = transaction.Connection; | ||
| } | ||
|
|
||
| public GBaseDatabaseConnection(string connectionString) | ||
| : this(CreateConnection(connectionString), isExternallyOwned: false) | ||
| { | ||
| } | ||
|
|
||
| private GBaseDatabaseConnection(IDbConnection connection, bool isExternallyOwned) | ||
| : base(connection, isExternallyOwned) | ||
| { | ||
| this._innerConnection = connection; | ||
| } | ||
|
|
||
| public override bool ShouldPrepareCommands => false; | ||
|
|
||
| public override bool IsCommandCancellationException(Exception exception) => | ||
| exception is GbsException gbsException | ||
| && (gbsException.ErrorCode == 01013 || gbsException.ErrorCode == 00936 || gbsException.ErrorCode == 00604); | ||
|
|
||
| public override async Task SleepAsync(TimeSpan sleepTime, CancellationToken cancellationToken, Func<DatabaseCommand, CancellationToken, ValueTask<int>> executor) | ||
| { | ||
| using var sleepCommand = this.CreateCommand(); | ||
| sleepCommand.SetCommandText("dbms_lock_sleep(?)"); | ||
| sleepCommand.AddParameter("seconds", sleepTime.TotalSeconds); | ||
|
|
||
| try | ||
| { | ||
| await executor(sleepCommand, cancellationToken).ConfigureAwait(false); | ||
| } | ||
| catch when (!cancellationToken.IsCancellationRequested) | ||
| { | ||
| // GBase doesn't fire StateChange unless the State is observed or the connection is explicitly opened/closed. Therefore, we observe | ||
| // the state on seeing any exception in order to for the event to fire. | ||
| _ = this._innerConnection.State; | ||
| throw; | ||
| } | ||
| } | ||
|
|
||
| public static GbsConnection CreateConnection(string connectionString) | ||
| { | ||
| if (connectionString == null) { throw new ArgumentNullException(connectionString, nameof(connectionString)); } | ||
|
|
||
| // The .NET GBase provider does not currently support ApplicationName natively as a connection string property. | ||
| // However, that functionality is relied on by many of our tests. As a workaround, we permit the application name | ||
| // to be included in the connection string using a custom encoding scheme. This is only intended to work in tests! | ||
| if (connectionString.StartsWith(ApplicationNameIndicatorPrefix, StringComparison.Ordinal)) | ||
| { | ||
| var firstSeparatorIndex = connectionString.IndexOf(';'); | ||
| var applicationName = connectionString.Substring(startIndex: ApplicationNameIndicatorPrefix.Length, length: firstSeparatorIndex - ApplicationNameIndicatorPrefix.Length); | ||
| // After upgrading the GBase client to 23.6.1, the connection pool sometimes seems to grow beyond what is strictly required. | ||
| // This causes issues if we're tracking connections by name. Therefore, we disable pooling on named connections | ||
| var connection = new GbsConnection(connectionString.Substring(startIndex: firstSeparatorIndex + 1)); | ||
| return connection; | ||
| } | ||
|
|
||
| return new GbsConnection(connectionString); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This library isn't well-established enough for use here (< 1K downloads, < 2 months old).
Looks like Odbc seems to be the more common pattern for GBase interactions in the NuGet world