On 07/20/2017 10:48 AM, Erik Skultety wrote: >> @@ -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. >
hrmph... this showed up after I posted v6.... I'll provide my comments here... Sure I meant "by-name"... The comment was originally sourced from _virDomainObjList... I've always just copied it around ;-) The comment in/for domain objs list was added in commit id 'a3adcce79' when the code was still part of domain_conf.c I think the "decoding" is that prior to that one would have 0(n) mutex locks taken for each domain obj in the list as the list was being traversed. With hash tables one as 0(1) mutex locks taken to lock the list before get the entry out of the hash table. >> + 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...) > This avoids obj->def->sysfs_path below. While obj->def isn't being made part of the object by any of these changes, it could well be someday. I guess it's mostly a personal preference. The compiler will certainly optimize away my preferences. >> + 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 > Oh - I've been down that fork in the road before - create what I think is a "simple" helper combining things only to get shot down during review because it was deemed unnecessary or that each of these should have their own separate pair of API's Each one of these is a unique way to search the objs list for a piece of data by some value that is not a key... FindBySysfsPath FindByWWNs FindByFabricWWN FindByCap FindSCSIHostByWWNs What comes to mind to me as a simple helper would be to create a 'typed' structure and API's to use switch/case in order to make the comparison. Perhaps some future change could do that. >> >> + 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; >> +} >> + >> + [...] >> @@ -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. > As stated above, personal preference. I know I'm swimming against the stream of very review though so eventually my fingers will capitulate and I won't be so offended by seeing obj->def->name. Of course if obj->def ever becomes part of the @obj, then guess what - all this works by only changing the def = obj->def to an def = virObject*GetDef(obj);. Because *all* these changes were made when that was a reality in my branches - I haven't changed them. Now it's less of a reality, but maybe some time I or someone else will come up with a grand way to add @def to @obj. Short term IDC other than personal preference. Again, the compiler will optimize my preference away. >> + 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 > Well..... That's the direction the common virObject series took, but no one has taken the plunge yet to look at that (see patch 12/16 in the series). John -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list