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); } }