CLOUDSTACK-1302: Allow a cache mode per disk offering

Per disk offering the setting none, writeback or writethrough can be set

This allows for both safety and performance for writes.
This commit is contained in:
Wido den Hollander 2013-08-01 16:49:15 +02:00
parent 31758ed8d0
commit 1edaa36cc6
18 changed files with 203 additions and 5 deletions

View File

@ -41,6 +41,7 @@ public class VolumeTO implements InternalIdentity {
private Long bytesWriteRate;
private Long iopsReadRate;
private Long iopsWriteRate;
private String cacheMode;
private Long chainSize;
public VolumeTO(long id, Volume.Type type, StoragePoolType poolType, String poolUuid, String name, String mountPoint, String path, long size, String chainInfo) {
@ -176,6 +177,14 @@ public class VolumeTO implements InternalIdentity {
return iopsWriteRate;
}
public void setCacheMode(String cacheMode) {
this.cacheMode = cacheMode;
}
public String getCacheMode() {
return cacheMode;
}
public Long getChainSize() {
return chainSize;
}

View File

@ -35,6 +35,21 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId
State getState();
public enum DiskCacheMode {
NONE("none"), WRITEBACK("writeback"), WRITETHROUGH("writethrough");
private final String _diskCacheMode;
DiskCacheMode(String cacheMode) {
_diskCacheMode = cacheMode;
}
@Override
public String toString() {
return _diskCacheMode;
}
};
String getUniqueName();
boolean getUseLocalStorage();
@ -92,4 +107,8 @@ public interface DiskOffering extends InfrastructureEntity, Identity, InternalId
void setHypervisorSnapshotReserve(Integer hypervisorSnapshotReserve);
Integer getHypervisorSnapshotReserve();
DiskCacheMode getCacheMode();
void setCacheMode(DiskCacheMode cacheMode);
}

View File

@ -39,6 +39,7 @@ public class DiskProfile {
private Long bytesWriteRate;
private Long iopsReadRate;
private Long iopsWriteRate;
private String cacheMode;
private HypervisorType hyperType;
@ -190,4 +191,12 @@ public class DiskProfile {
public Long getIopsWriteRate() {
return iopsWriteRate;
}
public void setCacheMode(String cacheMode) {
this.cacheMode = cacheMode;
}
public String getCacheMode() {
return cacheMode;
}
}

View File

@ -79,6 +79,9 @@ public class DiskOfferingResponse extends BaseResponse {
@SerializedName("diskIopsWriteRate") @Param(description="io requests write rate of the disk offering")
private Long iopsWriteRate;
@SerializedName("cacheMode") @Param(description="the cache mode to use for this disk offering. none, writeback or writethrough")
private String cacheMode;
@SerializedName("displayoffering") @Param(description="whether to display the offering to the end user or not.")
private Boolean displayOffering;
@ -187,6 +190,14 @@ public class DiskOfferingResponse extends BaseResponse {
this.maxIops = maxIops;
}
public String getCacheMode() {
return this.cacheMode;
}
public void setCacheMode(String cacheMode) {
this.cacheMode = cacheMode;
}
public String getStorageType() {
return storageType;
}

View File

@ -1096,6 +1096,7 @@ label.storage.tags=Storage Tags
label.storage.traffic=Storage Traffic
label.storage.type=Storage Type
label.qos.type=QoS Type
label.cache.mode=Write-cache Type
label.storage=Storage
label.subdomain.access=Subdomain Access
label.submit=Submit

View File

@ -40,6 +40,7 @@ public class AttachVolumeCommand extends Command {
private Long bytesWriteRate;
private Long iopsReadRate;
private Long iopsWriteRate;
private String cacheMode;
protected AttachVolumeCommand() {
}
@ -202,4 +203,12 @@ public class AttachVolumeCommand extends Command {
public Long getIopsWriteRate() {
return iopsWriteRate;
}
public void setCacheMode(String cacheMode) {
this.cacheMode = cacheMode;
}
public String getCacheMode() {
return cacheMode;
}
}

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.storage.to;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.offering.DiskOffering.DiskCacheMode;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import com.cloud.agent.api.to.DataObjectType;
@ -44,6 +45,7 @@ public class VolumeObjectTO implements DataTO {
private Long bytesWriteRate;
private Long iopsReadRate;
private Long iopsWriteRate;
private DiskCacheMode cacheMode;
private Hypervisor.HypervisorType hypervisorType;
public VolumeObjectTO() {
@ -71,6 +73,7 @@ public class VolumeObjectTO implements DataTO {
this.bytesWriteRate = volume.getBytesWriteRate();
this.iopsReadRate = volume.getIopsReadRate();
this.iopsWriteRate = volume.getIopsWriteRate();
this.cacheMode = volume.getCacheMode();
this.hypervisorType = volume.getHypervisorType();
setDeviceId(volume.getDeviceId());
}
@ -231,5 +234,12 @@ public class VolumeObjectTO implements DataTO {
this.deviceId = deviceId;
}
public void setCacheMode(DiskCacheMode cacheMode) {
this.cacheMode = cacheMode;
}
public DiskCacheMode getCacheMode() {
return cacheMode;
}
}

View File

@ -20,6 +20,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.agent.api.Answer;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.offering.DiskOffering.DiskCacheMode;
import com.cloud.storage.Volume;
public interface VolumeInfo extends DataObject, Volume {
@ -45,4 +46,6 @@ public interface VolumeInfo extends DataObject, Volume {
Long getBytesWriteRate();
Long getIopsReadRate();
Long getIopsWriteRate();
DiskCacheMode getCacheMode();
}

View File

@ -24,8 +24,8 @@ import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.EnumType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@ -37,7 +37,9 @@ import javax.persistence.TemporalType;
import javax.persistence.Transient;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.DiskOffering.DiskCacheMode;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.api.Identity;
@Entity
@Table(name = "disk_offering")
@ -120,6 +122,10 @@ public class DiskOfferingVO implements DiskOffering {
@Column(name="iops_write_rate")
Long iopsWriteRate;
@Column(name="cache_mode", updatable = true, nullable=false)
@Enumerated(value=EnumType.STRING)
private DiskCacheMode cacheMode;
@Column(name="display_offering")
boolean displayOffering = true;
@ -134,6 +140,24 @@ public class DiskOfferingVO implements DiskOffering {
uuid = UUID.randomUUID().toString();
}
public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized,
Boolean isCustomizedIops, Long minIops, Long maxIops, DiskCacheMode cacheMode) {
this.domainId = domainId;
this.name = name;
this.displayText = displayText;
this.diskSize = diskSize;
this.tags = tags;
this.recreatable = false;
this.type = Type.Disk;
this.useLocalStorage = false;
this.customized = isCustomized;
this.uuid = UUID.randomUUID().toString();
this.customizedIops = isCustomizedIops;
this.minIops = minIops;
this.maxIops = maxIops;
this.cacheMode = cacheMode;
}
public DiskOfferingVO(Long domainId, String name, String displayText, long diskSize, String tags, boolean isCustomized,
Boolean isCustomizedIops, Long minIops, Long maxIops) {
this.domainId = domainId;
@ -237,6 +261,16 @@ public class DiskOfferingVO implements DiskOffering {
this.maxIops = maxIops;
}
@Override
public DiskCacheMode getCacheMode() {
return cacheMode;
}
@Override
public void setCacheMode(DiskCacheMode cacheMode) {
this.cacheMode = cacheMode;
}
@Override
public String getUniqueName() {
return uniqueName;

View File

@ -39,6 +39,7 @@ import com.cloud.agent.api.storage.DownloadAnswer;
import com.cloud.agent.api.to.DataObjectType;
import com.cloud.agent.api.to.DataTO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.offering.DiskOffering.DiskCacheMode;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Volume;
@ -214,6 +215,15 @@ public class VolumeObject implements VolumeInfo {
return null;
}
@Override
public DiskCacheMode getCacheMode() {
DiskOfferingVO diskOfferingVO = getDiskOfferingVO();
if (diskOfferingVO != null) {
return diskOfferingVO.getCacheMode();
}
return null;
}
public void update() {
volumeDao.update(volumeVO.getId(), volumeVO);
volumeVO = volumeDao.findById(volumeVO.getId());

View File

@ -193,6 +193,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuTuneDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DevicesDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskProtocol;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskCacheMode;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FeaturesDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FilesystemDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GraphicDef;
@ -1510,6 +1511,7 @@ ServerResource {
volume.setBytesWriteRate(dskch.getBytesWriteRate());
volume.setIopsReadRate(dskch.getIopsReadRate());
volume.setIopsWriteRate(dskch.getIopsWriteRate());
volume.setCacheMode(dskch.getCacheMode());
return new CreateAnswer(cmd, volume);
} catch (CloudRuntimeException e) {
s_logger.debug("Failed to create volume: " + e.toString());
@ -2815,7 +2817,8 @@ ServerResource {
cmd.getPoolUuid());
KVMPhysicalDisk disk = primary.getPhysicalDisk(cmd.getVolumePath());
attachOrDetachDisk(conn, cmd.getAttach(), cmd.getVmName(), disk,
cmd.getDeviceId().intValue(), cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate());
cmd.getDeviceId().intValue(), cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate(),
cmd.getCacheMode());
} catch (LibvirtException e) {
return new AttachVolumeAnswer(cmd, e.toString());
} catch (InternalErrorException e) {
@ -3775,6 +3778,8 @@ ServerResource {
disk.setIopsReadRate(volumeObjectTO.getIopsReadRate());
if ((volumeObjectTO.getIopsWriteRate() != null) && (volumeObjectTO.getIopsWriteRate() > 0))
disk.setIopsWriteRate(volumeObjectTO.getIopsWriteRate());
if (volumeObjectTO.getCacheMode() != null)
disk.setCacheMode(DiskDef.diskCacheMode.valueOf(volumeObjectTO.getCacheMode().toString()));
}
vm.getDevices().addDevice(disk);
}
@ -3886,7 +3891,7 @@ ServerResource {
protected synchronized String attachOrDetachDisk(Connect conn,
boolean attach, String vmName, KVMPhysicalDisk attachingDisk,
int devId, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate) throws LibvirtException, InternalErrorException {
int devId, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, String cacheMode) throws LibvirtException, InternalErrorException {
List<DiskDef> disks = null;
Domain dm = null;
DiskDef diskdef = null;
@ -3934,6 +3939,10 @@ ServerResource {
diskdef.setIopsReadRate(iopsReadRate);
if ((iopsWriteRate != null) && (iopsWriteRate > 0))
diskdef.setIopsWriteRate(iopsWriteRate);
if (cacheMode != null) {
diskdef.setCacheMode(DiskDef.diskCacheMode.valueOf(cacheMode));
}
}
String xml = diskdef.toString();

View File

@ -36,6 +36,7 @@ import org.xml.sax.SAXException;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskProtocol;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.diskCacheMode;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.nicModel;
@ -69,6 +70,7 @@ public class LibvirtDomainXMLParser {
DiskDef def = new DiskDef();
if (type.equalsIgnoreCase("network")) {
String diskFmtType = getAttrValue("driver", "type", disk);
String diskCacheMode = getAttrValue("driver", "cache", disk);
String diskPath = getAttrValue("source", "name", disk);
String protocol = getAttrValue("source", "protocol", disk);
String authUserName = getAttrValue("auth", "username", disk);
@ -78,9 +80,12 @@ public class LibvirtDomainXMLParser {
String diskLabel = getAttrValue("target", "dev", disk);
String bus = getAttrValue("target", "bus", disk);
def.defNetworkBasedDisk(diskPath, host, port, authUserName, poolUuid, diskLabel,
DiskDef.diskBus.valueOf(bus.toUpperCase()), DiskDef.diskProtocol.valueOf(protocol.toUpperCase()));
DiskDef.diskBus.valueOf(bus.toUpperCase()),
DiskDef.diskProtocol.valueOf(protocol.toUpperCase()));
def.setCacheMode(DiskDef.diskCacheMode.valueOf(diskCacheMode));
} else {
String diskFmtType = getAttrValue("driver", "type", disk);
String diskCacheMode = getAttrValue("driver", "cache", disk);
String diskFile = getAttrValue("source", "file", disk);
String diskDev = getAttrValue("source", "dev", disk);
@ -103,6 +108,7 @@ public class LibvirtDomainXMLParser {
} else if (type.equalsIgnoreCase("block")) {
def.defBlockBasedDisk(diskDev, diskLabel,
DiskDef.diskBus.valueOf(bus.toUpperCase()));
def.setCacheMode(DiskDef.diskCacheMode.valueOf(diskCacheMode));
}
}

View File

@ -427,6 +427,23 @@ public class LibvirtVMDef {
}
}
public enum diskCacheMode {
NONE("none"), WRITEBACK("writeback"), WRITETHROUGH("writethrough");
String _diskCacheMode;
diskCacheMode(String cacheMode) {
_diskCacheMode = cacheMode;
}
@Override
public String toString() {
if (_diskCacheMode == null) {
return "none";
}
return _diskCacheMode;
}
}
private deviceType _deviceType; /* floppy, disk, cdrom */
private diskType _diskType;
private diskProtocol _diskProtocol;
@ -445,6 +462,7 @@ public class LibvirtVMDef {
private Long _bytesWriteRate;
private Long _iopsReadRate;
private Long _iopsWriteRate;
private diskCacheMode _diskCacheMode;
public void setDeviceType(deviceType deviceType) {
_deviceType = deviceType;
@ -606,6 +624,10 @@ public class LibvirtVMDef {
_iopsWriteRate = iopsWriteRate;
}
public void setCacheMode(diskCacheMode cacheMode) {
_diskCacheMode = cacheMode;
}
@Override
public String toString() {
StringBuilder diskBuilder = new StringBuilder();
@ -616,7 +638,7 @@ public class LibvirtVMDef {
diskBuilder.append(" type='" + _diskType + "'");
diskBuilder.append(">\n");
diskBuilder.append("<driver name='qemu'" + " type='" + _diskFmtType
+ "' cache='none' " + "/>\n");
+ "' cache='" + _diskCacheMode + "' " + "/>\n");
if (_diskType == diskType.FILE) {
diskBuilder.append("<source ");
if (_sourcePath != null) {

View File

@ -79,6 +79,7 @@ public class DiskOfferingJoinDaoImpl extends GenericDaoBase<DiskOfferingJoinVO,
diskOfferingResponse.setBytesWriteRate(offering.getBytesWriteRate());
diskOfferingResponse.setIopsReadRate(offering.getIopsReadRate());
diskOfferingResponse.setIopsWriteRate(offering.getIopsWriteRate());
diskOfferingResponse.setCacheMode(offering.getCacheMode());
diskOfferingResponse.setObjectName("diskoffering");
return diskOfferingResponse;

View File

@ -85,6 +85,9 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
@Column(name="iops_write_rate")
Long iopsWriteRate;
@Column(name="cache_mode")
String cacheMode;
@Column(name="type")
Type type;
@ -162,6 +165,18 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
return maxIops;
}
public void setMaxIops(Long maxIops) {
this.maxIops = maxIops;
}
public String getCacheMode() {
return cacheMode;
}
public void setCacheMode(String cacheMode) {
this.cacheMode = cacheMode;
}
public boolean isDisplayOffering() {
return displayOffering;
}

View File

@ -1078,6 +1078,7 @@ dictionary = {
'label.storage.tags': '<fmt:message key="label.storage.tags" />',
'label.storage.type': '<fmt:message key="label.storage.type" />',
'label.qos.type': '<fmt:message key="label.qos.type" />',
'label.cache.mode': '<fmt:message key="label.cache.mode" />',
'label.subdomain.access': '<fmt:message key="label.subdomain.access" />',
'label.submit': '<fmt:message key="label.submit" />',
'label.submitted.by': '<fmt:message key="label.submitted.by" />',

View File

@ -1354,6 +1354,28 @@
number: true
}
},
cacheMode: {
label: 'label.cache.mode',
docID: 'helpDiskOfferingCacheMode',
select: function(args) {
var items = [];
items.push({
id: 'none',
description: 'No disk cache'
});
items.push({
id: 'writeback',
description: 'Write-back disk caching'
});
items.push({
id: 'writethrough',
description: 'Write-through disk caching'
});
args.response.success({
data: items
});
}
},
tags: {
label: 'label.storage.tags',
docID: 'helpDiskOfferingStorageTags'
@ -1400,6 +1422,7 @@
name: args.data.name,
displaytext: args.data.description,
storageType: args.data.storageType,
cacheMode: args.data.cacheMode,
customized: (args.data.isCustomized == "on")
};
@ -1626,6 +1649,9 @@
diskIopsWriteRate: {
label: 'label.disk.iops.write.rate'
},
cacheMode: {
label: 'label.cache.mode',
},
tags: {
label: 'label.storage.tags'
},

View File

@ -328,6 +328,9 @@ cloudStack.docs = {
},
helpDiskOfferingHypervisorSnapshotReserve: {
desc: 'Hypervisor snapshot reserve space as a percent of a volume (for managed storage using Xen or VMware) (Ex. The value 25 means 25%.)).',
},
helpDiskOfferingCacheMode: {
desc: 'The write caching mode to use for disks created with this disk offering. This can improve write performance.',
externalLink: ''
},
helpDiskOfferingStorageTags: {