Skip to content

Conversation

fredericDelaporte
Copy link
Member

@fredericDelaporte fredericDelaporte commented Mar 13, 2018

This is causing FilterKey and QueryKey for the same queries but having different parameter values to always have the same hashcode, which is inefficient for keys lookup.

This PR is build over #1612, which includes the first four commits we can currently see here.

@fredericDelaporte fredericDelaporte force-pushed the DictionaryHashCode branch 2 times, most recently from a08d4e6 to 506c026 Compare March 14, 2018 01:01
@hazzik hazzik changed the title Fix CollectionHelper.GetHashCode ignoring values of dictionaries. Fix CollectionHelper.GetHashCode ignoring values of dictionaries Mar 20, 2018
@fredericDelaporte fredericDelaporte added this to the 5.2 milestone Mar 26, 2018
@hazzik
Copy link
Member

hazzik commented May 10, 2018

I would like this to go to master first. Need to have a separate unit test for the method.

@hazzik
Copy link
Member

hazzik commented May 10, 2018

Actually, do not want this change. The GetHashCode method should return the same value for the same object, but the uniqueness of these values are not required.

@hazzik hazzik closed this May 10, 2018
@hazzik hazzik removed this from the 5.2 milestone May 10, 2018
@fredericDelaporte
Copy link
Member Author

fredericDelaporte commented May 10, 2018

The GetHashCode method should return the same value for the same object, but the uniqueness of these values are not required.

Yes it is not required by GetHashCode, I am well aware of it. But this is still a bad thing for performances, since this means the cache lookup will be unable to benefit of the hashtable for distinguishing two queries differing only by their parameters values.

So when a query is cached for many different parameter values, its lookup in cache is an O(n) operation due to the current implementation (with n being the number of different parameter values).

@fredericDelaporte
Copy link
Member Author

Need to have a separate unit test for the method.

Done. This PR is now independent of #1612.

Still, if #1612 is merged before, it would then be better to also adjust query key and filter key hashcode tests (which cannot be adjusted without re-doing the fixes #1612 does).

/// individual elements key xored with their value if any, so that the value is independent of the
/// collection iteration order.
/// </remarks>
public static int GetHashCode<TK, TV>(IEnumerable<KeyValuePair<TK, TV>> coll)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe better to make an overload that accepts IEqualityComparer<T> and KeyValuePairComparer<TK, TV> instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

The overload added here is a specialization of the existing public static int GetHashCode<T>(IEnumerable<T> coll), allowing to handle the dictionary case specifically without source changes on the GetHashCode callers side: with a recompilation, when they supply a dictionary, that is this new overload which gets called, allowing to fix the issue.

Adding comparer overloads would require to change the calling code too (8 cases, in cache, engine and mapping namespaces). I would rather see this as a separate refactoring.

Copy link
Member

Choose a reason for hiding this comment

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

But this fix is too specialised. The problem exists for all struct types which can contain references.

Copy link
Member Author

Choose a reason for hiding this comment

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

This fix matches what NHibernate currently uses. CollectionHelper shoudn't be public in the first place but internal, and shouldn't aim at being generic but tailored to what NHibernate needs.

Copy link
Member

Choose a reason for hiding this comment

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

Can we make this method internal then?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. But now the test heavily relies on reflection, and it would be better to merge #1612 first then add tests here for checking QueryKey and FilterKey benefit of the internal overload. (Their tests fixtures are currently broken, causing them to be unusable. #1612 fixes them.)

@hazzik
Copy link
Member

hazzik commented May 11, 2018

CollectionHelper in the current form shall die. I propose to replace it with a set of content equality comparers (I will probably prepare a PR).

@fredericDelaporte
Copy link
Member Author

CollectionHelper in the current form shall die.

I agree. Nonetheless it should not prevent fixing its issues while it is still alive. So unless the switch to equality comparer can be done soon, better still fix its current implementation.

@hazzik
Copy link
Member

hazzik commented May 14, 2018

Maybe it's better to add a long overdue [InternalsVisibleToAttribute]?

@fredericDelaporte
Copy link
Member Author

This would require strong signing the test assembly too, because for assemblies to be friend, either both are unsigned or both are signed. An unsigned one cannot be friend of a signed one.

@hazzik
Copy link
Member

hazzik commented May 14, 2018

I've re-checked the code. CollectionHelper.GetHashCode has 2 invocations that accept a dictionary, both of them use the same type Dictionary<string, TypedValue>. I've submitted a PR with the GetHashCode method which accepts an IEqualityComparer<T> and also a specific comparer for this type of a dictionary. In total CollectionHelper.GetHashCode has 8 invocation, which changed in the PR as below:

  1. 2 invocations mentioned above;
  2. 1 invocation with an array - changed to ArrayHelper.ArrayGetHashCode;
  3. 3 invocations with an HashSet<>/ISet<> - changed to use set's comparer;
  4. 2 invocations with List<Column> - unchanged.

@hazzik
Copy link
Member

hazzik commented May 15, 2018

Replaced by #1694

@hazzik hazzik closed this May 15, 2018
@fredericDelaporte fredericDelaporte deleted the DictionaryHashCode branch May 15, 2018 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants