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

IndexSearcher fix for virtual calls from constructor #837

Conversation

laimis
Copy link
Contributor

@laimis laimis commented Apr 14, 2023

Continuation of fixes with virtual calls being made from constructors. The issue originally reported by SonarCloud scans: https://sonarcloud.io/project/issues?resolved=false&rules=csharpsquid%3AS1699&id=apache_lucenenet and referenced in this issue: #670

This one focuses on IndexSearcher. Since we discovered a separate constructor approach as an elegant way to address this issue, let's use it for IndexSearcher.

/// control whether or not the leaf slices are allocated.
/// If you choose to skip allocating the leaf slices here, you must
/// initialize <see cref="m_leafSlices" /> in your subclass's constructor, either
/// by calling <see cref="GetSlices"/> or using your own logic
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's be a bit more specific:

/// <summary>
/// LUCENENET specific constructor that can be used by the subclasses to
/// control whether the leaf slices are allocated in the base class or subclass.
/// </summary>
/// <remarks>
/// If executor is non-<c>null</c> and you choose to skip allocating the leaf slices
/// (i.e. <paramref name="allocateLeafSlices"/> == <c>false</c>), you must
/// set the <see cref="m_leafSlices"/> field in your subclass constructor.
/// This is commonly done by calling <see cref="GetSlices(IList{AtomicReaderContext})"/>
/// and using the result to set <see cref="m_leafSlices"/>. You may wish to do this if you
/// have state to pass into your constructor and need to set it prior to the call to
/// <see cref="GetSlices(IList{AtomicReaderContext})"/> so it is available for use
/// as a member field or property inside a custom override of
/// <see cref="GetSlices(IList{AtomicReaderContext})"/>.
/// </remarks>

@@ -464,6 +471,9 @@ protected virtual TopDocs Search(Weight weight, ScoreDoc after, int nDocs)
ReentrantLock @lock = new ReentrantLock();
ExecutionHelper<TopDocs> runner = new ExecutionHelper<TopDocs>(executor);

if (m_leafSlices == null)
Copy link
Contributor

Choose a reason for hiding this comment

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

Although it doesn't make any difference for arrays, all null equality checks have all been converted to use is in #617.

The is keyword doesn't take any overrides of the == operator into account, so it is not possible to circumvent our null check logic by passing a class that has one.

@@ -560,6 +570,9 @@ protected virtual TopFieldDocs Search(Weight weight, FieldDoc after, int nDocs,
ReentrantLock @lock = new ReentrantLock();
ExecutionHelper<TopFieldDocs> runner = new ExecutionHelper<TopFieldDocs>(executor);

if (m_leafSlices == null)
Copy link
Contributor

Choose a reason for hiding this comment

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

See my comment on line 474.

@@ -464,6 +471,9 @@ protected virtual TopDocs Search(Weight weight, ScoreDoc after, int nDocs)
ReentrantLock @lock = new ReentrantLock();
ExecutionHelper<TopDocs> runner = new ExecutionHelper<TopDocs>(executor);

if (m_leafSlices == null)
throw new InvalidOperationException("m_leafSlices must not be null and initialized in the constructor");
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's change this a bit:

throw new InvalidOperationException($"When the constructor is passed a non-null {nameof(TaskScheduler)}, {nameof(m_leafSlices)} must also be set to a non-null value in the constructor.");

@@ -560,6 +570,9 @@ protected virtual TopFieldDocs Search(Weight weight, FieldDoc after, int nDocs,
ReentrantLock @lock = new ReentrantLock();
ExecutionHelper<TopFieldDocs> runner = new ExecutionHelper<TopFieldDocs>(executor);

if (m_leafSlices == null)
throw new InvalidOperationException("m_leafSlices must not be null and initialized in the constructor");
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's change this a bit:

throw new InvalidOperationException($"When the constructor is passed a non-null {nameof(TaskScheduler)}, {nameof(m_leafSlices)} must also be set to a non-null value in the constructor.");

/// control whether the leaf slices are allocated in the base class or subclass.
/// </summary>
/// <remarks>
/// If executor is non-<c>null</c> and you choose to skip allocating the leaf slices
Copy link
Contributor

Choose a reason for hiding this comment

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

Oops. I missed that the second word here should be <paramref name="executor"/>.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated!

@laimis laimis requested a review from NightOwl888 April 14, 2023 18:28
src/Lucene.Net/Search/IndexSearcher.cs Outdated Show resolved Hide resolved
src/Lucene.Net/Search/IndexSearcher.cs Outdated Show resolved Hide resolved
src/Lucene.Net/Search/IndexSearcher.cs Outdated Show resolved Hide resolved
src/Lucene.Net/Search/IndexSearcher.cs Outdated Show resolved Hide resolved
src/Lucene.Net/Search/IndexSearcher.cs Show resolved Hide resolved
…s for all non-nullable parameters. Marked nullable parameters as such. Documented when ArgumentNullReferenceException is expected to be thrown from each method overload.
@NightOwl888 NightOwl888 merged commit 825f63e into apache:master Apr 14, 2023
// LUCENENET: Added guard clause
if (leaves is null)
throw new ArgumentNullException(nameof(leaves));

LeafSlice[] slices = new LeafSlice[leaves.Count];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not a fan of these type of additions. This is not present in the original source, not even in the latest version. We could add a lot of extra typing/code (that's not even interesting, just copy paste of exception docs and guar checks). This is why I wasn't sure what you meant by guard clauses as it seemed excessive.

@laimis laimis deleted the fix/virtual-calls-from-constructors-indexsearcher2 branch May 17, 2023 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants