package org.opencloudb.mpp.controller; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.opencloudb.backend.BackendConnection; import org.opencloudb.mpp.MutiDataMergeService; import org.opencloudb.mpp.RangRowDataPacketSorter; import org.opencloudb.mpp.model.NodeRowDataPacket; import org.opencloudb.mpp.model.RangRowDataPacket; import org.opencloudb.mysql.nio.handler.NodeWithLimitHandler; import org.opencloudb.mysql.nio.handler.ResponseHandler; import org.opencloudb.net.mysql.RowDataPacket; import org.opencloudb.route.RouteResultset; import org.opencloudb.route.RouteResultsetNode; import org.opencloudb.server.NonBlockingSession; public class NodeExcutionController { private static final Logger LOGGER = Logger .getLogger(NodeExcutionController.class); private boolean autocommit; private int nextCount = 0; private int currCount = 0; private Map<String, Boolean> nextExcuteMap = new HashMap<String, Boolean>(); private Map<String, ResponseHandler> nodeRpHandler = new HashMap<String, ResponseHandler>(); private final RouteResultset rrs; private Map<String, NodeRowDataPacket> result = null; private MutiDataMergeService mergeService = null; private NonBlockingSession session = null; private RangRowDataPacketSorter sorter = null; private long minStartIndex = 0; public NodeExcutionController(RouteResultset rrs, Map<String, NodeRowDataPacket> result, MutiDataMergeService mergeService) { this.rrs = rrs; this.result = result; this.mergeService = mergeService; minStartIndex = this.rrs.getLimitStart() - this.rrs.getNodes().length * this.rrs.getLimitSize(); this.initNextExcute(); } public void setSorter(RangRowDataPacketSorter sorter) { this.sorter = sorter; } public void initNextExcute() { nextCount = 0; RouteResultsetNode[] nodeArr = this.rrs.getNodes(); for (RouteResultsetNode node : nodeArr) { nextExcuteMap.put(node.getName(), true); nextCount++; } } private ResponseHandler getNodeRpHandler(String dataNode) { return nodeRpHandler.get(dataNode); } private Map<String, Integer> nodePageIndexMap = new HashMap<String, Integer>(); public void executeLastNode(RouteResultsetNode node) { BackendConnection conn = nodeBackendMap.get(node.getName()); this._execute(conn, node); } private void changeNodeSql(RouteResultsetNode node) { String sql = node.getStatement(); int index = sql.indexOf("OFFSET "); int lIndex = sql.indexOf("LIMIT "); int pageNum = 0; if (!nodePageIndexMap.containsKey(node.getName())) { pageNum++; nodePageIndexMap.put(node.getName(), pageNum); } else { pageNum = nodePageIndexMap.get(node.getName()); } long offset = (pageNum - 1) * this.mergeService.getPagePatchSize(); if (index != -1) { if (lIndex != -1) { sql = sql.substring(0, lIndex + 6) + this.mergeService.getPagePatchSize() + " OFFSET " + offset; node.setStatement(sql); } } } public void nextExcutePage() { LOGGER.debug("next page. "); Set<String> dataNodeNameSet = nextExcuteMap.keySet(); for (Iterator<String> iter = dataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); if (nextExcuteMap.get(dataNodeName)) { Integer index = nodePageIndexMap.get(dataNodeName); if (index == null) { index = 1; nodePageIndexMap.put(dataNodeName, index); } index++; nodePageIndexMap.put(dataNodeName, index); } } } private Map<String, BackendConnection> nodeBackendMap = new HashMap<String, BackendConnection>(); public void _execute(BackendConnection conn, RouteResultsetNode node) { changeNodeSql(node); nodeBackendMap.put(node.getName(), conn); conn.setResponseHandler(this.getNodeRpHandler(node.getName())); conn.setRunning(true); try { conn.execute(node, session.getSource(), autocommit); } catch (IOException e) { this.mergeService.connectionError(e, conn); } } public void releaseAllBackend() { Set<String> dataNodeNameSet = nodeBackendMap.keySet(); for (Iterator<String> iter = dataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); BackendConnection backendConn = nodeBackendMap.get(dataNodeName); backendConn.setRunning(false); // realse this connection if safe session.releaseConnectionIfSafe(backendConn, LOGGER.isDebugEnabled()); } } public void initHandler(NonBlockingSession session) { this.session = session; this.autocommit = session.getSource().isAutocommit(); RouteResultsetNode[] nodeArr = this.rrs.getNodes(); for (RouteResultsetNode node : nodeArr) { NodeWithLimitHandler handler = new NodeWithLimitHandler(node, session, this.mergeService); nodeRpHandler.put(node.getName(), handler); } } public boolean canStop() { Set<String> nDataNodeNameSet = nextExcuteMap.keySet(); for (Iterator<String> iter = nDataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); if (nextExcuteMap.get(dataNodeName)) { return false; } } return true; } private void trimPacket() { long lastTrimTotal = 0; Set<String> dataNodeNameSet = result.keySet(); for (Iterator<String> iter = dataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); NodeRowDataPacket nodePacket = result.get(dataNodeName); lastTrimTotal += nodePacket.loadTrimTotal(); } if (lastTrimTotal > minStartIndex) { return; } if (this.sorter == null) { long nextTrimTotal = lastTrimTotal; Set<String> dataNodeNameSet1 = result.keySet(); for (Iterator<String> iter = dataNodeNameSet1.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); NodeRowDataPacket nodePacket = result.get(dataNodeName); nextTrimTotal += nodePacket.loadNotTrimTotal(); } if (nextTrimTotal < this.rrs.getLimitStart()) { Set<String> dataNodeNameSet2 = result.keySet(); for (Iterator<String> iter = dataNodeNameSet2.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); NodeRowDataPacket nodePacket = result.get(dataNodeName); nodePacket.moveToTrim(); } } return; } //把前部分数据合并 List<String> elList = new ArrayList<String>(); Set<String> dataNodeNameSet1 = nextExcuteMap.keySet(); for (Iterator<String> iter = dataNodeNameSet1.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); NodeRowDataPacket nodePacket = result.get(dataNodeName); RangRowDataPacket rangRowDataPacket = nodePacket.loadTailPacket(); if (rangRowDataPacket == null) { continue; } RangRowDataPacket rangRowDataPacket1 = nodePacket.loadTailPacket(2); if (rangRowDataPacket.allSize() < this.rrs.getLimitSize()) { elList.add(dataNodeName); if (rangRowDataPacket1 == null) { continue; } } if (rangRowDataPacket1 == null) { continue; } nodePacket.moveHeadTail3ToTrim(); } boolean ascDesc = this.sorter.ascDesc(0); //把不足的数据节点移走 for (String dn : elList) { NodeRowDataPacket nodePacket = result.get(dn); RangRowDataPacket rangRowDataPacket = nodePacket.loadTailPacket(); if (rangRowDataPacket == null || rangRowDataPacket.getRowDataPacketList().isEmpty()) { rangRowDataPacket = nodePacket.loadTailPacket(2); if (rangRowDataPacket == null || rangRowDataPacket.getRowDataPacketList().isEmpty()) { continue; } } RowDataPacket tailPacket = rangRowDataPacket.getTail(); if (tailPacket == null) { tailPacket = rangRowDataPacket.getHead(); } Set<String> dataNodeNameSet2 = nextExcuteMap.keySet(); for (Iterator<String> iter = dataNodeNameSet2.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); if (!dataNodeName.equals(dn)) { NodeRowDataPacket nodePacket2 = result.get(dataNodeName); RangRowDataPacket rangRowDataPacket2 = nodePacket2.loadHeadPacket(); if (rangRowDataPacket2 == null) { continue; } RowDataPacket headPacket = rangRowDataPacket2.getHead(); if (headPacket == null) { continue; } int headResutl = this.sorter.compareRowData(tailPacket, headPacket, 0); if (ascDesc) { if (headResutl < 0) { nodePacket.moveAllToTrim(); } } else { if (headResutl > 0) { nodePacket.moveAllToTrim(); } } } } } } private void nextExcuteFalse() { Set<String> eDataNodeNameSet = nextExcuteMap.keySet(); for (Iterator<String> iter = eDataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); nextExcuteMap.put(dataNodeName, false); } } private void nextExcuteTrue() { Set<String> eDataNodeNameSet = nextExcuteMap.keySet(); for (Iterator<String> iter = eDataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); nextExcuteMap.put(dataNodeName, true); } } private void nextExcuteTrueWithClear(List<String> dataNodeList) { this.nextExcuteFalse(); for (String dn : dataNodeList) { nextExcuteMap.put(dn, true); } } private void nextExcuteTrue(List<String> dataNodeList) { for (String dn : dataNodeList) { nextExcuteMap.put(dn, true); } } private boolean isEnd = false; private void controllNext() { this.trimPacket(); long total = 0; Set<String> dataNodeNameSet = result.keySet(); Map<String, Boolean> fullMap = new HashMap<String, Boolean>(); for (Iterator<String> iter = dataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); NodeRowDataPacket nodePacket = result.get(dataNodeName); total += nodePacket.loadTotal(); RangRowDataPacket rPacket = nodePacket.loadTailPacket(); if (rPacket != null && rPacket.allSize() == this.mergeService.getPagePatchSize()) { fullMap.put(dataNodeName, true); } } //没有数据加载的后面不再加载 Set<String> eDataNodeNameSet = nextExcuteMap.keySet(); for (Iterator<String> iter = eDataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); Long lastCount = nodeExcuteAddCountMap.get(dataNodeName); if (lastCount == null || lastCount.compareTo((long) this.mergeService.getPagePatchSize()) < 0) { nextExcuteMap.put(dataNodeName, false); } } if (this.sorter == null) { return; } Set<String> fullDataNodeNameSet = fullMap.keySet(); for (Iterator<String> iter = fullDataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); if (fullMap.get(dataNodeName) && !nextExcuteMap.get(dataNodeName)) { nextExcuteMap.put(dataNodeName, true); } } //识别可继续加载node List<String> nextDataNameList = new ArrayList<String>(); Set<String> eDataNodeNameSet1 = nextExcuteMap.keySet(); for (Iterator<String> iter = eDataNodeNameSet1.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); if (nextExcuteMap.get(dataNodeName)) { nextDataNameList.add(dataNodeName); } } //不需要再加载就返回 if (nextDataNameList.size() == 1) { if (total - this.rrs.getLimitStart() >= this.rrs.getLimitSize()) { if (isEnd == false) { isEnd = true; } else { nextExcuteMap.put(nextDataNameList.get(0), false); return; } } } //得到头部处理最后 boolean ascDesc = this.sorter.ascDesc(0); RowDataPacket lastHeadTail = null; String lastRandHeadTailNode = null; for (String dataName : nextDataNameList) { NodeRowDataPacket nodePacket = result.get(dataName); RangRowDataPacket rangPacket = nodePacket.loadTailPacket(); if (rangPacket == null) { continue; } RowDataPacket headPacket = rangPacket.getHead(); if (lastHeadTail == null) { lastHeadTail = headPacket; lastRandHeadTailNode = dataName; continue; } int headResutl = this.sorter.compareRowData(lastHeadTail, headPacket, 0); if (ascDesc) { if (headResutl < 0) { lastHeadTail = headPacket; lastRandHeadTailNode = dataName; } } else { if (headResutl > 0) { lastHeadTail = headPacket; lastRandHeadTailNode = dataName; } } } //得到尾部在上面得到的头部前面节点 List<String> newNextDataList = new ArrayList<String>(); for (String dataName : nextDataNameList) { NodeRowDataPacket nodePacket = result.get(dataName); RangRowDataPacket rangPacket = nodePacket.loadTailPacket(); if (rangPacket == null || rangPacket.getRowDataPacketList().isEmpty()) { continue; } RowDataPacket tailPacket = rangPacket.getTail(); if (tailPacket == null) { tailPacket = rangPacket.getHead(); } int headResutl = this.sorter.compareRowData(lastHeadTail, tailPacket, 0); if (ascDesc) { if (headResutl > 0) { newNextDataList.add(dataName); } } else { if (headResutl < 0) { newNextDataList.add(dataName); } } } //出现断层数据就先加载 if (!newNextDataList.isEmpty()) { this.nextExcuteTrueWithClear(newNextDataList); return; } if (total < this.rrs.getLimitStart()) { List<String> newHeadNextDataList = new ArrayList<String>(); for (String dataName : nextDataNameList) { if (!dataName.equals(lastRandHeadTailNode)) { newHeadNextDataList.add(dataName); } } if (!newHeadNextDataList.isEmpty()) { this.nextExcuteTrueWithClear(newHeadNextDataList); return; } } } private Map<String, Long> nodeExcuteAddCountMap = new HashMap<String, Long>(); public void newRecord(String dataNode) { Long count = nodeExcuteAddCountMap.get(dataNode); if (count == null) { count = 0L; } count++; nodeExcuteAddCountMap.put(dataNode, count); } public void dataOk(String dataNode, byte[] eof, BackendConnection conn) { if (nextExcuteMap.get(dataNode)) { currCount++; } if (currCount == nextCount) { controllNext(); if (this.canStop()) { this.mergeService.rowEofResponse(eof, null); } else { nextCount = 0; Set<String> countDataNodeNameSet = nextExcuteMap.keySet(); for (Iterator<String> iter = countDataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); if (nextExcuteMap.get(dataNodeName)) { nextCount++; } } currCount = 0; nodeExcuteAddCountMap.clear(); Set<String> dataNodeNameSet = nextExcuteMap.keySet(); this.nextExcutePage(); for (Iterator<String> iter = dataNodeNameSet.iterator(); iter.hasNext();) { String dataNodeName = iter.next(); if (nextExcuteMap.get(dataNodeName)) { this.mergeService.onNewRangRecord(dataNodeName); this.executeLastNode(result.get(dataNodeName).getNode()); } } } } } }