示例#1
0
    bool BatchedCommandRequest::isVerboseWC() const {
        if ( !isWriteConcernSet() ) {
            return true;
        }

        BSONObj writeConcern = getWriteConcern();
        BSONElement wElem = writeConcern["w"];
        if ( !wElem.isNumber() || wElem.Number() != 0 ) {
            return true;
        }

        return false;
    }
/* ****************************************************************************
*
* mongoConnect - 
*
* Default value for writeConcern == 1 (0: unacknowledged, 1: acknowledged)
*/
static DBClientBase* mongoConnect
(
  const char*  host,
  const char*  db,
  const char*  rplSet,
  const char*  username,
  const char*  passwd,
  bool         multitenant,
  int          writeConcern,
  double       timeout
)
{
  std::string   err;
  DBClientBase* connection = NULL;

  LM_T(LmtMongo, ("Connection info: dbName='%s', rplSet='%s', timeout=%f", db, rplSet, timeout));

  bool connected     = false;
  int  retries       = RECONNECT_RETRIES;

  if (strlen(rplSet) == 0)
  {
    // Setting the first argument to true is to use autoreconnect
    connection = new DBClientConnection(true);

    //
    // Not sure of how to generalize the following code,
    // given that DBClientBase class doesn't have a common connect() method (surprisingly)
    //
    for (int tryNo = 0; tryNo < retries; ++tryNo)
    {
      if ( ((DBClientConnection*)connection)->connect(host, err))
      {
        connected = true;
        break;
      }

      if (tryNo == 0)
      {
        LM_E(("Database Startup Error (cannot connect to mongo - doing %d retries with a %d microsecond interval)",
              retries,
              RECONNECT_DELAY));
      }
      else
      {
        LM_T(LmtMongo, ("Try %d connecting to mongo failed", tryNo));
      }

      usleep(RECONNECT_DELAY * 1000);  // usleep accepts microseconds
    }
  }
  else
  {
    LM_T(LmtMongo, ("Using replica set %s", rplSet));

    // autoReconnect is always on for DBClientReplicaSet connections.
    std::vector<std::string>  hostTokens;
    int components = stringSplit(host, ',', hostTokens);

    std::vector<HostAndPort> rplSetHosts;
    for (int ix = 0; ix < components; ix++)
    {
      LM_T(LmtMongo, ("rplSet host <%s>", hostTokens[ix].c_str()));
      rplSetHosts.push_back(HostAndPort(hostTokens[ix]));
    }

    connection = new DBClientReplicaSet(rplSet, rplSetHosts, timeout);

    //
    // Not sure of to generalize the following code,
    // given that DBClientBase class hasn't a common connect() method (surprisingly)
    //
    for (int tryNo = 0; tryNo < retries; ++tryNo)
    {
      if ( ((DBClientReplicaSet*)connection)->connect())
      {
        connected = true;
        break;
      }

      if (tryNo == 0)
      {
        LM_E(("Database Startup Error (cannot connect to mongo - doing %d retries with a %d microsecond interval)",
              retries,
              RECONNECT_DELAY));
      }
      else
      {
        LM_T(LmtMongo, ("Try %d connecting to mongo failed", tryNo));
      }

      usleep(RECONNECT_DELAY * 1000);  // usleep accepts microseconds
    }
  }

  if (connected == false)
  {
    LM_E(("Database Error (connection failed, after %d retries: '%s')", retries, err.c_str()));
    return NULL;
  }

  LM_I(("Successful connection to database"));

  //
  // WriteConcern
  //
  mongo::WriteConcern writeConcernCheck;

  //
  // In the legacy driver, writeConcern is no longer an int, but a class.
  // We need a small conversion step here
  //
  mongo::WriteConcern wc = writeConcern == 1 ? mongo::WriteConcern::acknowledged : mongo::WriteConcern::unacknowledged;

  setWriteConcern(connection, wc, &err);
  getWriteConcern(connection, &writeConcernCheck, &err);

  if (writeConcernCheck.nodes() != wc.nodes())
  {
    LM_E(("Database Error (Write Concern not set as desired)"));
    return NULL;
  }
  LM_T(LmtMongo, ("Active DB Write Concern mode: %d", writeConcern));

  /* Authentication is different depending if multiservice is used or not. In the case of not
   * using multiservice, we authenticate in the single-service database. In the case of using
   * multiservice, it isn't a default database that we know at contextBroker start time (when
   * this connection function is invoked) so we authenticate on the admin database, which provides
   * access to any database */
  if (multitenant)
  {
    if (strlen(username) != 0 && strlen(passwd) != 0)
    {
      if (!connectionAuth(connection, "admin", std::string(username), std::string(passwd), &err))
      {
        return NULL;
      }
    }
  }
  else
  {
    if (strlen(db) != 0 && strlen(username) != 0 && strlen(passwd) != 0)
    {
      if (!connectionAuth(connection, std::string(db), std::string(username), std::string(passwd), &err))
      {
        return NULL;
      }
    }
  }

  /* Get mongo version with the 'buildinfo' command */
  BSONObj     result;
  std::string extra;
  runCollectionCommand(connection, "admin", BSON("buildinfo" << 1), &result, &err);
  std::string versionString = std::string(getStringField(result, "version"));
  if (!versionParse(versionString, mongoVersionMayor, mongoVersionMinor, extra))
  {
    LM_E(("Database Startup Error (invalid version format: %s)", versionString.c_str()));
    return NULL;
  }
  LM_T(LmtMongo, ("mongo version server: %s (mayor: %d, minor: %d, extra: %s)",
                  versionString.c_str(),
                  mongoVersionMayor,
                  mongoVersionMinor,
                  extra.c_str()));

  return connection;
}