/*
* Copyright 2015 Liu Huanting.
*
* 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 fm.liu.timo.server.session;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import fm.liu.timo.TimoConfig;
import fm.liu.timo.TimoServer;
import fm.liu.timo.backend.Node;
import fm.liu.timo.merger.Merger;
import fm.liu.timo.mysql.handler.MultiNodeHandler;
import fm.liu.timo.mysql.handler.SingleNodeHandler;
import fm.liu.timo.mysql.packet.OkPacket;
import fm.liu.timo.net.connection.BackendConnection;
import fm.liu.timo.net.connection.Variables;
import fm.liu.timo.route.Outlet;
import fm.liu.timo.route.Outlets;
import fm.liu.timo.server.ServerConnection;
import fm.liu.timo.server.parser.ServerParse;
import fm.liu.timo.server.session.handler.SessionResultHandler;
/**
* @author Liu Huanting 2015年5月9日
*/
public abstract class AbstractSession implements Session {
protected final ServerConnection front;
protected final ConcurrentHashMap<Integer, BackendConnection> connections;
protected final Variables variables;
public AbstractSession(ServerConnection front) {
this.front = front;
this.connections = new ConcurrentHashMap<Integer, BackendConnection>();
this.variables = new Variables();
this.variables.setCharsetIndex(front.getVariables().getCharsetIndex());
this.variables.setIsolationLevel(front.getVariables().getIsolationLevel());
}
@Override
public ServerConnection getFront() {
return front;
}
@Override
public Collection<BackendConnection> getConnections() {
return connections.values();
}
public Variables getVariables() {
return variables;
}
@Override
public Collection<BackendConnection> availableConnections() {
return getConnections().parallelStream().filter(con -> !con.isClosed())
.collect(Collectors.toList());
}
@Override
public final void offer(BackendConnection con) {
connections.put(con.getDatanodeID(), con);
}
@Override
public void execute(Outlets outs, int type) {
boolean read = type == ServerParse.SELECT;
boolean usingMaster = outs.usingMaster();
SessionResultHandler handler = chooseHandler(outs, type);
TimoConfig config = TimoServer.getInstance().getConfig();
for (Outlet out : outs.getResult()) {
String sql = out.getSql();
handler.setSQL(sql);
Node node = config.getNodes().get(out.getID());
BackendConnection con = connections.get(out.getID());
if (con != null) {
offer(con);
con.query(sql, handler);
} else {
if (usingMaster) {
node.getSource().query(out.getSql(), handler);
} else {
node.query(out.getSql(), handler, read);
}
}
}
}
protected SessionResultHandler chooseHandler(Outlets outs, int type) {
int size = outs.size();
if (1 == size) {
return new SingleNodeHandler(this);
}
return new MultiNodeHandler(this, new Merger(outs), size);
}
public void commit() {
ByteBuffer buffer = front.allocate();
buffer = front.writeToBuffer(OkPacket.OK, buffer);
front.write(buffer);
}
public void rollback(boolean response) {
ByteBuffer buffer = front.allocate();
buffer = front.writeToBuffer(OkPacket.OK, buffer);
front.write(buffer);
}
}