<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Thu Feb 08 09:01:26 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>MongoDB Jira</title>
    <link>https://jira.mongodb.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.7.1</version>
        <build-number>970001</build-number>
        <build-date>13-04-2023</build-date>
    </build-info>


<item>
            <title>[JAVA-4183] Calling cursor.next() and cursor.close() concurrently in Load Balanced mode uses the same connection simultaneously</title>
                <link>https://jira.mongodb.org/browse/JAVA-4183</link>
                <project id="10006" key="JAVA">Java Driver</project>
                    <description>

    &lt;div id=&quot;script-target-wrapper&quot;&gt;
        &lt;br&gt;
        &lt;b&gt;DRIVERS Ticket Description&lt;/b&gt;
        &lt;div id=&quot;lang-script-target&quot;&gt;
            &lt;!-- This block of HTML and the script in it auto-populate the DRIVERS ticket description on page load. --&gt;
            Script Target - If you can read this text, the script has failed
            &lt;script&gt;
                $.get(&apos;https://jira.mongodb.org/browse/DRIVERS-1789&apos;, function(data) {
                    var description = $(data).find(&quot;#description-val&quot;);
                    $(&quot;#lang-script-target&quot;).html(description);
                });
            &lt;/script&gt;
        &lt;/div&gt;
    &lt;/div&gt;
</description>
                <environment></environment>
        <key id="1765140">JAVA-4183</key>
            <summary>Calling cursor.next() and cursor.close() concurrently in Load Balanced mode uses the same connection simultaneously</summary>
                <type id="1" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14703&amp;avatarType=issuetype">Bug</type>
                                            <priority id="3" iconUrl="https://jira.mongodb.org/images/icons/priorities/major.svg">Major - P3</priority>
                        <status id="6" iconUrl="https://jira.mongodb.org/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="success"/>
                                    <resolution id="13201">Fixed</resolution>
                                        <assignee username="valentin.kovalenko@mongodb.com">Valentin Kavalenka</assignee>
                                    <reporter username="backlog-server-pm">Backlog - Core Eng Program Management Team</reporter>
                        <labels>
                            <label>spec-compliance</label>
                    </labels>
                <created>Tue, 1 Jun 2021 17:03:07 +0000</created>
                <updated>Sat, 28 Oct 2023 11:21:12 +0000</updated>
                            <resolved>Tue, 3 Aug 2021 14:07:17 +0000</resolved>
                                    <version>4.3.0</version>
                                    <fixVersion>4.3.1</fixVersion>
                                    <component>Connection Management</component>
                                        <votes>0</votes>
                                    <watches>2</watches>
                                                                                                                <comments>
                            <comment id="3977956" author="xgen-internal-githook" created="Tue, 3 Aug 2021 14:06:59 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{&apos;name&apos;: &apos;Valentin Kovalenko&apos;, &apos;email&apos;: &apos;valentin.kovalenko@mongodb.com&apos;, &apos;username&apos;: &apos;stIncMale&apos;}
&lt;p&gt;Message: Support calling `QueryBatchCursor.close` concurrently with other `QueryBatchCursor` methods (#765)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4183&quot; title=&quot;Calling cursor.next() and cursor.close() concurrently in Load Balanced mode uses the same connection simultaneously&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4183&quot;&gt;&lt;del&gt;JAVA-4183&lt;/del&gt;&lt;/a&gt;&lt;br/&gt;
Branch: 4.3.x&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/commit/bfd25ddfb1497c17dacb852fc534de8b7eaff370&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-java-driver/commit/bfd25ddfb1497c17dacb852fc534de8b7eaff370&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="3973343" author="xgen-internal-githook" created="Fri, 30 Jul 2021 17:45:28 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{&apos;name&apos;: &apos;Valentin Kovalenko&apos;, &apos;email&apos;: &apos;valentin.kovalenko@mongodb.com&apos;, &apos;username&apos;: &apos;stIncMale&apos;}
&lt;p&gt;Message: Support calling `QueryBatchCursor.close` concurrently with other `QueryBatchCursor` methods (#765)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jira.mongodb.org/browse/JAVA-4183&quot; title=&quot;Calling cursor.next() and cursor.close() concurrently in Load Balanced mode uses the same connection simultaneously&quot; class=&quot;issue-link&quot; data-issue-key=&quot;JAVA-4183&quot;&gt;&lt;del&gt;JAVA-4183&lt;/del&gt;&lt;/a&gt;&lt;br/&gt;
Branch: master&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo-java-driver/commit/7206b7100a3eb22ce7588460de0104c49809d8e2&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-java-driver/commit/7206b7100a3eb22ce7588460de0104c49809d8e2&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="3950629" author="JIRAUSER1258163" created="Mon, 19 Jul 2021 21:02:28 +0000"  >&lt;h2&gt;&lt;a name=&quot;Javadrivercursortypeshierarchy&quot;&gt;&lt;/a&gt;Java driver cursor types hierarchy&lt;/h2&gt;

&lt;ul&gt;
	&lt;li&gt;legacy API
	&lt;ul&gt;
		&lt;li&gt;interface &lt;tt&gt;com.mongodb.&lt;b&gt;Cursor&lt;/b&gt;&lt;/tt&gt;
		&lt;ul&gt;
			&lt;li&gt;&lt;tt&gt;com.mongodb.&lt;b&gt;DBCursor&lt;/b&gt;&lt;/tt&gt; (uses &lt;tt&gt;MongoBatchCursorAdapter&lt;/tt&gt; wrapping &lt;tt&gt;BatchCursor&lt;/tt&gt;)&lt;/li&gt;
			&lt;li&gt;&lt;tt&gt;com.mongodb.&lt;b&gt;MongoCursorAdapter&lt;/b&gt;&lt;/tt&gt; (adapts &lt;tt&gt;MongoCursor&lt;/tt&gt; to &lt;tt&gt;Cursor&lt;/tt&gt;)&lt;/li&gt;
		&lt;/ul&gt;
		&lt;/li&gt;
	&lt;/ul&gt;
	&lt;/li&gt;
	&lt;li&gt;modern API
	&lt;ul&gt;
		&lt;li&gt;interface &lt;tt&gt;com.mongodb.client.&lt;b&gt;MongoCursor&lt;/b&gt;&lt;/tt&gt;
		&lt;ul&gt;
			&lt;li&gt;interface &lt;tt&gt;com.mongodb.client.&lt;b&gt;MongoChangeStreamCursor&lt;/b&gt;&lt;/tt&gt;
			&lt;ul&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.client.internal.&lt;b&gt;MongoChangeStreamCursorImpl&lt;/b&gt;&lt;/tt&gt; (adapts &lt;tt&gt;BatchCursor&lt;/tt&gt; to &lt;tt&gt;MongoChangeStreamCursor&lt;/tt&gt;)&lt;/li&gt;
			&lt;/ul&gt;
			&lt;/li&gt;
			&lt;li&gt;&lt;tt&gt;com.mongodb.client.internal.&lt;b&gt;MongoBatchCursorAdapter&lt;/b&gt;&lt;/tt&gt; (adapts &lt;tt&gt;BatchCursor&lt;/tt&gt; to &lt;tt&gt;MongoCursor&lt;/tt&gt;)&lt;/li&gt;
			&lt;li&gt;&lt;tt&gt;com.mongodb.client.internal.&lt;b&gt;MongoMappingCursor&lt;/b&gt;&lt;/tt&gt; (wraps &lt;tt&gt;MongoCursor&lt;/tt&gt;)&lt;/li&gt;
		&lt;/ul&gt;
		&lt;/li&gt;
		&lt;li&gt;interface &lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;BatchCursor&lt;/b&gt;&lt;/tt&gt;
		&lt;ul&gt;
			&lt;li&gt;interface &lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;AggregateResponseBatchCursor&lt;/b&gt;&lt;/tt&gt;
			&lt;ul&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;ChangeStreamBatchCursor&lt;/b&gt;&lt;/tt&gt; (wraps &lt;tt&gt;AggregateResponseBatchCursor&lt;/tt&gt;, implements retries)&lt;/li&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;QueryBatchCursor&lt;/b&gt;&lt;/tt&gt; (will likely be renamed to &lt;tt&gt;CommandBatchCursor&lt;/tt&gt; in CSOT)
				&lt;ul&gt;
					&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;MapReduceInlineResultsCursor&lt;/b&gt;&lt;/tt&gt;&lt;/li&gt;
				&lt;/ul&gt;
				&lt;/li&gt;
			&lt;/ul&gt;
			&lt;/li&gt;
			&lt;li&gt;interface &lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;MapReduceBatchCursor&lt;/b&gt;&lt;/tt&gt;
			&lt;ul&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;MapReduceInlineResultsCursor&lt;/b&gt;&lt;/tt&gt;&lt;/li&gt;
			&lt;/ul&gt;
			&lt;/li&gt;
		&lt;/ul&gt;
		&lt;/li&gt;
		&lt;li&gt;interface &lt;tt&gt;com.mongodb.internal.async.&lt;b&gt;AsyncBatchCursor&lt;/b&gt;&lt;/tt&gt;
		&lt;ul&gt;
			&lt;li&gt;interface &lt;tt&gt;com.mongodb.internal.async.&lt;b&gt;AsyncAggregateResponseBatchCursor&lt;/b&gt;&lt;/tt&gt;
			&lt;ul&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;AsyncChangeStreamBatchCursor&lt;/b&gt;&lt;/tt&gt; (wraps &lt;tt&gt;AsyncAggregateResponseBatchCursor&lt;/tt&gt;, implements retries)&lt;/li&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;AsyncQueryBatchCursor&lt;/b&gt;&lt;/tt&gt; (will likely be renamed to &lt;tt&gt;AsyncCommandBatchCursor&lt;/tt&gt; in CSOT)&lt;/li&gt;
			&lt;/ul&gt;
			&lt;/li&gt;
			&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;AsyncSingleBatchQueryCursor&lt;/b&gt;&lt;/tt&gt; (adapts &lt;tt&gt;QueryResult*&lt;/tt&gt; to &lt;tt&gt;AsyncBatchCursor&lt;/tt&gt;)
			&lt;ul&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;MapReduceInlineResultsAsyncCursor&lt;/b&gt;&lt;/tt&gt;&lt;/li&gt;
			&lt;/ul&gt;
			&lt;/li&gt;
			&lt;li&gt;interface &lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;MapReduceAsyncBatchCursor&lt;/b&gt;&lt;/tt&gt;
			&lt;ul&gt;
				&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.&lt;b&gt;MapReduceInlineResultsAsyncCursor&lt;/b&gt;&lt;/tt&gt;&lt;/li&gt;
			&lt;/ul&gt;
			&lt;/li&gt;
			&lt;li&gt;&lt;tt&gt;com.mongodb.internal.operation.ListCollectionsOperation.&lt;b&gt;ProjectingAsyncBatchCursor&lt;/b&gt;&lt;/tt&gt; (wraps &lt;tt&gt;AsyncBatchCursor&lt;/tt&gt;)&lt;/li&gt;
		&lt;/ul&gt;
		&lt;/li&gt;
	&lt;/ul&gt;
	&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;&lt;a name=&quot;Analysis&quot;&gt;&lt;/a&gt;Analysis&lt;/h2&gt;

&lt;p&gt;We can see that only &lt;tt&gt;QueryBatchCursor&lt;/tt&gt; and &lt;tt&gt;AsyncQueryBatchCursor&lt;/tt&gt; implement the cursor logic, while all other classes are wrappers.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;AsyncQueryBatchCursor&lt;/tt&gt; supported concurrent &lt;tt&gt;next&lt;/tt&gt; and &lt;tt&gt;close&lt;/tt&gt; operations even before the support for LB was implemented, and as far a I can tell, that is now supported even for LB mode: &lt;tt&gt;killCursorOnClose&lt;/tt&gt; uses the &lt;tt&gt;pinnedConnection&lt;/tt&gt; and is executed after the concurrent &lt;tt&gt;getMore&lt;/tt&gt; returns, even if it returns with no results. This way users indeed can call &lt;tt&gt;close&lt;/tt&gt; to cancel &lt;tt&gt;next&lt;/tt&gt; if it spins doing &lt;tt&gt;getMore&lt;/tt&gt;. However, the driver does not cancel &lt;tt&gt;getMore&lt;/tt&gt;, and this operation is blocked until either results are available or &lt;a href=&quot;https://docs.mongodb.com/manual/reference/command/getMore/#syntax&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;tt&gt;maxTimeMS&lt;/tt&gt;&lt;/a&gt; is elapsed (see &lt;a href=&quot;https://mongodb.github.io/mongo-java-driver/4.3/apidocs/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/AggregatePublisher.html#maxAwaitTime(long,java.util.concurrent.TimeUnit)&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;tt&gt;AggregatePublisher.maxAwaitTime&lt;/tt&gt;&lt;/a&gt;, &lt;a href=&quot;https://mongodb.github.io/mongo-java-driver/4.3/apidocs/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/FindPublisher.html#maxAwaitTime(long,java.util.concurrent.TimeUnit)&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;tt&gt;FindPublisher.maxAwaitTime&lt;/tt&gt;&lt;/a&gt;, &lt;a href=&quot;https://mongodb.github.io/mongo-java-driver/4.3/apidocs/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ChangeStreamPublisher.html#maxAwaitTime(long,java.util.concurrent.TimeUnit)&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;tt&gt;ChangeStreamPublisher.maxAwaitTime&lt;/tt&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;QueryBatchCursor&lt;/tt&gt; does not have the same mechanism, most likely because &lt;tt&gt;AggregateResponseBatchCursor&lt;/tt&gt; is documented as &lt;tt&gt;@NotThreadSafe&lt;/tt&gt;. However, the &lt;tt&gt;closed&lt;/tt&gt; field is marked as &lt;tt&gt;volatile&lt;/tt&gt; and before the LB changes the &lt;tt&gt;close&lt;/tt&gt; method has been getting a new connection to &lt;tt&gt;killCursor&lt;/tt&gt;, which strongly suggests that we allowed calling &lt;tt&gt;close&lt;/tt&gt; concurrently with &lt;tt&gt;next&lt;/tt&gt; to cancel it. Thus, &lt;tt&gt;QueryBatchCursor&lt;/tt&gt; indeed has the bug described in this ticket.&lt;/p&gt;

&lt;p&gt;A user has access to &lt;tt&gt;QueryBatchCursor&lt;/tt&gt; via &lt;tt&gt;MongoCursor&lt;/tt&gt;. I suppose for asynchronous API (&lt;tt&gt;AsyncQueryBatchCursor.close&lt;/tt&gt;) the &lt;tt&gt;close&lt;/tt&gt; methods is called as a result of calling &lt;tt&gt;Subscription.cancel&lt;/tt&gt;.&lt;/p&gt;

&lt;h2&gt;&lt;a name=&quot;Nextsteps&quot;&gt;&lt;/a&gt;Next steps&lt;/h2&gt;

&lt;ol&gt;
	&lt;li&gt;Write a test that checks that &lt;tt&gt;next&lt;/tt&gt; can be cancelled by &lt;tt&gt;close&lt;/tt&gt; for both &lt;tt&gt;AsyncQueryBatchCursor&lt;/tt&gt; and &lt;tt&gt;QueryBatchCursor&lt;/tt&gt;.&lt;/li&gt;
	&lt;li&gt;Fix &lt;tt&gt;QueryBatchCursor&lt;/tt&gt; such that the test mentioned above passes.&lt;/li&gt;
	&lt;li&gt;Fix the documentation
	&lt;ol&gt;
		&lt;li&gt;&lt;tt&gt;MongoCursor&lt;/tt&gt; documentation should clearly state that &lt;tt&gt;close&lt;/tt&gt; can be called concurrently with other methods even though &lt;tt&gt;MongoCursor&lt;/tt&gt; is not thread-safe.&lt;/li&gt;
		&lt;li&gt;Explicitly mark &lt;tt&gt;MongoChangeStreamCursor&lt;/tt&gt; with &lt;tt&gt;@NotThreadSafe&lt;/tt&gt; similarly to &lt;tt&gt;MongoCursor&lt;/tt&gt;.&lt;/li&gt;
		&lt;li&gt;Fix examples in &lt;tt&gt;MongoCursor&lt;/tt&gt; and &lt;tt&gt;MongoChangeStreamCursor&lt;/tt&gt; as they do not seem to be correct: &lt;tt&gt;MongoCollection.find&lt;/tt&gt; returns &lt;tt&gt;FindIterable&lt;/tt&gt;, which is not &lt;tt&gt;MongoCursor&lt;/tt&gt;. The only way to get &lt;tt&gt;MongoCursor&lt;/tt&gt;/&lt;tt&gt;MongoChangeStreamCursor&lt;/tt&gt; is by calling &lt;tt&gt;watch&lt;/tt&gt;, which returns &lt;tt&gt;ChangeStreamIterable&lt;/tt&gt;, which in turn has the method &lt;tt&gt;ChangeStreamIterable.cursor&lt;/tt&gt;.&lt;/li&gt;
	&lt;/ol&gt;
	&lt;/li&gt;
&lt;/ol&gt;
</comment>
                    </comments>
                <issuelinks>
                            <issuelinktype id="10620">
                    <name>Issue split</name>
                                            <outwardlinks description="split to">
                                        <issuelink>
            <issuekey id="1830096">JAVA-4260</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="1830091">JAVA-4259</issuekey>
        </issuelink>
                            </outwardlinks>
                                                                <inwardlinks description="split from">
                                                        </inwardlinks>
                                    </issuelinktype>
                    </issuelinks>
                <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10257" key="com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons">
                        <customfieldname>Documentation Changes</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="11861"><![CDATA[Not Needed]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                <customfield id="customfield_21553" key="com.atlassian.jira.plugin.system.customfieldtypes:labels">
                        <customfieldname>Quarter</customfieldname>
                        <customfieldvalues>
                                        <label>FY22Q2</label>
    
                        </customfieldvalues>
                    </customfield>
                                                                                            <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|hr3mg7:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10558" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>9223372036854775807</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                        <customfield id="customfield_11150" key="com.atlassian.jira.plugin.system.customfieldtypes:multiselect">
                        <customfieldname>SERVER fixVersion</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="20500"><![CDATA[5.0]]></customfieldvalue>
    
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        </customfields>
    </item>
</channel>
</rss>