On Tue, Feb 28, 2017 at 04:39:52PM +0000, Daniel P. Berrange wrote:
On Tue, Feb 28, 2017 at 04:52:31PM +0100, Pavel Hrdina wrote:
On Tue, Feb 28, 2017 at 04:15:42PM +0100, Michal Privoznik wrote:
> On 02/11/2017 05:29 PM, John Ferlan wrote:
> > +struct _virPoolDef {
> > +    char *uuid;
> > +    char *name;
> > +};
> > +
> > +struct _virPoolObj {
> > +    virObjectLockable parent;
> > +
> > +    /* copy of the def->name and def->uuid (if available) used for lookups
> > +     * without needing to know the object type */
> > +    virPoolDefPtr pooldef;
> > +
> > +    /* Boolean states that can be managed by consumer */
> > +    bool active;       /* object is active or not */
> > +    bool beingRemoved; /* object being prepared for removal */
> > +    bool autostart;    /* object is autostarted */
> > +    bool persistent;   /* object definition is persistent */
> > +    bool updated;      /* object config has been updated in some way */
> > +
> > +    /* Boolean states managed by virPoolObj */
> > +    bool removing;  /* true when object has been removed from table(s) */
> > +
> > +    /* 'def' is the current config definition.
> > +     * 'newDef' is the next boot configuration.
> > +     * The 'type' value will describe which _vir*Def struct describes
> > +     * The 'privateData' will be private object data for each pool obj
> > +     * and specific to the 'type' of object being managed. */
> > +    void *def;
> > +    void *newDef;
> > +    virFreeCallback defFreeFunc;
> > +
> > +    /* Private data to be managed by the specific object using
> > +     * vir{$OBJ}ObjPrivate{Get|Set}{$FIELD} type API's. Each of those
> > +     * calling the virPoolObjGetPrivateData in order to access this field 
*/
> > +    void *privateData;
> > +    void (*privateDataFreeFunc)(void *);
> > +};
>
> So we are creating a new object to be put into hash table. How does this
> work with the actual object then? I mean, take patch 6/9 for instance.
> virSecretObj is actual object. Now, when dealing with virPoolObjList,
> it's just virPoolObj which is locked and not the actual virSecretObj.
> I'm worried that this could cause some trouble.
> Maybe virSecret is not the best example, because it doesn't usually get
> unlocked & locked again throughout virSecret APIs. Maybe virDomain would
> be a better example.
>
> A-ha! after going through all the patches, this new virPoolObj is a
> merge of all the vir*Obj (virSecretObj, virNetworkObj, virNodeDeviceObj,
> ...). So the issue I'm describing above will never occur.
>
> I wonder whether we can change this code so that we don't have to change
> all those objects to virPoolObj. I mean, our virObject supports morphism
> therefore we should be able to have APIs that are able to work over
> different classes derived from virObject. For instance:
>
> virSecretObjPtr sec;
> virNodeDeviceObjPtr node;
>
> virObjectListEndAPI(&sec);
> virObjectListEndAPI(&node);
>
>
> The same way we can call:
>
> virObjectLock(sec);
> virObjectLock((node);
>
> currently. This would help us to ensure type safeness when passing args
> to functions.
>
> One approach that comes to my mind right now as I'm writing these lines
> (read as "I haven't thought it through properly yet") is to create a new
> type of virObject. Currently we have virObject and virObjectLockable.
> What if we would have virObjectListable which would be derived from
> virObjectLockable. All those driver objects (virSecretObj for instance)
> would be derived from virObjectListable then. And in virObjectListable
> you could hold all those booleans you need. This would have the benefit
> of not dropping virSecretObj and thus rewriting half of libvirt.

I agree that the virPoolObj is not the best way to go.  This is similar to
what I had in mind while reading this series.  We should definitely preserve
all those object as they are.

I had a similar approach in my mind, it would basically follow how the
virDomainObjList is done, however the name would be generic (virObjectList,
virObjectListable or virObjectTable) with general APIs for searching by using
a function pointer, inserting, removing, etc.  And each object type would
implement specific stuff.  This would nicely follow how the real
object-inheritance is done in class oriented languages.

I definitely like the idea of having unified approach how to handle all
lists that we use in our code and this would give you the tool how to do it.
The virPoolObj kind of force you to use it.

FWIW, the virObject framework as it exists today was just the bare
minimum we needed in order to get a basic inheritance system up and
running in libvirt. I rather expected that we would extend it in the
future to add further concepts, inspired/borrowed from glib (which
is what stimulated my creation of virObject in the first place). In
particular I could see

- Interface support - the virObjectListable concept sounds like the
  kind of thing that would be suited to an interface, rather than a
  subclass, as it lets different objects support the API contract
  without forcing a common ancestor which might not be appropriate


This is really interesting and bunch of ideas *how* this would be
implemented pop into my mind.  I like the overall idea of using more
virObject goodness and expanding it so that it can to more.

I thing I get why interfaces are more suitable in some cases.  Having
'lockable'  and 'poolable' interfaces, for example, make it possible to
have classes that are lockable, poolable, both, or none of those things
without having three intermediate classes to derive from.

I do not understand one tiny thing, though.  Why is interface good for
this one particular occasion when every poolable object will always need
to be lockable?  I think in this particular case having
virObjectPoolable derive from virObjectLockable is pretty reasonable.

One more thing.  Can we do something about the static type-safety of
virObject APIs in the future?  The only idea I could come up with is
optional GCC plugin tailored to our usage, but that seems cumbersome.

- Signal support - a generalization of our current event reporting
  system to integrate directly with the object system


- Job control support - similarly to the signal support, we could have
                        generalized job control for any object.  This
                        could be an Interface for Lockable objects.

- Weak references - this is a concept which is useful with dealing
  with event callback registration. GLib uses this concept to
  dynamically kill off signal handlers when an object is disposed.
  This avoids problem we currently have where event handlers keep
  an object alive as long as they are registered, so you leak if
  you forget to unregister everything

In any case, I agree with the idea that it would be desirable to try and
model these pool concepts more rexplicitly in the object system, so that
we can maintain type safety instead of turning lots of things into void*
opaque pointers.

Regards,
Daniel
--
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://entangle-photo.org       -o-    http://search.cpan.org/~danberr/ :|

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Attachment: signature.asc
Description: Digital signature

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to