我是JNA的新手,正在尝试通过libvirt
c和JNA获取存储信息。
有两个libvirt c函数,virConnectListAllStoragePools()
和virStoragePoolGetInfo()
,如下所示。
/**
* virConnectListAllStoragePools:
* @conn: Pointer to the hypervisor connection.
* @pools: Pointer to a variable to store the array containing storage pool
* objects or NULL if the list is not required (just returns number
* of pools).
* @flags: bitwise-OR of virConnectListAllStoragePoolsFlags.
*
* Collect the list of storage pools, and allocate an array to store those
* objects. This API solves the race inherent between
* virConnectListStoragePools and virConnectListDefinedStoragePools.
*
* Normally, all storage pools are returned; however, @flags can be used to
* filter the results for a smaller list of targeted pools. The valid
* flags are divided into groups, where each group contains bits that
* describe mutually exclusive attributes of a pool, and where all bits
* within a group describe all possible pools.
*
* The first group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE (online)
* and VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE (offline) to filter the pools
* by state.
*
* The second group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_PERSITENT
* (defined) and VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT (running but not
* defined), to filter the pools by whether they have persistent config or not.
*
* The third group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART
* and VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART, to filter the pools by
* whether they are marked as autostart or not.
*
* The last group of @flags is provided to filter the pools by the types,
* the flags include:
* VIR_CONNECT_LIST_STORAGE_POOLS_DIR
* VIR_CONNECT_LIST_STORAGE_POOLS_FS
* VIR_CONNECT_LIST_STORAGE_POOLS_NETFS
* VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL
* VIR_CONNECT_LIST_STORAGE_POOLS_DISK
* VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI
* VIR_CONNECT_LIST_STORAGE_POOLS_SCSI
* VIR_CONNECT_LIST_STORAGE_POOLS_MPATH
* VIR_CONNECT_LIST_STORAGE_POOLS_RBD
* VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG
* VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER
* VIR_CONNECT_LIST_STORAGE_POOLS_ZFS
* VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE
* VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI_DIRECT
*
* Returns the number of storage pools found or -1 and sets @pools to
* NULL in case of error. On success, the array stored into @pools is
* guaranteed to have an extra allocated element set to NULL but not included
* in the return count, to make iteration easier. The caller is responsible
* for calling virStoragePoolFree() on each array element, then calling
* free() on @pools.
*/
int
virConnectListAllStoragePools(virConnectPtr conn,
virStoragePoolPtr **pools,
unsigned int flags)
{
//logic about set pool pointer to parameter '**pools' and return number of pools.
}
/**
* virStoragePoolGetInfo:
* @pool: pointer to storage pool
* @info: pointer at which to store info
*
* Get volatile information about the storage pool
* such as free space / usage summary
*
* Returns 0 on success, or -1 on failure.
*/
int
virStoragePoolGetInfo(virStoragePoolPtr pool,
virStoragePoolInfoPtr info)
{
// logic about set pool info to parameter 'info'.
}
我使用JNA的Java代码是:。
1)StoragePoolPointer.java
import com.sun.jna.PointerType;
public class StoragePoolPointer extends PointerType {}
2)virStoragePoolInfo
public class virStoragePoolInfo extends Struture {
public int state;
public long capacity;
public long allocation;
public long available;
private static final List<String> filedls = Arrays.asList("state", "capacity", "allocation", "available");
protected List<String> getFieldOrder() {
return fields;
}
}
3)Libvirt.java接口
public interface Libvirt extends Library {
int virConnectListAllStoragePools(ConnectionPoinet VCP, StoragePoolPointer[] pPointers, int flag);
int virStoragePoolGetInfo(StoragePoolPointer poolPointer, virStoragePoolInfo info);
}
4)jna测试代码
public void listAllStoragePools(ConnectionPointer VCP) {
Libvirt libvirt = (Libvirt) Native.loadLibrary("virt", Libvirt.class);
StoragePoolPointer[] pPointerArr = new StoragePoolPointer[10];
int result = livirt.virConnectListAllStoragePools(VCP, pPointerArr, 64);
// result is fine. i get storage pool count. and also i get StoragePoolPointer object inside array.
virStoragePoolInfo poolInfo = new virStoragePoolInfo();
libvirt.virStoragePoolGetInfo(pPointerArr[0], poolInfo);
// when i call libvirt.virStoragePoolGetInfo(). i get a error msg like this. 'libvirt: Storage Driver error : invalid storage pool pointer in virStoragePoolGetInfo.
//error msg : org.libvirt.LibvirtException: invalid storage pool pointer in virStoragePoolGetInfo.
}
我认为我使用了错误的接口方法virConnectListAllStoragePools()
,并且为'virStoragePoolPtr ** pools'传递了错误的参数。
本机数组布置在连续内存中。在这种情况下,virStoragePoolPtr **pools
是指向数组beginning的单个指针; C使用指针大小的知识来使用偏移量来查找其余元素。
JNA不会将(大多数)Java数组转换为该本机布局。当这样做时,它将使用明确定义的大小,例如JNA可以计算其大小并使用其int[]
方法进行分配的原始数组(例如Structure
)或toArray
数组。
您已经在此处定义了Java端数组:
StoragePoolPointer[] pPointerArr = new StoragePoolPointer[10];
但是您尚未分配任何Java对象来填充数组,因此它只是
null
的数组。此外,即使您确实通过迭代和设置pPointerArr[i] = new StoragePoolPointer()
来填充数组,您也将在这些指针上附加了不连续的本机内存。
(至少有两种方法可以解决此问题。一种是使用JNA的Memory
类直接分配本机内存,如下所示:
pPointerArr = new Memory(10 * Native.POINTER_SIZE);
[对
virConnectListAllStoragePools()
的方法调用之后,您将在该缓冲区中保存指针,并且可以进行迭代,例如,当您递增Pointer p = pPointerArr.share(i * Native.POINTER_SIZE)
时,i
将是每个指针。
或者,您可以定义一个包含指针的Structure
,如下所示:
连续的本机内存:@FieldOrder({ "storagePool" }) public class StoragePoolPointer extends Structure { public Pointer storagePool; }
然后,您可以通过以下两种方式获得Java数组的便利性和
StoragePoolPointer[] pPointerArr = (StoragePoolPointer[]) new StoragePoolPointer().toArray(10);
[填充数组后,
pPointerArr[i].storagePool
将是第i
个指针。
假设您正在使用的10
只是一个测试占位符,这种情况下的标准JNA习惯用法是使用空指针调用一次virConnectListAllStoragePools()
以获取要使用的元素数,然后按我的方式分配内存。上面已经描述过,并使用适当大小的缓冲区(或由缓冲区支持的结构数组)再次调用它。