-
Notifications
You must be signed in to change notification settings - Fork 248
Expand file tree
/
Copy pathOracleDistributedReaderWriterLockHandle.cs
More file actions
123 lines (102 loc) · 5.26 KB
/
Copy pathOracleDistributedReaderWriterLockHandle.cs
File metadata and controls
123 lines (102 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using Medallion.Threading.Internal;
using Medallion.Threading.Internal.Data;
namespace Medallion.Threading.Oracle;
/// <summary>
/// Implements <see cref="IDistributedSynchronizationHandle"/>
/// </summary>
public abstract class OracleDistributedReaderWriterLockHandle : IDistributedSynchronizationHandle
{
// forbid external inheritors
internal OracleDistributedReaderWriterLockHandle() { }
/// <summary>
/// Implements <see cref="IDistributedSynchronizationHandle.HandleLostToken"/>
/// </summary>
public abstract CancellationToken HandleLostToken { get; }
/// <summary>
/// Releases the lock
/// </summary>
public void Dispose() => this.DisposeSyncViaAsync();
/// <summary>
/// Releases the lock asynchronously
/// </summary>
public abstract ValueTask DisposeAsync();
}
internal sealed class OracleDistributedReaderWriterLockNonUpgradeableHandle : OracleDistributedReaderWriterLockHandle
{
private IDistributedSynchronizationHandle? _innerHandle;
internal OracleDistributedReaderWriterLockNonUpgradeableHandle(IDistributedSynchronizationHandle? handle)
{
this._innerHandle = handle;
}
public override CancellationToken HandleLostToken => this._innerHandle?.HandleLostToken ?? throw this.ObjectDisposed();
public override ValueTask DisposeAsync() => Interlocked.Exchange(ref this._innerHandle, null)?.DisposeAsync() ?? default;
}
/// <summary>
/// Implements <see cref="IDistributedLockUpgradeableHandle"/>
/// </summary>
public sealed class OracleDistributedReaderWriterLockUpgradeableHandle : OracleDistributedReaderWriterLockHandle, IInternalDistributedLockUpgradeableHandle
{
private RefBox<(IDistributedSynchronizationHandle innerHandle, IDbDistributedLock @lock, IDistributedSynchronizationHandle? upgradedHandle)>? _box;
internal OracleDistributedReaderWriterLockUpgradeableHandle(IDistributedSynchronizationHandle innerHandle, IDbDistributedLock @lock)
{
this._box = RefBox.Create((innerHandle, @lock, default(IDistributedSynchronizationHandle?)));
}
/// <summary>
/// Implements <see cref="IDistributedSynchronizationHandle.HandleLostToken"/>
/// </summary>
public override CancellationToken HandleLostToken => (this._box ?? throw this.ObjectDisposed()).Value.innerHandle.HandleLostToken;
/// <summary>
/// Releases the lock asynchronously
/// </summary>
public override async ValueTask DisposeAsync()
{
if (RefBox.TryConsume(ref this._box, out var contents))
{
try { await (contents.upgradedHandle?.DisposeAsync() ?? default).ConfigureAwait(false); }
finally { await contents.innerHandle.DisposeAsync().ConfigureAwait(false); }
}
}
/// <summary>
/// Implements <see cref="IDistributedLockUpgradeableHandle.TryUpgradeToWriteLock(TimeSpan, CancellationToken)"/>
/// </summary>
public bool TryUpgradeToWriteLock(TimeSpan timeout = default, CancellationToken cancellationToken = default) =>
DistributedLockHelpers.TryUpgradeToWriteLock(this, timeout, cancellationToken);
/// <summary>
/// Implements <see cref="IDistributedLockUpgradeableHandle.TryUpgradeToWriteLockAsync(TimeSpan, CancellationToken)"/>
/// </summary>
public ValueTask<bool> TryUpgradeToWriteLockAsync(TimeSpan timeout = default, CancellationToken cancellationToken = default) =>
this.As<IInternalDistributedLockUpgradeableHandle>().InternalTryUpgradeToWriteLockAsync(timeout, cancellationToken);
/// <summary>
/// Implements <see cref="IDistributedLockUpgradeableHandle.UpgradeToWriteLock(TimeSpan?, CancellationToken)"/>
/// </summary>
public void UpgradeToWriteLock(TimeSpan? timeout = null, CancellationToken cancellationToken = default) =>
DistributedLockHelpers.UpgradeToWriteLock(this, timeout, cancellationToken);
/// <summary>
/// Implements <see cref="IDistributedLockUpgradeableHandle.UpgradeToWriteLockAsync(TimeSpan?, CancellationToken)"/>
/// </summary>
public ValueTask UpgradeToWriteLockAsync(TimeSpan? timeout = null, CancellationToken cancellationToken = default) =>
DistributedLockHelpers.UpgradeToWriteLockAsync(this, timeout, cancellationToken);
ValueTask<bool> IInternalDistributedLockUpgradeableHandle.InternalTryUpgradeToWriteLockAsync(TimeoutValue timeout, CancellationToken cancellationToken)
{
var box = this._box ?? throw this.ObjectDisposed();
var contents = box.Value;
if (contents.upgradedHandle != null) { throw new InvalidOperationException("the lock has already been upgraded"); }
return TryPerformUpgradeAsync();
async ValueTask<bool> TryPerformUpgradeAsync()
{
var upgradedHandle =
await contents.@lock.TryAcquireAsync(timeout, OracleDbmsLock.UpgradeLock, cancellationToken, contextHandle: contents.innerHandle).ConfigureAwait(false);
if (upgradedHandle == null)
{
return false;
}
contents.upgradedHandle = upgradedHandle;
var newBox = RefBox.Create(contents);
if (Interlocked.CompareExchange(ref this._box, newBox, comparand: box) != box)
{
await upgradedHandle.DisposeAsync().ConfigureAwait(false);
}
return true;
}
}
}