/* * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software;Designed and Developed mainly by many Chinese * opensource volunteers. you can redistribute it and/or modify it under the * terms of the GNU General Public License version 2 only, as published by the * Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Any questions about this component can be directed to it's project Web address * https://code.google.com/p/opencloudb/. * */ package org.opencloudb.mysql.nio.handler; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Logger; import org.opencloudb.backend.BackendConnection; import org.opencloudb.net.mysql.ErrorPacket; /** * heartbeat check for mysql connections * * @author wuzhih * */ public class ConnectionHeartBeatHandler implements ResponseHandler { private static final Logger LOGGER = Logger .getLogger(ConnectionHeartBeatHandler.class); protected final ReentrantLock lock = new ReentrantLock(); private final ConcurrentHashMap<Long, HeartBeatCon> allCons = new ConcurrentHashMap<Long, HeartBeatCon>(); public void doHeartBeat(BackendConnection conn, String sql) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("do heartbeat for con " + conn); } try { HeartBeatCon hbCon = new HeartBeatCon(conn); boolean notExist = (allCons.putIfAbsent(hbCon.conn.getId(), hbCon) == null); if (notExist) { conn.setRunning(true); conn.setResponseHandler(this); conn.query(sql); } } catch (Exception e) { executeException(conn, e); } } /** * remove timeout connections */ public void abandTimeOuttedConns() { if (allCons.isEmpty()) { return; } Collection<BackendConnection> abandCons = new LinkedList<BackendConnection>(); long curTime = System.currentTimeMillis(); Iterator<Entry<Long, HeartBeatCon>> itors = allCons.entrySet() .iterator(); while (itors.hasNext()) { HeartBeatCon hbCon =itors.next().getValue(); if (hbCon.timeOutTimestamp < curTime) { abandCons.add(hbCon.conn); itors.remove(); } } if (!abandCons.isEmpty()) { for (BackendConnection con : abandCons) { try { // if(con.isBorrowed()) con.close("heartbeat timeout "); } catch (Exception e) { LOGGER.warn("close err:" + e); } } } } @Override public void connectionAcquired(BackendConnection conn) { // not called } @Override public void connectionError(Throwable e, BackendConnection conn) { // not called } @Override public void errorResponse(byte[] data, BackendConnection conn) { removeFinished(conn); conn.setRunning(false); ErrorPacket err = new ErrorPacket(); err.read(data); LOGGER.warn("errorResponse " + err.errno + " " + new String(err.message)); conn.release(); } @Override public void okResponse(byte[] ok, BackendConnection conn) { boolean executeResponse = conn.syncAndExcute(); if (executeResponse) { removeFinished(conn); conn.setRunning(false); conn.release(); } } @Override public void rowResponse(byte[] row, BackendConnection conn) { } @Override public void rowEofResponse(byte[] eof, BackendConnection conn) { removeFinished(conn); conn.setRunning(false); conn.release(); } private void executeException(BackendConnection c, Throwable e) { removeFinished(c); LOGGER.warn("executeException ", e); c.close("heatbeat exception:" + e); } private void removeFinished(BackendConnection con) { Long id = ((BackendConnection) con).getId(); this.allCons.remove(id); } @Override public void writeQueueAvailable() { } @Override public void connectionClose(BackendConnection conn, String reason) { removeFinished(conn); LOGGER.warn("connection closed " + conn + " reason:" + reason); } @Override public void fieldEofResponse(byte[] header, List<byte[]> fields, byte[] eof, BackendConnection conn) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("received field eof from " + conn); } } } class HeartBeatCon { public final long timeOutTimestamp; public final BackendConnection conn; public HeartBeatCon(BackendConnection conn) { super(); this.timeOutTimestamp = System.currentTimeMillis() + 20 * 1000L; this.conn = conn; } }