Skip to content

Concurrency Warning#288

Merged
YuKitsune merged 12 commits into
masterfrom
nick/deadlock-aware-lock-logging
Jul 7, 2024
Merged

Concurrency Warning#288
YuKitsune merged 12 commits into
masterfrom
nick/deadlock-aware-lock-logging

Conversation

@YuKitsune
Copy link
Copy Markdown
Contributor

@YuKitsune YuKitsune commented Jul 2, 2024

[sc-82478]

  • Removes DeadlockAwareLock (Most calls to it were using Lock() and LockAsync() which bypassed the deadlock checks)
  • Replaces DeadlockAwareLock with ITransactionConcurrencyHandler
    • Includes various implementations for different scenarios (No locking, locking enabled, locking with logging, and logging only)
    • Logging variants will log a warning when attempting to run queries in parallel on the same transaction
  • Replaces SupportConcurrentExecution option with ConcurrencyMode option
  • Replaces ThreadSafeEnumerables with EnumerableWithConcurrencyHandling for clarity

@YuKitsune YuKitsune changed the title Nick/deadlock aware lock logging Enable logging on parallel queries Jul 2, 2024
@YuKitsune YuKitsune changed the title Enable logging on parallel queries Concurrency Detection Jul 2, 2024
@YuKitsune YuKitsune requested review from a team and borland July 2, 2024 05:47
@YuKitsune YuKitsune marked this pull request as ready for review July 2, 2024 05:47
@YuKitsune YuKitsune changed the title Concurrency Detection Concurrency Warning Jul 2, 2024
Comment on lines +7 to +12
public interface ITransactionConcurrencyHandler : IDisposable
{
IDisposable Lock();

Task<IDisposable> LockAsync(CancellationToken cancellationToken);
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided to replace the DeadlockAwareLock with this abstraction as a way for us to enable logging without locking. It's a bit much, but felt cleaner than introducing a bunch of additional checks into a single class.
Open to alternatives.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a spike of what this would look like if we had a single type: #289

Comment thread source/Nevermore/Advanced/Concurrency/NoOpConcurrencyHandler.cs Outdated
return configuration.SupportConcurrentExecution
? new ThreadSafeEnumerable<TRecord>(Execute, DeadlockAwareLock)
// Use the thread safe variant if we know it's going to be used
return configuration.ConcurrencyMode is not ConcurrencyMode.NoLock
Copy link
Copy Markdown
Contributor

@borland borland Jul 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: A clearer and more reliable way to make this decision could be

  • Add a bool IsThreadSafe { get; } property to TransactionConcurrencyHandler
  • The implementations can return true/false appropriately

return TransactionConcurrencyHandler.IsThreadSafe ? new ThreadSafeEnumerable<TRecord>...

If you wanted to go full-hog with this you could hide the creation of the ThreadSafeEnumerable inside the concurrency handler, and then do return TransactionConcurrencyHandler.WrapEnumerable(Execute()) all the time with zero if statements. That'd be the safest and "best" in terms of OOP, but I'm not sure I'd personally take it that far, as it introduces a new concern (Enumerables) into the ConcurrencyHandler. Maybe I'll change my mind in the morning.

Copy link
Copy Markdown
Contributor

@borland borland Jul 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Underlying principle here: You've got one input - the ConcurrencyMode enum, but you make decisions about it in two places. If the decisions don't need to align, that's fine -- however in this case the choice to use ThreadSafeEnumerable, and the behaviour of the TransactionConcurrencyHandler are highly aligned. If you used a locking handler without the threadsafe enumerable (or vice versa) that would be a bug.

Technique: Reduce the decision-points (and thus, risk of bugs) by having one decision "flow through" to the next. If that all sounds like gibberish, hit me up for a zoom tomorrow 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm keen to follow up here on zoom. Another concern here is that we still want to use the logging-only concurrency handler.
I think the cleanest way forward is to always return the ThreadSafeEnumerable, and give it what ever concurrency handler we've got. The only thing I don't like about that is the fact that we can return a ThreadSafeEnumerable with a concurrency handler that doesn't provide thread safety, but we need it for the logging anyway 😕

Comment thread source/Nevermore/Advanced/ReadTransaction.cs Outdated
Comment thread source/Nevermore/ConcurrencyMode.cs
Copy link
Copy Markdown
Contributor

@borland borland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm quite happy with the removal of DeadlockAwareLock, the choice of four implementations of concurrency handler, and the interface is nice. I would appreciate a quick zoom though, I'd like someone to show me all the places you found where the deadlockawarelock wasn't working properly.

Some comments about the implementation details in ReadTransaction, nothing obviously bad, but it'd be nice to have a chat about them before I approve.
Note: I'm not blocking; if someone else is happy to approve before I get there and you want to merge, fair game

Comment thread source/Nevermore/Advanced/Concurrency/LockOnlyConcurrencyHandler.cs Outdated
Copy link
Copy Markdown
Contributor

@borland borland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looking good, approved!

@YuKitsune YuKitsune merged commit 7bd1d9b into master Jul 7, 2024
@YuKitsune YuKitsune deleted the nick/deadlock-aware-lock-logging branch July 7, 2024 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants