package org.zstack.header.storage.snapshot;
import org.zstack.utils.DebugUtils;
import org.zstack.utils.function.Function;
import java.util.*;
/**
*/
public class VolumeSnapshotTree {
/**
* @inventory inventory for volume snapshot tree leaf
* @category volume snapshot
* @example {
* "inventory": {
* "uuid": "59187fd8ae914927b8b3be7c51aae035",
* "name": "Snapshot-d71b1fffebb143549dadbecd82aac998",
* "description": "Test snapshot",
* "type": "Hypervisor",
* "volumeUuid": "d71b1fffebb143549dadbecd82aac998",
* "treeUuid": "4c4fdfe0ec4b47528c23047b140ed577",
* "hypervisorType": "KVM",
* "primaryStorageUuid": "342ecf7e70a44f6ba81dc0533aad2b8d",
* "primaryStorageInstallPath": "/opt/zstack/nfsprimarystorage/prim-342ecf7e70a44f6ba81dc0533aad2b8d/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-d71b1fffebb143549dadbecd82aac998/snapshots/59187fd8ae914927b8b3be7c51aae035.qcow2",
* "type": "Root",
* "latest": false,
* "size": 10485760,
* "state": "Enabled",
* "status": "Ready",
* "createDate": "May 3, 2014 12:17:22 PM",
* "lastOpDate": "May 3, 2014 12:17:22 PM",
* "backupStorageRefs": [
* {
* "volumeSnapshotUuid": "59187fd8ae914927b8b3be7c51aae035",
* "backupStorageUuid": "23a96d7b4305453f9413020efaca64b2",
* "installPath": "nfs:/test/volumeSnapshots/acct-36c27e8ff05c4780bf6d2fa65700f22e/59187fd8ae914927b8b3be7c51aae035/59187fd8ae914927b8b3be7c51aae035.qcow2"
* }
* ]
* },
* "children": [
* {
* "inventory": {
* "uuid": "7ba07e804fd24a8fa6b2a3f04bb8ad94",
* "name": "Snapshot-d71b1fffebb143549dadbecd82aac998",
* "description": "Test snapshot",
* "type": "Hypervisor",
* "volumeUuid": "d71b1fffebb143549dadbecd82aac998",
* "treeUuid": "4c4fdfe0ec4b47528c23047b140ed577",
* "hypervisorType": "KVM",
* "parentUuid": "59187fd8ae914927b8b3be7c51aae035",
* "primaryStorageUuid": "342ecf7e70a44f6ba81dc0533aad2b8d",
* "primaryStorageInstallPath": "/opt/zstack/nfsprimarystorage/prim-342ecf7e70a44f6ba81dc0533aad2b8d/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-d71b1fffebb143549dadbecd82aac998/snapshots/7ba07e804fd24a8fa6b2a3f04bb8ad94.qcow2",
* "type": "Root",
* "latest": false,
* "size": 10485760,
* "state": "Enabled",
* "status": "Ready",
* "createDate": "May 3, 2014 12:17:22 PM",
* "lastOpDate": "May 3, 2014 12:17:22 PM",
* "backupStorageRefs": [
* {
* "volumeSnapshotUuid": "7ba07e804fd24a8fa6b2a3f04bb8ad94",
* "backupStorageUuid": "23a96d7b4305453f9413020efaca64b2",
* "installPath": "nfs:/test/volumeSnapshots/acct-36c27e8ff05c4780bf6d2fa65700f22e/7ba07e804fd24a8fa6b2a3f04bb8ad94/7ba07e804fd24a8fa6b2a3f04bb8ad94.qcow2"
* }
* ]
* },
* "parentUuid": "59187fd8ae914927b8b3be7c51aae035",
* "children": [
* {
* "inventory": {
* "uuid": "e90f94533871408ab945396653208026",
* "name": "Snapshot-d71b1fffebb143549dadbecd82aac998",
* "description": "Test snapshot",
* "type": "Hypervisor",
* "volumeUuid": "d71b1fffebb143549dadbecd82aac998",
* "treeUuid": "4c4fdfe0ec4b47528c23047b140ed577",
* "hypervisorType": "KVM",
* "parentUuid": "7ba07e804fd24a8fa6b2a3f04bb8ad94",
* "primaryStorageUuid": "342ecf7e70a44f6ba81dc0533aad2b8d",
* "primaryStorageInstallPath": "/opt/zstack/nfsprimarystorage/prim-342ecf7e70a44f6ba81dc0533aad2b8d/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-d71b1fffebb143549dadbecd82aac998/snapshots/e90f94533871408ab945396653208026.qcow2",
* "type": "Root",
* "latest": false,
* "size": 10485760,
* "state": "Enabled",
* "status": "Ready",
* "createDate": "May 3, 2014 12:17:22 PM",
* "lastOpDate": "May 3, 2014 12:17:22 PM",
* "backupStorageRefs": [
* {
* "volumeSnapshotUuid": "e90f94533871408ab945396653208026",
* "backupStorageUuid": "23a96d7b4305453f9413020efaca64b2",
* "installPath": "nfs:/test/volumeSnapshots/acct-36c27e8ff05c4780bf6d2fa65700f22e/e90f94533871408ab945396653208026/e90f94533871408ab945396653208026.qcow2"
* }
* ]
* },
* "parentUuid": "7ba07e804fd24a8fa6b2a3f04bb8ad94",
* "children": [
* {
* "inventory": {
* "uuid": "bf534fd8305d4c56aa3842b2c3dd52ab",
* "name": "Snapshot-d71b1fffebb143549dadbecd82aac998",
* "description": "Test snapshot",
* "type": "Hypervisor",
* "volumeUuid": "d71b1fffebb143549dadbecd82aac998",
* "treeUuid": "4c4fdfe0ec4b47528c23047b140ed577",
* "hypervisorType": "KVM",
* "parentUuid": "e90f94533871408ab945396653208026",
* "primaryStorageUuid": "342ecf7e70a44f6ba81dc0533aad2b8d",
* "primaryStorageInstallPath": "/opt/zstack/nfsprimarystorage/prim-342ecf7e70a44f6ba81dc0533aad2b8d/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-d71b1fffebb143549dadbecd82aac998/snapshots/bf534fd8305d4c56aa3842b2c3dd52ab.qcow2",
* "type": "Root",
* "latest": true,
* "size": 10485760,
* "state": "Enabled",
* "status": "Ready",
* "createDate": "May 3, 2014 12:17:22 PM",
* "lastOpDate": "May 3, 2014 12:17:22 PM",
* "backupStorageRefs": [
* {
* "volumeSnapshotUuid": "bf534fd8305d4c56aa3842b2c3dd52ab",
* "backupStorageUuid": "23a96d7b4305453f9413020efaca64b2",
* "installPath": "nfs:/test/volumeSnapshots/acct-36c27e8ff05c4780bf6d2fa65700f22e/bf534fd8305d4c56aa3842b2c3dd52ab/bf534fd8305d4c56aa3842b2c3dd52ab.qcow2"
* }
* ]
* },
* "parentUuid": "e90f94533871408ab945396653208026",
* "children": []
* }
* ]
* }
* ]
* }
* ]
* }
* @since 0.1.0
*/
public static class SnapshotLeafInventory {
/**
* @desc see :ref:`VolumeSnapshotInventory`
*/
private VolumeSnapshotInventory inventory;
/**
* @desc parent snapshot uuid. Null if this leaf is the tree root
* @nullable
*/
private String parentUuid;
/**
* @desc a list of children which are :ref:`SnapshotLeafInventory` as well
*/
private List<SnapshotLeafInventory> children = new ArrayList<SnapshotLeafInventory>();
public VolumeSnapshotInventory getInventory() {
return inventory;
}
public void setInventory(VolumeSnapshotInventory inventory) {
this.inventory = inventory;
}
public String getParentUuid() {
return parentUuid;
}
public void setParentUuid(String parentUuid) {
this.parentUuid = parentUuid;
}
public List<SnapshotLeafInventory> getChildren() {
return children;
}
public void setChildren(List<SnapshotLeafInventory> children) {
this.children = children;
}
}
public static class SnapshotLeaf {
private VolumeSnapshotInventory inventory;
private SnapshotLeaf parent;
private List<SnapshotLeaf> children = new ArrayList<SnapshotLeaf>();
private List<VolumeSnapshotInventory> descendants;
private List<VolumeSnapshotInventory> ancestors;
public VolumeSnapshotInventory getInventory() {
return inventory;
}
public void setInventory(VolumeSnapshotInventory inventory) {
this.inventory = inventory;
}
public SnapshotLeaf getParent() {
return parent;
}
public void setParent(SnapshotLeaf parent) {
this.parent = parent;
}
public List<SnapshotLeaf> getChildren() {
return children;
}
public void setChildren(List<SnapshotLeaf> children) {
this.children = children;
}
public String getUuid() {
return inventory.getUuid();
}
public void setUuid(String uuid) {
if (inventory == null) {
inventory = new VolumeSnapshotInventory();
}
inventory.setUuid(uuid);
}
public VolumeSnapshotTree toSubTree() {
VolumeSnapshotTree tree = new VolumeSnapshotTree();
tree.root = this;
tree.volumeUuid = inventory.getVolumeUuid();
return tree;
}
private SnapshotLeaf walkUp(SnapshotLeaf leaf, Function<Boolean, VolumeSnapshotInventory> func) {
if (func.call(leaf.inventory)) {
return leaf;
}
if (leaf.getParent() == null) {
return null;
}
return walkUp(leaf.getParent(), func);
}
public SnapshotLeaf walkUp(Function<Boolean, VolumeSnapshotInventory> func) {
if (func.call(inventory)) {
return this;
}
if (getParent() == null) {
return null;
}
return walkUp(getParent(), func);
}
public SnapshotLeaf walkDown(Function<Boolean, VolumeSnapshotInventory> func) {
return walkDown(this, func);
}
private SnapshotLeaf walkDown(SnapshotLeaf leaf, Function<Boolean, VolumeSnapshotInventory> func) {
if (func.call(leaf.inventory)) {
return leaf;
}
if (leaf.getChildren().isEmpty()) {
return null;
}
for (SnapshotLeaf l : leaf.getChildren()) {
SnapshotLeaf ret = walkDown(l, func);
if (ret != null) {
return ret;
}
}
return null;
}
public List<VolumeSnapshotInventory> getDescendants() {
if (descendants == null) {
descendants = new ArrayList<VolumeSnapshotInventory>();
walkDown(new Function<Boolean, VolumeSnapshotInventory>() {
@Override
public Boolean call(VolumeSnapshotInventory arg) {
descendants.add(arg);
return false;
}
});
}
return descendants;
}
public List<VolumeSnapshotInventory> getAncestors() {
if (ancestors == null) {
ancestors = new ArrayList<VolumeSnapshotInventory>();
walkUp(new Function<Boolean, VolumeSnapshotInventory>() {
@Override
public Boolean call(VolumeSnapshotInventory arg) {
ancestors.add(arg);
return false;
}
});
Collections.reverse(ancestors);
}
return ancestors;
}
public SnapshotLeafInventory toLeafInventory() {
SnapshotLeafInventory leafInventory = new SnapshotLeafInventory();
leafInventory.setInventory(getInventory());
if (parent != null) {
leafInventory.setParentUuid(parent.getUuid());
}
for (SnapshotLeaf leaf : children) {
leafInventory.getChildren().add(leaf.toLeafInventory());
}
return leafInventory;
}
}
private SnapshotLeaf root;
private String volumeUuid;
public static VolumeSnapshotTree fromInventories(List<VolumeSnapshotInventory> invs) {
VolumeSnapshotTree tree = new VolumeSnapshotTree();
Map<String, SnapshotLeaf> map = new HashMap<String, SnapshotLeaf>();
for (VolumeSnapshotInventory inv : invs) {
SnapshotLeaf leaf = map.get(inv.getUuid());
if (leaf == null) {
leaf = new SnapshotLeaf();
leaf.inventory = inv;
map.put(inv.getUuid(), leaf);
} else {
leaf.inventory = inv;
}
if (inv.getParentUuid() != null) {
SnapshotLeaf parent = map.get(inv.getParentUuid());
if (parent == null) {
parent = new SnapshotLeaf();
parent.setUuid(inv.getParentUuid());
map.put(parent.getUuid(), parent);
}
parent.children.add(leaf);
leaf.parent = parent;
} else {
tree.root = leaf;
}
tree.volumeUuid = inv.getVolumeUuid();
}
DebugUtils.Assert(tree.root != null, "why tree root is null???");
return tree;
}
public static VolumeSnapshotTree fromVOs(List<VolumeSnapshotVO> vos) {
return fromInventories(VolumeSnapshotInventory.valueOf(vos));
}
public SnapshotLeaf getRoot() {
return root;
}
public void setRoot(SnapshotLeaf root) {
this.root = root;
}
public String getVolumeUuid() {
return volumeUuid;
}
public void setVolumeUuid(String volumeUuid) {
this.volumeUuid = volumeUuid;
}
private SnapshotLeaf findSnapshot(final List<SnapshotLeaf> leafs, final Function<Boolean, VolumeSnapshotInventory> func) {
for (SnapshotLeaf leaf : leafs) {
SnapshotLeaf ret = findSnapshot(leaf.children, func);
if (ret != null) {
return ret;
}
if (func.call(leaf.getInventory())) {
return leaf;
}
}
return null;
}
public SnapshotLeaf findSnapshot(Function<Boolean, VolumeSnapshotInventory> func) {
if (func.call(root.getInventory())) {
return root;
}
return findSnapshot(root.children, func);
}
}