Skip to content

Commit 4d9acd9

Browse files
committed
Version bumps and readme update
1 parent 306be8b commit 4d9acd9

8 files changed

Lines changed: 29 additions & 19 deletions

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ Contributions are welcome! If you are interested in contributing towards a new o
141141
Setup steps for working with the repository locally are documented [here](docs/Developing%20DistributedLock.md).
142142

143143
## Release notes
144+
- 2.6
145+
- Add support for acquiring transaction-scoped Postgres locks using externally-owned transactions. Thanks [@Tzachi009](https://github.com/Tzachi009) for implementing! ([#213](https://github.com/madelson/DistributedLock/issues/213), DistributedLock.Postgres 1.3)
144146
- 2.5.1
145147
- Increase efficiency of Azure blob locks when the blob does not exist. Thanks [@richardkooiman](https://github.com/richardkooiman) for implementing! ([#227](https://github.com/madelson/DistributedLock/pull/227), DistributedLock.Azure 1.0.2)
146148
- Improve error handling in race condition scenarios for Azure blobs. Thanks [@MartinDembergerR9](https://github.com/MartinDembergerR9) for implementing! ([#228](https://github.com/madelson/DistributedLock/pull/228), DistributedLock.Azure 1.0.2)

docs/DistributedLock.Postgres.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ await using (await @lock.AcquireAsync())
1818
- The `PostgresDistributedReaderWriterLock` class implements the `IDistributedReaderWriterLock` interface.
1919
- The `PostgresDistributedSynchronizationProvider` class implements the `IDistributedLockProvider` and `IDistributedReaderWriterLockProvider` interfaces.
2020

21+
As of version 1.3, an additional set of static APIs on `PostgresDistributedLock` allows you to leverage transaction-scoped locking with an existing `IDbTransaction` instance. Since Postgres offers no way to explicitly release transaction-scoped locks and the caller controls the transaction, these locks are acquire-only and do not need a using block. For example:
22+
```C#
23+
using (var transaction = connection.BeginTransaction())
24+
{
25+
...
26+
// acquires the lock; it will be held until the transaction ends
27+
await PostgresDistributedLock.AcquireWithTransactionAsync(key, transaction);
28+
...
29+
}
30+
```
31+
2132
## Implementation notes
2233

2334
Under the hood, [Postgres advisory locks can be based on either one 64-bit integer value or a pair of 32-bit integer values](https://www.postgresql.org/docs/12/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS). Because of this, rather than taking in a name the lock constructors take a `PostgresAdvisoryLockKey` object which can be constructed in several ways:

src/DistributedLock.Postgres/DistributedLock.Postgres.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</PropertyGroup>
1212

1313
<PropertyGroup>
14-
<Version>1.2.1</Version>
14+
<Version>1.3.0</Version>
1515
<AssemblyVersion>1.0.0.0</AssemblyVersion>
1616
<Authors>Michael Adelson</Authors>
1717
<Description>Provides a distributed lock implementation based on Postgresql</Description>

src/DistributedLock.Postgres/PostgresAdvisoryLock.cs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,15 @@ private DatabaseCommand CreateAcquireCommand(DatabaseConnection connection, Post
211211
var capturedTimeoutSettings = new CapturedTimeoutSettings(statementTimeout!, lockTimeout!);
212212

213213
return capturedTimeoutSettings;
214-
}
215214

216-
private static async ValueTask<string?> GetCurrentSetting(string settingName, DatabaseConnection connection, CancellationToken cancellationToken)
217-
{
218-
using var getCurrentSettingCommand = connection.CreateCommand();
215+
async ValueTask<string?> GetCurrentSetting(string settingName, DatabaseConnection connection, CancellationToken cancellationToken)
216+
{
217+
using var getCurrentSettingCommand = connection.CreateCommand();
219218

220-
getCurrentSettingCommand.SetCommandText($"SELECT current_setting('{settingName}', 'true') AS {settingName};");
219+
getCurrentSettingCommand.SetCommandText($"SELECT current_setting('{settingName}', 'true') AS {settingName};");
221220

222-
return (string?) await getCurrentSettingCommand.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
221+
return (string?)await getCurrentSettingCommand.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
222+
}
223223
}
224224

225225
private static async ValueTask<bool> ShouldDefineSavePoint(DatabaseConnection connection)
@@ -240,13 +240,13 @@ private static async ValueTask<bool> ShouldDefineSavePoint(DatabaseConnection co
240240
}
241241
catch (InvalidOperationException)
242242
{
243-
// If we reached this point, it means the externally-owned connection has a transaction, therefore we need to define a save point.
243+
// Externally-owned connection with a transaction => we need to define a save point.
244244
return true;
245245
}
246246

247247
await connection.DisposeTransactionAsync().ConfigureAwait(false);
248248

249-
// If we reached this point, it means the externally-owned connection has no transaction, therefore we can't define a save point.
249+
// Externally-owned connection with no transaction => no save point
250250
return false;
251251
}
252252

@@ -257,8 +257,7 @@ private static async ValueTask RestoreTimeoutSettingsIfNeededAsync(CapturedTimeo
257257

258258
using var restoreTimeoutSettingsCommand = connection.CreateCommand();
259259

260-
var commandText = new StringBuilder();
261-
260+
StringBuilder commandText = new();
262261
commandText.AppendLine($"SET LOCAL statement_timeout = {settings.Value.StatementTimeout};");
263262
commandText.AppendLine($"SET LOCAL lock_timeout = {settings.Value.LockTimeout};");
264263

src/DistributedLock.Postgres/PostgresDistributedLock.Transactions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ internal static ValueTask AcquireWithTransactionAsyncInternal(PostgresAdvisoryLo
127127
async ValueTask AcquireAsync()
128128
{
129129
var connection = new PostgresDatabaseConnection(transaction);
130-
131130
await using (connection.ConfigureAwait(false))
132131
{
133132
await PostgresAdvisoryLock.ExclusiveLock.TryAcquireAsync(connection, key.ToString(), timeout, cancellationToken).ThrowTimeoutIfNull().ConfigureAwait(false);

src/DistributedLock.Postgres/PublicAPI.Shipped.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,8 @@ override Medallion.Threading.Postgres.PostgresAdvisoryLockKey.Equals(object? obj
4646
override Medallion.Threading.Postgres.PostgresAdvisoryLockKey.GetHashCode() -> int
4747
override Medallion.Threading.Postgres.PostgresAdvisoryLockKey.ToString() -> string!
4848
static Medallion.Threading.Postgres.PostgresAdvisoryLockKey.operator !=(Medallion.Threading.Postgres.PostgresAdvisoryLockKey a, Medallion.Threading.Postgres.PostgresAdvisoryLockKey b) -> bool
49-
static Medallion.Threading.Postgres.PostgresAdvisoryLockKey.operator ==(Medallion.Threading.Postgres.PostgresAdvisoryLockKey a, Medallion.Threading.Postgres.PostgresAdvisoryLockKey b) -> bool
49+
static Medallion.Threading.Postgres.PostgresAdvisoryLockKey.operator ==(Medallion.Threading.Postgres.PostgresAdvisoryLockKey a, Medallion.Threading.Postgres.PostgresAdvisoryLockKey b) -> bool
50+
static Medallion.Threading.Postgres.PostgresDistributedLock.AcquireWithTransaction(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan? timeout = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> void
51+
static Medallion.Threading.Postgres.PostgresDistributedLock.AcquireWithTransactionAsync(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan? timeout = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
52+
static Medallion.Threading.Postgres.PostgresDistributedLock.TryAcquireWithTransaction(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan timeout = default(System.TimeSpan), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> bool
53+
static Medallion.Threading.Postgres.PostgresDistributedLock.TryAcquireWithTransactionAsync(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan timeout = default(System.TimeSpan), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<bool>
Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +0,0 @@
1-
#nullable enable
2-
static Medallion.Threading.Postgres.PostgresDistributedLock.AcquireWithTransaction(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan? timeout = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> void
3-
static Medallion.Threading.Postgres.PostgresDistributedLock.AcquireWithTransactionAsync(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan? timeout = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
4-
static Medallion.Threading.Postgres.PostgresDistributedLock.TryAcquireWithTransaction(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan timeout = default(System.TimeSpan), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> bool
5-
static Medallion.Threading.Postgres.PostgresDistributedLock.TryAcquireWithTransactionAsync(Medallion.Threading.Postgres.PostgresAdvisoryLockKey key, System.Data.IDbTransaction! transaction, System.TimeSpan timeout = default(System.TimeSpan), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<bool>

src/DistributedLock/DistributedLock.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</PropertyGroup>
1111

1212
<PropertyGroup>
13-
<Version>2.5.1</Version>
13+
<Version>2.6.0</Version>
1414
<AssemblyVersion>2.0.0.0</AssemblyVersion>
1515
<Authors>Michael Adelson</Authors>
1616
<Description>Provides easy-to-use mutexes, reader-writer locks, and semaphores that can synchronize across processes and machines. This is an umbrella package that brings in the entire family of DistributedLock.* packages (e. g. DistributedLock.SqlServer) as references. Those packages can also be installed individually.

0 commit comments

Comments
 (0)