package org.ovirt.engine.core.dao;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.common.businessentities.NumaNodeStatistics;
import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
import org.ovirt.engine.core.compat.Guid;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@Named
@Singleton
public class VdsNumaNodeDaoImpl extends NumaNodeDaoBase<VdsNumaNode> implements VdsNumaNodeDao {
@Override
public List<VdsNumaNode> getAllVdsNumaNodeByVdsId(Guid vdsId) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("vds_id", vdsId);
return getCallsHandler().executeReadList("GetNumaNodeByVdsId",
vdsNumaNodeRowMapper, parameterSource);
}
@Override
public void massSaveNumaNode(List<VdsNumaNode> numaNodes, Guid vdsId) {
insertNodes(numaNodes, node -> createNumaNodeParametersMapper(node).addValue("vds_id", vdsId));
insertCpus(numaNodes);
}
@Override
public void massUpdateNumaNode(List<VdsNumaNode> numaNodes) {
updateNodes(numaNodes, node -> createNumaNodeParametersMapper(node));
removeCpus(numaNodes);
insertCpus(numaNodes);
}
@Override
public void massUpdateNumaNodeStatistics(List<VdsNumaNode> numaNodes) {
List<MapSqlParameterSource> executions = numaNodes.stream()
.map(node -> createNumaNodeStatisticsParametersMapper(node))
.collect(Collectors.toList());
getCallsHandler().executeStoredProcAsBatch("UpdateNumaNodeStatistics", executions);
}
private static final RowMapper<VdsNumaNode> vdsNumaNodeRowMapper = (rs, rowNum) -> {
VdsNumaNode entity = new VdsNumaNode();
NumaNodeStatistics stat = new NumaNodeStatistics();
entity.setId(getGuid(rs, "numa_node_id"));
entity.setIndex(rs.getInt("numa_node_index"));
entity.setMemTotal(rs.getLong("mem_total"));
stat.setMemFree(rs.getLong("mem_free"));
stat.setMemUsagePercent(rs.getInt("usage_mem_percent"));
stat.setCpuSys(rs.getDouble("cpu_sys"));
stat.setCpuUser(rs.getDouble("cpu_user"));
stat.setCpuIdle(rs.getDouble("cpu_idle"));
stat.setCpuUsagePercent(rs.getInt("usage_cpu_percent"));
entity.setNumaNodeStatistics(stat);
entity.setNumaNodeDistances(getDistanceMap(rs.getString("distance")));
entity.setCpuIds(Arrays.asList((Integer[]) rs.getArray("cpu_core_ids").getArray()));
return entity;
};
// format: (<index_id>, <distance>);*, for example: "0, 10; 2, 16"
private static Map<Integer, Integer> getDistanceMap(String distance) {
if (StringUtils.isBlank(distance)) {
return new HashMap<>();
}
return Arrays.stream(distance.split(";")).map(d -> d.split(",")).collect(
Collectors.toMap(k -> Integer.valueOf(k[0]), v -> Integer.valueOf(v[1])));
}
protected MapSqlParameterSource createNumaNodeParametersMapper(VdsNumaNode node) {
return super.createNumaNodeParametersMapper(node)
.addValue("distance", getDistanceString(node.getNumaNodeDistances()));
}
private static String getDistanceString(Map<Integer, Integer> distance) {
if (distance == null || distance.isEmpty()) {
return null;
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<Integer, Integer> entry : distance.entrySet()) {
sb.append(entry.getKey());
sb.append(",");
sb.append(entry.getValue());
sb.append(";");
}
return sb.deleteCharAt(sb.length() - 1).toString();
}
private MapSqlParameterSource createNumaNodeStatisticsParametersMapper(VdsNumaNode node) {
return getCustomMapSqlParameterSource()
.addValue("numa_node_id", node.getId())
.addValue("mem_free", node.getNumaNodeStatistics().getMemFree())
.addValue("usage_mem_percent", node.getNumaNodeStatistics().getMemUsagePercent())
.addValue("cpu_sys", node.getNumaNodeStatistics().getCpuSys())
.addValue("cpu_user", node.getNumaNodeStatistics().getCpuUser())
.addValue("cpu_idle", node.getNumaNodeStatistics().getCpuIdle())
.addValue("usage_cpu_percent", node.getNumaNodeStatistics().getCpuUsagePercent());
}
}