MongoDB cxx driver stable branch bug?

27 views
Skip to first unread message

Hatchi

unread,
Jan 10, 2018, 2:29:27 PM1/10/18
to mongodb-dev
Dear all

I am developing a web application using Qt 5.7.0 and the MSVC 2015 64-bit compiler. I am using Qt Creator as IDE. I managed  to build and link the mongoc, mongocxx and bsoncxx libraries with the system. These libraries have been built in release mode with the same compilers and runtimes as the Qt web application.

In the debug build everything works fine. However, in the release build of the web application, I manage to create an instance and connection pool in the main thread of the application but when I try to acquire a connection from this pool in a child thread, the system crashes.

I am not sure if this is a bug in the driver or in my multithreaded code so I include the relevant snippets of code below. The MongoPool object is created in the main thread. The MongoConnector objects are created in the child threads when a new user request is received.


#include <QCoreApplication>
#include <QDir>
#include <QSettings>

#include "mongoconnector.h"
#include "mongopool.h"

#include <cstdlib>
#include <iostream>
#include <string>
#include <memory>

MongoPool *pool;

int main(int argc, char *argv[])
{
   
QCoreApplication app(argc,argv);

   
// Initialize MongoDB
    pool
= new MongoPool();

    qWarning
("Application has started");

    app
.exec();

    qWarning
("Application has stopped");
}

#include "mongoconnector.h"

extern MongoPool *pool;

MongoConnector::MongoConnector()
{
}

bool MongoConnector::storeDocument(QString dbName,
                                   
QString collectionName,
                                   
QString docID,
                                   
QString doc)
{
    std
::cout << "Storing document" << "\n";

   
// Initialize MongoDB
   
using bsoncxx::builder::basic::document;
   
using bsoncxx::builder::basic::kvp;

   
try {
        std
::cout << "Creating database connection" << "\n";

        mongocxx
::pool::entry client = pool->get_connection();
       
if(!client)
       
{
            std
::cout << "No Connection!";
       
}

        std
::cout << "Obtaining database and collection" << "\n";

        mongocxx
::database dataDB = client->database(dbName.toLatin1().toStdString());
        mongocxx
::collection dataCollection = dataDB[collectionName.toLatin1().toStdString()];

        std
::string docDB = doc.toLatin1().toStdString();

        std
::cout << "Creating bson object" << "\n";

        bsoncxx
::document::value obj = bsoncxx::from_json(docDB);

        std
::cout << "Creating builder" << "\n";

        bsoncxx
::builder::basic::document basic_builder{};
        basic_builder
.append(kvp("_id", docID.toStdString()));
        basic_builder
.append(kvp("doc", obj));
        bsoncxx
::document::value doc_value = basic_builder.extract();

        bsoncxx
::document::view view = doc_value.view();

        std
::cout << "Inserting document" << "\n";

        dataCollection
.insert_one(view);

        std
::cout << bsoncxx::to_json(view) << "\n";
   
} catch (const std::exception& xcp) {
        std
::cout << "connection failed: " << xcp.what() << "\n";
   
}

   
return true;
}

QString MongoConnector::retrieveDocument(QString dbName,
                                         
QString collectionName,
                                         
QString docID,
                                         
bool retrieveMultipleDocuments)
{
   
QString result;

   
// Initialize MongoDB
   
using bsoncxx::builder::stream::document;

   
try {
        mongocxx
::pool::entry client = pool->get_connection();

        mongocxx
::database dataDB = client->database(dbName.toLatin1().toStdString());
        mongocxx
::collection dataCollection = dataDB[collectionName.toLatin1().toStdString()];

        std
::string docIDStd = docID.toLatin1().toStdString();

       
auto builder = bsoncxx::builder::stream::document{};
        bsoncxx
::document::value doc_value = builder
               
<< "_id" << docIDStd
               
<< bsoncxx::builder::stream::finalize;

        bsoncxx
::document::view view = doc_value.view();

       
if(retrieveMultipleDocuments)
       
{
            mongocxx
::cursor cursor =
                    dataCollection
.find(view);

           
for(auto doc : cursor)
           
{
                std
::cout << bsoncxx::to_json(doc) << "\n";
                result
+= QString::fromStdString(bsoncxx::to_json(doc))+"\n\n**********\n\n";
           
}
       
}
       
else
       
{
            bsoncxx
::stdx::optional<bsoncxx::document::value> maybe_result =
                    dataCollection
.find_one(view);

           
if(maybe_result)
           
{
                std
::cout << bsoncxx::to_json(*maybe_result) << "\n";
                result
= QString::fromStdString(bsoncxx::to_json(*maybe_result));
           
}
       
}

   
} catch (const std::exception& xcp) {
        std
::cout << "connection failed: " << xcp.what() << "\n";
   
}

   
return result;
}

