[libvirt] [PATCH v5 2/3] nodedev: Convert virNodeDeviceObjListPtr to use hash tables
Erik Skultety
eskultet at redhat.com
Thu Jul 20 14:48:15 UTC 2017
> @@ -39,13 +40,19 @@ struct _virNodeDeviceObj {
> };
>
> struct _virNodeDeviceObjList {
> - size_t count;
> - virNodeDeviceObjPtr *objs;
> + virObjectLockable parent;
> +
> + /* name string -> virNodeDeviceObj mapping
> + * for O(1), lockless lookup-by-uuid */
I think you meant lookup-by-name ^here. More importantly though, I don't
understand the comment at all, well I understand the words :), but the context
is all noise - why should be the lookup lockless? You always lock the objlist
prior to calling virHashLookup, followed by ref'ing and returning the result, I
know we have that in other conf/vir*obj* modules and those don't make any more
sense to me either.
> + virHashTable *objs;
> +
> };
>
>
> static virClassPtr virNodeDeviceObjClass;
> +static virClassPtr virNodeDeviceObjListClass;
> static void virNodeDeviceObjDispose(void *opaque);
> +static void virNodeDeviceObjListDispose(void *opaque);
>
> static int
> virNodeDeviceObjOnceInit(void)
> @@ -56,6 +63,12 @@ virNodeDeviceObjOnceInit(void)
> virNodeDeviceObjDispose)))
> return -1;
>
> + if (!(virNodeDeviceObjListClass = virClassNew(virClassForObjectLockable(),
> + "virNodeDeviceObjList",
> + sizeof(virNodeDeviceObjList),
> + virNodeDeviceObjListDispose)))
> + return -1;
> +
> return 0;
> }
>
> @@ -211,26 +224,49 @@ virNodeDeviceFindVPORTCapDef(const virNodeDeviceObj *obj)
> }
>
>
> +static int
> +virNodeDeviceObjListFindBySysfsPathCallback(const void *payload,
> + const void *name ATTRIBUTE_UNUSED,
> + const void *opaque)
> +{
> + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload;
> + virNodeDeviceDefPtr def;
I recall having discussed ^this with you already, but this is one-time use only
and I simply don't think it's necessary, I'd use helper variables for the sole
purpose of getting rid of multiple levels of dereference either in a multi-use
situation, or the number of levels dereferenced makes the line really long and
the usage unreadable. (this also occurs on multiple places...no need to repeat
this...)
> + const char *sysfs_path = opaque;
> + int want = 0;
> +
> + virObjectLock(obj);
> + def = obj->def;
> + if (STREQ_NULLABLE(def->sysfs_path, sysfs_path))
> + want = 1;
> + virObjectUnlock(obj);
> + return want;
> +}
> +
> +
> virNodeDeviceObjPtr
> virNodeDeviceObjListFindBySysfsPath(virNodeDeviceObjListPtr devs,
> const char *sysfs_path)
> {
> - size_t i;
> + virNodeDeviceObjPtr obj;
>
> - for (i = 0; i < devs->count; i++) {
> - virNodeDeviceObjPtr obj = devs->objs[i];
> - virNodeDeviceDefPtr def;
> + virObjectLock(devs);
> + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindBySysfsPathCallback,
> + (void *)sysfs_path);
> + virObjectRef(obj);
> + virObjectUnlock(devs);
^This pattern occurs multiple times within the patch, I think it deserves a
simple helper
>
> + if (obj)
> virObjectLock(obj);
> - def = obj->def;
> - if ((def->sysfs_path != NULL) &&
> - (STREQ(def->sysfs_path, sysfs_path))) {
> - return virObjectRef(obj);
> - }
> - virObjectUnlock(obj);
> - }
>
> - return NULL;
> + return obj;
> +}
> +
> +
> +static virNodeDeviceObjPtr
> +virNodeDeviceObjListFindByNameLocked(virNodeDeviceObjListPtr devs,
> + const char *name)
> +{
> + return virObjectRef(virHashLookup(devs->objs, name));
> }
>
>
> @@ -238,20 +274,42 @@ virNodeDeviceObjPtr
> virNodeDeviceObjListFindByName(virNodeDeviceObjListPtr devs,
> const char *name)
> {
> - size_t i;
> -
> - for (i = 0; i < devs->count; i++) {
> - virNodeDeviceObjPtr obj = devs->objs[i];
> - virNodeDeviceDefPtr def;
> + virNodeDeviceObjPtr obj;
>
> + virObjectLock(devs);
> + obj = virNodeDeviceObjListFindByNameLocked(devs, name);
> + virObjectUnlock(devs);
> + if (obj)
> virObjectLock(obj);
> - def = obj->def;
> - if (STREQ(def->name, name))
> - return virObjectRef(obj);
> - virObjectUnlock(obj);
> - }
>
> - return NULL;
> + return obj;
> +}
> +
> +
> +struct virNodeDeviceObjListFindByWWNsData {
> + const char *parent_wwnn;
> + const char *parent_wwpn;
> +};
> +
> +static int
> +virNodeDeviceObjListFindByWWNsCallback(const void *payload,
> + const void *name ATTRIBUTE_UNUSED,
> + const void *opaque)
> +{
> + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload;
> + struct virNodeDeviceObjListFindByWWNsData *data =
> + (struct virNodeDeviceObjListFindByWWNsData *) opaque;
> + virNodeDevCapsDefPtr cap;
> + int want = 0;
> +
> + virObjectLock(obj);
> + if ((cap = virNodeDeviceFindFCCapDef(obj)) &&
> + STREQ_NULLABLE(cap->data.scsi_host.wwnn, data->parent_wwnn) &&
> + STREQ_NULLABLE(cap->data.scsi_host.wwpn, data->parent_wwpn) &&
> + virNodeDeviceFindVPORTCapDef(obj))
> + want = 1;
> + virObjectUnlock(obj);
> + return want;
> }
>
>
> @@ -260,22 +318,40 @@ virNodeDeviceObjListFindByWWNs(virNodeDeviceObjListPtr devs,
> const char *parent_wwnn,
> const char *parent_wwpn)
> {
> - size_t i;
> + virNodeDeviceObjPtr obj;
> + struct virNodeDeviceObjListFindByWWNsData data = {
> + .parent_wwnn = parent_wwnn, .parent_wwpn = parent_wwpn };
>
> - for (i = 0; i < devs->count; i++) {
> - virNodeDeviceObjPtr obj = devs->objs[i];
> - virNodeDevCapsDefPtr cap;
> + virObjectLock(devs);
> + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindByWWNsCallback,
> + &data);
> + virObjectRef(obj);
> + virObjectUnlock(devs);
>
> + if (obj)
> virObjectLock(obj);
> - if ((cap = virNodeDeviceFindFCCapDef(obj)) &&
> - STREQ_NULLABLE(cap->data.scsi_host.wwnn, parent_wwnn) &&
> - STREQ_NULLABLE(cap->data.scsi_host.wwpn, parent_wwpn) &&
> - virNodeDeviceFindVPORTCapDef(obj))
> - return virObjectRef(obj);
> - virObjectUnlock(obj);
> - }
>
> - return NULL;
> + return obj;
> +}
> +
> +
> +static int
> +virNodeDeviceObjListFindByFabricWWNCallback(const void *payload,
> + const void *name ATTRIBUTE_UNUSED,
> + const void *opaque)
> +{
> + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload;
> + const char *matchstr = opaque;
> + virNodeDevCapsDefPtr cap;
> + int want = 0;
> +
> + virObjectLock(obj);
> + if ((cap = virNodeDeviceFindFCCapDef(obj)) &&
> + STREQ_NULLABLE(cap->data.scsi_host.fabric_wwn, matchstr) &&
> + virNodeDeviceFindVPORTCapDef(obj))
> + want = 1;
> + virObjectUnlock(obj);
> + return want;
> }
>
>
> @@ -283,21 +359,35 @@ static virNodeDeviceObjPtr
> virNodeDeviceObjListFindByFabricWWN(virNodeDeviceObjListPtr devs,
> const char *parent_fabric_wwn)
> {
> - size_t i;
> + virNodeDeviceObjPtr obj;
>
> - for (i = 0; i < devs->count; i++) {
> - virNodeDeviceObjPtr obj = devs->objs[i];
> - virNodeDevCapsDefPtr cap;
> + virObjectLock(devs);
> + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindByFabricWWNCallback,
> + (void *)parent_fabric_wwn);
> + virObjectRef(obj);
> + virObjectUnlock(devs);
>
> + if (obj)
> virObjectLock(obj);
> - if ((cap = virNodeDeviceFindFCCapDef(obj)) &&
> - STREQ_NULLABLE(cap->data.scsi_host.fabric_wwn, parent_fabric_wwn) &&
> - virNodeDeviceFindVPORTCapDef(obj))
> - return virObjectRef(obj);
> - virObjectUnlock(obj);
> - }
>
> - return NULL;
> + return obj;
> +}
> +
> +
> +static int
> +virNodeDeviceObjListFindByCapCallback(const void *payload,
> + const void *name ATTRIBUTE_UNUSED,
> + const void *opaque)
> +{
> + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload;
> + const char *matchstr = opaque;
> + int want = 0;
> +
> + virObjectLock(obj);
> + if (virNodeDeviceObjHasCap(obj, matchstr))
> + want = 1;
> + virObjectUnlock(obj);
> + return want;
> }
>
>
> @@ -305,18 +395,59 @@ static virNodeDeviceObjPtr
> virNodeDeviceObjListFindByCap(virNodeDeviceObjListPtr devs,
> const char *cap)
> {
> - size_t i;
> + virNodeDeviceObjPtr obj;
>
> - for (i = 0; i < devs->count; i++) {
> - virNodeDeviceObjPtr obj = devs->objs[i];
> + virObjectLock(devs);
> + obj = virHashSearch(devs->objs, virNodeDeviceObjListFindByCapCallback,
> + (void *)cap);
> + virObjectRef(obj);
> + virObjectUnlock(devs);
>
> + if (obj)
> virObjectLock(obj);
> - if (virNodeDeviceObjHasCap(obj, cap))
> - return virObjectRef(obj);
> - virObjectUnlock(obj);
> - }
>
> - return NULL;
> + return obj;
> +}
> +
> +
> +struct virNodeDeviceObjListFindSCSIHostByWWNsData {
> + const char *wwnn;
> + const char *wwpn;
> +};
> +
> +static int
> +virNodeDeviceObjListFindSCSIHostByWWNsCallback(const void *payload,
> + const void *name ATTRIBUTE_UNUSED,
> + const void *opaque)
> +{
> + virNodeDeviceObjPtr obj = (virNodeDeviceObjPtr) payload;
> + virNodeDeviceDefPtr def;
> + struct virNodeDeviceObjListFindSCSIHostByWWNsData *data =
> + (struct virNodeDeviceObjListFindSCSIHostByWWNsData *) opaque;
> + virNodeDevCapsDefPtr cap;
> + int want = 0;
> +
> + virObjectLock(obj);
> + def = obj->def;
> + cap = def->caps;
> +
> + while (cap) {
> + if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) {
> + virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host);
> + if (cap->data.scsi_host.flags &
> + VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
> + if (STREQ(cap->data.scsi_host.wwnn, data->wwnn) &&
> + STREQ(cap->data.scsi_host.wwpn, data->wwpn)) {
> + want = 1;
> + break;
> + }
> + }
> + }
> + cap = cap->next;
> + }
> +
> + virObjectUnlock(obj);
> + return want;
> }
>
>
> @@ -325,31 +456,30 @@ virNodeDeviceObjListFindSCSIHostByWWNs(virNodeDeviceObjListPtr devs,
> const char *wwnn,
> const char *wwpn)
> {
> - size_t i;
> + virNodeDeviceObjPtr obj;
> + struct virNodeDeviceObjListFindSCSIHostByWWNsData data = {
> + .wwnn = wwnn, .wwpn = wwpn };
>
> - for (i = 0; i < devs->count; i++) {
> - virNodeDeviceObjPtr obj = devs->objs[i];
> - virNodeDevCapsDefPtr cap;
> + virObjectLock(devs);
> + obj = virHashSearch(devs->objs,
> + virNodeDeviceObjListFindSCSIHostByWWNsCallback,
> + &data);
> + virObjectRef(obj);
> + virObjectUnlock(devs);
>
> + if (obj)
> virObjectLock(obj);
> - cap = obj->def->caps;
> -
> - while (cap) {
> - if (cap->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) {
> - virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host);
> - if (cap->data.scsi_host.flags &
> - VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
> - if (STREQ(cap->data.scsi_host.wwnn, wwnn) &&
> - STREQ(cap->data.scsi_host.wwpn, wwpn))
> - return virObjectRef(obj);
> - }
> - }
> - cap = cap->next;
> - }
> - virObjectUnlock(obj);
> - }
>
> - return NULL;
> + return obj;
> +}
> +
> +
> +static void
> +virNodeDeviceObjListDispose(void *obj)
> +{
> + virNodeDeviceObjListPtr devs = obj;
> +
> + virHashFree(devs->objs);
> }
>
>
> @@ -358,8 +488,17 @@ virNodeDeviceObjListNew(void)
> {
> virNodeDeviceObjListPtr devs;
>
> - if (VIR_ALLOC(devs) < 0)
> + if (virNodeDeviceObjInitialize() < 0)
> + return NULL;
> +
> + if (!(devs = virObjectLockableNew(virNodeDeviceObjListClass)))
> return NULL;
> +
> + if (!(devs->objs = virHashCreate(50, virObjectFreeHashData))) {
> + virObjectUnref(devs);
> + return NULL;
> + }
> +
> return devs;
> }
>
> @@ -367,11 +506,7 @@ virNodeDeviceObjListNew(void)
> void
> virNodeDeviceObjListFree(virNodeDeviceObjListPtr devs)
> {
> - size_t i;
> - for (i = 0; i < devs->count; i++)
> - virObjectUnref(devs->objs[i]);
> - VIR_FREE(devs->objs);
> - VIR_FREE(devs);
> + virObjectUnref(devs);
> }
>
>
> @@ -381,22 +516,28 @@ virNodeDeviceObjListAssignDef(virNodeDeviceObjListPtr devs,
> {
> virNodeDeviceObjPtr obj;
>
> - if ((obj = virNodeDeviceObjListFindByName(devs, def->name))) {
> + virObjectLock(devs);
> +
> + if ((obj = virNodeDeviceObjListFindByNameLocked(devs, def->name))) {
> + virObjectLock(obj);
> virNodeDeviceDefFree(obj->def);
> obj->def = def;
> - return obj;
> - }
> + } else {
> + if (!(obj = virNodeDeviceObjNew()))
> + goto cleanup;
>
> - if (!(obj = virNodeDeviceObjNew()))
> - return NULL;
> + if (virHashAddEntry(devs->objs, def->name, obj) < 0) {
> + virNodeDeviceObjEndAPI(&obj);
> + goto cleanup;
> + }
>
> - if (VIR_APPEND_ELEMENT_COPY(devs->objs, devs->count, obj) < 0) {
> - virNodeDeviceObjEndAPI(&obj);
> - return NULL;
> + obj->def = def;
> + virObjectRef(obj);
> }
> - obj->def = def;
>
> - return virObjectRef(obj);
> + cleanup:
> + virObjectUnlock(devs);
> + return obj;
> }
>
>
> @@ -404,21 +545,20 @@ void
> virNodeDeviceObjListRemove(virNodeDeviceObjListPtr devs,
> virNodeDeviceObjPtr obj)
> {
> - size_t i;
> -
> - virObjectUnlock(obj);
> + virNodeDeviceDefPtr def;
>
> - for (i = 0; i < devs->count; i++) {
> - virObjectLock(devs->objs[i]);
> - if (devs->objs[i] == obj) {
> - virObjectUnlock(devs->objs[i]);
> - virObjectUnref(devs->objs[i]);
> + if (!obj)
> + return;
> + def = obj->def;
In this specific case, what's the benefit of having @def...
>
> - VIR_DELETE_ELEMENT(devs->objs, i, devs->count);
> - break;
> - }
> - virObjectUnlock(devs->objs[i]);
> - }
> + virObjectRef(obj);
> + virObjectUnlock(obj);
> + virObjectLock(devs);
> + virObjectLock(obj);
> + virHashRemoveEntry(devs->objs, def->name);
...and use it here instead of obj->def->name... I'd prefer if you just dropped
it here.
> + virObjectUnlock(obj);
> + virObjectUnref(obj);
> + virObjectUnlock(devs);
> }
>
>
> @@ -643,25 +783,89 @@ virNodeDeviceCapMatch(virNodeDeviceObjPtr obj,
> }
>
>
> +struct virNodeDeviceCountData {
> + virConnectPtr conn;
> + virNodeDeviceObjListFilter aclfilter;
> + const char *matchstr;
> + int count;
> +};
These single purpose structures often have the same members across multiple
callbacks, I was wondering whether we could just make one generic one, call it
virNodeDeviceQueryData. But then, it would unnecessarily big, most fields would
be unused, I don't know, it might not be a "nicer" solution eventually, so I'm
ambivalent on this...
Erik
More information about the libvir-list
mailing list