-
Notifications
You must be signed in to change notification settings - Fork 0
<feature>[vm_local_volume_cache]: vm local volume cache imp #3484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature-5.5.6-local-cache
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,11 +23,8 @@ | |
| import org.zstack.header.image.ImageConstant; | ||
| import org.zstack.header.image.ImageConstant.ImageMediaType; | ||
| import org.zstack.header.message.MessageReply; | ||
| import org.zstack.header.vm.VmInstanceConstant; | ||
| import org.zstack.header.vm.VmInstanceSpec; | ||
| import org.zstack.header.vm.*; | ||
| import org.zstack.header.vm.VmInstanceSpec.VolumeSpec; | ||
| import org.zstack.header.vm.VmInstanceVO; | ||
| import org.zstack.header.vm.VmInstanceVO_; | ||
| import org.zstack.header.volume.*; | ||
| import org.zstack.header.volume.VolumeDeletionPolicyManager.VolumeDeletionPolicy; | ||
| import org.zstack.identity.AccountManager; | ||
|
|
@@ -76,6 +73,19 @@ protected List<CreateVolumeMsg> prepareMsg(Map<String, Object> ctx) { | |
| } | ||
| }); | ||
| } | ||
| if (!spec.getDataDiskCacheConfigOnIndex().isEmpty() && !CollectionUtils.isEmpty(spec.getDataDiskOfferings())) { | ||
| List<VolumeSpec> dataVolumeSpecs = spec.getVolumeSpecs().stream() | ||
| .filter(s -> s.getType().equals(VolumeType.Data.toString())).collect(Collectors.toList()); | ||
|
|
||
| IntStream.range(0, dataVolumeSpecs.size()).forEach(index -> { | ||
| APICreateVmInstanceMsg.VolumeCacheConfig config = spec.getDataDiskCacheConfigOnIndex().get(index); | ||
| if (config != null) { | ||
| dataVolumeSpecs.get(index).setEnableVolumeCache(true); | ||
| dataVolumeSpecs.get(index).setCachePoolUuid(config.getCachePoolUuid()); | ||
| dataVolumeSpecs.get(index).setCacheMode(config.getCacheMode()); | ||
| } | ||
| }); | ||
| } | ||
|
Comment on lines
+76
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 给 Line 76 直接对新 map 调 💡 建议修改- if (!spec.getDataDiskCacheConfigOnIndex().isEmpty() && !CollectionUtils.isEmpty(spec.getDataDiskOfferings())) {
+ Map<Integer, APICreateVmInstanceMsg.VolumeCacheConfig> dataDiskCacheConfigs = spec.getDataDiskCacheConfigOnIndex();
+ if (dataDiskCacheConfigs != null && !dataDiskCacheConfigs.isEmpty()
+ && !CollectionUtils.isEmpty(spec.getDataDiskOfferings())) {
List<VolumeSpec> dataVolumeSpecs = spec.getVolumeSpecs().stream()
.filter(s -> s.getType().equals(VolumeType.Data.toString())).collect(Collectors.toList());
IntStream.range(0, dataVolumeSpecs.size()).forEach(index -> {
- APICreateVmInstanceMsg.VolumeCacheConfig config = spec.getDataDiskCacheConfigOnIndex().get(index);
+ APICreateVmInstanceMsg.VolumeCacheConfig config = dataDiskCacheConfigs.get(index);
if (config != null) {
dataVolumeSpecs.get(index).setEnableVolumeCache(true);
dataVolumeSpecs.get(index).setCachePoolUuid(config.getCachePoolUuid());🤖 Prompt for AI Agents |
||
|
|
||
| List<VolumeSpec> volumeSpecs = spec.getVolumeSpecs(); | ||
| List<CreateVolumeMsg> msgs = new ArrayList<>(volumeSpecs.size()); | ||
|
|
@@ -93,6 +103,9 @@ protected List<CreateVolumeMsg> prepareMsg(Map<String, Object> ctx) { | |
| DebugUtils.Assert(vspec.getType() != null, "VolumeType can not be null!"); | ||
|
|
||
| if (VolumeType.Root.toString().equals(vspec.getType())) { | ||
| vspec.setEnableVolumeCache(spec.getEnableRootVolumeCache()); | ||
| vspec.setCachePoolUuid(spec.getRootVolumeCachePoolUuid()); | ||
| vspec.setCacheMode(spec.getRootVolumeCacheMode()); | ||
|
Comment on lines
+106
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
fd 'VmInstanceSpec\.java$' | while read -r f; do
echo "== $f =="
rg -n -C3 'Boolean\s+enableRootVolumeCache|getEnableRootVolumeCache|setEnableVolumeCache\(' "$f"
doneRepository: MatheMatrix/zstack Length of output: 1027 🏁 Script executed: #!/bin/bash
# Find VmAllocateVolumeFlow.java and check lines around 106-108
fd 'VmAllocateVolumeFlow\.java$' | while read -r f; do
echo "== $f =="
sed -n '100,115p' "$f"
echo ""
echo "== Checking VolumeSpec setter methods =="
done
# Also find VolumeSpec to check all setter parameter types
echo "=== VolumeSpec class ==="
fd 'VolumeSpec\.java$' | while read -r f; do
echo "== $f =="
rg -n -A1 'setCachePoolUuid|setCacheMode|setEnableVolumeCache' "$f"
doneRepository: MatheMatrix/zstack Length of output: 1130 🏁 Script executed: #!/bin/bash
# Find VolumeSpec more broadly
fd 'VolumeSpec' --type f | grep -E '\.java$' | head -20
# Search for setCachePoolUuid and setCacheMode definitions
echo "=== Searching for setCachePoolUuid and setCacheMode ==="
rg -n 'setCachePoolUuid|setCacheMode' --type java -A2 | head -50Repository: MatheMatrix/zstack Length of output: 4345 🏁 Script executed: #!/bin/bash
# Search for getRootVolumeCachePoolUuid and getRootVolumeCacheMode getters in VmInstanceSpec
rg -n 'getRootVolumeCachePoolUuid|getRootVolumeCacheMode|rootVolumeCachePoolUuid|rootVolumeCacheMode' header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java -A2Repository: MatheMatrix/zstack Length of output: 788 避免在根盘默认路径上对 Line 106 中, - vspec.setEnableVolumeCache(spec.getEnableRootVolumeCache());
+ vspec.setEnableVolumeCache(Boolean.TRUE.equals(spec.getEnableRootVolumeCache()));Line 107 与 108 的 🤖 Prompt for AI Agents |
||
| msg.setResourceUuid((String) ctx.get("uuid")); | ||
| msg.setName("ROOT-for-" + spec.getVmInventory().getName()); | ||
| msg.setDescription(String.format("Root volume for VM[uuid:%s]", spec.getVmInventory().getUuid())); | ||
|
|
@@ -116,7 +129,13 @@ protected List<CreateVolumeMsg> prepareMsg(Map<String, Object> ctx) { | |
| } else { | ||
| continue; | ||
| } | ||
|
|
||
| if (vspec.getEnableVolumeCache()) { | ||
| tags.add("volumeCache::enable"); | ||
| tags.add("volumeCache::cacheMode::" + vspec.getCacheMode()); | ||
| if(vspec.getCachePoolUuid() != null) { | ||
| tags.add("volumeCache::poolUuid::" + vspec.getCachePoolUuid()); | ||
| } | ||
| } | ||
|
Comment on lines
+132
to
+138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 不要把未配置的 Line 134 对 💡 建议修改 if (vspec.getEnableVolumeCache()) {
tags.add("volumeCache::enable");
- tags.add("volumeCache::cacheMode::" + vspec.getCacheMode());
+ if (vspec.getCacheMode() == null || vspec.getCacheMode().isEmpty()) {
+ throw new CloudRuntimeException(String.format(
+ "cacheMode cannot be empty when volume cache is enabled, vmUuid:%s, volumeType:%s",
+ spec.getVmInventory().getUuid(), vspec.getType()));
+ }
+ tags.add("volumeCache::cacheMode::" + vspec.getCacheMode());
if(vspec.getCachePoolUuid() != null) {
tags.add("volumeCache::poolUuid::" + vspec.getCachePoolUuid());
}🤖 Prompt for AI Agents |
||
| msg.setSystemTags(new ArrayList<>(tags)); | ||
| msg.setDiskOfferingUuid(vspec.getDiskOfferingUuid()); | ||
| msg.setSize(vspec.getSize()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.beans.factory.annotation.Configurable; | ||
| import org.zstack.compute.allocator.HostAllocatorManager; | ||
| import org.zstack.core.Platform; | ||
| import org.zstack.core.cloudbus.CloudBus; | ||
| import org.zstack.core.cloudbus.CloudBusCallBack; | ||
| import org.zstack.core.componentloader.PluginRegistry; | ||
|
|
@@ -18,6 +19,7 @@ | |
| import org.zstack.header.errorcode.ErrorCode; | ||
| import org.zstack.header.image.ImageBackupStorageRefVO; | ||
| import org.zstack.header.image.ImageVO; | ||
| import org.zstack.header.localVolumeCache.*; | ||
| import org.zstack.header.message.MessageReply; | ||
| import org.zstack.header.storage.backup.BackupStorageVO; | ||
| import org.zstack.header.storage.backup.BackupStorageVO_; | ||
|
|
@@ -60,6 +62,23 @@ public class VmInstantiateOtherDiskFlow implements Flow { | |
| this.diskAO = diskAO; | ||
| } | ||
|
|
||
| private VmLocalVolumeCacheVO initCacheRecord() { | ||
| VmLocalVolumeCacheVO existing = Q.New(VmLocalVolumeCacheVO.class) | ||
| .eq(VmLocalVolumeCacheVO_.volumeUuid, volumeInventory.getUuid()) | ||
| .find(); | ||
| if (existing != null) { | ||
| return existing; | ||
| } | ||
| VmLocalVolumeCacheVO cacheVO = new VmLocalVolumeCacheVO(); | ||
| cacheVO.setUuid(Platform.getUuid()); | ||
| cacheVO.setVolumeUuid(volumeInventory.getUuid()); | ||
| cacheVO.setState(VmLocalVolumeCacheState.Uninstantiated); | ||
| cacheVO.setCacheMode(VmLocalVolumeCacheMode.valueOf(diskAO.getCacheMode())); | ||
| cacheVO.setPoolUuid(diskAO.getCachePoolUuid()); | ||
| dbf.persist(cacheVO); | ||
| return cacheVO; | ||
| } | ||
|
Comment on lines
+65
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 缓存记录创建缺少回滚清理,失败路径会遗留脏数据。
🧹 建议修复(记录“本次是否新建”,并在 rollback 清理)@@
- VolumeInventory volumeInventory;
+ VolumeInventory volumeInventory;
+ String createdCacheRecordUuid;
@@
private VmLocalVolumeCacheVO initCacheRecord() {
VmLocalVolumeCacheVO existing = Q.New(VmLocalVolumeCacheVO.class)
.eq(VmLocalVolumeCacheVO_.volumeUuid, volumeInventory.getUuid())
.find();
if (existing != null) {
return existing;
}
VmLocalVolumeCacheVO cacheVO = new VmLocalVolumeCacheVO();
cacheVO.setUuid(Platform.getUuid());
@@
cacheVO.setPoolUuid(diskAO.getCachePoolUuid());
dbf.persist(cacheVO);
+ createdCacheRecordUuid = cacheVO.getUuid();
return cacheVO;
}// 建议补充到 rollback(...) 开头(位于当前变更段之外)
if (createdCacheRecordUuid != null) {
VmLocalVolumeCacheVO cacheVO = Q.New(VmLocalVolumeCacheVO.class)
.eq(VmLocalVolumeCacheVO_.uuid, createdCacheRecordUuid)
.find();
if (cacheVO != null) {
dbf.remove(cacheVO);
}
}Also applies to: 421-436 🤖 Prompt for AI Agents |
||
|
|
||
| @Override | ||
| public void run(FlowTrigger trigger, Map data) { | ||
| VmInstanceInventory instantiateVm = (VmInstanceInventory) data.get(VmInstanceInventory.class.getSimpleName()); | ||
|
|
@@ -398,6 +417,23 @@ public void run(MessageReply reply) { | |
| }); | ||
| } | ||
| }); | ||
|
|
||
| // Enable volume cache if requested for this DiskAO | ||
| if (Boolean.TRUE.equals(diskAO.getEnableCache())) { | ||
| flow(new NoRollbackFlow() { | ||
| String __name__ = String.format("create-cache-record-for-diskAO-volume-on-vm-%s", vmUuid); | ||
|
|
||
| @Override | ||
| public void run(final FlowTrigger innerTrigger, Map data) { | ||
| if (volumeInventory == null) { | ||
| innerTrigger.next(); | ||
| return; | ||
| } | ||
| initCacheRecord(); | ||
| innerTrigger.next(); | ||
| } | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| private void setupAttachOtherDiskFlows() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| CREATE TABLE IF NOT EXISTS `VmLocalVolumeCachePoolVO` ( | ||
| `uuid` VARCHAR(32) NOT NULL, | ||
| `hostUuid` VARCHAR(32) NOT NULL, | ||
| `name` VARCHAR(255) DEFAULT NULL, | ||
| `description` VARCHAR(2048) DEFAULT NULL, | ||
| `metadata` VARCHAR(2048) DEFAULT NULL, | ||
| `state` VARCHAR(32) NOT NULL, | ||
| `status` VARCHAR(32) NOT NULL, | ||
| `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', | ||
| `lastOpDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| PRIMARY KEY (`uuid`), | ||
| CONSTRAINT `fkVmLocalVolumeCachePoolVOHostEO` | ||
| FOREIGN KEY (`hostUuid`) REFERENCES `HostEO` (`uuid`) | ||
| ON DELETE CASCADE | ||
| ) ENGINE = InnoDB DEFAULT CHARSET = utf8; | ||
|
|
||
| CREATE TABLE IF NOT EXISTS `VmLocalVolumeCachePoolCapacityVO` ( | ||
| `uuid` VARCHAR(32) NOT NULL, | ||
| `totalCapacity` BIGINT NOT NULL DEFAULT 0, | ||
| `availableCapacity` BIGINT NOT NULL DEFAULT 0, | ||
| `allocated` BIGINT NOT NULL DEFAULT 0, | ||
| `dirty` BIGINT NOT NULL DEFAULT 0, | ||
| PRIMARY KEY (`uuid`), | ||
| CONSTRAINT `fkVmLocalVolumeCachePoolCapacityVOVmLocalVolumeCachePoolVO` | ||
| FOREIGN KEY (`uuid`) REFERENCES `VmLocalVolumeCachePoolVO` (`uuid`) | ||
| ON DELETE CASCADE | ||
| ) ENGINE = InnoDB DEFAULT CHARSET = utf8; | ||
|
|
||
| CREATE TABLE IF NOT EXISTS `VmLocalVolumeCacheVO` ( | ||
| `uuid` VARCHAR(32) NOT NULL, | ||
| `volumeUuid` VARCHAR(32) NOT NULL, | ||
| `poolUuid` VARCHAR(32) DEFAULT NULL, | ||
| `installPath` VARCHAR(2048) DEFAULT NULL, | ||
| `cacheMode` VARCHAR(32) NOT NULL, | ||
| `state` VARCHAR(32) NOT NULL, | ||
| `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', | ||
| `lastOpDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| PRIMARY KEY (`uuid`), | ||
| UNIQUE KEY `uniVmLocalVolumeCacheVOVolumeUuid` (`volumeUuid`), | ||
| CONSTRAINT `fkVmLocalVolumeCacheVOVolumeEO` | ||
| FOREIGN KEY (`volumeUuid`) REFERENCES `VolumeEO` (`uuid`) | ||
| ON DELETE CASCADE, | ||
| CONSTRAINT `fkVmLocalVolumeCacheVOPoolUuid` | ||
| FOREIGN KEY (`poolUuid`) REFERENCES `VmLocalVolumeCachePoolVO` (`uuid`) | ||
| ON DELETE SET NULL | ||
| ) ENGINE = InnoDB DEFAULT CHARSET = utf8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
潜在的 IndexOutOfBoundsException 风险
代码使用
dataDiskCacheConfigs.keySet()中的index直接访问spec.getDataDiskOfferings().get(index),但没有验证index是否在DataDiskOfferings列表的有效范围内。如果用户配置的 cache 索引超出了实际数据盘数量,将抛出IndexOutOfBoundsException。此外,第 161 行声明的变量
dataDiskCacheConfig未被使用,属于无用代码。🛡️ 建议添加边界检查并移除无用变量
Map<Integer, APICreateVmInstanceMsg.VolumeCacheConfig> dataDiskCacheConfigs = spec.getDataDiskCacheConfigOnIndex(); if (dataDiskCacheConfigs != null && !dataDiskCacheConfigs.isEmpty()) { + List<DiskOfferingInventory> dataDisks = spec.getDataDiskOfferings(); for (Integer index : dataDiskCacheConfigs.keySet()) { - APICreateVmInstanceMsg.VolumeCacheConfig dataDiskCacheConfig = dataDiskCacheConfigs.get(index); - totalCacheSize += spec.getDataDiskOfferings().get(index).getDiskSize(); + if (index >= 0 && index < dataDisks.size()) { + totalCacheSize += dataDisks.get(index).getDiskSize(); + } } - }📝 Committable suggestion
🤖 Prompt for AI Agents