Skip to content

Return error directly for unsupported command#304

Merged
xiexiaoy merged 2 commits intoeloqdata:mainfrom
xiexiaoy:reset_deadlock_rsp
Nov 12, 2025
Merged

Return error directly for unsupported command#304
xiexiaoy merged 2 commits intoeloqdata:mainfrom
xiexiaoy:reset_deadlock_rsp

Conversation

@xiexiaoy
Copy link
Copy Markdown
Collaborator

@xiexiaoy xiexiaoy commented Nov 12, 2025

eloqdata/tx_service#207

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling for catalog entry validation to avoid abrupt termination.
    • Two maintenance commands now return explicit "unsupported" errors instead of executing.
    • Time zone database initialization made more robust during context reset.
  • Tests

    • Disabled several mapReduce test cases across multiple suites for compatibility review.
  • Chores

    • Updated a submodule reference.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 12, 2025

Warning

Rate limit exceeded

@xiexiaoy has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 24 minutes and 26 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ff27be6 and c866ca1.

📒 Files selected for processing (6)
  • src/mongo/db/modules/eloq/store_handler (1 hunks)
  • src/mongo/db/modules/eloq/tx_service (1 hunks)
  • src/mongo/db/pipeline/expression_context.cpp (1 hunks)
  • tests/jstests/core/geo_big_polygon3.js (1 hunks)
  • tests/jstests/core/index_stats.js (1 hunks)
  • tests/jstests/core/or4.js (1 hunks)

Walkthrough

This PR marks the dbhash and rename collection commands unsupported for the Eloq storage engine, replaces an assert with guarded error handling in the Eloq KV engine, updates the eloq tx_service submodule pointer, comments out several mapReduce test blocks, and tweaks timezone initialization in ExpressionContext::reset.

Changes

Cohort / File(s) Summary
Command unsupport
src/mongo/db/commands/dbhash.cpp, src/mongo/db/commands/rename_collection_cmd.cpp
errmsgRun implementations now immediately set a fixed error message and return false, short-circuiting command execution; minor license/header formatting in dbhash.cpp.
Error handling in Eloq KV Engine
src/mongo/db/modules/eloq/src/eloq_kv_engine.cpp
Replaced an assert in getAllIdents with guarded error handling: log on error, convert Tx error codes to Mongo Status via uassertStatusOK, and skip non-existent catalog entries.
Submodule update
src/mongo/db/modules/eloq/tx_service
Updated tracked commit pointer from f4a1afb... to 54f9ed6... (submodule reference change).
Test disablement (mapReduce)
tests/jstests/core/geo_big_polygon3.js, tests/jstests/core/index_stats.js, tests/jstests/core/or4.js
MapReduce test blocks replaced with commented-out code; surrounding tests retained.
ExpressionContext tweak
src/mongo/db/pipeline/expression_context.cpp
ExpressionContext::reset now initializes timeZoneDatabase from opCtx->getServiceContext() when available; previously assigned nullptr directly.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant CommandLayer
    participant EloqEngine

    Note over CommandLayer,EloqEngine: New short-circuit behavior for Eloq commands

    Client->>CommandLayer: send dbhash/renameCollection Cmd
    CommandLayer->>CommandLayer: errmsgRun checks storage engine
    alt storage engine == Eloq
        CommandLayer-->>Client: return error message (unsupported) `#ffcccb`
    else other engine
        CommandLayer->>EloqEngine: proceed with normal command flow
        EloqEngine-->>CommandLayer: success / failure
        CommandLayer-->>Client: final result
    end
Loading
sequenceDiagram
    participant Caller
    participant EloqKV

    Note over EloqKV: getAllIdents read path adjusted

    Caller->>EloqKV: read catalog entry
    EloqKV->>EloqKV: check Tx errorCode
    alt errorCode != NO_ERROR
        EloqKV-->>Caller: log + uassertStatusOK(TxErrorCodeToMongoStatus(...)) `#ffe4b5`
    else exists == false
        EloqKV-->>Caller: log missing entry and skip
    else
        EloqKV-->>Caller: process ident
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay attention to eloq_kv_engine.cpp (getAllIdents) for correct status conversion and logging granularity.
  • Verify the intentionality and messaging for early returns in dbhash.cpp and rename_collection_cmd.cpp.
  • Check commented-out mapReduce tests for whether they should be removed or re-enabled with alternatives.
  • Confirm ExpressionContext::reset change doesn't affect downstream timezone-dependent behavior.

