目录

前文列表

VMware 虚拟化编程(1) — VMDK/VDDK/VixDiskLib/VADP 概念简析

VMware 虚拟化编程(2) — 虚拟磁盘文件类型详解

VMware 虚拟化编程(3) —VMware vSphere Web Service API 解析

VMware 虚拟化编程(4) — VDDK 安装

VMware 虚拟化编程(5) — VixDiskLib 虚拟磁盘库详解之一

VMware 虚拟化编程(6) — VixDiskLib 虚拟磁盘库详解之二

VMware 虚拟化编程(7) — VixDiskLib 虚拟磁盘库详解之三

VMware 虚拟化编程(8) — 多线程中的 VixDiskLib

VMware 虚拟化编程(9) — VMware 虚拟机的快照

VMware 虚拟化编程(10) — VMware 数据块修改跟踪技术 CBT

VMware 虚拟化编程(11) — VMware 虚拟机的全量备份与增量备份方案

VMware 虚拟化编程(12) — VixDiskLib Sample 程序使用

VMware 虚拟化编程(13) — VMware 虚拟机的备份方案设计

VMware 虚拟化编程(14) — VDDK 的高级传输模式详解

将已存在的虚拟机恢复到指定时间点

  • 使用 vSphere WS API 连接到 VC/ESXi。
  • 使用 vSphere WS API 关闭恢复目标虚拟机的电源,因为 VixDiskLib 对正在运行的虚拟机磁盘没有写权限。
  • 使用 VixDiskLib 连接到恢复目标虚拟机的虚拟磁盘,如果使用 SAN、HotAdd、NBDSSL 高级传输模式来进行连接,还需要在执行恢复数据操作前创建一个临时快照。对于 SAN 传输模式,如果在创建临时快照前就已经存在快照了,那么你就需要在创建临时快照前确保移除了之前的所有快照,否则 SAN 传输模式的还原会失败。
  • 使用 VixDiskLib 的 VixDiskLib_Write 将备份数据恢复到虚拟磁盘。恢复磁盘数据的前提是需要获得恢复目标虚拟磁盘当前实际的全称(包括一些序列号),否则备份数据无法正确定位到恢复目标虚拟磁盘,因为当前恢复目标虚拟机的虚拟磁盘可能从一个或多个快照继承而来。VixDiskLib_Write 函数以偶数扇区为单位传输数据,且传输长度必须为扇区大小的偶数倍。
  • 如果创建了临时快照,还需要使用 vSphere WS API 删除快照。尤其对于 SAN 传输模式,还需要先恢复临时快照,然后再删除临时快照。如果没有恢复临时快照,就会因为 CID 不匹配导致无法删除临时快照。如果临时快照没有删除,会导致虚拟机不能开机,而且这个临时快照还会引起后续备份的还原问题。
  • 使用 vSphere WS API 开启恢复目标虚拟机的电源。

恢复为新建虚拟机 (灾难恢复)

  • 使用 vSphere WS API 连接 VC/ESXi
  • 使用 vSphere WS API 来创建新的虚拟机和虚拟磁盘,需要使用在备份时保存的虚拟机配置信息(VirtualMachineConfigInfo)。
  • 使用 VixDiskLib 的 VixDiskLib_WriteMetadata 写入虚拟磁盘元数据。
  • 使用 VixDiskLib 的 VixDiskLib_Write 将备份数据恢复到新建的虚拟磁盘。
  • 使用 vSphere WS API 开启新建虚拟机的电源。

恢复细节