#ifndef MONGOCONNECTOR_H
#define MONGOCONNECTOR_H

#include <QtCore>

#include "mongopool.h"

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/builder/basic/document.hpp>

#include <bsoncxx/json.hpp>
#include <bsoncxx/string/view_or_value.hpp>

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/uri.hpp>
#include <mongocxx/database.hpp>
#include <mongocxx/collection.hpp>

#include <cstdlib>
#include <iostream>
#include <string>
#include <memory>

#include <bsoncxx/stdx/make_unique.hpp>
#include <mongocxx/logger.hpp>
#include <mongocxx/options/client.hpp>
#include <mongocxx/pool.hpp>

class MongoConnector
{
public:
   
MongoConnector();

   
bool storeDocument(QString dbName,
                       
QString collectionName,
                       
QString docID,
                       
QString doc);

   
QString retrieveDocument(QString dbName,
                             
QString collectionName,
                             
QString docID,
                             
bool retrieveMultipleDocuments);

private:
};

#endif // MONGOCONNECTOR_H

#include "mongopool.h"

MongoPool::MongoPool()
{
   
using bsoncxx::builder::stream::document;

   
auto uri = mongocxx::uri{mongocxx::uri::k_default_uri};
    configure
(std::move(uri));

   
try {
        mongocxx
::pool::entry client = get_connection();

       
auto admin = client->database("admin");

        document ismaster
;
        ismaster
<< "isMaster" << 1;

       
auto result = admin.run_command(ismaster.view());

   
} catch (const std::exception& xcp) {
        std
::cout << "connection failed: " << xcp.what() << "\n";
   
}
}

void MongoPool::configure(mongocxx::uri uri) {
   
class noop_logger : public mongocxx::logger {
   
public:
       
virtual void operator()(mongocxx::log_level, mongocxx::stdx::string_view,
                                mongocxx
::stdx::string_view) noexcept {
       
}
   
};

   
auto instance =
            mongocxx
::stdx::make_unique<mongocxx::instance>(mongocxx::stdx::make_unique<noop_logger>());

    configure
(std::move(instance),
              mongocxx
::stdx::make_unique<mongocxx::pool>(std::move(uri)));
}

void MongoPool::configure(std::unique_ptr<mongocxx::instance> instance,
                               std
::unique_ptr<mongocxx::pool> pool) {
    _instance
= std::move(instance);
    _pool
= std::move(pool);
}

mongocxx
::pool::entry MongoPool::get_connection() {
   
return _pool->acquire();
}

mongocxx
::stdx::optional<mongocxx::pool::entry> MongoPool::try_get_connection() {
   
return _pool->try_acquire();
}


#ifndef MONGOPOOL_H
#define MONGOPOOL_H

#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/string/view_or_value.hpp>

#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/uri.hpp>
#include <mongocxx/database.hpp>
#include <mongocxx/collection.hpp>

#include <cstdlib>
#include <iostream>
#include <string>
#include <memory>

#include <bsoncxx/stdx/make_unique.hpp>
#include <mongocxx/logger.hpp>
#include <mongocxx/options/client.hpp>
#include <mongocxx/pool.hpp>

class MongoPool
{
public:
   
MongoPool();

   
void configure(mongocxx::uri uri);
   
void configure(std::unique_ptr<mongocxx::instance> instance,
                   std
::unique_ptr<mongocxx::pool> pool);
    mongocxx
::pool::entry get_connection();
    mongocxx
::stdx::optional<mongocxx::pool::entry> try_get_connection();

private:
    std
::unique_ptr<mongocxx::instance> _instance;
    std
::unique_ptr<mongocxx::pool> _pool;

};

#endif // MONGOPOOL_H






Andrew Morrow

unread,
Jan 12, 2018, 8:41:46 AM1/12/18
to mongodb-dev

Hi -

I'm going to need some more information before I can help you with this:

- What is the stack trace for the crash?
- What versions of the C driver and C++ Driver are you using? How did you build them?
- Have you run your program under whatever the windows analogue of valgrind or ASAN would be?
- Can you reduce the above to a smaller test case that reproduces the issue?

Thanks,
Andrew


--
You received this message because you are subscribed to the Google Groups "mongodb-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mongodb-dev+unsubscribe@googlegroups.com.
To post to this group, send email to mongo...@googlegroups.com.
Visit this group at https://groups.google.com/group/mongodb-dev.
To view this discussion on the web visit https://groups.google.com/d/msgid/mongodb-dev/b4cc45e6-b37a-4a25-881b-d19b74e4c699%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages