mikependon / RepoDB

A hybrid ORM library for .NET.
Apache License 2.0
1.68k stars 122 forks source link

Mitigate thread race conditions & hashcode collision risks #1153

Closed alexn-tinwell closed 11 months ago

alexn-tinwell commented 12 months ago

We have been seeing intermittent instances of this issue happening https://github.com/mikependon/RepoDB/issues/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.

alexn-tinwell commented 11 months ago

@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 commented 11 months ago

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