[libvirt] [PATCHv2 1/5] lib: Introduce API for retrieving bulk domain stats

Peter Krempa pkrempa at redhat.com
Tue Aug 26 17:28:18 UTC 2014


On 08/26/14 18:49, Eric Blake wrote:
> On 08/26/2014 08:14 AM, Peter Krempa wrote:

....

>> +typedef int
>> +(*virDrvDomainListGetStats)(virConnectPtr conn,
>> +                            virDomainPtr *doms,
>> +                            unsigned int ndoms,
>> +                            unsigned int stats,
>> +                            virDomainStatsRecordPtr **retStats,
>> +                            unsigned int flags);
> 
> Ah, so under the hood, we only have to implement one callback, where
> doms is NULL for virConnectGetAllDomainStats and non-NULL for
> virDomainListGetStats?  I suppose that works, although it might make the
> RPC interesting.  I guess I'll see later in the series, but as this is
> internal-only, it shouldn't matter for what we commit to in the public API.
> 
>> +
>> +
>> +/**
>> + * virConnectGetAllDomainStats:
>> + * @conn: pointer to the hypervisor connection
>> + * @stats: stats to return, binary-OR of virDomainStatsTypes
>> + * @retStats: Pointer that will be filled with the array of returned stats.
>> + * @flags: extra flags; not used yet, so callers should always pass 0
> 
> Would it make sense for @flags to provide the same filtering as
> virConnectListAllDomains(), for selecting a subset of domains to get
> stats on?  But can definitely be added later.

I already thought about implementing the filtering capability for this
function although I doubt that all of the filtering flags may be useful
here.

Requesting stats for a machine that has (or doesn't have) snapshot
doesn't seem useful at all.

> 
>> + *
>> + * Query statistics for all domains on a given connection.
>> + *
>> + * Report statistics of various parameters for a running VM according to @stats
>> + * field. The statistics are returned as an array of structures for each queried
>> + * domain. The structure contains an array of typed parameters containing the
>> + * individual statistics. The typed parameter name for each statistic field
>> + * consists of a dot-separated string containing name of the requested group
>> + * followed by a group specific description of the statistic value.
>> + *
>> + * The statistic groups are enabled using the @stats parameter which is a
>> + * binary-OR of enum virDomainStatsTypes. The following groups are available
>> + * (although not necessarily implemented for each storage driver):
> 
> s/storage driver/hypervisor/
> 
>> + *
>> + * VIR_DOMAIN_STATS_ALL: Return all statistics supported by the hypervisor
>> + * driver. This allows to query everything the driver supports without getting
>> + * an error.
> 
> See my above comments about how this feels like it should be something
> in the @flags parameter, rather than the @stats parameter (that is, a
> flag _ENFORCE that says whether the hypervisor lacking a particular stat
> group is fatal).
> 
>> + *
>> + * VIR_DOMAIN_STATS_STATE: Return domain state and reason for entering that
>> + * state. The typed parameter keys are in format:
>> + * "state.state" - state of the VM, returned as int from virDomainState enum
>> + * "state.reason" - reason for entering given state, returned as in from
> 
> s/in/int/
> 
>> + *                  virDomain*Reason enmum corresponding to given state.
> 
> s/enmum/enum/
> 
>> + *
>> + * Returns the count of returned statistics strucutres on success, -1 on error.
> 
> s/strucutres/structures/
> 
>> + * The requested data are returned in the @retStats parameter. The returned
>> + * array should be freed by the caller. See virDomainStatsRecordListFree.
>> + */
>> +int
>> +virConnectGetAllDomainStats(virConnectPtr conn,
>> +                            unsigned int stats,
>> +                            virDomainStatsRecordPtr **retStats,
>> +                            unsigned int flags)
>> +{
>> +    int ret = -1;
>> +
>> +    VIR_DEBUG("conn=%p, stats=0x%x, retStats=%p, flags=0x%x",
>> +              conn, stats, retStats, flags);
>> +
>> +    virResetLastError();
>> +
>> +    virCheckConnectReturn(conn, -1);
> 
> virCheckNonNullArg(retStats)?  Matters depending on whether you plan to
> allow NULL retStats across RPC.

Yep we always want to have retStats. I forgot to add the check.

> 
> Right now, it looks like you are planning on allowing NULL for retStats
> to use the return value to see how many domains there are (or get an
> error that a requested stat is impossible).  Is it worth that
> complexity, given that virConnectListAllDomains can already return a
> count of the number of domains?  Then again, consistency is easier to
> copy-and-paste and therefore maintain.
> 
> 
>> +/**
>> + * virDomainListGetStats:
>> + * @doms: NULL terminated array of domains
> 
> I'm a little bit surprised that we aren't requiring the user to just
> pass a length; but since virConnectListAllDomains returns a
> NULL-terminated array, having one less parameter does seem easier on the
> caller.



> 
>> + * @stats: stats to return, binary-OR of virDomainStatsTypes
>> + * @retStats: Pointer that will be filled with the array of returned stats.
>> + * @flags: extra flags; not used yet, so callers should always pass 0
>> + *
>> + * Query statistics for domains provided by @doms. Note that all domains in
>> + * @doms must share the same connection.
> 
> Yes, that better be enforced :)
> 
>> + *
>> + * VIR_DOMAIN_STATS_STATE: Return domain state and reason for entering that
>> + * state. The typed parameter keys are in format:
>> + * "state.state" - state of the VM, returned as int from virDomainState enum
>> + * "state.reason" - reason for entering given state, returned as in from
>> + *                  virDomain*Reason enmum corresponding to given state.
> 
> Same typos as above.  I'm okay with the duplication (it's easier for a
> user to read the right docs on the first hit than to have to chase
> links), but be sure to fix both places identically.
> 
>> + *
>> + * Returns the count of returned statistics strucutres on success, -1 on error.
> 
> Probably worth a simple mention that the return count may be smaller
> than the count of doms passed in.  (Probably not worth mentioning why,
> but possible reasons might include: domain no longer exists, duplicate
> domains on input consolidated into common domain on output, driver can
> only list stats for a running domain so it omits an entire structure for
> an offline domain, ...)
> 
>> +int
>> +virDomainListGetStats(virDomainPtr *doms,
>> +                      unsigned int stats,
>> +                      virDomainStatsRecordPtr **retStats,
>> +                      unsigned int flags)
>> +{
>> +    virConnectPtr conn = NULL;
>> +    virDomainPtr *nextdom = doms;
>> +    unsigned int ndoms = 0;
>> +    int ret = -1;
>> +
>> +    VIR_DEBUG("doms=%p, stats=0x%x, retStats=%p, flags=0x%x",
>> +              doms, stats, retStats, flags);
>> +
>> +    virResetLastError();
>> +
>> +    if (!*doms) {
> 
> Missing virCheckNonNullArgReturn(doms, -1) prior to dereferencing *doms.
>  (I would have suggested virCheckNonNullArgGoto(doms, error), except
> that the error label only works if we have validated the connection).
> 
>> +        virReportError(VIR_ERR_INVALID_ARG,
>> +                       _("doms array in %s must contain at least one domain"),
>> +                       __FUNCTION__);
>> +        goto cleanup;
> 
> Ouch.  You can't use the cleanup label unless you know the conn is
> valid, but you don't validate the conn until...
> 

Actually you can. The function that validates "conn" calls the same
error dispatching function with NULL argument. Exactly what will happen
here.

>> +    }
>> +
>> +    conn = doms[0]->conn;
>> +    virCheckConnectReturn(conn, -1);
> 
> ...here.  All failures before this point have to be direct 'return -1'.
>  But you want as few of those as possible, so that the bulk of the error
> detection can report the error through the connection.
> 
# define virCheckConnectReturn(obj, retval)
    do {
        if (!virObjectIsClass(obj, virConnectClass)) {
            virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INVALID_CONN,
                                 __FILE__, __FUNCTION__, __LINE__,
                                 __FUNCTION__);
            virDispatchError(NULL);
            return retval;
        }
    } while (0)



>> +void
>> +virDomainStatsRecordListFree(virDomainStatsRecordPtr *stats)
>> +{
>> +    virDomainStatsRecordPtr *next = stats;
>> +
>> +    while (*next) {
>> +        virTypedParamsFree((*next)->params, (*next)->nparams);
>> +        virDomainFree((*next)->dom);
>> +        VIR_FREE((*next));
> 
> Extra () on that last line (only needed on the first 2 of the three lines).
> 
> Looking close, but I'd feel more comfortable with a v3.

Peter


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20140826/9a9c7201/attachment-0001.sig>


More information about the libvir-list mailing list