package org.ovirt.engine.core.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.common.businessentities.QuotaEnforcementTypeEnum;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType;
import org.ovirt.engine.core.common.businessentities.storage.ImageStatus;
import org.ovirt.engine.core.common.businessentities.storage.ImageTransferPhase;
import org.ovirt.engine.core.common.businessentities.storage.QcowCompat;
import org.ovirt.engine.core.common.businessentities.storage.StorageType;
import org.ovirt.engine.core.common.businessentities.storage.VolumeClassification;
import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat;
import org.ovirt.engine.core.common.businessentities.storage.VolumeType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dal.dbbroker.DbFacadeUtils;
import org.ovirt.engine.core.utils.GuidUtils;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
/**
* {@code DiskImageDaoImpl} provides an implementation of {@link DiskImageDao}.
*/
@Named
@Singleton
public class DiskImageDaoImpl extends BaseDao implements DiskImageDao {
@Override
public DiskImage get(Guid id) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("image_guid", id);
return getCallsHandler().executeRead("GetImageByImageGuid", DiskImageRowMapper.instance, parameterSource);
}
@Override
public DiskImage getSnapshotById(Guid id) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("image_guid", id);
return getCallsHandler().executeRead("GetSnapshotByGuid", DiskImageRowMapper.instance, parameterSource);
}
@Override
public List<DiskImage> getAllSnapshotsForParent(Guid id) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("parent_guid", id);
return getCallsHandler().executeReadList("GetSnapshotByParentGuid",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public List<DiskImage> getAllSnapshotsForLeaf(Guid id) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("image_guid", id);
return getCallsHandler().executeReadList("GetSnapshotByLeafGuid",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public List<DiskImage> getAllSnapshotsForStorageDomain(Guid id) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("storage_domain_id", id);
return getCallsHandler().executeReadList("GetSnapshotsByStorageDomainId",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public List<DiskImage> getAllSnapshotsForVmSnapshot(Guid id) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("vm_snapshot_id", id);
return getCallsHandler().executeReadList("GetSnapshotsByVmSnapshotId",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public DiskImage getDiskSnapshotForVmSnapshot(Guid diskId, Guid vmSnapshotId) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("vm_snapshot_id", vmSnapshotId)
.addValue("image_group_id", diskId);
return getCallsHandler().executeRead("GetDiskSnapshotForVmSnapshot",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public List<DiskImage> getAllSnapshotsForImageGroup(Guid id) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("image_group_id", id);
return getCallsHandler().executeReadList("GetSnapshotsByImageGroupId",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public Set<DiskImage> getAllSnapshotsForParents(Collection<Guid> parentIds) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("parent_guids", createArrayOfUUIDs(parentIds));
return new HashSet<>(getCallsHandler().executeReadList("GetSnapshotsByParentsGuid",
DiskImageRowMapper.instance,
parameterSource));
}
@Override
public List<DiskImage> getAttachedDiskSnapshotsToVm(Guid vmId, Boolean isPlugged) {
return getCallsHandler().executeReadList("GetAttachedDiskSnapshotsToVm", DiskImageRowMapper.instance,
getCustomMapSqlParameterSource().addValue("vm_guid", vmId).addValue("is_plugged", isPlugged));
}
@Override
public List<DiskImage> getAll() {
throw new UnsupportedOperationException();
}
@Override
public DiskImage getAncestor(Guid id) {
return getAncestor(id, null, false);
}
@Override
public DiskImage getAncestor(Guid id, Guid userID, boolean isFiltered) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("image_guid", id).addValue("user_id", userID).addValue("is_filtered", isFiltered);
return getCallsHandler().executeRead("GetAncestralImageByImageGuid",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public List<DiskImage> getImagesWithNoDisk(Guid vmId) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("vm_id", vmId);
return getCallsHandler().executeReadList("GetImagesWhichHaveNoDisk",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public List<DiskImage> getAllForStorageDomain(Guid storageDomainId) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("storage_domain_id", storageDomainId);
return getCallsHandler().executeReadList("GetAllForStorageDomain",
DiskImageRowMapper.instance,
parameterSource);
}
@Override
public List<DiskImage> getAllForDiskProfiles(Collection<Guid> diskProfileIds) {
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("disk_profile_ids", createArrayOfUUIDs(diskProfileIds));
return getCallsHandler().executeReadList("GetAllForDiskProfiles",
DiskImageRowMapper.instance,
parameterSource);
}
protected static class DiskImageRowMapper extends AbstractDiskRowMapper<DiskImage> {
public static final DiskImageRowMapper instance = new DiskImageRowMapper();
private DiskImageRowMapper() {
}
@Override
public DiskImage mapRow(ResultSet rs, int rowNum) throws SQLException {
DiskImage entity = null;
DiskStorageType diskStorageType = DiskStorageType.forValue(rs.getInt("disk_storage_type"));
switch (diskStorageType) {
case IMAGE:
entity = super.mapRow(rs, rowNum);
mapEntity(rs, entity);
break;
case CINDER:
entity = CinderDiskRowMapper.instance.mapRow(rs, rowNum);
break;
}
return entity;
}
protected void mapEntity(ResultSet rs, DiskImage entity) throws SQLException {
entity.setCreationDate(DbFacadeUtils.fromDate(rs
.getTimestamp("creation_date")));
entity.setActualSizeInBytes(rs.getLong("actual_size"));
entity.setDescription(rs.getString("description"));
entity.setImageId(getGuidDefaultEmpty(rs, "image_guid"));
entity.setImageTemplateId(getGuidDefaultEmpty(rs, "it_guid"));
entity.setSize(rs.getLong("size"));
entity.setParentId(getGuidDefaultEmpty(rs, "ParentId"));
entity.setImageStatus(ImageStatus.forValue(rs
.getInt("imageStatus")));
entity.setLastModified(DbFacadeUtils.fromDate(rs
.getTimestamp("lastModified")));
entity.setAppList(rs.getString("app_list"));
entity.setStorageIds(GuidUtils.getGuidListFromString(rs.getString("storage_id")));
entity.setStorageTypes(getStorageTypesList(rs.getString("storage_type")));
entity.setStoragesNames(split(rs.getString("storage_name")));
entity.setVmSnapshotId(getGuid(rs, "vm_snapshot_id"));
entity.setVolumeType(VolumeType.forValue(rs
.getInt("volume_type")));
entity.setVolumeFormat(VolumeFormat.forValue(rs
.getInt("volume_format")));
if (entity.isQcowFormat()) {
entity.setQcowCompat(QcowCompat.forValue(rs.getInt("qcow_compat")));
}
entity.setId(getGuidDefaultEmpty(rs, "image_group_id"));
entity.setStoragePoolId(getGuid(rs, "storage_pool_id"));
entity.setReadRate(rs.getInt("read_rate"));
entity.setWriteRate(rs.getInt("write_rate"));
entity.setImageTransferPhase(rs.getObject("image_transfer_phase") != null
? ImageTransferPhase.forValue(rs.getInt("image_transfer_phase")) : null);
entity.setImageTransferBytesSent(rs.getLong("image_transfer_bytes_sent"));
entity.setImageTransferBytesTotal(rs.getLong("image_transfer_bytes_total"));
entity.setProgress(getInteger(rs, "progress"));
entity.setReadLatency(rs.getObject("read_latency_seconds") != null ? rs.getDouble("read_latency_seconds")
: null);
entity.setWriteLatency(rs.getObject("write_latency_seconds") != null ? rs.getDouble("write_latency_seconds")
: null);
entity.setFlushLatency(rs.getObject("flush_latency_seconds") != null ? rs.getDouble("flush_latency_seconds")
: null);
entity.setActive(Boolean.TRUE.equals(rs.getObject("active")));
entity.setQuotaIds(getGuidListFromStringPreserveAllTokens(rs.getString("quota_id")));
entity.setQuotaNames(splitPreserveAllTokens(rs.getString("quota_name")));
entity.setQuotaEnforcementType(QuotaEnforcementTypeEnum.forValue(rs.getInt("quota_enforcement_type")));
entity.setDiskProfileIds(getGuidListFromStringPreserveAllTokens(rs.getString("disk_profile_id")));
entity.setDiskProfileNames(splitPreserveAllTokens(rs.getString("disk_profile_name")));
entity.setVolumeClassification(VolumeClassification.forValue(rs.getInt("volume_classification")));
}
@Override
protected DiskImage createDiskEntity() {
return new DiskImage();
}
private ArrayList<StorageType> getStorageTypesList(String storageTypesString) throws SQLException {
List<String> splitTypes = split(storageTypesString);
if (splitTypes == null) {
return null;
}
ArrayList<StorageType> types = new ArrayList<>();
for (String typeStr : splitTypes) {
try {
types.add(StorageType.forValue(Integer.parseInt(typeStr)));
}
catch (NumberFormatException e) {
throw new SQLException("Could not parse disk image storage domain type " + typeStr, e);
}
}
return types;
}
/**
* since quota can be null, we need to preserve null in the list
*/
private ArrayList<String> splitPreserveAllTokens(String str) {
if (StringUtils.isEmpty(str)) {
return null;
}
return new ArrayList<>(Arrays.asList(StringUtils.splitPreserveAllTokens(str, SEPARATOR)));
}
/**
* since some disk images can contain empty quota, we need to preserve null in the list.
*/
private ArrayList<Guid> getGuidListFromStringPreserveAllTokens(String str) {
ArrayList<Guid> guidList = new ArrayList<>();
if (StringUtils.isEmpty(str)) {
return new ArrayList<>();
}
for (String guidString : splitPreserveAllTokens(str)) {
Guid guidToAdd = null;
if (!StringUtils.isEmpty(guidString)) {
guidToAdd = Guid.createGuidFromString(guidString);
}
guidList.add(guidToAdd);
}
return guidList;
}
}
protected static class CinderDiskRowMapper extends AbstractDiskRowMapper<CinderDisk> {
public static final CinderDiskRowMapper instance = new CinderDiskRowMapper();
private CinderDiskRowMapper() {
}
@Override
public CinderDisk mapRow(ResultSet rs, int rowNum) throws SQLException {
CinderDisk cinderDisk = super.mapRow(rs, rowNum);
DiskImageRowMapper.instance.mapEntity(rs, cinderDisk);
mapEntity(rs, cinderDisk);
return cinderDisk;
}
private void mapEntity(ResultSet rs, CinderDisk entity) throws SQLException {
entity.setCinderVolumeType(rs.getString("cinder_volume_type"));
}
@Override
protected CinderDisk createDiskEntity() {
return new CinderDisk();
}
}
}