emqx / mongodb-erlang

MongoDB driver for Erlang
Apache License 2.0
9 stars 14 forks source link

Add support for MongoDB 5.1+ to mc_worker_api #32

Closed kjellwinblad closed 1 year ago

kjellwinblad commented 1 year ago

The MongoDB protocol has evolved and the only protocol that this driver supported before this commit has been removed in MongoDB 5.1. This commit makes it possible to use the module mc_worker_api (that handles a connection to a single MongoDB server) with MongoDB 5.1+ by configuring the driver with application:set_env(mongodb, use_legacy_protocol, false). This functionality can be tested by running ./test/test_without_legacy_protocol.sh. The mongo_api module still needs to be fixed before it can be used with MongoDB 5.1+.

The commit also includes some fixes to Dialyzer warnings that existed even before the commit (there are still a few warnings left).

kjellwinblad commented 1 year ago

I added a commit that also makes the mongo_api work with MongoDB 5.1+ when the setting use_legacy_protocol is set to true.

kjellwinblad commented 1 year ago

@thalesmg @zmstone . Thanks for the reviews and comments. I will try to make appropriate fixes. FYI, I just added a new commit that makes detection of the appropriate protocol type automatic. I would appreciate reviews for that commit as well. Thank you!

kjellwinblad commented 1 year ago

Rebased after latest changes on master

kjellwinblad commented 1 year ago

I have tried to do hot-upgrade of this library from the commit before this PR to the last commit of the PR together with EMQX. When doing operations on a connection after the upgrade it fails with the following error:

