<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Thu Feb 08 04:43:16 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>[SERVER-36493] Invalidate in-memory prepared transaction state on replication rollback</title>
                <link>https://jira.mongodb.org/browse/SERVER-36493</link>
                <project id="10000" key="SERVER">Core Server</project>
                    <description>&lt;p&gt;Before calling &lt;tt&gt;recoverToStableTimestamp&lt;/tt&gt;, we must abort any prepared transactions. This will require us to iterate through all active sessions and check if there is a prepared transaction on that session. If there is, we must abort the storage transaction. We will not update ServerTransactionMetrics or make any writes to the transactions table. &lt;/p&gt;

&lt;p&gt;There are several scenarios that we have to consider, but in each it should be safe to abort the prepared transaction and reconstruct the state during startup recovery.&lt;/p&gt;

&lt;p&gt;For the following examples, prepare timestamp = the oldest prepare timestamp whose corresponding commit/abort oplog entry is not majority committed. &lt;/p&gt;

&lt;p&gt;Case #1: stable timestamp is before the prepare timestamp&lt;/p&gt;

&lt;p&gt;When we rollback to a stable timestamp that is before the prepare timestamp, we can safely clear the prepared transaction states because we will reconstruct the prepared transaction and its commit/abort if one exists. We are not writing to the transactions table and will call the corresponding functions in TransactionParticipant (prepareTransaction, commitPreparedTransaction, and abortActiveTransaction) during startup recovery. Therefore, the oldestActiveOplogEntryOpTimes and oldestNonMajorityCommittedOpTimes will be be re-populated accordingly. &lt;/p&gt;

&lt;p&gt;Case #2: stable timestamp is at the prepare timestamp&lt;/p&gt;

&lt;p&gt;Since we will be reconstructing prepared transactions even if the stable timestamp is AT the prepare timestamp, this case is the same as Case #1.&lt;/p&gt;

&lt;p&gt;Case #3: stable timestamp is after the prepare timestamp.&lt;/p&gt;

&lt;p&gt;The stable timestamp would only advance farther than the prepare timestamp if its corresponding commit/abort oplog entry has been majority committed. This would mean that neither the prepare or commit/abort should be rolled back since the common point would have to be after the majority commit point. In this case, we technically should no longer have information about the prepared transaction, so its safe to clear the data structure. If another prepared transaction exists, we would defer to Case #1 or Case #2. &lt;/p&gt;

&lt;p&gt;We already have a function that invalidates sessions in &lt;tt&gt;session_catalog_mongod&lt;/tt&gt; that is called in &lt;tt&gt;OpObserverImpl::onReplicationRollback&lt;/tt&gt;. This is used to invalidate sessions that had operations that would have been rolled back. Similarly we would create a function called &lt;tt&gt;invalidateSessionsWithPreparedTransactions&lt;/tt&gt; that would scan all sessions and call &lt;tt&gt;txnParticipant-&amp;gt;shutdown()&lt;/tt&gt; on prepared transactions.&lt;/p&gt;

&lt;p&gt;Currently, the shutdown() function is only used on shutdown and aborts the storage transaction of any transaction. We will modify this function to have a flag &lt;tt&gt;isInRollback&lt;/tt&gt; so we know to only abort prepared transactions if this is set to true. We will also clear the &lt;tt&gt;oldestActiveOplogEntryOpTimes&lt;/tt&gt; and &lt;tt&gt;oldestNonMajorityCommittedOpTimes&lt;/tt&gt; in this function.&lt;/p&gt;

&lt;p&gt;Finally, we will have to decide how to properly update ServerTransactionsMetrics during a rollback. For example, if we call abortActiveTransaction on a prepared transaction, it will increment the count of both &lt;tt&gt;totalAborted&lt;/tt&gt; and &lt;tt&gt;totalPreparedThenAborted&lt;/tt&gt;. &lt;/p&gt;

