/* * Copyright(C) 1999-2010 Alibaba Group Holding Limited All rights reserved. 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.alibaba.doris.client.operation.failover.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.alibaba.doris.client.AccessException; import com.alibaba.doris.client.DataSourceManager; import com.alibaba.doris.client.net.DataSource; import com.alibaba.doris.client.net.NetException; import com.alibaba.doris.client.net.exception.ClientConnectionException; import com.alibaba.doris.client.net.exception.RouteVersionOutOfDateException; import com.alibaba.doris.client.operation.DataSourceOpFuture; import com.alibaba.doris.client.operation.OperationDataSourceGroup; import com.alibaba.doris.client.operation.failover.LogicCallback; import com.alibaba.doris.client.operation.failover.LogicCallbackHandler; import com.alibaba.doris.client.operation.failover.PeerCallback; import com.alibaba.doris.client.operation.result.DataSourceOpResult; import com.alibaba.doris.common.AdminServiceConstants; import com.alibaba.doris.common.StoreNode; import com.alibaba.doris.common.data.Key; import com.alibaba.doris.common.route.DorisRouterException; /** * PeerFailoverCallbackHandler * * @author Kun He (Raymond He), kun.hek@alibaba-inc.com * @since 1.0 2011-4-25 */ public class LogicFailoverCallbackHandler extends BaseFailoverCallbackHandler implements LogicCallbackHandler { private Log log = LogFactory.getLog(LogicFailoverCallbackHandler.class); @Override public void setDataSourceManager(DataSourceManager dataSourceManager) { super.setDataSourceManager(dataSourceManager); this.timeoutOfOperation = dataSourceManager.getConfigManager().getClientConfiguration().getTimeoutOfOperation(); } /** * @see com.alibaba.doris.CallbackHandler.operation.failover.FailoverHandler#doFailover(com.alibaba.doris.Callback.operation.failover.FailoverCallback) */ public List<List<DataSourceOpResult>> doLogicExecute(List<LogicCallback> callbacks, List<OperationDataSourceGroup> operationDataSourceGroups) throws AccessException { List<List<DataSourceOpFuture>> futuresList = new ArrayList<List<DataSourceOpFuture>>(); for (LogicCallback callback : callbacks) { callback.execute(); List<DataSourceOpFuture> dataSourceOpFutures = callback.getDataSourceOpFutures(); futuresList.add(dataSourceOpFutures); } List<List<DataSourceOpResult>> dataSourceOpResultsList = new ArrayList<List<DataSourceOpResult>>(); int size = futuresList.size(); for (int k = 0; k < size; k++) { List<DataSourceOpFuture> dataSourceOpFutures = futuresList.get(k); OperationDataSourceGroup group = operationDataSourceGroups.get(k); List<DataSourceOpResult> dataSourceOpResults = new ArrayList<DataSourceOpResult>(); for (DataSourceOpFuture dsOpfuture : dataSourceOpFutures) { boolean failed = true; // try 5 times for one node, try 3 nodes total PeerCallback peerCallback = dsOpfuture.getPeerCallback(); DataSource dataSource = peerCallback.getDataSource(); for (int i = 1; i <= 5; i++) { try { Object value = peerCallback.getOperationFuture().get(timeoutOfOperation, TimeUnit.MILLISECONDS); DataSourceOpResult dataSourceOpResult = new DataSourceOpResult(); dataSourceOpResult.setDataSource(dataSource); dataSourceOpResult.setResult(value); dataSourceOpResults.add(dataSourceOpResult); failed = false; break; } catch (RouteVersionOutOfDateException routeException) { proceeRouteException(routeException, peerCallback, group); } catch (ClientConnectionException cce) { processClientConnectionException(peerCallback); } catch (InterruptedException e) { throw new AccessException(e); } catch (ExecutionException e) { throw new AccessException(e); } catch (TimeoutException e) { processClientConnectionException(peerCallback); } sleep(i); } if (failed) { throw new AccessException("LogicFailoverCallbackHandler could not process."); } } dataSourceOpResultsList.add(dataSourceOpResults); } return dataSourceOpResultsList; } private void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } private void proceeRouteException(RouteVersionOutOfDateException routeException, PeerCallback peerCallback, OperationDataSourceGroup group) throws AccessException { // 从异常中获取路由表,更新本地路由 String routeConfig = routeException.getNewRouteTable(); if (log.isWarnEnabled()) { log.warn("Process RouteVersionOutOfDateException: currentDataSource:" + peerCallback.getDataSource().getSequence() + "." + peerCallback.getDataSource().getNo() + "get new route config from data server:::" + routeConfig); } Map<String, String> configs = new HashMap<String, String>(); configs.put(AdminServiceConstants.ROUTE_CONFIG_ACTION, routeConfig); this.getDataSourceManager().getConfigManager().refreshConfig(configs); // 将新版本写入请求 long routeVersion = this.getDataSourceManager().getDataSourceRouter().getRouteTableConfiger().getRouteTable().getVersion(); Key phKey = (Key) peerCallback.getOperationData().getKey(); phKey.setRouteVersion(routeVersion); if (log.isWarnEnabled()) { log.warn("Get new route version:" + routeVersion); } // 根据新路由重新构造OperationDataSourceGroup的datasource try { // 获取新路由,重构OperationDataSourceGroup String physicalKey = peerCallback.getOperationData().getKey().getPhysicalKey(); List<StoreNode> nodes = this.getDataSourceManager().getDataSourceRouter().getRouteStrategy().findNodes(peerCallback.getOperationData().getOperation().getOperationType(peerCallback.getOperationData()), peerCallback.getOperationData().getNamespace().getCopyCount(), physicalKey); if (log.isInfoEnabled()) { log.info("find new route by key:" + physicalKey); } if (log.isInfoEnabled()) { log.info("new route nodes - " + nodes); } List<DataSource> oldDsList = group.getDataSources(); if (log.isInfoEnabled()) { log.info("old route datasource:" + oldDsList); } for (int x = 0; x < oldDsList.size(); x++) {// 遍历旧路由数据源List if (oldDsList.get(x).equals(peerCallback.getDataSource())) {// 找到当前数据源在旧数据源List中的下标 StoreNode oldSn = this.getDataSourceManager().getDataSourceRouter().getStoreNodeOf( peerCallback.getDataSource());// 找到旧数据源对应节点 StoreNode newSn = nodes.get(x);// 找到新节点对应节点,新旧节点在路由List中的下标是一样的 // 新旧路由节点不一样 if (!newSn.getPhId().equals(oldSn.getPhId())) { // !newSn.getPhId().equals(oldSn.getPhId()) || !newSn.getSequence().equals(oldSn.getPhId())) { DataSource ds = this.getDataSourceManager().getDataSourceRouter().getDataSourceOf(newSn); if (log.isWarnEnabled()) { log.warn("New store node != Old store node, new one is " + newSn + "," + newSn.getPhId() + ". key=" + physicalKey); } peerCallback.setDataSource(ds);// 使用新节点的数据源为当前数据源,准备重试 } else { if (log.isWarnEnabled()) { log.warn("New store node == Old store node, new one is also " + newSn + "," + newSn.getPhId() + ". key=" + physicalKey); } } } } if (log.isWarnEnabled()) { log.warn("Redirect access after route version exception:" + peerCallback.getDataSource()); } processCallbackExecute(peerCallback); } catch (DorisRouterException e1) { if (log.isErrorEnabled()) { log.error("Route error:" + e1); } throw new AccessException(e1); } } private void processClientConnectionException(PeerCallback peerCallback) throws AccessException { // processAccessException(i, peerCallback); processCallbackExecute(peerCallback); } private void processCallbackExecute(PeerCallback peerCallback) throws AccessException { boolean failed = true; for (int j = 1; j <= 10; j++) { try { peerCallback.execute(); failed = false; break; } catch (AccessException e) { if (e.getCause() instanceof NetException) { processAccessException(j, peerCallback); } else { throw e; } } } if (failed) { throw new AccessException("Coundn't connect data server:" + peerCallback.getDataSource()); } } private long timeoutOfOperation; }