Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReplicaSet & Reused pipes #119

Open
acondolu opened this issue Aug 4, 2020 · 1 comment
Open

ReplicaSet & Reused pipes #119

acondolu opened this issue Aug 4, 2020 · 1 comment

Comments

@acondolu
Copy link
Contributor

acondolu commented Aug 4, 2020

Hello,

This is more of a question about the current design of the ReplicaSet functions, which don't seem to play well with multi-threading.

Background

Connection.hs supports mongo replica sets by storing the known members in a ReplicaSet object. If the user desires e.g. the replica set primary, the function primary first queries the known members for the address of the primary host; then it returns a Pipe to the primary, if available. However, that function does not actually return a new connection to the primary, but instead it possibly re-uses a previously open connection (see connection function).

Question

My scenario is a multi-threaded application, using a connection pool to distribute connections to server threads. It would be great if I could simply use primary as the resource-creating function of the pool, but this is not possible since subsequent connections taken from the pool would then be exactly the same connection (because of re-use).

This is a blocker, since I can't use any of the ReplicaSet functions. A trivial solution would be to expose an additional function that simply returns the Host, instead of a Pipe, like:

primary :: ReplicaSet -> IO Host

But I was wondering: is there any particular reason for re-using connections in the primary/secondaryOk/routedHost functions? I may be missing somthing, but it looks like this behaviour is good for simple single-threaded apps, but no-good for more realistic multi-threaded servers.

@acondolu
Copy link
Contributor Author

acondolu commented Oct 7, 2020

Hi!
If there are no objections I will open a PR solving this issue. Since sharing the connections as it is done now is not thread-safe, I propose to not reuse connections at all, making connection always return a new connection.

Another solution (see here): allow reusing connections, but only by a thread at a time. In the linked commit, I've moved the code calling fetchReplicaInfo inside the scope of the modifyMVar, so that only one thread at a time can update the members of the replica set. The downside is that updating the members then blocks the other threads asking for a connection, so I'm not sure this is a good idea.

acondolu pushed a commit to acondolu/mongodb that referenced this issue Dec 16, 2020
This commit addresses mongodb-haskell#119 i.e. the fact that pipes to replica set
members are reused. That choice is not thread-safe. For instance:
- thread 1 asks for a pipe to some host of the replica set; a new pipe is
  opened and returned.
- after that, thread 2 asks for another pipe; updateMembers may reuse the pipe
  returned to thread 1 to fetch the replica info, which is bad.

This commit disables previous pipes to be stored into a ReplicaSet object.
Subsequent calls to updateMembers will open a new pipe to fetch the
replica info. However, that pipe is not closed right away, but
temporarily kept in case the host we want to connect to is the same
as the one that has been used to fetch the replica info. If it isn't,
the pipe is closed and not stored as it was before.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant