package fm.liu.timo.mysql.handler.xa; import java.util.Collection; import java.util.HashSet; import java.util.Map; import org.pmw.tinylog.Logger; import fm.liu.timo.TimoServer; import fm.liu.timo.backend.Node; import fm.liu.timo.mysql.packet.ErrorPacket; import fm.liu.timo.mysql.packet.OkPacket; import fm.liu.timo.net.connection.BackendConnection; import fm.liu.timo.server.session.XATransactionSession; /** * @author liuhuanting */ public class XARollbackHandler extends XAHandler { private boolean response; public XARollbackHandler(XATransactionSession session, Collection<BackendConnection> cons, boolean response) { super(session, cons); this.response = response; } @Override public void ok(byte[] ok, BackendConnection con) { results.replace(con.getDatanodeID(), true); if (decrement()) { if (failed()) { error(); return; } session.release(); if (response) { session.getFront().write(OkPacket.OK); } recycleResources(); } } private void error() { Collection<BackendConnection> connections = new HashSet<>(); results.entrySet().stream().filter(entry -> !entry.getValue()) .forEach(i -> connections.add(cons.get(i))); Map<Integer, Node> nodes = TimoServer.getInstance().getConfig().getNodes(); Collection<BackendConnection> cons = new HashSet<>(); for (BackendConnection con : connections) { if (con.isClosed()) { cons.add(nodes.get(con.getDatanodeID()).getSource().notNullGet()); } else { cons.add(con); } } XARollbackHandler handler = new XARollbackHandler(session, cons, true); connections.forEach(con -> con.query("XA ROLLBACK " + session.getXID(), handler)); recycleResources(); } @Override public void error(byte[] error, BackendConnection con) { ErrorPacket err = new ErrorPacket(); err.read(error); String message = new String(err.message); Logger.warn("error :{} received from :{} when XA PREPARE", con, message); this.setFail(err.errno, message); if (decrement()) { error(); } } }