Java Code Examples for org.apache.helix.HelixManager#addLiveInstanceChangeListener()

The following examples show how to use org.apache.helix.HelixManager#addLiveInstanceChangeListener() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: GenericLeaderStandbyModel.java    From helix with Apache License 2.0 6 votes vote down vote up
@Transition(to = "LEADER", from = "STANDBY")
public void onBecomeLeaderFromStandby(Message message, NotificationContext context)
    throws Exception {
  LOG.info("Become LEADER from STANDBY");
  HelixManager manager = context.getManager();
  if (manager == null) {
    throw new IllegalArgumentException("Require HelixManager in notification conext");
  }
  for (ChangeType notificationType : _notificationTypes) {
    if (notificationType == ChangeType.LIVE_INSTANCE) {
      manager.addLiveInstanceChangeListener(_particHolder);
    } else if (notificationType == ChangeType.CONFIG) {
      manager.addConfigChangeListener(_particHolder);
    } else if (notificationType == ChangeType.EXTERNAL_VIEW) {
      manager.addExternalViewChangeListener(_particHolder);
    } else {
      LOG.error("Unsupport notificationType:" + notificationType.toString());
    }
  }
}
 
Example 2
Source File: HelixClusterSpectator.java    From ambry with Apache License 2.0 6 votes vote down vote up
@Override
public void spectate() throws Exception {
  Map<String, DcZkInfo> dataCenterToZkAddress =
      parseDcJsonAndPopulateDcInfo(clusterMapConfig.clusterMapDcsZkConnectStrings);
  HelixFactory helixFactory = new HelixFactory();
  String selfInstanceName =
      ClusterMapUtils.getInstanceName(clusterMapConfig.clusterMapHostName, clusterMapConfig.clusterMapPort);

  // Should we fail here if even one of the remote zk connection fails? If we have just one datacenter, then this will not be a problem.
  // If we have two data centers, then its not clear if we should pass the startup with one remote zk connection failure. Because if remote
  // zk connection fails on both data centers, then things like replication between data centers might just stop.
  // For now, since we have only one fabric in cloud, and the spectator is being used for only cloud to store replication, this will work.
  // Once we add more fabrics, we should revisit this.
  for (DcZkInfo dcZkInfo : dataCenterToZkAddress.values()) {
    // only handle vcr clusters for now
    if (dcZkInfo.getReplicaType() == ReplicaType.CLOUD_BACKED) {
      HelixManager helixManager =
          helixFactory.getZKHelixManager(cloudConfig.vcrClusterName, selfInstanceName, InstanceType.SPECTATOR,
              dcZkInfo.getZkConnectStrs().get(0));
      helixManager.connect();

      helixManager.addInstanceConfigChangeListener(this);
      helixManager.addLiveInstanceChangeListener(this);
    }
  }
}
 
Example 3
Source File: TestMessageThrottle2.java    From helix with Apache License 2.0 5 votes vote down vote up
void registerWith(HelixManager helixManager) throws Exception {
  helixManager.addIdealStateChangeListener(this);
  helixManager.addInstanceConfigChangeListener(this);
  helixManager.addExternalViewChangeListener(this);
  helixManager.addLiveInstanceChangeListener(this);
  helixManager.addControllerListener(this);
}
 
Example 4
Source File: TestZKLiveInstanceData.java    From helix with Apache License 2.0 4 votes vote down vote up
@Test
public void testDataChange() throws Exception {
  // Create an admin and add LiveInstanceChange listener to it
  HelixManager adminManager =
      HelixManagerFactory.getZKHelixManager(clusterName, null, InstanceType.ADMINISTRATOR,
          ZK_ADDR);
  adminManager.connect();
  final BlockingQueue<List<LiveInstance>> changeList =
      new LinkedBlockingQueue<List<LiveInstance>>();

  adminManager.addLiveInstanceChangeListener(new LiveInstanceChangeListener() {
    @Override
    public void onLiveInstanceChange(List<LiveInstance> liveInstances,
        NotificationContext changeContext) {
      // The queue is basically unbounded, so shouldn't throw exception when calling
      // "add".
      changeList.add(deepCopy(liveInstances));
    }
  });

  // Check the initial condition
  List<LiveInstance> instances = changeList.poll(1, TimeUnit.SECONDS);
  Assert.assertNotNull(instances, "Expecting a list of live instance");
  Assert.assertTrue(instances.isEmpty(), "Expecting an empty list of live instance");
  // Join as participant, should trigger a live instance change event
  HelixManager manager =
      HelixManagerFactory.getZKHelixManager(clusterName, "localhost_54321",
          InstanceType.PARTICIPANT, ZK_ADDR);
  manager.connect();
  instances = changeList.poll(1, TimeUnit.SECONDS);
  Assert.assertNotNull(instances, "Expecting a list of live instance");
  Assert.assertEquals(instances.size(), 1, "Expecting one live instance");
  Assert.assertEquals(instances.get(0).getInstanceName(), manager.getInstanceName());
  // Update data in the live instance node, should trigger another live instance change
  // event
  HelixDataAccessor helixDataAccessor = manager.getHelixDataAccessor();
  PropertyKey propertyKey =
      helixDataAccessor.keyBuilder().liveInstance(manager.getInstanceName());
  LiveInstance instance = helixDataAccessor.getProperty(propertyKey);

  Map<String, String> map = new TreeMap<String, String>();
  map.put("k1", "v1");
  instance.getRecord().setMapField("test", map);
  Assert.assertTrue(helixDataAccessor.updateProperty(propertyKey, instance),
      "Failed to update live instance node");

  instances = changeList.poll(1, TimeUnit.SECONDS);
  Assert.assertNotNull(instances, "Expecting a list of live instance");
  Assert.assertEquals(instances.get(0).getRecord().getMapField("test"), map, "Wrong map data.");
  manager.disconnect();
  Thread.sleep(1000); // wait for callback finish

  instances = changeList.poll(1, TimeUnit.SECONDS);
  Assert.assertNotNull(instances, "Expecting a list of live instance");
  Assert.assertTrue(instances.isEmpty(), "Expecting an empty list of live instance");

  adminManager.disconnect();

}
 
Example 5
Source File: DatacenterInitializer.java    From ambry with Apache License 2.0 4 votes vote down vote up
/**
 * Perform initialization for a helix-managed datacenter of servers.
 * @return the {@link DcInfo} for the datacenter.
 * @throws Exception if something went wrong during startup
 */
private DcInfo initializeHelixDatacenter() throws Exception {
  // For now, the first ZK endpoint (if there are more than one endpoints) will be adopted by default for initialization.
  // Note that, Ambry currently doesn't support multiple spectators, because there should be only one source of truth.
  String zkConnectStr = dcZkInfo.getZkConnectStrs().get(0);
  HelixManager manager;
  if (dcZkInfo.getDcName().equals(clusterMapConfig.clusterMapDatacenterName)) {
    manager = Objects.requireNonNull(localManager, "localManager should have been set");
  } else {
    manager = helixFactory.getZKHelixManager(clusterMapConfig.clusterMapClusterName, selfInstanceName,
        InstanceType.SPECTATOR, zkConnectStr);
    logger.info("Connecting to Helix manager at {}", zkConnectStr);
    manager.connect();
    logger.info("Established connection to Helix manager at {}", zkConnectStr);
  }
  HelixClusterChangeHandler clusterChangeHandler;
  String clusterChangeHandlerType = clusterMapConfig.clusterMapClusterChangeHandlerType;
  if (clusterChangeHandlerType.equals(SimpleClusterChangeHandler.class.getSimpleName())) {
    clusterChangeHandler =
        new SimpleClusterChangeHandler(clusterMapConfig, dcName, selfInstanceName, partitionOverrideInfoMap,
            partitionMap, partitionNameToAmbryPartition, ambryPartitionToAmbryReplicas, helixClusterManagerCallback,
            helixClusterManagerMetrics, this::onInitializationFailure, sealedStateChangeCounter);
  } else if (clusterChangeHandlerType.equals(DynamicClusterChangeHandler.class.getSimpleName())) {
    clusterChangeHandler =
        new DynamicClusterChangeHandler(clusterMapConfig, dcName, selfInstanceName, partitionOverrideInfoMap,
            helixClusterManagerCallback, clusterChangeHandlerCallback, helixClusterManagerMetrics,
            this::onInitializationFailure, sealedStateChangeCounter);
  } else {
    throw new IllegalArgumentException("Unsupported cluster change handler type: " + clusterChangeHandlerType);
  }
  // Create RoutingTableProvider of each DC to keep track of partition(replicas) state. Here, we use current
  // state based RoutingTableProvider to remove dependency on Helix's pipeline and reduce notification latency.
  logger.info("Creating routing table provider associated with Helix manager at {}", zkConnectStr);
  RoutingTableProvider routingTableProvider = new RoutingTableProvider(manager, PropertyType.CURRENTSTATES);
  logger.info("Routing table provider is created in {}", dcName);
  routingTableProvider.addRoutingTableChangeListener(clusterChangeHandler, null);
  logger.info("Registered routing table change listeners in {}", dcName);

  // The initial instance config change notification is required to populate the static cluster
  // information, and only after that is complete do we want the live instance change notification to
  // come in. We do not need to do anything extra to ensure this, however, since Helix provides the initial
  // notification for a change from within the same thread that adds the listener, in the context of the add
  // call. Therefore, when the call to add a listener returns, the initial notification will have been
  // received and handled.
  DataNodeConfigSource dataNodeConfigSource = new InstanceConfigToDataNodeConfigAdapter(manager, clusterMapConfig);
  dataNodeConfigSource.addDataNodeConfigChangeListener(clusterChangeHandler);
  logger.info("Registered instance config change listeners for Helix manager at {}", zkConnectStr);
  manager.addIdealStateChangeListener(clusterChangeHandler);
  logger.info("Registered ideal state change listeners for Helix manager at {}", zkConnectStr);
  // Now register listeners to get notified on live instance change in every datacenter.
  manager.addLiveInstanceChangeListener(clusterChangeHandler);
  logger.info("Registered live instance change listeners for Helix manager at {}", zkConnectStr);

  // in case initial event occurs before adding routing table listener, here we explicitly set snapshot in
  // ClusterChangeHandler. The reason is, if listener missed initial event, snapshot inside routing table
  // provider should be already populated.
  clusterChangeHandler.setRoutingTableSnapshot(routingTableProvider.getRoutingTableSnapshot());
  // the initial routing table change should populate the instanceConfigs. If it's empty that means initial
  // change didn't come and thread should wait on the init latch to ensure routing table snapshot is non-empty
  if (clusterChangeHandler.getRoutingTableSnapshot().getInstanceConfigs().isEmpty()) {
    // Periodic refresh in routing table provider is enabled by default. In worst case, routerUpdater should
    // trigger routing table change within 5 minutes
    logger.info("Routing table snapshot in {} is currently empty. Waiting for initial notification.", dcName);
    clusterChangeHandler.waitForInitNotification();
  }

  if (!clusterMapConfig.clustermapListenCrossColo && manager != localManager) {
    manager.disconnect();
    logger.info("Stopped listening to cross colo ZK server {}", zkConnectStr);
  }

  return new HelixDcInfo(dcName, dcZkInfo, manager, clusterChangeHandler);
}