恢复增量备份数据

  • 使用 vSphere WS API 关闭虚拟机电源。
  • 使用 vSphere WS API 来创建新的虚拟机和虚拟磁盘,需要使用在备份时保存的虚拟机配置信息(VirtualMachineConfigInfo)。
  • 使用 VixDiskLib 的 VixDiskLib_Write 把全量备份数据恢复到新建的虚拟磁盘中作为基准虚拟磁盘(Base Disk),进行全量恢复的期间,需要关闭 CBT。
  • 使用 vSphere WS API 创建一个快照,这在高级传输模式下是必须的。
  • 对于 SAN 传输模式的恢复,也需要禁用 CBT,否则增量数据的 VixDiskLib_Write 写操作不可用,这是因为文件系统需要统计精简置备虚拟磁盘(Thin)的分配状况以及进行延迟清零(Lazy Zeroed)的操作。
  • 使用 VixDiskLib 的 VixDiskLib_Write 依次恢复增量备份数据到虚拟磁盘。
    • 如果你向前还原,还原时某些相同的扇区可能会被写入多次。
    • 如果你向后还原,必须手动记录哪些扇区已经更新过了,以避免再次写入更旧的数据。
    • 在增量备份时,需要保存调用 QueryChangedDiskAreas 获取的相应「已修改数据库偏移量」,以此来得知要恢复哪些虚拟磁盘的扇区。
  • 建议将备份数据直接恢复到基准虚拟磁盘,避免创建创建重做日志文件。

以 RDM 的方式创建虚拟磁盘

使用 vSphere WS API 中的 CreateVM_Task 创建 RDM 磁盘时,需要用到了一个可用且未被占用的 LUN 设备。在组装 VirtualDiskRawDiskMappingVer1BackInfo 类型虚拟磁盘的 backingInfo 时,我们可以按照下述方法来获取 LUN 设备的相关信息,并以此组装创建 RDM 磁盘所需要的参数:

  • 调用 QueryConfigTarget 获得 ConfigTarget.ScsiDisk.Disk.CanonicalName 属性值,并设置到 VirtualDiskRawDiskMappingVer1BackInfo.deviceName 属性中。

  • 调用 QueryConfgiTarget 获得 ConfigTarget.ScsiDisk.Disk.uuid 属性值,并设置到 VirtualDiskRawDiskMappingVer1BackInfo.lunUuid 属性中。

NOTE:有些开发者可能会使用 ESXi configInfo 对象中的 LUN uuid。需要注意的是,这样做很可能会导致错误,因为实际可用的 LUN uuid 是由 Datastore 指定的,而非 ESXi。

创建虚拟机

在实际调用 vSphere WS API 中的 CreateVM_Task 新建一个虚拟机前,需要组装一个 VirtualMachineConfigSpec 配置数据集来描述虚拟机的各项配置以及虚拟设备。大部分需要的信息都可以从 VirtualMachine Managed Object 的 VirtualMachineConfigInfo 得到,其中的 config.hardware.device 就包含了虚拟机所有虚拟设备配置信息。不同设备间的关系使用 key 的值表示,它是设备的唯一标识符。除此之外,每个设备还都拥有 controllerKey 属性,controllerKey 的值就是设备所连接的控制器的唯一标识符。我们在组装 VirtualMachineConfigSpec 时,应该使用一个负整数作为临时的 controllerKey 值,以此来保证临时 controllerKey 值不会和实际分配给这些控制器的值发送冲突。当虚拟设备关联到默认设备时,controllerKey 值应该重置为对应控制器的 key 值。

一般的,为了恢复一个新的虚拟机,我们会在备份时保留备份目标虚拟机的 VirtualMachineConfigInfo 数据,为了恢复出「一模一样」的虚拟机,甚至有些开发者会完整的将其保留。但实际上,VirtualMachineConfigInfo 中的一些数据是不需要的,而且如果强行引用到 VirtualMachineConfigSpec 中的话,还会导致虚拟机创建失败。例如,包含了「Default Devices」的 VirtualMachineConfigSpec 就会创建失败,「Default Devices」列表如下,这些设备的信息都是无需组装到 VirtualMachineConfigInfo 中的。但是,除此之外的其他控制器和虚拟设备就必须组装到 VirtualMachineConfigSpec 中了。

  • vim.vm.device.VirtualIDEController
  • vim.vm.device.VirtualPS2Controller
  • vim.vm.device.VirtualPCIController
  • vim.vm.device.VirtualSIOController
  • vim.vm.device.VirtualKeybord
  • vim.vm.device.VirtualVMCIDevice
  • vim.vm.device.VirtualPointingDevice

