private void registerDataNodeConfigChangeListener(String dcName) throws Exception {
    DcZkInfo dcZkInfo = dataCenterToZkAddress.get(dcName);
    String zkConnectStr = dcZkInfo.getZkConnectStrs().get(0);
    DataNodeConfigSource dataNodeConfigSource =
        helixFactory.getDataNodeConfigSource(clusterMapConfig, zkConnectStr, dataNodeConfigSourceMetrics);
    // When attaching a listener, current data is fetched from Helix using blocking call and notified to the listener
    // (Please see PropertyStoreToDataNodeConfigAdapter.Subscription#start() method). I.e. by the time we return from
    // below method, initial notification of data node configs would have been arrived. So, we don't need separate latch
    // to wait for notification of data node configs.
    logger.info(
        "Registering data node config change listeners for cluster {} in data center {} via Helix manager at {}",
        clusterMapConfig.clusterMapClusterName, dcZkInfo.getDcName(), zkConnectStr);
    dataNodeConfigSource.addDataNodeConfigChangeListener(new DataNodeConfigChangeListener() {
      // We could directly register HelixClusterChangeHandler as listener. But, in order to the pass data center name
      // and helix cluster name for logging purpose, having an additional listener here.
      @Override
      public void onDataNodeConfigChange(Iterable<DataNodeConfig> configs) {
        clusterChangeHandler.handleDataNodeConfigChange(configs, dcName, clusterMapConfig.clusterMapClusterName);
      }

      @Override
      public void onDataNodeDelete(String instanceName) {
        clusterChangeHandler.onDataNodeDelete(instanceName);
      }
    });
    dataNodeConfigSources.add(dataNodeConfigSource);
  }
Register for data node configs from Helix Property store.
@param dcName data center for which we are interested in data node configs.
ambry-clustermap/src/main/java/com/github/ambry/clustermap/HelixAggregatedViewClusterInitializer.java