> mongo_api:insert(Conn, <<"upgrade2">>, [#{<<"hej">> => 2}]).
2022-12-25T17:00:03.456390+01:00 [error] Generic server <0.2900.0> terminating. Reason: {{badfun,#Fun<mc_worker.0.130118026>},[{mc_worker,process_read_request,3,[{file,"mc_worker.erl"},{line,197}]},{gen_server,try_handle_call,4,[{file,"gen_server.erl"},{line,721}]},{gen_server,handle_msg,6,[{file,"gen_server.erl"},{line,750}]},{proc_lib,wake_up,3,[{file,"proc_lib.erl"},{line,236}]}]}. Last message: {query,<<"$cmd">>,false,false,false,false,false,0,-1,{<<"insert">>,<<"upgrade2">>,<<"documents">>,[#{<<"_id">> => {<<99,168,115,131,144,170,99,247,84,0,0,2>>},<<"hej">> => 2}],<<"writeConcern">>,{<<"w">>,1}},#{}}. State: {state,#Port<0.24>,#{},<<>>,{conn_state,unsafe,master,<<"test_db">>,<<"admin">>},undefined,#Fun<mc_worker.0.130118026>,gen_tcp}. Client <0.2831.0> stacktrace: [{gen,do_call,4,[{file,"gen.erl"},{line,214}]},{gen_server,call,3,[{file,"gen_server.erl"},{line,243}]},{mc_connection_man,request_worker,2,[{file,"mc_connection_man.erl"},{line,89}]},{mc_connection_man,read_one,2,[{file,"mc_connection_man.erl"},{line,45}]}].
2022-12-25T17:00:03.457056+01:00 [error] crasher: initial call: mc_worker:init/1, pid: <0.2900.0>, registered_name: [], error: {{badfun,#Fun<mc_worker.0.130118026>},[{mc_worker,process_read_request,3,[{file,"mc_worker.erl"},{line,197}]},{gen_server,try_handle_call,4,[{file,"gen_server.erl"},{line,721}]},{gen_server,handle_msg,6,[{file,"gen_server.erl"},{line,750}]},{proc_lib,wake_up,3,[{file,"proc_lib.erl"},{line,236}]}]}, ancestors: [<0.2899.0>,<0.2898.0>,<0.2880.0>,<0.2876.0>,<0.2831.0>], message_queue_len: 0, messages: [], links: [<0.2899.0>,<0.2898.0>], dictionary: [], trap_exit: false, status: running, heap_size: 6772, stack_size: 29, reductions: 16303; neighbours:
2022-12-25T17:00:03.457555+01:00 [error] Supervisor: {<0.2899.0>,poolboy_sup}. Context: child_terminated. Reason: {{badfun,#Fun<mc_worker.0.130118026>},[{mc_worker,process_read_request,3,[{file,"mc_worker.erl"},{line,197}]},{gen_server,try_handle_call,4,[{file,"gen_server.erl"},{line,721}]},{gen_server,handle_msg,6,[{file,"gen_server.erl"},{line,750}]},{proc_lib,wake_up,3,[{file,"proc_lib.erl"},{line,236}]}]}. Offender: id=mc_worker,pid=<0.2900.0>.
{error,{{{badfun,#Fun<mc_worker.0.130118026>},
         [{mc_worker,process_read_request,3,
                     [{file,"mc_worker.erl"},{line,197}]},
          {gen_server,try_handle_call,4,
                      [{file,"gen_server.erl"},{line,721}]},
          {gen_server,handle_msg,6,
                      [{file,"gen_server.erl"},{line,750}]},
          {proc_lib,wake_up,3,[{file,"proc_lib.erl"},{line,236}]}]},
        {gen_server,call,
                    [<0.2900.0>,
                     {query,<<"$cmd">>,false,false,false,false,false,0,-1,
                            {<<"insert">>,<<"upgrade2">>,<<"documents">>,
                             [#{<<"_id">> => {<<"c¨s"...>>},<<"hej">> => 2}],
                             <<"writeConcern">>,
                             {<<"w">>,1}},
                            #{}},
                     infinity]}}}
(emqx@127.0.0.1)4> 2022-12-25T17:00:03.654410+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
2022-12-25T17:00:34.656559+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
2022-12-25T17:00:34.657120+01:00 [error] Supervisor: {<0.2899.0>,poolboy_sup}. Context: shutdown_error. Reason: killed. Offender: id=mc_worker,nb_children=1.
2022-12-25T17:00:34.657425+01:00 [error] Generic server <0.2899.0> terminating. Reason: killed. Last message: {'EXIT',<0.2898.0>,killed}. State: {state,{<0.2899.0>,poolboy_sup},simple_one_for_one,{[mc_worker],#{mc_worker => {child,undefined,mc_worker,{mc_worker,start_link,[[{host,"localhost"},{port,27017},{database,<<"test_db">>}]]},temporary,false,5000,worker,[mc_worker]}}},{mapsets,#{<0.3128.0> => []}},0,1,[],0,never,poolboy_sup,{mc_worker,[{host,"localhost"},{port,27017},{database,<<"test_db">>}]}}.
2022-12-25T17:00:34.657776+01:00 [error] crasher: initial call: supervisor:poolboy_sup/1, pid: <0.2899.0>, registered_name: [], exit: {killed,[{gen_server,decode_msg,9,[{file,"gen_server.erl"},{line,481}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,226}]}]}, ancestors: [<0.2898.0>,<0.2880.0>,<0.2876.0>,<0.2831.0>], message_queue_len: 0, messages: [], links: [], dictionary: [], trap_exit: true, status: running, heap_size: 6772, stack_size: 29, reductions: 23135; neighbours:

(emqx@127.0.0.1)4> 2022-12-25T17:01:05.658398+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout

(emqx@127.0.0.1)4> 2022-12-25T17:01:36.660417+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
2022-12-25T17:02:07.662466+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
2022-12-25T17:02:38.664530+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
2022-12-25T17:03:09.666399+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
2022-12-25T17:03:40.668396+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
2022-12-25T17:04:11.670474+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout

(emqx@127.0.0.1)4> 2022-12-25T17:04:42.672517+01:00 [error] [ecpool_worker_sup] wait_connect_complete timeout
(emqx@127.0.0.1)4>

This seems to be because a fun referring the old mc_worker module is stored in the mc_worker state (see https://github.com/emqx/mongodb-erlang/blob/89f7cc8566bef15c507b05bf354d2408477a1f0b/src/connection/mc_worker.erl#L200). This problem existed even before this PR so I conclude that hot-upgrade seems to have been broken for a very long time. Therefore I do not think it is worth fixing it (if a broken hot-upgrade for this driver hasn't been a problem until now it is probably not a problem now as well).