-
Notifications
You must be signed in to change notification settings - Fork 126
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
Mitigate thread race conditions & hashcode collision risks #1153
Conversation
@@ -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" /> |
There was a problem hiding this comment.
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
… possibility in caching
d5a7f08
to
8cc8164
Compare
@@ -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()); |
There was a problem hiding this comment.
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
@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 |
@alexn-tinwell thanks for this PR. We are reviewing this already. |
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>()
, wherepropertyHandlerWasSet
is false, so it proceeds to setpropertyHandlerWasSet = true
before it has obtained a reference toPropertyHandlerCache.Get<TPropertyHandler>(GetDeclaringType(), PropertyInfo);
. A second thread enteringGetPropertyHandler<TPropertyHandler>()
at this point can then observepropertyHandlerWasSet
to betrue
, 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
.