Possibly related PRs

Suggested reviewers

  • lzxddz
  • liunyl

Poem

🐇 I hopped through code both brave and spry,
Commands now say "not here" and fly,
Errors caught with gentler art,
Tests take naps, submodules start,
A rabbit cheers these small changes nigh.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Return error directly for unsupported command' accurately reflects the main changes: dbhash and rename_collection commands now return errors immediately instead of proceeding with validation logic.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@xiexiaoy xiexiaoy marked this pull request as ready for review November 12, 2025 07:16
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/jstests/core/or4.js (1)

74-83: Consider removing commented code or testing for unsupported command behavior.

Commented-out code creates maintenance burden and can confuse future readers. Consider one of these alternatives:

  1. Remove the code entirely if mapReduce will remain permanently unsupported on the Eloq storage engine.
  2. Add test tags to skip this test on Eloq (e.g., // @tags: [requires_mapreduce]).
  3. Test that the command fails gracefully by verifying it returns an appropriate "unsupported" error.

Option 3 provides the most value:

-    // assert.eq(5,
-    //           coll.mapReduce(
-    //                   function() {
-    //                       emit('a', this.a);
-    //                   },
-    //                   function(key, vals) {
-    //                       return vals.length;
-    //                   },
-    //                   {out: {inline: true}, query: {$or: [{a: 2}, {b: 3}]}})
-    //               .counts.input);
+    // Verify mapReduce is unsupported on Eloq storage engine
+    const mapReduceResult = db.runCommand({
+        mapReduce: coll.getName(),
+        map: function() { emit('a', this.a); },
+        reduce: function(key, vals) { return vals.length; },
+        out: {inline: true},
+        query: {$or: [{a: 2}, {b: 3}]}
+    });
+    // Assert command is rejected with appropriate error code for unsupported operations
+    assert.commandFailedWithCode(mapReduceResult, ErrorCodes.CommandNotSupported);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9191f59 and 5eac673.

📒 Files selected for processing (7)
  • src/mongo/db/commands/dbhash.cpp (3 hunks)
  • src/mongo/db/commands/rename_collection_cmd.cpp (1 hunks)
  • src/mongo/db/modules/eloq/src/eloq_kv_engine.cpp (1 hunks)
  • src/mongo/db/modules/eloq/tx_service (1 hunks)
  • tests/jstests/core/geo_big_polygon3.js (1 hunks)
  • tests/jstests/core/index_stats.js (1 hunks)
  • tests/jstests/core/or4.js (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: githubzilla
Repo: eloqdata/eloqdoc PR: 211
File: src/mongo/db/modules/eloq/cmake/build_eloq_log_service.cmake:26-80
Timestamp: 2025-09-25T12:24:06.434Z
Learning: The user githubzilla implemented a fix in commit fe98aaf to address the MEMORY state incorrectly triggering RocksDB discovery in build_eloq_log_service.cmake. This was a control flow issue where MEMORY builds were falling into an else branch that still attempted RocksDB discovery.
📚 Learning: 2025-09-25T12:24:06.434Z
Learnt from: githubzilla
Repo: eloqdata/eloqdoc PR: 211
File: src/mongo/db/modules/eloq/cmake/build_eloq_log_service.cmake:26-80
Timestamp: 2025-09-25T12:24:06.434Z
Learning: The user githubzilla implemented a fix in commit fe98aaf to address the MEMORY state incorrectly triggering RocksDB discovery in build_eloq_log_service.cmake. This was a control flow issue where MEMORY builds were falling into an else branch that still attempted RocksDB discovery.

Applied to files:

  • src/mongo/db/modules/eloq/src/eloq_kv_engine.cpp
🧬 Code graph analysis (1)
src/mongo/db/modules/eloq/src/eloq_kv_engine.cpp (2)
src/mongo/db/modules/eloq/src/base/eloq_util.cpp (2)
  • TxErrorCodeToMongoStatus (11-75)
  • TxErrorCodeToMongoStatus (11-11)
src/mongo/db/modules/eloq/src/eloq_record_store.cpp (6)
  • MONGO_LOG (91-119)
  • MONGO_LOG (445-480)
  • MONGO_LOG (520-524)
  • MONGO_LOG (526-532)
  • MONGO_LOG (534-540)
  • MONGO_LOG (542-547)
🔇 Additional comments (4)
src/mongo/db/modules/eloq/tx_service (1)

1-1: Verify submodule commit aligns with PR objectives.

Submodule pointer updates can obscure significant changes. Please confirm that commit 54f9ed618c78efa5275e6093c4fb502538d7b749 addresses the deadlock response handling mentioned in tx_service#207 and is tested as part of this PR.

tests/jstests/core/geo_big_polygon3.js (1)

81-88: LGTM - MapReduce test disabled for Eloq storage engine.

The mapReduce test has been properly disabled by commenting out the test block, which aligns with the PR objective to mark mapReduce as unsupported for the Eloq storage engine.

tests/jstests/core/index_stats.js (1)

173-186: LGTM - MapReduce test disabled for Eloq storage engine.

The mapReduce test block has been properly disabled, consistent with the PR's objective to mark mapReduce as unsupported for the Eloq storage engine.

src/mongo/db/modules/eloq/src/eloq_kv_engine.cpp (1)

1181-1189: LGTM - Improved error handling replaces assert.

This change replaces an assert with proper error handling that:

  • Propagates non-NO_ERROR errors as MongoDB status via uassertStatusOK
  • Gracefully skips non-existent catalog entries with logging

This is a critical improvement that prevents crashes when catalog entries are missing or invalid, and is consistent with the error handling pattern used elsewhere in the codebase (e.g., eloq_record_store.cpp lines 90-118).

Comment on lines +95 to +96
errmsg = "Unsupported feature. The Eloq storage engine does not support dbhash command.";
return false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unreachable code after early return.

The early return at line 96 makes all subsequent code in this function (lines 98-209) unreachable. This dead code should be removed to avoid confusion and reduce maintenance burden.

Apply this diff to remove the unreachable code:

     virtual bool errmsgRun(OperationContext* opCtx,
                            const std::string& dbname,
                            const BSONObj& cmdObj,
                            std::string& errmsg,
                            BSONObjBuilder& result) {
         errmsg = "Unsupported feature. The Eloq storage engine does not support dbhash command.";
         return false;
-
-        Timer timer;
-
-        std::set<std::string> desiredCollections;
-        if (cmdObj["collections"].type() == Array) {
-            BSONObjIterator i(cmdObj["collections"].Obj());
-            while (i.more()) {
-                BSONElement e = i.next();
-                if (e.type() != String) {
-                    errmsg = "collections entries have to be strings";
-                    return false;
-                }
-                desiredCollections.insert(e.String());
-            }
-        }
-
-        const std::string ns = parseNs(dbname, cmdObj);
-        uassert(ErrorCodes::InvalidNamespace,
-                str::stream() << "Invalid db name: " << ns,
-                NamespaceString::validDBName(ns, NamespaceString::DollarInDbNameBehavior::Allow));
-
-        // We lock the entire database in S-mode in order to ensure that the contents will not
-        // change for the snapshot.
-        auto lockMode = LockMode::MODE_S;
-        auto* session = OperationContextSession::get(opCtx);
-        if (session && session->inMultiDocumentTransaction()) {
-            // However, if we are inside a multi-statement transaction, then we only need to lock
-            // the database in intent mode to ensure that none of the collections get dropped.
-            lockMode = getLockModeForQuery(opCtx);
-        }
-        AutoGetDb autoDb(opCtx, ns, lockMode);
-        Database* db = autoDb.getDb();
-        std::list<std::string> colls;
-        if (db) {
-            db->getDatabaseCatalogEntry()->getCollectionNamespaces(&colls);
-            colls.sort();
-        }
-
-        result.append("host", prettyHostName());
-
-        md5_state_t globalState;
-        md5_init(&globalState);
-
-        // A set of 'system' collections that are replicated, and therefore included in the db hash.
-        const std::set<StringData> replicatedSystemCollections{"system.backup_users",
-                                                               "system.js",
-                                                               "system.new_users",
-                                                               "system.roles",
-                                                               "system.users",
-                                                               "system.version",
-                                                               "system.views"};
-
-        BSONArrayBuilder cappedCollections;
-        BSONObjBuilder collectionsByUUID;
-
-        BSONObjBuilder bb(result.subobjStart("collections"));
-        for (const auto& collectionName : colls) {
-
-            NamespaceString collNss(collectionName);
-
-            if (collNss.size() - 1 <= dbname.size()) {
-                errmsg = str::stream() << "weird fullCollectionName [" << collNss.toString() << "]";
-                return false;
-            }
-
-            // Only include 'system' collections that are replicated.
-            bool isReplicatedSystemColl =
-                (replicatedSystemCollections.count(collNss.coll().toString()) > 0);
-            if (collNss.isSystem() && !isReplicatedSystemColl)
-                continue;
-
-            if (collNss.coll().startsWith("tmp.mr.")) {
-                // We skip any incremental map reduce collections as they also aren't replicated.
-                continue;
-            }
-
-            if (desiredCollections.size() > 0 &&
-                desiredCollections.count(collNss.coll().toString()) == 0)
-                continue;
-
-            // Don't include 'drop pending' collections.
-            if (collNss.isDropPendingNamespace())
-                continue;
-
-            if (Collection* collection = db->getCollection(opCtx, collectionName)) {
-                if (collection->isCapped()) {
-                    cappedCollections.append(collNss.coll());
-                }
-
-                if (OptionalCollectionUUID uuid = collection->uuid()) {
-                    uuid->appendToBuilder(&collectionsByUUID, collNss.coll());
-                }
-            }
-
-            // Compute the hash for this collection.
-            std::string hash = _hashCollection(opCtx, db, collNss.toString());
-
-            bb.append(collNss.coll(), hash);
-            md5_append(&globalState, (const md5_byte_t*)hash.c_str(), hash.size());
-        }
-        bb.done();
-
-        result.append("capped", BSONArray(cappedCollections.done()));
-        result.append("uuids", collectionsByUUID.done());
-
-        md5digest d;
-        md5_finish(&globalState, d);
-        std::string hash = digestToString(d);
-
-        result.append("md5", hash);
-        result.appendNumber("timeMillis", timer.millis());
-
-        return 1;
     }
🤖 Prompt for AI Agents
In src/mongo/db/commands/dbhash.cpp around lines 95 to 96, there is an early
return that sets errmsg and returns false which renders the subsequent code
(lines 98-209) unreachable; remove the dead/unreachable code after that return
(or alternatively remove the early return and properly implement behavior) so
the function contains only reachable logic—delete the unreachable block and
ensure the function compiles and behaves as intended after removal.

Comment on lines +97 to +100
errmsg =
"Unsupported feature. The Eloq storage engine does not support rename collection "
"command.";
return false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unreachable code after early return.

The early return at line 100 makes all subsequent code in this function (lines 102-167) unreachable. This dead code should be removed to avoid confusion and reduce maintenance burden.

Apply this diff to remove the unreachable code:

     virtual bool errmsgRun(OperationContext* opCtx,
                            const string& dbname,
                            const BSONObj& cmdObj,
                            string& errmsg,
                            BSONObjBuilder& result) {
         errmsg =
             "Unsupported feature. The Eloq storage engine does not support rename collection "
             "command.";
         return false;
-
-        const auto sourceNsElt = cmdObj[getName()];
-        const auto targetNsElt = cmdObj["to"];
-
-        uassert(ErrorCodes::TypeMismatch,
-                "'renameCollection' must be of type String",
-                sourceNsElt.type() == BSONType::String);
-        uassert(ErrorCodes::TypeMismatch,
-                "'to' must be of type String",
-                targetNsElt.type() == BSONType::String);
-
-        const NamespaceString source(sourceNsElt.valueStringData());
-        const NamespaceString target(targetNsElt.valueStringData());
-
-        uassert(ErrorCodes::InvalidNamespace,
-                str::stream() << "Invalid source namespace: " << source.ns(),
-                source.isValid());
-        uassert(ErrorCodes::InvalidNamespace,
-                str::stream() << "Invalid target namespace: " << target.ns(),
-                target.isValid());
-
-        if ((repl::ReplicationCoordinator::get(opCtx)->getReplicationMode() !=
-             repl::ReplicationCoordinator::modeNone)) {
-            if (source.isOplog()) {
-                errmsg = "can't rename live oplog while replicating";
-                return false;
-            }
-            if (target.isOplog()) {
-                errmsg = "can't rename to live oplog while replicating";
-                return false;
-            }
-        }
-
-        if (source.isOplog() != target.isOplog()) {
-            errmsg = "If either the source or target of a rename is an oplog name, both must be";
-            return false;
-        }
-
-        Status sourceStatus = userAllowedWriteNS(source);
-        if (!sourceStatus.isOK()) {
-            errmsg = "error with source namespace: " + sourceStatus.reason();
-            return false;
-        }
-
-        Status targetStatus = userAllowedWriteNS(target);
-        if (!targetStatus.isOK()) {
-            errmsg = "error with target namespace: " + targetStatus.reason();
-            return false;
-        }
-
-        if (source.isSystemDotIndexes() || target.isSystemDotIndexes()) {
-            errmsg = "renaming system.indexes is not allowed";
-            return false;
-        }
-
-        if (source.isServerConfigurationCollection()) {
-            uasserted(ErrorCodes::IllegalOperation,
-                      "renaming the server configuration "
-                      "collection (admin.system.version) is not "
-                      "allowed");
-        }
-
-        RenameCollectionOptions options;
-        options.dropTarget = cmdObj["dropTarget"].trueValue();
-        options.stayTemp = cmdObj["stayTemp"].trueValue();
-        uassertStatusOK(renameCollection(opCtx, source, target, options));
-        return true;
     }
🤖 Prompt for AI Agents
In src/mongo/db/commands/rename_collection_cmd.cpp around lines 97 to 100, the
function sets errmsg and returns false at line 100, which makes the subsequent
code (lines 102–167) unreachable; remove the dead code block from lines 102
through 167 so only the intended early-return path remains and update any
related comments or includes if they become unused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5eac673 and ff27be6.

📒 Files selected for processing (4)
  • src/mongo/db/pipeline/expression_context.cpp (1 hunks)
  • tests/jstests/core/geo_big_polygon3.js (1 hunks)
  • tests/jstests/core/index_stats.js (1 hunks)
  • tests/jstests/core/or4.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/jstests/core/or4.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/jstests/core/index_stats.js
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: githubzilla
Repo: eloqdata/eloqdoc PR: 211
File: src/mongo/db/modules/eloq/cmake/build_eloq_log_service.cmake:26-80
Timestamp: 2025-09-25T12:24:06.434Z
Learning: The user githubzilla implemented a fix in commit fe98aaf to address the MEMORY state incorrectly triggering RocksDB discovery in build_eloq_log_service.cmake. This was a control flow issue where MEMORY builds were falling into an else branch that still attempted RocksDB discovery.
🔇 Additional comments (1)
src/mongo/db/pipeline/expression_context.cpp (1)

87-89: LGTM! Improved consistency and correctness.

This change properly initializes timeZoneDatabase from the service context when opCtx is available, aligning with the constructor (lines 113-115) and the other reset method (lines 139-141). Previously, this reset method likely set it to nullptr unconditionally, which would break timezone-related aggregation operations after reset when a valid service context was present.

@xiexiaoy xiexiaoy requested a review from lzxddz November 12, 2025 08:28
@xiexiaoy xiexiaoy merged commit bd9d442 into eloqdata:main Nov 12, 2025
2 checks passed
@xiexiaoy xiexiaoy deleted the reset_deadlock_rsp branch November 12, 2025 08:44
xiexiaoy added a commit that referenced this pull request Nov 12, 2025
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