还有一些设备的信息如果被提供了的话也可能会出问题,组装 VirtualMachineConfigSpec 的要点如下:

  • 从 VirtualMachineConfigSpec 中排除「Default Devices」以及 VirtualController.device 的属性域
  • 设置 VirtualDisk.FlatVer2BackingInfo 类型虚拟磁盘的 parent backing(父磁盘) 信息为 null
  • 将 VirtualMachineConfigInfo 中的 cpuFeatureMask 属性域下的 HostCpuIdInfo 数组项转换为 VirtualMachineCpuIdInfoSpec 的 ArrayUpdateSpec 属性值,并且添加 ArrayUpdateOperation::add 项。

Sample of VirtualMachineConfigSpec

// beginning of VirtualMachineConfigSpec, ends several pages later
{ dynamicType = <unset>, changeVersion = <unset>,
//This is the display name of the VM name = “My New VM“,
version = "vmx-04",
uuid = <unset>,
instanceUuid = <unset>,
npivWorldWideNameType = <unset>,
npivDesiredNodeWwns = <unset>,
npivDesiredPortWwns = <unset>,
npivTemporaryDisabled = <unset>,
npivOnNonRdmDisks = <unset>,
npivWorldWideNameOp = <unset>,
locationId = <unset>, // This is advisory, the disk determines the O/S
guestId = "winNetStandardGuest", alternateGuestName = "Microsoft Windows Server 2008, Enterprise Edition",
annotation = <unset>,
files = (vim.vm.FileInfo) { dynamicType = <unset>,
vmPathName = "[plat004-local]",
snapshotDirectory = "[plat004-local]",
suspendDirectory = <unset>,
logDirectory = <unset>, },
tools = (vim.vm.ToolsConfigInfo) { dynamicType = <unset>,
toolsVersion = <unset>,
afterPowerOn = true,
afterResume = true,
beforeGuestStandby = true,
beforeGuestShutdown = true,
beforeGuestReboot = true,
toolsUpgradePolicy = <unset>,
pendingCustomization = <unset>,
syncTimeWithHost = <unset>, },
flags = (vim.vm.FlagInfo) {
dynamicType = <unset>,
disableAcceleration = <unset>,
enableLogging = <unset>,
useToe = <unset>,
runWithDebugInfo = <unset>,
monitorType = <unset>,
htSharing = <unset>,
snapshotDisabled = <unset>,
snapshotLocked = <unset>,
diskUuidEnabled = <unset>,
virtualMmuUsage = <unset>,
snapshotPowerOffBehavior = "powerOff",
recordReplayEnabled = <unset>, },
consolePreferences = (vim.vm.ConsolePreferences) null,
powerOpInfo = (vim.vm.DefaultPowerOpInfo) { dynamicType = <unset>,
powerOffType = "preset",
suspendType = "preset",
resetType = "preset",
defaultPowerOffType = <unset>,
defaultSuspendType = <unset>,
defaultResetType = <unset>,
standbyAction = "powerOnSuspend", },
// the number of CPUs numCPUs = 1,
// the number of memory megabytes memoryMB = 256,
memoryHotAddEnabled = <unset>,
cpuHotAddEnabled = <unset>,
cpuHotRemoveEnabled = <unset>,
deviceChange = (vim.vm.device.VirtualDeviceSpec) [ (vim.vm.device.VirtualDeviceSpec) {
dynamicType = <unset>,
operation = "add",
fileOperation = <unset>, // CDROM
device = (vim.vm.device.VirtualCdrom) {
dynamicType = <unset>, // key number of CDROM
key = -42, deviceInfo = (vim.Description) null,
backing = (vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo) {
dynamicType = <unset>,
deviceName = "",
useAutoDetect = <unset>,
exclusive = false, },
connectable = (vim.vm.device.VirtualDevice.ConnectInfo) { dynamicType = <unset>,
startConnected = false,
allowGuestControl = true,
connected = false, },
// connects to this controller controllerKey = 200, unitNumber = 0,
}, },
(vim.vm.device.VirtualDeviceSpec) { dynamicType = <unset>,
operation = "add",
fileOperation = <unset>, // SCSI controller
device = (vim.vm.device.VirtualLsiLogicController) { dynamicType = <unset>, // key number of SCSI controller
key = -44, deviceInfo = (vim.Description) null,
backing = (vim.vm.device.VirtualDevice.BackingInfo) null,
connectable = (vim.vm.device.VirtualDevice.ConnectInfo) null,
controllerKey = <unset>,
unitNumber = <unset>,
busNumber = 0,
hotAddRemove = <unset>,
sharedBus = "noSharing",
scsiCtlrUnitNumber = <unset>, }, },
(vim.vm.device.VirtualDeviceSpec) {
dynamicType = <unset>,
operation = "add",
fileOperation = <unset>, // Network controller
device = (vim.vm.device.VirtualPCNet32) { dynamicType = <unset>,
// key number of Network controller key = -48,
deviceInfo = (vim.Description) null,
backing = (vim.vm.device.VirtualEthernetCard.NetworkBackingInfo) { dynamicType = <unset>,
deviceName = "Virtual Machine Network",
useAutoDetect = <unset>,
network = <unset>,
inPassthroughMode = <unset>, },
connectable = (vim.vm.device.VirtualDevice.ConnectInfo) { dynamicType = <unset>,
startConnected = true,
allowGuestControl = true,
connected = true, },
controllerKey = <unset>,
unitNumber = <unset>,
addressType = "generated",
macAddress = <unset>,
wakeOnLanEnabled = true, }, },
(vim.vm.device.VirtualDeviceSpec) {
dynamicType = <unset>,
operation = "add",
fileOperation = "create", // SCSI disk one
device = (vim.vm.device.VirtualDisk) { dynamicType = <unset>,
// key number for SCSI disk one key = -1000000,
deviceInfo = (vim.Description) null,
backing = (vim.vm.device.VirtualDisk.FlatVer2BackingInfo) { dynamicType = <unset>,
fileName = "",
datastore = <unset>,
diskMode = "persistent",
split = false,
writeThrough = false,
thinProvisioned = <unset>,
eagerlyScrub = <unset>,
uuid = <unset>, contentId = <unset>,
changeId = <unset>,
parent = (vim.vm.device.VirtualDisk.FlatVer2BackingInfo) null, },
connectable = (vim.vm.device.VirtualDevice.ConnectInfo) { dynamicType = <unset>,
startConnected = true,
allowGuestControl = false,
connected = true, },
// controller for SCSI disk one controllerKey = -44, unitNumber = 0,
// size in MB SCSI disk one capacityInKB = 524288,
committedSpace = <unset>,
shares = (vim.SharesInfo) null, }, },
(vim.vm.device.VirtualDeviceSpec) {
dynamicType = <unset>,
operation = "add",
fileOperation = "create", // SCSI disk two
device = (vim.vm.device.VirtualDisk) { dynamicType = <unset>,
// key number of SCSI disk two key = -100,
deviceInfo = (vim.Description) null,
backing = (vim.vm.device.VirtualDisk.FlatVer2BackingInfo) { dynamicType = <unset>,
fileName = "",
datastore = <unset>,
diskMode = "persistent",
split = false,
writeThrough = false,
thinProvisioned = <unset>,
eagerlyScrub = <unset>,
uuid = <unset>, contentId = <unset>,
changeId = <unset>,
parent = (vim.vm.device.VirtualDisk.FlatVer2BackingInfo) null, },
connectable = (vim.vm.device.VirtualDevice.ConnectInfo) { dynamicType = <unset>,
startConnected = true,
allowGuestControl = false,
connected = true, },
// controller for SCSI disk two controllerKey = -44, unitNumber = 1,
// size in MB SCSI disk two capacityInKB = 131072,
committedSpace = <unset>,
shares = (vim.SharesInfo) null, }, }
},
cpuAllocation = (vim.ResourceAllocationInfo) { dynamicType = <unset>,
reservation = 0,
expandableReservation = <unset>,
limit = <unset>, shares = (vim.SharesInfo) {
dynamicType = <unset>,
shares = 100,
level = "normal", },
overheadLimit = <unset>,
}, memoryAllocation = (vim.ResourceAllocationInfo) {
dynamicType = <unset>,
reservation = 0,
expandableReservation = <unset>,
limit = <unset>,
shares = (vim.SharesInfo) { dynamicType = <unset>,
shares = 100,
level = "normal", },
overheadLimit = <unset>,
}, cpuAffinity = (vim.vm.AffinityInfo) null,
memoryAffinity = (vim.vm.AffinityInfo) null,
networkShaper = (vim.vm.NetworkShaperInfo) null,
swapPlacement = <unset>, swapDirectory = <unset>,
preserveSwapOnPowerOff = <unset>,
bootOptions = (vim.vm.BootOptions) null,
appliance = (vim.vService.ConfigSpec) null,
ftInfo = (vim.vm.FaultToleranceConfigInfo) null,
applianceConfigRemoved = <unset>,
vAssertsEnabled = <unset>,
changeTrackingEnabled = <unset>, }
// end of VirtualMachineConfigSpec

