comtihon / mongodb-erlang

MongoDB driver for Erlang
Apache License 2.0
343 stars 268 forks source link

Usage of any rp_mode other than primary or primaryPreferred results in not_master error #129

Open ShauneStark opened 8 years ago

ShauneStark commented 8 years ago

I am new to Elixir/Erlang so please excuse me if this question is stupid... I am trying to use this driver from within Elixir, and am connecting to a MongoDB replicaset using the following code:

Logger.info "Reading from My MongoDB..."
    # Setup Mongo Database
    mongodbmapbase = %{
      hostname: "mongo1.mydomain.com",
      hostlist: ['mongo1.mydomain.com:27017', 'mongo2.mydomain.com:27017', 'mongo3.mydomain.com:27017'],
      replicasetname: "myreplica",
      database: "MyData",
      collection: nil,
      port: 27017,
      username: "RethinkDB",
      password: "uWwsfNmO2Xm5"
    }
    # Setup My Data table list
    mytables = [
      "Ma6f029a2ba544b9a843c6ebf3dc10987",
      "M02a2fa2566394e64a9a49edfc86386f1",
      "M81b8d562792a4ac7aba298ad31913742",
      "M90e01a2599b4488f8718ac98cffc1ada",
      "Md6ece821b0d84d8787433e4664945bb7"
    ]

    # Get MongoDB connection
    {:ok, mtconn} = :mongoc.connect(
      {:rs, mongodbmapbase.replicasetname, mongodbmapbase.hostlist},
      [
        {:name, :mypool},
        {:register, :mytopology},
        {:rp_mode, :primary}
      ],
      [
        {:database, mongodbmapbase.database}
      ]
    )

    Enum.map(mytables ,
      fn (x) ->
        # Define database info maps
        mongodbmap = %{mongodbmapbase | collection: x}

        randomlyreadrecords(:mytopology, mongodbmap)
      end
    )
    Logger.info "Finished Reading from MyMongoDB..."
    Process.exit(mtconn, :kill)
    {:ok, %{}}

This code simply reads a record at a random position in the collection until a certain number of reads has been performed, just to support load testing. However, when we try to use any rp_mode other than primary or primaryPreferred we get a not_master error as soon as we try to read a record...
The error I get is:

09:50:01.098 [info]  Starting Reads from: Ma6f029a2ba544b9a843c6ebf3dc10987
** (ErlangError) erlang error: :not_master
                     (mongodb) src/connection/mc_connection_man.erl:56: :mc_connection_man.process_error/2
                     (mongodb) src/core/mc_action_man.erl:22: :mc_action_man.read_one/2
                     (poolboy) src/poolboy.erl:78: :poolboy.transaction/3
    (mdberlangdrivertestsuite) lib/MProc.ex:109: MPROC.read/5
    (mdberlangdrivertestsuite) lib/mdberlangdrivertestsuite.ex:322: MDBERL.randomlyreadrecords/2
                      (elixir) lib/enum.ex:1184: Enum."-map/2-lists^map/1-0-"/2
    (mdberlangdrivertestsuite) lib/mdberlangdrivertestsuite.ex:412: MDBERL.readmydata/0

Any help would be appreciated!!!

comtihon commented 8 years ago

Hi, Error raised is - not_master. You are trying to read from master or slave? What are your read preferences?

ShauneStark commented 8 years ago

I'm new to Elixir/Erlang, but from the Mongo docs, I thought I would be able to read from secondary servers by specifying rp_mode = secondary or secondaryPreferred, but the driver returns an error when I reference a topology with that rp_mode selected... Am I misunderstanding the Mongo driver specs or am I mis-configuring the driver? I seed it with 3 mongo servers in our replica set, one of which is primary of course. We would like for reads to be able to continue even if the primary goes down, but since we cannot read from a secondary at all, we cannot test that scenario.

comtihon commented 8 years ago

Please, show the code of randomlyreadrecords/2

