package org.ovirt.engine.core.dao;
import static org.ovirt.engine.core.utils.CollectionUtils.pairsToMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Named;
import javax.inject.Singleton;
import org.ovirt.engine.core.common.businessentities.VmNumaNode;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.compat.Guid;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@Named
@Singleton
public class VmNumaNodeDaoImpl extends NumaNodeDaoBase<VmNumaNode> implements VmNumaNodeDao {
@Override
public List<VmNumaNode> getAllVmNumaNodeByVmId(Guid vmId) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("vm_id", vmId);
List<VmNumaNode> vmNumaNodes =
getCallsHandler().executeReadList("GetNumaNodeByVmId",
vmNumaNodeCpuRowMapper, parameterSource);
Map<Guid, List<Integer>> vmNumaNodesPinMap = getAllVmNumaNodePinInfo();
vmNumaNodes.stream().filter(node -> vmNumaNodesPinMap.containsKey(node.getId())).forEach(
node -> node.setVdsNumaNodeList(vmNumaNodesPinMap.get(node.getId())));
return vmNumaNodes;
}
@Override
public Map<Guid, List<VmNumaNode>> getVmNumaNodeInfoByClusterId(Guid clusterId) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("cluster_id", clusterId);
List<Pair<Guid, VmNumaNode>> vmNumaNodes =
getCallsHandler().executeReadList("GetVmNumaNodeByCluster",
vmNumaNodeInfoWithClusterRowMapper, parameterSource);
Map<Guid, List<Integer>> numaNodesCpusMap = getAllNumaNodeCpuMap();
Map<Guid, List<Integer>> vmNumaNodesPinMap = getAllVmNumaNodePinInfo();
for (Pair<Guid, VmNumaNode> pair : vmNumaNodes) {
if (numaNodesCpusMap.containsKey(pair.getSecond().getId())) {
pair.getSecond().setCpuIds(numaNodesCpusMap.get(pair.getSecond().getId()));
}
if (vmNumaNodesPinMap.containsKey(pair.getSecond().getId())) {
pair.getSecond().setVdsNumaNodeList(vmNumaNodesPinMap.get(pair.getSecond().getId()));
}
}
return pairsToMap(vmNumaNodes);
}
@Override
public void massSaveNumaNode(List<VmNumaNode> numaNodes, Guid vmId) {
insertNodes(numaNodes, node -> createNumaNodeParametersMapper(node).addValue("vm_id", vmId));
insertNumaNodeMap(numaNodes);
insertCpus(numaNodes);
}
@Override
public void massUpdateNumaNode(List<VmNumaNode> numaNodes) {
updateNodes(numaNodes, node -> createNumaNodeParametersMapper(node));
removeCpus(numaNodes);
insertCpus(numaNodes);
getCallsHandler().executeStoredProcAsBatch("DeleteNumaNodeMapByVmNumaNodeId", numaNodes.stream()
.map(node -> getCustomMapSqlParameterSource().addValue("vm_numa_node_id", node.getId()))
.collect(Collectors.toList()));
insertNumaNodeMap(numaNodes);
}
private Map<Guid, List<Integer>> getAllNumaNodeCpuMap() {
List<Pair<Guid, Integer>> numaNodesCpus =
getCallsHandler().executeReadList("GetAllFromNumaNodeCpuMap",
vmNumaNodeCpusRowMapper, null);
return pairsToMap(numaNodesCpus);
}
private Map<Guid, List<Integer>> getAllVmNumaNodePinInfo() {
List<Pair<Guid, Integer>> numaNodesAssign =
getCallsHandler().executeReadList("GetAllAssignedNumaNodeInfomation",
vmNumaNodeAssignmentRowMapper, null);
return pairsToMap(numaNodesAssign);
}
private static final RowMapper<VmNumaNode> vmNumaNodeRowMapper = (rs, rowNum) -> {
VmNumaNode entity = new VmNumaNode();
entity.setId(getGuid(rs, "numa_node_id"));
entity.setIndex(rs.getInt("numa_node_index"));
entity.setMemTotal(rs.getLong("mem_total"));
return entity;
};
private static final RowMapper<VmNumaNode> vmNumaNodeCpuRowMapper = (rs, rowNum) -> {
VmNumaNode entity = vmNumaNodeRowMapper.mapRow(rs, rowNum);
// We need to copy the array to a normal ArrayList to be GWT compatible. GWT has deserialization
// problems with the Arrays.asList implementation returned by getArray() (Java8 related?)
entity.setCpuIds(new ArrayList<>(Arrays.asList((Integer[]) rs.getArray("cpu_core_ids").getArray())));
return entity;
};
private static final RowMapper<Pair<Guid, VmNumaNode>> vmNumaNodeInfoWithClusterRowMapper = (rs, rowNum) -> {
VmNumaNode entity = new VmNumaNode();
entity.setId(getGuid(rs, "vm_numa_node_id"));
entity.setIndex(rs.getInt("vm_numa_node_index"));
entity.setMemTotal(rs.getLong("vm_numa_node_mem_total"));
return new Pair<>(getGuid(rs, "vm_numa_node_vm_id"), entity);
};
private void insertNumaNodeMap(List<VmNumaNode> numaNodes) {
List<MapSqlParameterSource> vNodeToPnodeExecutions = new ArrayList<>();
for (VmNumaNode node : numaNodes) {
node.getVdsNumaNodeList().stream()
.map(index -> createVnodeToPnodeParametersMapper(index, node.getId()))
.forEach(vNodeToPnodeExecutions::add);
}
getCallsHandler().executeStoredProcAsBatch("InsertNumaNodeMap", vNodeToPnodeExecutions);
}
private static final RowMapper<Pair<Guid, Integer>> vmNumaNodeCpusRowMapper =
(rs, rowNum) -> new Pair<>(getGuid(rs, "numa_node_id"), rs.getInt("cpu_core_id"));
private static final RowMapper<Pair<Guid, Integer>> vmNumaNodeAssignmentRowMapper =
(rs, rowNum) -> new Pair<>(getGuid(rs, "assigned_vm_numa_node_id"),
rs.getInt("run_in_vds_numa_node_index"));
private MapSqlParameterSource createVnodeToPnodeParametersMapper(
Integer pinnedIndex, Guid vNodeId) {
return getCustomMapSqlParameterSource()
.addValue("id", Guid.newGuid())
.addValue("vm_numa_node_id", vNodeId)
.addValue("vds_numa_node_index", pinnedIndex);
}
}