[CXX-2126] Error "cannot run getMore on cursor" is occasionally thrown Created: 06/Nov/20  Updated: 27/Oct/23  Resolved: 19/Nov/20

Status: Closed
Project: C++ Driver
Component/s: API
Affects Version/s: 3.4.0
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Malik Mokhadri Assignee: Clyde Bazile III (Inactive)
Resolution: Works as Designed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows 10



 Description   

Occasionally, running getMore command on a cursor would throw the following error:

  • errmsg: Cannot run getMore on cursor <CURSOR_ID>, which was created in session <SESSION_ID>, in session <SESSION_ID>
  • err_code: 3
  • code: 50738
  • codeName: Location50738

 

Example Code:

#include "mongocxx/instance.hpp"
 
#include <vector>
#include <thread>
#include <exception>
#include <atomic>
 
int main()
{
    const int ITERATIONS = 100;           // you might need to increase the number of iterations
    const int DOCS_COUNT = 300;       // the collection has 300 docs, more than the 101 of 1st batch
    const int THREADS_COUNT = 2;    // at least 2 threads are needed
 
    mongocxx::instance instance{};
    mongocxx::pool pool{ mongocxx::uri{} };
 
    std::atomic<ptrdiff_t> num_docs = 0;
    std::vector<std::thread> threads{};
 
    for (int t = 0; t < THREADS_COUNT; ++t)
    {
        threads.emplace_back([&pool, &num_docs, &ITERATIONS]() {
            auto client = pool.acquire();
            auto db = (*client)["DatabaseName"];
            for (int i = 0; i < ITERATIONS; ++i)
            {
                auto cmd = bsoncxx::from_json("{\"find\" : \"CollectionName\"}");
                while (true)
                {
                    auto ret = db.run_command(cmd.view());
                    auto view = ret.view();
                    bsoncxx::document::element cur{ view["cursor"] };
                    if (cur)
                    {
                        auto res = cur["firstBatch"];
                        if (!res)
                        {
                            res = cur["nextBatch"];
                            if (!res)
                                break;
                        }
                        if (res.type() != bsoncxx::type::k_array)
                            throw std::exception("Result is not an array!");
                        bsoncxx::array::view subarr{ res.get_array().value };
                        std::atomic_fetch_add(&num_docs, std::distance(std::begin(subarr), std::end(subarr)));
                        auto id = cur["id"].get_int64();
                        if (id == 0)
                            break;
                        std::string cmd2_str = "{\"getMore\" : " + std::to_string(id) + ", \"collection\" : \"CollectionName\"}";
                        cmd = bsoncxx::from_json(cmd2_str);
                    }
                }
            }
        });
    }
 
    for (auto& thread : threads)
        thread.join();
 
    if (ITERATIONS * DOCS_COUNT * THREADS_COUNT != num_docs)
        throw std::exception("Count is not as expected!");
}

 
Related question:

Are different connections allowed to use the same implicit session or not? In other words, can a cursor ID returned by a find command be used with a getMore command but using a different implicit session? This doesn't seem to be well documented.



 Comments   
Comment by Clyde Bazile III (Inactive) [ 19/Nov/20 ]

Thank you for your patience. To answer your question, no, getMore commands on a cursor must use the same session ID (whether implicit or explicit) as the find or aggregate command that produced it. Check out our docs on driver sessions for more info.

In the provided code, each client creates a new implicit session to run the find command. Subsequent getMore commands will reuse those same session IDs, though, not necessarily the ones associated with its cursor. When a getMore uses the concurrent thread's session ID, it causes the error you're experiencing.

There's a couple of solutions to this: each client could start an explicit session, or you could use a mongocxx::cursor. Operations on a mongocxx::cursor will use the same session ID.

Comment by Clyde Bazile III (Inactive) [ 16/Nov/20 ]

Hi Malik,

Thanks for reporting this issue. We will look into this soon.

Generated at Wed Feb 07 22:04:59 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.