Demo of VirtualMachineConfigSpec

// Duplicate virtual machine configuration
VirtualMachineConfigSpec configSpec = new VirtualMachineConfigSpec();
// Set the VM values
configSpec.setName("My New VM");
configSpec.setVersion("vmx-04");
configSpec.setGuestId("winNetStandardGuest");
configSpec.setNumCPUs(1);
configSpec.setMemoryMB(256);
// Set up file storage info
VirtualMachineFileInfo vmfi = new VirtualMachineFileInfo(); vmfi.setVmPathName("[plat004-local]");
configSpec.setFiles(vmfi);
vmfi.setSnapshotDirectory("[plat004-local]");
// Set up tools config info
ToolsConfigInfo tools = new ToolsConfigInfo();
configSpec.setTools(tools);
tools.setAfterPowerOn(new Boolean(true));
tools.setAfterResume(new Boolean(true));
tools.setBeforeGuestStandby(new Boolean(true));
tools.setBeforeGuestShutdown(new Boolean(true));
tools.setBeforeGuestReboot(new Boolean(true));
// Set flags
VirtualMachineFlagInfo flags = new VirtualMachineFlagInfo(); configSpec.setFlags(flags);
flags.setSnapshotPowerOffBehavior("powerOff");
// Set power op info
VirtualMachineDefaultPowerOpInfo powerInfo = new VirtualMachineDefaultPowerOpInfo(); configSpec.setPowerOpInfo(powerInfo);
powerInfo.setPowerOffType("preset");
powerInfo.setSuspendType("preset");
powerInfo.setResetType("preset");
powerInfo.setStandbyAction("powerOnSuspend");
// Now add in the devices
VirtualDeviceConfigSpec[] deviceConfigSpec = new VirtualDeviceConfigSpec [5]; configSpec.setDeviceChange(deviceConfigSpec);
// Formulate the CDROM deviceConfigSpec[0].setOperation(VirtualDeviceConfigSpecOperation.add);
VirtualCdrom cdrom = new VirtualCdrom();
VirtualCdromIsoBackingInfo cdDeviceBacking = new VirtualCdromRemotePassthroughBackingInfo(); cdDeviceBacking.setDatastore(datastoreRef);
cdrom.setBacking(cdDeviceBacking);
cdrom.setKey(-42);
cdrom.setControllerKey(new Integer(-200)); // Older Java required type for optional properties cdrom.setUnitNumber(new Integer(0));
deviceConfigSpec[0].setDevice(cdrom);
// Formulate the SCSI controller deviceConfigSpec[1].setOperation(VirtualDeviceConfigSpecOperation.add); VirtualLsiLogicController scsiCtrl = new VirtualLsiLogicController(); scsiCtrl.setBusNumber(0);
deviceConfigSpec[1].setDevice(scsiCtrl);
scsiCtrl.setKey(-44);
scsiCtrl.setSharedBus(VirtualSCSISharing.noSharing);
// Formulate SCSI disk one deviceConfigSpec[2].setFileOperation(VirtualDeviceConfigSpecFileOperation.create); deviceConfigSpec[2].setOperation(VirtualDeviceConfigSpecOperation.add); VirtualDisk disk = new VirtualDisk();
VirtualDiskFlatVer2BackingInfo diskfileBacking = new VirtualDiskFlatVer2BackingInfo(); diskfileBacking.setDatastore(datastoreRef);
diskfileBacking.setFileName(volumeName);
diskfileBacking.setDiskMode("persistent");
diskfileBacking.setSplit(new Boolean(false));
diskfileBacking.setWriteThrough(new Boolean(false));
disk.setKey(-1000000);
disk.setControllerKey(new Integer(-44));
disk.setUnitNumber(new Integer(0));
disk.setBacking(diskfileBacking);
disk.setCapacityInKB(524288);
deviceConfigSpec[2].setDevice(disk);
// Formulate SCSI disk two deviceConfigSpec[3].setFileOperation(VirtualDeviceConfigSpecFileOperation.create); deviceConfigSpec[3].setOperation(VirtualDeviceConfigSpecOperation.add);
VirtualDisk disk2 = new VirtualDisk();
VirtualDiskFlatVer2BackingInfo diskfileBacking2 = new VirtualDiskFlatVer2BackingInfo(); diskfileBacking2.setDatastore(datastoreRef);
diskfileBacking2.setFileName(volumeName);
diskfileBacking2.setDiskMode("persistent");
diskfileBacking2.setSplit(new Boolean(false));
diskfileBacking2.setWriteThrough(new Boolean(false));
disk2.setKey(-100);
disk2.setControllerKey(new Integer(-44));
disk2.setUnitNumber(new Integer(1));
disk2.setBacking(diskfileBacking2);
disk2.setCapacityInKB(131072);
deviceConfigSpec[3].setDevice(disk2);
// Finally, formulate the NIC deviceConfigSpec[4].setOperation(VirtualDeviceConfigSpecOperation.add); com.VMware.vim.VirtualEthernetCard nic = new VirtualPCNet32(); VirtualEthernetCardNetworkBackingInfo nicBacking = new VirtualEthernetCardNetworkBackingInfo(); nicBacking.setNetwork(networkRef);
nicBacking.setDeviceName(networkName);
nic.setAddressType("generated");
nic.setBacking(nicBacking);
nic.setKey(-48);
deviceConfigSpec[4].setDevice(nic);
// Now that it is all put together, create the virtual machine.
// Note that folderMo, resourcePool, and hostMo, are moRefs to
// the Folder, ResourcePool, and Host where the VM is to be created.
ManagedObjectReference taskMoRef =
serviceConnection.getService().createVM_Task(folderMo, configSpec, resourcePool, hostMo);