&lt;p&gt;Since we cannot write an integration test for this ticket until the state transition work is in, we will unit test the &lt;tt&gt;shutdown&lt;/tt&gt; and &lt;tt&gt;invalidateSessionsWithPreparedTransactions&lt;/tt&gt; functions. &lt;/p&gt;</description>
                <environment></environment>
        <key id="584989">SERVER-36493</key>
            <summary>Invalidate in-memory prepared transaction state on replication rollback</summary>
                <type id="3" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14718&amp;avatarType=issuetype">Task</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="pavithra.vetriselvan@mongodb.com">Pavithra Vetriselvan</assignee>
                                    <reporter username="judah.schvimer@mongodb.com">Judah Schvimer</reporter>
                        <labels>
                            <label>prepare_durability</label>
                    </labels>
                <created>Tue, 7 Aug 2018 16:23:18 +0000</created>
                <updated>Sun, 29 Oct 2023 22:29:12 +0000</updated>
                            <resolved>Tue, 11 Dec 2018 00:18:43 +0000</resolved>
                                                    <fixVersion>4.1.7</fixVersion>
                                    <component>Replication</component>
                                        <votes>0</votes>
                                    <watches>4</watches>
                                                                                                                <comments>
                            <comment id="2086514" author="xgen-internal-githook" created="Tue, 11 Dec 2018 00:17:10 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{&apos;name&apos;: &apos;Pavi Vetriselvan&apos;, &apos;email&apos;: &apos;pvselvan@umich.edu&apos;, &apos;username&apos;: &apos;pvselvan&apos;}
&lt;p&gt;Message: &lt;a href=&quot;https://jira.mongodb.org/browse/SERVER-36493&quot; title=&quot;Invalidate in-memory prepared transaction state on replication rollback&quot; class=&quot;issue-link&quot; data-issue-key=&quot;SERVER-36493&quot;&gt;&lt;del&gt;SERVER-36493&lt;/del&gt;&lt;/a&gt; invalidate in-memory state of prepared txns on repl rollback&lt;br/&gt;
Branch: master&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo/commit/6f6748705abc029db91c91505ae2c0047049bc46&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo/commit/6f6748705abc029db91c91505ae2c0047049bc46&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="2055847" author="kaloian.manassiev" created="Thu, 8 Nov 2018 16:50:41 +0000"  >&lt;p&gt;What this quote describes is essentially the same as the &lt;a href=&quot;https://github.com/mongodb/mongo/blob/1dbb12023ff57af62a9daee85cf7637432231b5f/src/mongo/db/kill_sessions_local.cpp#L114&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;tt&gt;killAllExpiredTransactions&lt;/tt&gt;&lt;/a&gt; loop. Inside the &lt;tt&gt;scanSessions&lt;/tt&gt; callback you have the session available, so you can get the participant from it and do whatever atomic checks need to be done (&lt;tt&gt;isPrepared&lt;/tt&gt; for example) and decided whether to call &lt;tt&gt;kill&lt;/tt&gt; on the session.&lt;/p&gt;

&lt;p&gt;Once all the kill tokens are collected, you can either call &lt;tt&gt;SessionCatalog::checkoutSessionForKill&lt;/tt&gt; &lt;a href=&quot;https://github.com/mongodb/mongo/blob/1dbb12023ff57af62a9daee85cf7637432231b5f/src/mongo/db/kill_sessions_local.cpp#L72&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;inline&lt;/a&gt; or &lt;a href=&quot;https://github.com/mongodb/mongo/blob/1dbb12023ff57af62a9daee85cf7637432231b5f/src/mongo/db/session_catalog_mongod.cpp#L155&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;on a separate thread&lt;/a&gt; if you don&apos;t want to block the caller.&lt;/p&gt;

&lt;p&gt;One thing to consider is - what happens if a transaction becomes prepared after scanSessions has skipped over it and didn&apos;t find it prepared? Or will you abort all transactions regardless of what state they are? See &lt;a href=&quot;https://github.com/mongodb/mongo/blob/1dbb12023ff57af62a9daee85cf7637432231b5f/src/mongo/db/kill_sessions_local.cpp#L132&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;this comment&lt;/a&gt; which is related to this situation.&lt;/p&gt;</comment>
                            <comment id="2055681" author="judah.schvimer" created="Thu, 8 Nov 2018 15:30:13 +0000"  >&lt;blockquote&gt;
