
On 12/13/2017 11:40 AM, Michal Privoznik wrote:
On 12/05/2017 02:43 AM, John Ferlan wrote:
Now that we have a private storage pool list, we can take the next step and convert to using objects. In this case, we're going to use RWLockable objects (just like every other driver) with two hash tables for lookup by UUID or Name.
Along the way the ForEach and Search API's will be adjusted to use the related Hash API's and the various FindBy functions altered and augmented to allow for HashLookup w/ and w/o the pool lock already taken.
After virStoragePoolObjRemove we will need to virObjectUnref(obj) after to indicate the caller is "done" with it's reference. The Unlock occurs during the Remove.
The NumOf, GetNames, and Export functions all have their own callback functions to return the required data and the FindDuplicate code can use the HashSearch function callbacks.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/conf/virstorageobj.c | 638 +++++++++++++++++++++++++++++-------------- src/conf/virstorageobj.h | 3 - src/libvirt_private.syms | 1 - src/storage/storage_driver.c | 8 +- src/test/test_driver.c | 7 +- 5 files changed, 449 insertions(+), 208 deletions(-)
diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index a48346b24..0e5c98bf7 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -27,6 +27,7 @@ #include "viralloc.h" #include "virerror.h" #include "virfile.h" +#include "virhash.h" #include "virlog.h" #include "virscsihost.h" #include "virstring.h" @@ -37,9 +38,12 @@ VIR_LOG_INIT("conf.virstorageobj");
static virClassPtr virStoragePoolObjClass; +static virClassPtr virStoragePoolObjListClass;
static void virStoragePoolObjDispose(void *opaque); +static void +virStoragePoolObjListDispose(void *opaque);
struct _virStorageVolDefList { @@ -63,8 +67,15 @@ struct _virStoragePoolObj { };
struct _virStoragePoolObjList { - size_t count; - virStoragePoolObjPtr *objs; + virObjectRWLockable parent; + + /* uuid string -> virStoragePoolObj mapping + * for (1), lockless lookup-by-uuid */ + virHashTable *objs; + + /* name string -> virStoragePoolObj mapping + * for (1), lockless lookup-by-name */ + virHashTable *objsName; };
@@ -77,6 +88,12 @@ virStoragePoolObjOnceInit(void) virStoragePoolObjDispose))) return -1;
+ if (!(virStoragePoolObjListClass = virClassNew(virClassForObjectRWLockable(), + "virStoragePoolObjList", + sizeof(virStoragePoolObjList), + virStoragePoolObjListDispose))) + return -1; + return 0; }
@@ -240,13 +257,15 @@ virStoragePoolObjDispose(void *opaque)
void -virStoragePoolObjListFree(virStoragePoolObjListPtr pools) +virStoragePoolObjListDispose(void *opaque) { - size_t i; - for (i = 0; i < pools->count; i++) - virObjectUnref(pools->objs[i]); - VIR_FREE(pools->objs); - VIR_FREE(pools); + virStoragePoolObjListPtr pools = opaque; + + if (!pools) + return;
This shouldn't be needed. This function is called iff pools are still not NULL.
Oh right, it's removed...
+ + virHashFree(pools->objs); + virHashFree(pools->objsName); }
@@ -255,13 +274,44 @@ virStoragePoolObjListNew(void) { virStoragePoolObjListPtr pools;
- if (VIR_ALLOC(pools) < 0) + if (virStoragePoolObjInitialize() < 0) + return NULL; + + if (!(pools = virObjectRWLockableNew(virStoragePoolObjListClass))) + return NULL; + + if (!(pools->objs = virHashCreate(20, virObjectFreeHashData)) || + !(pools->objsName = virHashCreate(20, virObjectFreeHashData))) { + virObjectUnref(pools); return NULL; + }
return pools; }
+struct _virStoragePoolObjListForEachData { + virStoragePoolObjListIterator iter; + const void *opaque; +}; + +static int +virStoragePoolObjListForEachCb(void *payload, + const void *name ATTRIBUTE_UNUSED, + void *opaque) +{ + virStoragePoolObjPtr obj = payload; + struct _virStoragePoolObjListForEachData *data = + (struct _virStoragePoolObjListForEachData *)opaque;
Do we need this typecast? I don't think so. You're assigning void *payload to virStoragePoolObjPtr obj directly, without any typecast.
True - it's probably a holdover from undoing something. Been too long to remember though. Consider it gone.
+ + virObjectLock(obj); + data->iter(obj, data->opaque); + virObjectUnlock(obj); + + return 0; +} + + /** * virStoragePoolObjListForEach * @pools: Pointer to pools object @@ -279,15 +329,35 @@ virStoragePoolObjListForEach(virStoragePoolObjListPtr pools, virStoragePoolObjListIterator iter, const void *opaque) { - size_t i; - virStoragePoolObjPtr obj; + struct _virStoragePoolObjListForEachData data = { .iter = iter, + .opaque = opaque };
- for (i = 0; i < pools->count; i++) { - obj = pools->objs[i]; - virObjectLock(obj); - iter(obj, opaque); - virObjectUnlock(obj); - } + virObjectRWLockRead(pools); + virHashForEach(pools->objs, virStoragePoolObjListForEachCb, &data); + virObjectRWUnlock(pools); +} + + +struct _virStoragePoolObjListSearchData { + virStoragePoolObjListSearcher searcher; + const void *opaque; +}; + + +static int +virStoragePoolObjListSearchCb(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload; + struct _virStoragePoolObjListSearchData *data = + (struct _virStoragePoolObjListSearchData *)opaque;
Of course, typecast is needed here because we need to drop 'const'. Grrr. I wonder if locking an object is considered as modifying it. IOW if virObjectLock() should take 'void *' or 'const void *'.
I would think taking a lock is considered violation of const-ness. I can certainly see cause for why a Search callback would say don't change something though. Taking a different approach - if the caller knew that the opaque was a LockableObject, then it could do the right thing and keep the const argument. It could probably even be better if it was a RWReadLock. But that's a different rabbit-hole that I'm not sure I want to jump into yet. Although I did dip my toes in that water and got more or less rejected, so this is as close as I think I'm going to get for now. Thanks for the review - John
+ + virObjectLock(obj); + if (data->searcher(obj, data->opaque)) + return 1; + virObjectUnlock(obj); + return 0; }
Michal