VMware 虚拟化编程(15) — VMware 虚拟机的恢复方案设计的更多相关文章

  1. VMware 虚拟化编程(9) — VMware 虚拟机的快照

    目录 目录 前文列表 VMware 虚拟机的快照 快照的执行过程 删除快照 快照类型 Quiseced Snapshot 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDis ...

  2. VMware 虚拟化编程(13) — VMware 虚拟机的备份方案设计

    目录 目录 前文列表 备份思路 备份算法 备份细节 连接到 vCenter 还是 ESXi 如何选择快照类型 是否开启 CBT 如何获取备份数据 如何提高备份数据的传输率 备份厚置备磁盘和精简置备磁盘 ...

  3. VMware 虚拟化编程(11) — VMware 虚拟机的全量备份与增量备份方案

    目录 目录 前文列表 全量备份数据的获取方式 增量备份数据的获取过程 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编 ...

  4. VMware 虚拟化编程(10) — VMware 数据块修改跟踪技术 CBT

    目录 目录 前文列表 数据块修改跟踪技术 CBT 为虚拟机开启 CBT CBT 修改数据块偏移量获取函数 QueryChangedDiskAreas changeId 一个 QueryChangedD ...

  5. VMware 虚拟化编程(3) —VMware vSphere Web Service API 解析

    目录 目录 前文列表 VMware vSphere Web Services API VMware vSphere Web Services SDK vSphere WS API 中的托管对象 Man ...

  6. VMware 虚拟化编程(14) — VDDK 的高级传输模式详解

    目录 目录 前文列表 虚拟磁盘数据的传输方式 Transport Methods Local File Access NBD and NBDSSL Transport SAN Transport Ho ...

  7. VMware 虚拟化编程(12) — VixDiskLib Sample 程序使用

    目录 目录 前文列表 vixDiskLibSample 安装 Sample 程序 Sample 程序使用方法 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/V ...

  8. VMware 虚拟化编程(7) — VixDiskLib 虚拟磁盘库详解之三

    目录 目录 前文列表 VixDiskLib 虚拟磁盘库 VixDiskLib_GetMetadataKeys VixDiskLib_ReadMetadata 获取虚拟磁盘元数据 VixDiskLib_ ...

  9. VMware 虚拟化编程(5) — VixDiskLib 虚拟磁盘库详解之一

    目录 目录 前文列表 VixDiskLib 虚拟磁盘库 虚拟磁盘数据的传输方式 Transport Methods VixDiskLib_ListTransportModes 枚举支持的传输模式 Vi ...

