// check and initialize versioned configuration
  private Configuration checkVersionedConfiguration() {
    String serviceVersion = _serviceInfo.getVersion();
    String dbSchemaVersion = _dbClient.getSchemaVersion();
    if (!serviceVersion.equals(dbSchemaVersion)) {
      _log.warn(
          "The db service version {} doesn't equals Db schema version {}, "
              + "set db service version to Db schema version",
          serviceVersion,
          dbSchemaVersion);
      _serviceInfo.setVersion(dbSchemaVersion);
    }

    String kind =
        _coordinator.getVersionedDbConfigPath(_serviceInfo.getName(), _serviceInfo.getVersion());
    Configuration config =
        _coordinator.queryConfiguration(_coordinator.getSiteId(), kind, _serviceInfo.getId());
    if (config == null) {
      // check if it is upgraded from previous version to yoda - configuration may be stored in
      // znode /config
      config = _coordinator.queryConfiguration(kind, _serviceInfo.getId());
      if (config != null) {
        _log.info("Upgrade from pre-2.5 release, move versioned dbconfig to new location");
        _coordinator.persistServiceConfiguration(_coordinator.getSiteId(), config);
        return config;
      }

      ConfigurationImpl cfg = new ConfigurationImpl();
      cfg.setId(_serviceInfo.getId());
      cfg.setKind(kind);
      // persist configuration
      _coordinator.persistServiceConfiguration(_coordinator.getSiteId(), cfg);
      config = cfg;
    }
    return config;
  }
  /** Initializes the keystore/truststore if the paths have been provided. */
  private void initKeystoreAndTruststore() {
    try {
      DbClientContext ctx = _dbClient.getLocalContext();

      if (isGeoDbsvc()) {
        ctx = _dbClient.getGeoContext();
      }

      String keystorePath = ctx.getKeyStoreFile();
      String truststorePath = ctx.getTrustStoreFile();

      if (keystorePath == null && truststorePath == null) {
        _log.info("Skipping keystore/truststore initialization, no paths provided");
        return;
      }

      String password = ctx.getTrustStorePassword();
      CassandraKeystoreHandler keystoreHandler =
          new CassandraKeystoreHandler(_coordinator, keystorePath, truststorePath, password);

      if (keystorePath != null) {
        _log.info("Initializing keystore for current node: {}", keystorePath);
        keystoreHandler.saveKeyStore();
      } else {
        _log.info("Skipping keystore initialization, no path provided");
      }

      if (truststorePath != null) {
        _log.info("Initializing truststore for current node: {}", truststorePath);
        keystoreHandler.saveTrustStore();
      } else {
        _log.info("Skipping truststore initialization, no path provided");
      }
    } catch (Exception e) {
      _log.error("Unexpected exception during initializing cassandra keystore", e);
      throw new IllegalStateException(e);
    }
  }
  /**
   * Create DbClient to embedded DB
   *
   * @return
   */
  protected static DbClient createDbClient() {
    ENCRYPTION_PROVIDER.setCoordinator(ModelTestSuite.getCoordinator());

    DbClientContext localCtx = new DbClientContext();
    localCtx.setClusterName("Test");
    localCtx.setKeyspaceName("Test");

    DbClientImpl dbClient = new DbClientImpl();
    dbClient.setCoordinatorClient(ModelTestSuite.getCoordinator());
    dbClient.setEncryptionProvider(ENCRYPTION_PROVIDER);
    dbClient.setBypassMigrationLock(true);
    dbClient.setDbVersionInfo(ModelTestSuite.getDbVersionInfo());
    dbClient.setLocalContext(localCtx);

    VdcUtil.setDbClient(dbClient);
    dbClient.start();

    return dbClient;
  }
  public static DbClientImpl newDBClient() throws Exception {
    ZkConnection zkConnection = new ZkConnection();
    zkConnection.setServer(Lists.newArrayList(new URI("coordinator://localhost:2181")));
    zkConnection.build();

    DualInetAddress dualInetAddress = DualInetAddress.fromAddresses("127.0.0.1", "::1");
    Map<String, DualInetAddress> addresses = Maps.newHashMap();
    addresses.put("localhost", dualInetAddress);

    CoordinatorClientInetAddressMap map = new CoordinatorClientInetAddressMap();
    map.setNodeId("standalone");
    map.setDualInetAddress(dualInetAddress);
    map.setControllerNodeIPLookupMap(addresses);

    CoordinatorClientImpl coordinatorClient = new CoordinatorClientImpl();
    coordinatorClient.setZkConnection(zkConnection);
    coordinatorClient.setInetAddessLookupMap(map);
    coordinatorClient.start();

    DbClientContext localContext = new DbClientContext();
    localContext.setKeyspaceName("StorageOS");
    localContext.setClusterName("StorageOs");

    DbClientContext geoContext = new DbClientContext();
    geoContext.setKeyspaceName("GeoStorageOs");
    geoContext.setClusterName("GeoStorageOs");

    DbVersionInfo versionInfo = new DbVersionInfo();
    versionInfo.setSchemaVersion("2.0");

    DbClientImpl client = new DbClientImpl();
    client.setDbVersionInfo(versionInfo);
    client.setLocalContext(localContext);
    client.setGeoContext(geoContext);
    client.setCoordinatorClient(coordinatorClient);
    client.setLocalContext(new DbClientContext());

    client.start();

    VdcUtil.setDbClient(client);

    return client;
  }
  @Override
  public void start() throws IOException {
    if (_log.isInfoEnabled()) {
      _log.info("Starting DB service...");
    }

    // Suppress Sonar violation of Lazy initialization of static fields should be synchronized
    // start() method will be only called one time when startup dbsvc, so it's safe to ignore sonar
    // violation
    instance = this; // NOSONAR ("squid:S2444")

    if (backCompatPreYoda) {
      _log.info(
          "Pre-yoda back compatible flag detected. Initialize local keystore/truststore for Cassandra native encryption");
      initKeystoreAndTruststore();
      _schemaUtil.setBackCompatPreYoda(true);
    }
    System.setProperty("cassandra.config", _config);
    System.setProperty("cassandra.config.loader", CassandraConfigLoader.class.getName());

    // Set to false to clear all gossip state for the node on restart.
    //
    // We encounter a weird Cassandra grossip issue(COP-19246) - some nodes are missing from gossip
    // when rebooting the entire cluster simultaneously. Critical Gossip
    // fields(ApplicationState.STATUS, ApplicationState.TOKENS)
    // are not synchronized during handshaking. It looks like some problem caused by incorrect
    // gossip version/generation
    // at system local table. So add this option to cleanup local gossip state during reboot
    //
    // Make sure add-vdc/add-standby passed when you would remove this option in the future.
    //
    // We need make sure majority local nodes are added as seed nodes. Otherwise cassandra may not
    // see other nodes if it loses
    // connection to other sites
    System.setProperty("cassandra.load_ring_state", "false");

    // Nodes in new data center should not auto-bootstrap.
    // See
    // https://docs.datastax.com/en/cassandra/2.0/cassandra/operations/ops_add_dc_to_cluster_t.html
    if (_schemaUtil.isStandby()) {
      System.setProperty("cassandra.auto_bootstrap", "false");
    }
    InterProcessLock lock = null;
    Configuration config = null;

    StartupMode mode = null;

    try {
      // we use this lock to discourage more than one node bootstrapping / joining at the same time
      // Cassandra can handle this but it's generally not recommended to make changes to schema
      // concurrently
      lock = getLock(getSchemaLockName());

      config = checkConfiguration();
      checkGlobalConfiguration();
      checkVersionedConfiguration();
      removeStaleConfiguration();

      mode = checkStartupMode(config);
      _log.info("Current startup mode is {}", mode);

      // Check if service is allowed to get started by querying db offline info to avoid bringing
      // back stale data.
      // Skipping hibernate mode for node recovery procedure to recover the overdue node.
      int nodeCount = ((CoordinatorClientImpl) _coordinator).getNodeCount();
      if (nodeCount != 1 && mode.type != StartupMode.StartupModeType.HIBERNATE_MODE) {
        checkDBOfflineInfo();
      }

      // this call causes instantiation of a seed provider instance, so the check*Configuration
      // calls must be preceed it
      removeCassandraSavedCaches();

      mode.onPreStart();

      if (_jmxServer != null) {
        _jmxServer.start();
        System.setProperty(
            "com.sun.management.jmxremote.port", Integer.toString(_jmxServer.getPort()));
      }

      _service = new CassandraDaemon();
      _service.init(null);
      _service.start();

      cassandraInitialized = true;
      mode.onPostStart();
    } catch (Exception e) {
      if (mode != null && mode.type == StartupMode.StartupModeType.HIBERNATE_MODE) {
        printRecoveryWorkAround(e);
      }
      _log.error("e=", e);
      throw new IllegalStateException(e);
    } finally {
      if (lock != null) {
        try {
          lock.release();
        } catch (Exception ignore) {
          _log.debug("lock release failed");
        }
      }
    }

    if (config.getConfig(DbConfigConstants.JOINED) == null) {
      config.setConfig(DbConfigConstants.JOINED, Boolean.TRUE.toString());
      _coordinator.persistServiceConfiguration(_coordinator.getSiteId(), config);
    }

    _statusChecker.waitForAllNodesJoined();

    _svcBeacon.start();
    if (backCompatPreYoda) {
      _log.info("Enable duplicated beacon in global area during pre-yoda upgrade");
      startDupBeacon();
    }

    setDbInitializedFlag();
    setDbConfigInitDone();

    _dbClient.start();

    if (_schemaUtil.isStandby()) {
      String localDataRevision = getLocalDataRevision();
      if (localDataRevision != null) {
        _schemaUtil.checkDataRevision(localDataRevision);
      }
    }

    // Setup the vdc information, so that login enabled before migration
    if (!isGeoDbsvc()) {
      _schemaUtil.checkAndSetupBootStrapInfo(_dbClient);
    }

    dbMgr.init();

    if (_handler.run()) {
      // Setup the bootstrap info root tenant, if root tenant migrated from local db, then skip it
      if (isGeoDbsvc()) {
        _schemaUtil.checkAndSetupBootStrapInfo(_dbClient);
      } else {
        _schemaUtil.checkAndInitStorageSystemTypes(_dbClient);
      }

      startBackgroundTasks();

      _log.info("DB service started");
    } else {
      _log.error("DB migration failed. Skipping starting background tasks.");
    }
  }