package com.breakersoft.plow.dao.pgsql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.breakersoft.plow.Cluster;
import com.breakersoft.plow.Defaults;
import com.breakersoft.plow.Node;
import com.breakersoft.plow.NodeE;
import com.breakersoft.plow.dao.AbstractDao;
import com.breakersoft.plow.dao.NodeDao;
import com.breakersoft.plow.exceptions.PlowWriteException;
import com.breakersoft.plow.rnd.thrift.Ping;
import com.breakersoft.plow.thrift.NodeState;
import com.breakersoft.plow.thrift.SlotMode;
import com.breakersoft.plow.util.JdbcUtils;
import com.breakersoft.plow.util.PlowUtils;
import com.google.common.base.Preconditions;
@Repository
public class NodeDaoImpl extends AbstractDao implements NodeDao {
private static final String INSERT[] = {
JdbcUtils.Insert("plow.node",
"pk_node",
"pk_cluster",
"str_name",
"str_ipaddr",
"str_tags"),
JdbcUtils.Insert("plow.node_sys",
"pk_node",
"int_phys_cores",
"int_log_cores",
"int_ram",
"int_free_ram",
"int_swap",
"int_free_swap",
"time_booted",
"str_cpu_model",
"str_platform",
"flt_load"),
JdbcUtils.Insert("plow.node_dsp",
"pk_node",
"int_cores",
"int_idle_cores",
"int_ram",
"int_free_ram")
};
@Override
public Node create(final Cluster cluster, final Ping ping) {
final UUID id = UUID.randomUUID();
final List<String> tags = jdbc.queryForList("SELECT unnest(str_tags) " +
"FROM plow.cluster WHERE pk_cluster=?", String.class, cluster.getClusterId());
jdbc.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(final Connection conn) throws SQLException {
final PreparedStatement ps = conn.prepareStatement(INSERT[0]);
ps.setObject(1, id);
ps.setObject(2, cluster.getClusterId());
ps.setString(3, ping.hostname);
ps.setString(4, ping.ipAddr);
ps.setArray(5, conn.createArrayOf("text", tags.toArray()));
return ps;
}
});
jdbc.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(final Connection conn) throws SQLException {
final PreparedStatement ps = conn.prepareStatement(INSERT[1]);
ps.setObject(1, id);
ps.setInt(2, ping.hw.physicalCpus);
ps.setInt(3, ping.hw.logicalCpus);
ps.setInt(4, ping.hw.totalRamMb);
ps.setInt(5, ping.hw.freeRamMb);
ps.setInt(6, ping.hw.totalSwapMb);
ps.setInt(7, ping.hw.freeSwapMb);
ps.setLong(8, ping.bootTime * 1000);
ps.setString(9, ping.hw.cpuModel);
ps.setString(10, ping.hw.platform);
if (!PlowUtils.isValid(ping.hw.load)) {
ps.setArray(11, conn.createArrayOf("float", new Float[] { 0.0f, 0.0f, 0.0f }));
}
else {
ps.setArray(11, conn.createArrayOf("float", ping.hw.load.toArray()));
}
return ps;
}
});
final int memMb = ping.hw.totalRamMb
- PlowUtils.getReservedRam(ping.hw.totalRamMb);
jdbc.update(INSERT[2], id,
ping.hw.physicalCpus,
ping.hw.physicalCpus,
memMb,
memMb);
NodeE node = new NodeE();
node.setNodeId(id);
node.setClusterId(cluster.getClusterId());
node.setName(ping.hostname);
return node;
}
private static final String FULL_UPDATE =
JdbcUtils.Update("plow.node_sys",
"pk_node",
"int_phys_cores",
"int_log_cores",
"int_ram",
"int_free_ram",
"int_swap",
"int_free_swap",
"time_booted",
"str_cpu_model",
"str_platform");
@Override
public void update(Node node, Ping ping) {
jdbc.update("UPDATE plow.node SET " +
"time_updated=plow.txTimeMillis() WHERE pk_node=?", node.getNodeId());
jdbc.update("UPDATE plow.node SET " +
"int_state=? WHERE pk_node=? AND int_state=?",
NodeState.UP.ordinal(), node.getNodeId(), NodeState.DOWN.ordinal());
jdbc.update(FULL_UPDATE,
ping.hw.physicalCpus,
ping.hw.logicalCpus,
ping.hw.totalRamMb,
ping.hw.freeRamMb,
ping.hw.totalSwapMb,
ping.hw.freeSwapMb,
ping.bootTime * 1000,
ping.hw.cpuModel,
ping.hw.platform,
node.getNodeId());
}
public static final RowMapper<Node> MAPPER = new RowMapper<Node>() {
@Override
public Node mapRow(ResultSet rs, int rowNum)
throws SQLException {
NodeE node = new NodeE();
node.setNodeId((UUID) rs.getObject(1));
node.setClusterId((UUID) rs.getObject(2));
node.setName(rs.getString(3));
return node;
}
};
private static final String GET_BY_NAME =
"SELECT " +
"pk_node, " +
"pk_cluster, "+
"str_name " +
"FROM " +
"plow.node " +
"WHERE " +
"str_name = ?";
@Override
public Node get(String hostname) {
return jdbc.queryForObject(GET_BY_NAME, MAPPER, hostname);
}
private static final String GET_BY_ID =
"SELECT " +
"pk_node, " +
"pk_cluster, "+
"str_name " +
"FROM " +
"plow.node " +
"WHERE " +
"node.pk_node=?";
@Override
public Node get(UUID id) {
return jdbc.queryForObject(GET_BY_ID, MAPPER, id);
}
private static final String GET_UNRESPONSIVE =
"SELECT " +
"pk_node, " +
"pk_cluster, "+
"str_name " +
"FROM " +
"plow.node " +
"WHERE " +
"node.int_state = ? " +
"AND " +
"plow.currentTimeMillis() - node.time_updated >= ? " +
"LIMIT 50";
@Override
public List<Node> getUnresponsiveNodes() {
return jdbc.query(GET_UNRESPONSIVE, MAPPER, NodeState.UP.ordinal(), Defaults.NODE_UNRESPONSIVE_MS);
}
private static final String ALLOCATE_RESOURCES =
"UPDATE " +
"plow.node_dsp " +
"SET " +
"int_idle_cores = int_idle_cores - ?," +
"int_free_ram = int_free_ram - ? " +
"WHERE " +
"node_dsp.pk_node = ? ";
@Override
public void allocate(Node node, int cores, int memory) {
// Check constraints will throw.
jdbc.update(ALLOCATE_RESOURCES,
cores, memory, node.getNodeId());
}
private static final String FREE_RESOURCES =
"UPDATE " +
"plow.node_dsp " +
"SET " +
"int_idle_cores = int_idle_cores + ?," +
"int_free_ram = int_free_ram + ? " +
"WHERE " +
"node_dsp.pk_node = ? ";
@Override
public void free(Node node, int cores, int memory) {
jdbc.update(FREE_RESOURCES, cores, memory, node.getNodeId());
}
@Override
public void setLocked(Node node, boolean locked) {
jdbc.update("UPDATE plow.node SET bool_locked=? WHERE pk_node=?", locked, node.getNodeId());
}
@Override
public boolean hasProcs(Node node, boolean lock) {
String query = "SELECT int_cores - int_idle_cores FROM plow.node_dsp WHERE pk_node=?";
if (lock) {
query = query + " FOR UPDATE";
}
return jdbc.queryForObject(query, Integer.class, node.getNodeId()) != 0;
}
private static final String SET_CLUSTER = "UPDATE plow.node SET pk_cluster=?, str_tags=? WHERE pk_node=?";
@Override
public void setCluster(final Node node, final Cluster cluster) {
final List<String> tags = jdbc.queryForList("SELECT unnest(str_tags) " +
"FROM plow.cluster WHERE pk_cluster=?", String.class, cluster.getClusterId());
if (tags.isEmpty()) {
throw new PlowWriteException("Cannot assign node, the cluster " + cluster + " has no tags.");
}
jdbc.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(final Connection conn) throws SQLException {
final PreparedStatement ret = conn.prepareStatement(SET_CLUSTER);
ret.setObject(1, cluster.getClusterId());
ret.setObject(2, JdbcUtils.toArray(conn, tags));
ret.setObject(3, node.getNodeId());
return ret;
}
});
}
private static final String UPDATE_TAGS =
"UPDATE plow.node SET str_tags=? WHERE pk_node=?";
@Override
public void setTags(final Node node, final Set<String> tags) {
jdbc.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(final Connection conn) throws SQLException {
final PreparedStatement ret = conn.prepareStatement(UPDATE_TAGS);
ret.setObject(1, JdbcUtils.toArray(conn, tags));
ret.setObject(2, node.getNodeId());
return ret;
}
});
}
@Override
public boolean setState(Node node, NodeState state) {
return jdbc.update("UPDATE plow.node SET int_state=? WHERE pk_node=? AND int_state!=?",
state.ordinal(), node.getNodeId(), state.ordinal()) == 1;
}
private static final String UPDATE_SLOT_MODE =
"UPDATE " +
"plow.node " +
"SET " +
"int_slot_mode=?,"+
"int_slot_cores=?,"+
"int_slot_ram=? "+
"WHERE " +
"pk_node=?";
@Override
public void setSlotMode(Node node, SlotMode mode, int cores, int ram) {
if (mode.equals(SlotMode.SINGLE) || mode.equals(SlotMode.DYNAMIC)) {
cores = 0;
ram = 0;
}
else if (mode.equals(SlotMode.SLOTS)) {
Preconditions.checkArgument(cores > 0, "Cores must be greater than 0 in slot mode");
Preconditions.checkArgument(ram > 0, "Ram must be greater than 0 in slot mode");
}
jdbc.update(UPDATE_SLOT_MODE, mode.ordinal(), cores, ram, node.getNodeId());
}
}