Gandalf
Gandalf

Reputation: 3257

How does Connection.prototype.useDb() method in mongoose works under the hood?

I am trying to understand the Connection.prototype.useDb() method better. I would appreciate it if someone could help me.

1. The mongoose document for useDb() states:

Switches to a different database using the same connection pool.

Does this mean that if there is an available connection in the connection pool useDb('db1') will reuse the connection? in other words can a connection used by useDb('db1'), be reused by useDb('db2')? Or does the statement simply mean that useDb('db1') will create a new connection in the connection pool and can only reuse connections already created by useDb('db1')?

2. The mongoose document for useDb() states:

[options.useCache=false] «Boolean» If true, cache results so calling useDb() multiple times with the same name only creates 1 connection object.

What happens in the following scenario(assuming that maxIdleTimeMS equals 0 which means no limit and maxPoolSize equals 2)? enter image description here 3. Considering:

[options.useCache=false] «Boolean» If true, cache results so calling useDb() multiple times with the same name only creates 1 connection object.

and considering this from mongodb.com which states:

MongoDB is synchronous and uses a single execution thread per socket, meaning that MongoDB will execute one single operation per socket at any point in time. Any other operation sent to that socket will have to wait until the current operation is finished.

Does this mean 5 queries which are supposed to be executed on mydb2, using the connection from conn.useDb('mydb2', { useCache: true }), would have to wait in queue to be executed one after another? as opposed to conn.useDb('mydb2', { useCache: false }), which means they will be executed on separate connections and in parallel?

EDIT Since mongoose uses Nodejs mongo driver's db method to implement its useDb method, and since the documentation for db() method in mongo driver states:

Create a new Db instance sharing the current socket connections.

I guess this means that each connection(socket) in the connection pool can be shared regardless whether they were created by calling conn.useDb('mydb1') or conn.useDb('mydb2')

Upvotes: 0

Views: 738

Answers (1)

Gandalf
Gandalf

Reputation: 3257

I conducted certain experiments to be able to understand how useDb works by examining it's behavior in certain situations.

useDb() reuses connections in the connection pool

Experiment

  1. create a connection with maxPoolSize = 1(only 1 connection(socket) allowed in the connection pool) and socketTimeoutMS = 30000(MongoDB driver kills a connection(socket) after 30 seconds of inactivity)
  2. call conn.useDb('db1') which creates a new connection or uses an existing connection from the connection pool
  3. right after step 2(under 30 seconds after step two), call conn.useDb('db2') and execute a query on the returned connection, the query runs without being blocked and waiting for 30 seconds for the connection to get killed. which shows that since only 1 connection(socket) is allowed in the connection pool and each connection will at least stay on the pool for 30 seconds(in case there are no errors) then it seems that the socket is being reused(although it might also mean that the mongo driver kills the connection created by conn.useDb('db1') and creates a new socket for conn.useDb('db2')).

Result

It seems like if there is an available connection(socket) in the connection pool conn.useDb will reuse the connection, in other words a connection used/created by conn.useDb('db1'), can be reused by conn.useDb('db2').

{ useCache: true } does not block

Experiement

  1. create a connection with maxPoolSize = 2 and socketTimeoutMS = 30000
  2. execute a slow operation(long running query which runs for 20 seconds) on the connection returned by conn.useDb('db1', { useCache: true })("MongoDB uses a single execution thread per socket" which means this connection won't be available for 20 seconds, which means only one connection will be available in the connection pool)
  3. right after step 2(in less than 20 seconds), we execute a fast query on the connection returned by conn.useDb('db1', { useCache: true }) and it gets executed instantly

This shows that instead of waiting for the cached connection to get returned, the second conn.useDb('db1', { useCache: true }) call will either create a new connection or use another available connection from the pool and does not wait for the cached connection.

Result

It does not mean that 5 queries which are supposed to be executed on db2, using the connection from conn.useDb('db2', { useCache: true }), would have to wait in queue to be executed one after another. It seems to me, when conn.useDb('db2', { useCache: true })) call checks out a connection, next conn.useDb('db2', { useCache: true })) will get the cached connection if only the checked out connection has released and returned to the pool, if not it won't wait for the connection to get released instead either it uses another available connections in the pool or if all the connections have been checked out resulting the pool being empty and maxPoolSize has not reached, it will create a new connection in the pool(if maxPoolSize's been reached, it would wait for a connection to return to the bool).

Upvotes: 0

Related Questions