ShauneStark commented 8 years ago
  def randomlyreadrecords(:mytopology, mongodbmap) do
    Logger.info "Starting Reads from: " <> mongodbmap.collection

    numrandom = :rand.uniform(100000)
    maxnumberreads = 1000000
    currentreadnumber = 1
    MUVPROC.read(:mytopology, mongodbmap, numrandom, currentreadnumber, maxnumberreads)

    Logger.info "Ending Reads from: " <> mongodbmap.collection
    {:ok, %{}}
  end
  def read(:mytopology, mongodbmap, numrandom, currentreadnumber, maxnumberreads) do
    record = :mongoc.transaction_query(
      :mytopology,
      fn(worker) ->
        :mongoc.find_one(worker, mongodbmap.collection, %{}, %{}, numrandom)
      end,
      [],
      5000
    )
    IO.inspect(record)
    numrandom = :rand.uniform(100000)
    currentreadnumber = currentreadnumber + 1
    read(:mytopology, mongodbmap, numrandom, currentreadnumber, maxnumberreads)
  end
comtihon commented 8 years ago

The thing is - you create a connection and specify {:rp_mode, :primary}. When you use :mongoc.transaction_query you did not specify your read preference, so driver takes primary (which is default) and which you specified on start. Request comes to slave - so error not master returns. Do you have master in your hostlist?

ShauneStark commented 8 years ago

When I change the rp_mode to secondary or secondaryPreferred when I create the topology, all reads fail immediately. The code I sent you uses primary because that's the only value that appears to work... When I change it to anything else, I get the no_master error. Do I need to set it to secondary when I create the topology AND when I try to read? IE in both places? I thought if I specified rp_mode in creating the connection/topology that that would be the default for all reads/writes using that connection/topology...

comtihon commented 8 years ago

Try to use secondary or secondaryPreferred when reading. I do not know elexir, but in erlang you should pass proplist [{rp_mode, secondaryPreferred}] to mongoc:transaction_query/3 as third parameter

ShauneStark commented 8 years ago

Just to make sure, when I run this code

    # Get MongoDB connection
    {:ok, mtconn} = :mongoc.connect(
      {:rs, mongodbmapbase.replicasetname, mongodbmapbase.hostlist},
      [
        {:name, :vertifypool},
        {:register, :vertifytopology},
        {:rp_mode, :secondaryPreferred}
      ],
      [
        {:database, mongodbmapbase.database}
      ]
    )

I still need to specify rp_mode = secondaryPreferred to mongoc:transaction_query/3 ? The reason I ask is because I just tried this and it still returns the erlang error not_master...

comtihon commented 8 years ago

read with rp_mode = secondaryPreferred return not_master error?

ShauneStark commented 8 years ago

Yes, sir it did...

comtihon commented 8 years ago
  hostlist: ['mongo1.mydomain.com:27017', 'mongo2.mydomain.com:27017', 'mongo3.mydomain.com:27017'] 

who is master in this replica set?

ShauneStark commented 8 years ago

mongo3

ShauneStark commented 8 years ago

I have tried listing the master first, last and in the middle, but it does not seem to make a difference....

comtihon commented 8 years ago

Ok, please, try { unknown, ["hostname1:port1", "hostname2:port2"] } instead of rs

ShauneStark commented 8 years ago

Yes, sir... One moment please...

ShauneStark commented 8 years ago

I tried the following:

    # Get MongoDB connection
    {:ok, mtconn} = :mongoc.connect(
      {:unknown, ['mongo1.mydomain.com:27017', 'mongo2.mydomain.com:27017', 'mongo3.mydomain.com:27017']},
      [
        {:name, :mypool},
        {:register, :mytopology},
        {:rp_mode, :secondaryPreferred}
      ],
      [
        {:database, mongodbmapbase.database}
      ]
    )

And still got the no_master error...

ShauneStark commented 8 years ago

I also removed the mongo3 server from the list and got the same error...

comtihon commented 8 years ago

Please try tag v.1.1.4

ShauneStark commented 8 years ago

Changed deps to use tag v1.1.4 and still get the same no_master error, sadly...

comtihon commented 8 years ago

@alttagil need your help in mongoc

alttagil commented 8 years ago

ShauneStark, may I ask you to email me directly?

ShauneStark commented 8 years ago

I would be happy to email you directly, but I don't see an email address in your profile... You may reach me at sstark@thenewoffice.com if you would rather not publish your email address... Thank you for your willingness to help!

alttagil commented 8 years ago

ShauneStark, I've sent an email to you.