随机推荐

  1. 我的第一个Delphi DLL

    library dd; { 使用字符串参数或嵌套字符串参数需要在uses子句中包括sharemm单元,并将BorlandMM.dll与您的应用程序一起发布. 否则需要对参数值使用PChar或Short ...

  2. JS中对数组元素进行增、删、改、查的方法,以及其他方法

    前言 昨天联调一个页面,看着就一个页面,接口倒是不少. 热点问题配置测试联调完成(同步异步接口共11个) 1.配置新增 2.配置编辑 3.配置删除 4.热点问题新增 5.热点问题编辑 6.热点问题删除 ...

  3. linux系统特殊权限位 suid、sgid、sticky

    linux系统特殊权限位 suid.sgid.stickysuid 使任意用户获得用文件属主相同的权限,sgid使用户获得与文件属组相同的权限(通过sgid获得的权限等同于同一用户组的权限) 表示方法 ...

  4. 005-sort 命令使用

    字符处理命令 sort 排序命令 排序选项: -f, --ignore-case 忽略字母大小写 -n, --numeric-sort 根据字符串数值比较 -r, --reverse 逆序输出排序结果 ...

  5. MySQL安装+更换yum源+mysql密码忘记(2019更新)

    安装mysql步骤:1.yum install mysql-server -y2.service mysqld start3.mysql4.切换数据库 use mysql 查看表 show table ...

  6. Candidate Generation and LUNA16 preprocessing

    在这个kernel中,我们将讨论有助于更好地理解问题陈述和数据可视化的方法. 我还将提供有用的资源和信息的链接. 此脚本是用Python编写的. 我建议人们在桌面上安装anaconda,因为here提 ...

  7. UVa11538 A Chess Queen

    A Chess Queen Problem A Chess Queen  Input: Standard Input Output: Standard Output You probably know ...

  8. Stack Overflow 推荐编程书单

    Stack Overflow 推荐编程书单   1 Working Effectively with Legacy Code Michael C. Feathers 修改代码是每一位软件开发人员的日常 ...

  9. 快速幂(Fast Pow)

    定义 快速求a^b%c的算法 原理 指数可以被二进制分解 那么a^b可以分解为a^2^k1*a^2^k2*…… 又显然a^2^(k+1)=a^(2^k*2)=(a^2^k)^2 所以可以将指数在二进制 ...

  10. 详述 DB2 分页查询及 Java 实现的示例_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 博主说:有时候,我们需要对数据库中现有的数据进行大量处理操作(例如表中的某个字段需要全部更新等),如果直接使用selec ...