Skip to content

Conversation

@eerhardt
Copy link
Member

@eerhardt eerhardt commented Dec 2, 2021

Backport of #61187 to release/6.0

Customer Impact

There is a race condition in MemoryCache compaction that can cause apps to crash (since the compaction happens on a background thread, and an unhandled exception can be thrown). This can seemingly crash their process randomly.

Testing

Added a new multi-threaded test that tests the scenario.

Risk

Low Risk. The change is to snapshot the LastAccessed value, so even if it is updated during compaction, it won't cause an issue.

Note for reviewers

I have 2 commits. The first commit is what was merged into main with #61187. The second commit are the changes necessary for servicing.

Fix #61032

* Cache LastAccessed during MemoryCache compaction

During cache compaction, we are sorting entries based on their LastAccessed time. However, since the cache entries can still be used concurrently on other threads, the LastAccessed time may be updated in the middle of sorting the entries. This leads to exceptions in a background thread, crashing the process.

The fix is to cache the LastAccessed time outside of the entry when we are adding it to the list. This will ensure the time is stable during the compaction process.

Fix dotnet#61032
1. Remove the dependency on ValueTuple and use a custom struct instead.
2. Add servicing package changes.
3. In the tests, move the DisableParallelization collection declaration in the test project, since it is only in "Common" in main.
@eerhardt eerhardt added Servicing-consider Issue for next servicing release review area-Extensions-Caching labels Dec 2, 2021
@eerhardt eerhardt requested review from adamsitnik and safern December 2, 2021 17:27
@ghost
Copy link

ghost commented Dec 2, 2021

Tagging subscribers to this area: @dotnet/area-extensions-caching
See info in area-owners.md if you want to be subscribed.

Issue Details

Backport of #61187 to release/6.0

Customer Impact

There is a race condition in MemoryCache compaction that can cause apps to crash (since the compaction happens on a background thread, and an unhandled exception can be thrown). This can seemingly crash their process randomly.

Testing

Added a new multi-threaded test that tests the scenario.

Risk

Low Risk. The change is to snapshot the LastAccessed value, so even if it is updated during compaction, it won't cause an issue.

Note for reviewers

I have 2 commits. The first commit is what was merged into main with #61187. The second commit are the changes necessary for servicing.

Fix #61032

Author: eerhardt
Assignees: -
Labels:

Servicing-consider, area-Extensions-Caching

Milestone: -

@eerhardt eerhardt requested a review from maryamariyan December 2, 2021 17:40
@Pilchie Pilchie added Servicing-approved Approved for servicing release and removed Servicing-consider Issue for next servicing release review labels Dec 2, 2021
@Pilchie Pilchie added this to the 6.0.2 milestone Dec 2, 2021
{
case CacheItemPriority.Low:
lowPriEntries.Add(entry);
lowPriEntries.Add(new CompactPriorityEntry(entry, entry.LastAccessed));
Copy link
Member

Choose a reason for hiding this comment

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

I assume there will not be any boxing operation that causes additional allocations. right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct. We are using a List<CompactPriorityEntry>, so no boxing will occur. The small structs will just be copied in and out of the list. This is the same with the 7.0+ implementation, but there we are using ValueTuple instead of a custom struct.

@safern safern added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Dec 2, 2021
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

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

LGTM, thank you @eerhardt !

<EnableDefaultItems>true</EnableDefaultItems>
<PackageDescription>In-memory cache implementation of Microsoft.Extensions.Caching.Memory.IMemoryCache.</PackageDescription>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<ServicingVersion>1</ServicingVersion>
Copy link
Member Author

Choose a reason for hiding this comment

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

@safern - this is all I need to do to service this package, correct?

Copy link
Member

Choose a reason for hiding this comment

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

Yes 😄

Copy link
Member

@safern safern left a comment

Choose a reason for hiding this comment

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

Packaging updates look good to me.

@safern safern removed the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Dec 15, 2021
@safern safern merged commit e1f08db into dotnet:release/6.0 Dec 15, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Jan 15, 2022
@eerhardt eerhardt deleted the Port61187 branch June 16, 2022 12:03
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Caching Servicing-approved Approved for servicing release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants