/** * Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.linkedin.pinot.broker.broker.helix; import com.linkedin.pinot.common.response.ServerInstance; import com.linkedin.pinot.common.utils.CommonConstants; import com.linkedin.pinot.transport.netty.PooledNettyClientResourceManager; import com.linkedin.pinot.transport.pool.KeyedPool; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.helix.LiveInstanceChangeListener; import org.apache.helix.NotificationContext; import org.apache.helix.model.LiveInstance; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LiveInstancesChangeListenerImpl implements LiveInstanceChangeListener { private static final Logger LOGGER = LoggerFactory.getLogger(LiveInstancesChangeListenerImpl.class); private static final boolean DO_NOT_RECREATE = false; private long timeout; private final Map<String, String> liveInstanceToSessionIdMap; private KeyedPool<PooledNettyClientResourceManager.PooledClientConnection> connectionPool; public LiveInstancesChangeListenerImpl(String clusterName) { this.liveInstanceToSessionIdMap = new HashMap<String, String>(); } public void init(final KeyedPool<PooledNettyClientResourceManager.PooledClientConnection> connectionPool, final long timeout) { this.connectionPool = connectionPool; this.timeout = timeout; } @Override public void onLiveInstanceChange(List<LiveInstance> liveInstances, NotificationContext changeContext) { if (connectionPool == null) { LOGGER.info("init hasn't been called yet on the live instances listener..."); return; } LOGGER.info("Connection pool found, moving on..."); for (LiveInstance instance : liveInstances) { String instanceId = instance.getInstanceName(); String sessionId = instance.getSessionId(); if (!instanceId.startsWith(CommonConstants.Helix.PREFIX_OF_SERVER_INSTANCE)) { LOGGER.info("Skipping non-server instance: {}", instanceId); continue; } String namePortStr = instanceId.split(CommonConstants.Helix.PREFIX_OF_SERVER_INSTANCE)[1]; String hostName = namePortStr.split("_")[0]; int port; try { port = Integer.parseInt(namePortStr.split("_")[1]); } catch (Exception e) { LOGGER.warn("Port for server instance " + instanceId + " does not appear to be numeric", e); port = CommonConstants.Helix.DEFAULT_SERVER_NETTY_PORT; } ServerInstance ins = new ServerInstance(hostName, port); if (liveInstanceToSessionIdMap.containsKey(instanceId)) { // sessionId has changed LOGGER.info("found instance Id : {} with new session Id : {} old session Id {}", instanceId, sessionId, liveInstanceToSessionIdMap.get(instanceId)); if (!sessionId.equals(liveInstanceToSessionIdMap.get(instanceId))) { try { connectionPool.validatePool(ins, DO_NOT_RECREATE); liveInstanceToSessionIdMap.put(instanceId, sessionId); } catch (Exception e) { LOGGER.error("Error trying to validate & destroy dead connections for {}", instanceId, e); } } } else { LOGGER.info("found instance Id : {} with new session Id : {}", instanceId, sessionId); // we don't have this instanceId // lets first check if the connection is valid or not try { connectionPool.validatePool(ins, DO_NOT_RECREATE); liveInstanceToSessionIdMap.put(instanceId, sessionId); } catch (Exception e) { LOGGER.error("Error trying to destroy dead connections for {}", instanceId, e); } } } } }