Skip to content

Commit af4d10e

Browse files
authored
Merge pull request #105 from zookzook/feature/replica-set-connection
Feature/replica set connection
2 parents b7aa63c + 44f0897 commit af4d10e

File tree

12 files changed

+336
-107
lines changed

12 files changed

+336
-107
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# An Alternative Elixir Driver for MongoDB
22
[![Build Status](https://travis-ci.org/zookzook/elixir-mongodb-driver.svg?branch=master)](https://travis-ci.org/zookzook/elixir-mongodb-driver)
3-
[![Coverage Status](https://coveralls.io/repos/github/zookzook/elixir-mongodb-driver/badge.svg?branch=master)](https://coveralls.io/github/zookzook/elixir-mongodb-driver?branch=master)
43
[![Hex.pm](https://img.shields.io/hexpm/v/mongodb_driver.svg)](https://hex.pm/packages/mongodb_driver)
54
[![Hex.pm](https://img.shields.io/hexpm/dt/mongodb_driver.svg)](https://hex.pm/packages/mongodb_driver)
65
[![Hex.pm](https://img.shields.io/hexpm/dw/mongodb_driver.svg)](https://hex.pm/packages/mongodb_driver)
76
[![Hex.pm](https://img.shields.io/hexpm/dd/mongodb_driver.svg)](https://hex.pm/packages/mongodb_driver)
87

98
## Features
109

11-
* Supports MongoDB versions 3.2, 3.4, 3.6, 4.0, 4.2, 4.4
10+
* Supports MongoDB versions 3.2, 3.4, 3.6, 4.x, 5.x
1211
* Connection pooling ([through DBConnection 2.x](https://github.com/elixir-ecto/db_connection))
1312
* Streaming cursors
1413
* Performant ObjectID generation

examples/reader.ex

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
defmodule Reader do
2+
3+
require Logger
4+
5+
##
6+
# see https://github.com/zookzook/elixir-mongodb-driver/issues/63 for more information
7+
#
8+
# 1. start a replica set and call the Reader.test()
9+
# 2. go to the primary db and call db.adminCommand({replSetStepDown: 30})
10+
# 3. check the log to see the error message only one time
11+
##
12+
def start_link(conn) do
13+
Logger.info("starting reader")
14+
15+
Task.start_link(fn -> read(conn, false) end)
16+
end
17+
18+
defp read(conn, error) do
19+
20+
if error do
21+
Logger.info("Called with error")
22+
end
23+
24+
# Gets an enumerable cursor for the results
25+
cursor = Mongo.find(conn, "data", %{})
26+
27+
error = case cursor do
28+
{:error, error} ->
29+
Logger.info("Error: #{inspect error}")
30+
true
31+
32+
_ ->
33+
cursor
34+
|> Enum.to_list()
35+
|> Enum.count()
36+
false
37+
end
38+
39+
read(conn, error)
40+
end
41+
42+
def test() do
43+
{:ok, conn} = Mongo.start_link(url: "mongodb://localhost:27017,localhost:27018,localhost:27019/load?replicaSet=rs_1")
44+
45+
Enum.map(1..10_000, fn counter -> Mongo.insert_one(conn, "data", %{counter: counter}) end)
46+
Reader.start_link(conn)
47+
end
48+
end

lib/mongo.ex

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ defmodule Mongo do
5252
import Mongo.Utils
5353
import Mongo.WriteConcern
5454

55+
require Logger
56+
5557
use Bitwise
5658
use Mongo.Messages
5759

@@ -413,16 +415,20 @@ defmodule Mongo do
413415
:ok <- Session.end_implict_session(topology_pid, session) do
414416
case result do
415417
{:error, error} ->
416-
case Error.should_retry_read(error, cmd, opts) do
417-
true -> issue_command(topology_pid, cmd, :read, Keyword.put(opts, :read_counter, 2))
418-
false -> {:error, error}
418+
419+
cond do
420+
Error.not_writable_primary_or_recovering?(error, opts) ->
421+
## in case of explicity
422+
issue_command(topology_pid, cmd, :read, Keyword.put(opts, :retry_counter, 2))
423+
424+
Error.should_retry_read(error, cmd, opts) ->
425+
issue_command(topology_pid, cmd, :read, Keyword.put(opts, :read_counter, 2))
426+
427+
true ->
428+
{:error, error}
419429
end
420430
_other -> result
421431
end
422-
else
423-
{:new_connection, _server} ->
424-
:timer.sleep(1000)
425-
issue_command(topology_pid, cmd, :read, opts)
426432
end
427433
end
428434
def issue_command(topology_pid, cmd, :write, opts) do
@@ -433,11 +439,25 @@ defmodule Mongo do
433439
with {:ok, session} <- Session.start_implicit_session(topology_pid, :write, opts),
434440
result <- exec_command_session(session, cmd, opts),
435441
:ok <- Session.end_implict_session(topology_pid, session) do
436-
result
437-
else
438-
{:new_connection, _server} ->
439-
:timer.sleep(1000)
440-
issue_command(topology_pid, cmd, :write, opts)
442+
443+
case result do
444+
{:error, error} ->
445+
cond do
446+
Error.not_writable_primary_or_recovering?(error, opts) ->
447+
## in case of explicity
448+
issue_command(topology_pid, cmd, :read, Keyword.put(opts, :retry_counter, 2))
449+
450+
Error.should_retry_write(error, cmd, opts) ->
451+
issue_command(topology_pid, cmd, :write, Keyword.put(opts, :write_counter, 2))
452+
453+
true ->
454+
{:error, error}
455+
end
456+
457+
result ->
458+
result
459+
end
460+
441461
end
442462
end
443463

@@ -731,16 +751,16 @@ defmodule Mongo do
731751
doc <- Session.update_session(session, doc, opts),
732752
{:ok, doc} <- check_for_error(doc, event) do
733753
{:ok, doc}
734-
else
754+
else
735755
{:error, error} ->
736-
## todo update Topology
737-
case Error.should_retry_write(error, cmd, opts) do
738-
true ->
739-
with :ok <- Session.select_server(session, opts) do
740-
exec_command_session(session, cmd, Keyword.put(opts, :write_counter, 2))
741-
end
742-
false -> {:error, error}
756+
case Error.not_writable_primary_or_recovering?(error, opts) do
757+
true ->
758+
Session.mark_server_unknown(session)
759+
{:error, error}
760+
false ->
761+
{:error, error}
743762
end
763+
744764
end
745765

746766
end

lib/mongo/bulk_write.ex

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,11 @@ defmodule Mongo.BulkWrite do
187187
result = one_bulk_write(topology_pid, session, bulk, opts),
188188
:ok <- Session.end_implict_session(topology_pid, session) do
189189
result
190-
else
191-
{:new_connection, _server} ->
192-
:timer.sleep(1000)
193-
write(topology_pid, bulk, opts)
194190
end
195191

196192
end
197193

198-
def write(topology_pid, %OrderedBulk{coll: coll, ops: ops} = bulk, opts) do
194+
def write(topology_pid, %OrderedBulk{coll: coll, ops: ops}, opts) do
199195

200196
write_concern = write_concern(opts)
201197

@@ -210,10 +206,6 @@ defmodule Mongo.BulkWrite do
210206
|> BulkWriteResult.reduce(empty) do
211207

212208
result
213-
else
214-
{:new_connection, _server} ->
215-
:timer.sleep(1000)
216-
write(topology_pid, bulk, opts)
217209
end
218210

219211
end

lib/mongo/change_stream.ex

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ defmodule Mongo.ChangeStream do
8888
"cursor" => %{
8989
"id" => cursor_id,
9090
"ns" => coll,
91-
"firstBatch" => docs} = response} <- doc,
92-
{:ok, wire_version} <- Mongo.wire_version(topology_pid) do
91+
"firstBatch" => docs} = response} <- doc do
9392

9493
[%{"$changeStream" => stream_opts} | _pipeline] = Keyword.get(cmd, :pipeline) # extract the change stream options
9594

@@ -101,7 +100,7 @@ defmodule Mongo.ChangeStream do
101100
# The initial aggregate response did not include a postBatchResumeToken.
102101

103102
has_values = stream_opts["startAtOperationTime"] || stream_opts["startAfter"] || stream_opts["resumeAfter"]
104-
op_time = update_operation_time(op_time, has_values, docs, response["postBatchResumeToken"], wire_version)
103+
op_time = update_operation_time(op_time, has_values, docs, response["postBatchResumeToken"], Session.wire_version(session))
105104

106105
# When the ChangeStream is started:
107106
# If startAfter is set, cache it.
@@ -145,7 +144,7 @@ defmodule Mongo.ChangeStream do
145144

146145
case token_changes(old_token, new_token) do
147146
true -> fun.(new_token)
148-
false -> nil
147+
false -> :noop
149148
end
150149

151150
{:ok, %{cursor_id: new_cursor_id, docs: docs, change_stream: change_stream}}
@@ -154,22 +153,20 @@ defmodule Mongo.ChangeStream do
154153
{:error, %Mongo.Error{resumable: false} = not_resumable} -> {:error, not_resumable}
155154
{:error, _error} ->
156155

157-
with {:ok, wire_version} <- Mongo.wire_version(topology_pid) do
156+
[%{"$changeStream" => stream_opts} | pipeline] = Keyword.get(aggregate_cmd, :pipeline) # extract the change stream options
158157

159-
[%{"$changeStream" => stream_opts} | pipeline] = Keyword.get(aggregate_cmd, :pipeline) # extract the change stream options
158+
stream_opts = update_stream_options(stream_opts, resume_token, op_time, Session.wire_version(session))
159+
aggregate_cmd = Keyword.update!(aggregate_cmd, :pipeline, fn _ -> [%{"$changeStream" => stream_opts} | pipeline] end)
160160

161-
stream_opts = update_stream_options(stream_opts, resume_token, op_time, wire_version)
162-
aggregate_cmd = Keyword.update!(aggregate_cmd, :pipeline, fn _ -> [%{"$changeStream" => stream_opts} | pipeline] end)
161+
# kill the cursor
162+
kill_cursors(session, coll, [cursor_id], opts)
163163

164-
# kill the cursor
165-
kill_cursors(session, coll, [cursor_id], opts)
166-
167-
# Start aggregation again...
168-
with {:ok, state} <- aggregate(topology_pid, aggregate_cmd, fun, opts) do
169-
{:resume, state}
170-
end
164+
# Start aggregation again...
165+
with {:ok, state} <- aggregate(topology_pid, aggregate_cmd, fun, opts) do
166+
{:resume, state}
171167
end
172-
168+
reason ->
169+
{:error, reason}
173170
end
174171
end
175172

0 commit comments

Comments
 (0)