Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mitigate thread race conditions & hashcode collision risks #1153

Merged

Conversation

alexn-tinwell
Copy link
Contributor

@alexn-tinwell alexn-tinwell commented Jul 11, 2023

We have been seeing intermittent instances of this issue happening #1133

It has taken a lot of debugging and stepping through in order to isolate the potential issue, but we've observed no recurrence of the errors since applying this patch locally and are therefore submitting a PR.

We are in a TimescaleDb / Postgresql 15 environment and are using RepoDb for its binary protocol support for bulk operations.

Findings

Race conditions

When creating db commands during both reads and inserts, the ClassProperty.GetPropertyHandler<TPropertyHandler>() is executed. The returned property handler is used to modify db commands such that their type matches what the database engine expects, and the value of the parameters is converted using the property handler. Quite elegant and also explains why at first we could find no use of Npgsql's TypeMapper system in the Postgresql-specific projects!

However, the code as-is can cause a null return for properties that do have a property handler.

Consider 2 threads:

One enters GetPropertyHandler<TPropertyHandler>(), where propertyHandlerWasSet is false, so it proceeds to set propertyHandlerWasSet = true before it has obtained a reference to PropertyHandlerCache.Get<TPropertyHandler>(GetDeclaringType(), PropertyInfo);. A second thread entering GetPropertyHandler<TPropertyHandler>() at this point can then observe propertyHandlerWasSet to be true, causing the method to return null. When this method returns null, the db parameter is not modified, and leads to errors such as reported in the mentioned issue because the unconverted type is passed through to the database provider.

Hashcode collisions

Furthermore in other areas we observed a chance for hashcode collisions when constructing cache keys, due to summing other hashcodes. Instead, this code has been converted to use HashCode.Combine.

@@ -13,7 +13,7 @@
<PackageReference Include="linq2db.PostgreSQL" Version="4.3.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="NHibernate" Version="5.4.0" />
<PackageReference Include="Npgsql" Version="7.0.0" />
<PackageReference Include="Npgsql" Version="7.0.4" />
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was upgraded to resolve a build warning at the head

@alexn-tinwell alexn-tinwell force-pushed the hotfix/tinwell/cache-thread-collisions branch from d5a7f08 to 8cc8164 Compare July 11, 2023 21:01
@@ -732,8 +732,12 @@ private static class ParameterizedMethodFuncCache<TEntity, TResult>
public static Func<TEntity, object[], TResult> GetFunc(string methodName,
Type[] types)
{
var key = methodName.GetHashCode() + types?.Sum(e => e.GetHashCode());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change has the added benefit of removing the allocation of an iterator during hash code creation

@alexn-tinwell
Copy link
Contributor Author

@mikependon hi there just FYI we've been running this build since this PR and have not seen a resurgence of the errors in the related issue

@mikependon
Copy link
Owner

@alexn-tinwell thanks for this PR. We are reviewing this already.

@mikependon mikependon self-assigned this Jul 19, 2023
@mikependon mikependon added the review The changes are under or being reviewed label Jul 19, 2023
@mikependon mikependon merged commit 7d90b1d into mikependon:master Jul 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
review The changes are under or being reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants