Skip to content

Commit bb93bc2

Browse files
authored
Fix yet another deadlock in mocks (#946)
* Fix yet another deadlock in mocks * tweak
1 parent 6ec1258 commit bb93bc2

File tree

2 files changed

+41
-18
lines changed

2 files changed

+41
-18
lines changed

NGitLab.Mock/Clients/ClientContext.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Runtime.CompilerServices;
34
using System.Threading;
45

56
namespace NGitLab.Mock.Clients;
@@ -14,10 +15,20 @@ internal sealed class ClientContext(GitLabServer server, User user)
1415

1516
public bool IsAuthenticated => User != null;
1617

17-
public IDisposable BeginOperationScope()
18+
public IDisposable BeginOperationScope(
19+
[CallerMemberName] string callingMethod = null,
20+
[CallerFilePath] string callingFilePath = null,
21+
[CallerLineNumber] int callingLineNumber = -1)
1822
{
1923
Server.RaiseOnClientOperation();
20-
return new Releaser(_operationLock);
24+
var releaser = new Releaser(_operationLock);
25+
26+
// Store caller info for debugging purposes
27+
Releaser.MethodWhereLockWasTaken = callingMethod;
28+
Releaser.FilePathWhereLockWasTaken = callingFilePath;
29+
Releaser.LineNumberWhereLockWasTaken = callingLineNumber;
30+
31+
return releaser;
2132
}
2233

2334
private sealed class Releaser : IDisposable
@@ -27,11 +38,18 @@ private sealed class Releaser : IDisposable
2738
public Releaser(SemaphoreSlim operationLock)
2839
{
2940
_operationLock = operationLock;
30-
if (Debugger.IsAttached && _operationLock.CurrentCount == 0)
41+
if (_operationLock.CurrentCount == 0 && Debugger.IsAttached)
3142
Debugger.Break();
3243
_operationLock.Wait();
3344
}
3445

46+
// The following is for debugging purposes only. It stores info about where the active lock was taken.
47+
public static string MethodWhereLockWasTaken { get; set; }
48+
49+
public static string FilePathWhereLockWasTaken { get; set; }
50+
51+
public static int LineNumberWhereLockWasTaken { get; set; }
52+
3553
public void Dispose()
3654
{
3755
_operationLock.Release();

NGitLab.Mock/Clients/RepositoryClient.cs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -142,28 +142,33 @@ public CompareResults Compare(CompareQuery query)
142142
{
143143
using (Context.BeginOperationScope())
144144
{
145-
var project = GetProject(_projectId, ProjectPermission.View);
146-
var treeChanges = project.Repository.Compare(query.From, query.To);
147-
return new CompareResults()
148-
{
149-
Diff = treeChanges.Select(change
150-
=> new Diff()
151-
{
152-
NewPath = change.Path,
153-
OldPath = change.OldPath,
154-
IsNewFile = change.Status is ChangeKind.Added,
155-
IsDeletedFile = change.Status is ChangeKind.Deleted,
156-
IsRenamedFile = change.Status is ChangeKind.Renamed,
157-
}).ToArray(),
158-
};
145+
return CompareLockless(query);
159146
}
160147
}
161148

149+
private CompareResults CompareLockless(CompareQuery query)
150+
{
151+
var project = GetProject(_projectId, ProjectPermission.View);
152+
var treeChanges = project.Repository.Compare(query.From, query.To);
153+
return new CompareResults()
154+
{
155+
Diff = treeChanges.Select(change
156+
=> new Diff()
157+
{
158+
NewPath = change.Path,
159+
OldPath = change.OldPath,
160+
IsNewFile = change.Status is ChangeKind.Added,
161+
IsDeletedFile = change.Status is ChangeKind.Deleted,
162+
IsRenamedFile = change.Status is ChangeKind.Renamed,
163+
}).ToArray(),
164+
};
165+
}
166+
162167
public Task<CompareResults> CompareAsync(CompareQuery query, CancellationToken cancellationToken = default)
163168
{
164169
using (Context.BeginOperationScope())
165170
{
166-
return Task.FromResult(Compare(query));
171+
return Task.FromResult(CompareLockless(query));
167172
}
168173
}
169174
}

0 commit comments

Comments
 (0)