&lt;p&gt;We will likely have to create a new function in session_catalog_mongod that both aborts prepared transactions and invalidates the associated sessions. Alternatively, we could call scanSessions and pass in a custom function that aborts prepared transactions (txnParticipant-&amp;gt;abortActiveTransaction()).&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://jira.mongodb.org/secure/ViewProfile.jspa?name=kaloian.manassiev&quot; class=&quot;user-hover&quot; rel=&quot;kaloian.manassiev&quot;&gt;kaloian.manassiev&lt;/a&gt;, any input on the best way to accomplish this with your refactor?&lt;/p&gt;</comment>
                            <comment id="2029076" author="judah.schvimer" created="Wed, 10 Oct 2018 15:19:05 +0000"  >&lt;p&gt;Rather than invalidating sessions between the stable timestamp and the common point, we&apos;ll need to abort any prepared transactions and possibly invalidate those sessions &lt;b&gt;before&lt;/b&gt; calling &lt;tt&gt;recoverToStableTimestamp&lt;/tt&gt;. This will make replication recovery more in line with startup recovery anyways, and it will reconstruct the prepared transactions before users can begin any reads.&lt;/p&gt;</comment>
                            <comment id="2023766" author="judah.schvimer" created="Thu, 4 Oct 2018 15:46:13 +0000"  >&lt;p&gt;We&apos;ll have to consider if we have to invalidate any sessions between the stable timestamp and the common point before they are recovered.&lt;/p&gt;</comment>
                    </comments>
                <issuelinks>
                            <issuelinktype id="10012">
                    <name>Related</name>
                                            <outwardlinks description="related to">
                                        <issuelink>
            <issuekey id="607766">SERVER-37235</issuekey>
        </issuelink>
                            </outwardlinks>
                                                                <inwardlinks description="is related to">
                                        <issuelink>
            <issuekey id="626553">SERVER-37811</issuekey>
        </issuelink>
                            </inwardlinks>
                                    </issuelinktype>
                    </issuelinks>
                <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                <customfield id="customfield_10050" key="com.atlassian.jira.toolkit:comments">
                        <customfieldname># Replies</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>5.0</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_18555" key="com.onresolve.jira.groovy.groovyrunner:scripted-field">
                        <customfieldname># of Sprints</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>6.0</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                            <customfield id="customfield_10011" key="com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons">
                        <customfieldname>Backwards Compatibility</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10038"><![CDATA[Fully Compatible]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                            <customfield id="customfield_10055" key="com.atlassian.jira.ext.charting:firstresponsedate">
                        <customfieldname>Date of 1st Reply</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>Thu, 8 Nov 2018 16:50:41 +0000</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10052" key="com.atlassian.jira.toolkit:dayslastcommented">
                        <customfieldname>Days since reply</customfieldname>
                        <customfieldvalues>
                                        5 years, 9 weeks, 2 days ago
    
                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_18254" key="com.onresolve.jira.groovy.groovyrunner:scripted-field">
                        <customfieldname>Dependencies</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue><![CDATA[]]></customfieldvalue>


                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                            <customfield id="customfield_10857" key="com.pyxis.greenhopper.jira:gh-epic-link">
                        <customfieldname>Epic Link</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>PM-1032</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                <customfield id="customfield_10057" key="com.atlassian.jira.toolkit:lastusercommented">
                        <customfieldname>Last comment by Customer</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>true</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                            <customfield id="customfield_10056" key="com.atlassian.jira.toolkit:lastupdaterorcommenter">
                        <customfieldname>Last commenter</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>luke.bonanomi@mongodb.com</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_11151" key="com.atlassian.jira.toolkit:LastCommentDate">
                        <customfieldname>Last public comment date</customfieldname>
                        <customfieldvalues>
                            5 years, 9 weeks, 2 days ago
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                    <customfield id="customfield_10051" key="com.atlassian.jira.toolkit:participants">
                        <customfieldname>Participants</customfieldname>
                        <customfieldvalues>
                                        <customfieldvalue>xgen-internal-githook</customfieldvalue>
            <customfieldvalue>judah.schvimer@mongodb.com</customfieldvalue>
            <customfieldvalue>kaloian.manassiev@mongodb.com</customfieldvalue>
            <customfieldvalue>pavithra.vetriselvan@mongodb.com</customfieldvalue>
    
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                        <customfield id="customfield_14254" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Product Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>1|hu4xgn:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|htvjbr:</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_23361" key="com.onresolve.jira.groovy.groovyrunner:scripted-field">
                        <customfieldname>Requested By</customfieldname>
                        <customfieldvalues>
                                

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                        <customfield id="customfield_10557" key="com.pyxis.greenhopper.jira:gh-sprint">
                        <customfieldname>Sprint</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue id="2541">Repl 2018-10-08</customfieldvalue>
    <customfieldvalue id="2542">Repl 2018-10-22</customfieldvalue>
    <customfieldvalue id="2543">Repl 2018-11-05</customfieldvalue>
    <customfieldvalue id="2605">Repl 2018-11-19</customfieldvalue>
    <customfieldvalue id="2606">Repl 2018-12-03</customfieldvalue>
    <customfieldvalue id="2607">Repl 2018-12-17</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                            <customfield id="customfield_10053" key="com.atlassian.jira.ext.charting:timeinstatus">
                        <customfieldname>Time In Status</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <customfield id="customfield_22870" key="com.onresolve.jira.groovy.groovyrunner:scripted-field">
                        <customfieldname>Triagers</customfieldname>
                        <customfieldvalues>
                                

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_14350" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>serverRank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>1|hu4jpz:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                    </customfields>
    </item>
</channel>
</rss>