[libvirt] [PATCH 00/10] Introduce worker tuning APIs

Erik Skultety (10): libvirt-host: Move virTypedParam* to libvirt-common admin: Enable usage of typed parameters admin: Introduce virAdmConnectServerLookupByName util: Refactor thread creation by introducing virThreadPoolExpand util: Report system error when virThreadCreateFull fails util: Add more getters to threadpool parameters admin: Prepare admin protocol for future worker related procedures admin: Introduce virAdmServerGethreadPoolParameters admin: Introduce virAdmServerSetThreadPoolParameters virt-admin: Introduce srv-workertune command cfg.mk | 2 +- daemon/admin.c | 129 ++++++++++++++++++++++++ daemon/admin_server.c | 129 ++++++++++++++++++++++++ daemon/admin_server.h | 15 +++ include/libvirt/libvirt-admin.h | 74 ++++++++++++++ include/libvirt/libvirt-common.h.in | 185 ++++++++++++++++++++++++++++++++++ include/libvirt/libvirt-host.h | 186 ---------------------------------- include/libvirt/virterror.h | 1 + po/POTFILES.in | 4 +- src/admin/admin_protocol.x | 67 +++++++++++- src/admin/admin_remote.c | 104 +++++++++++++++++++ src/admin_protocol-structs | 52 ++++++++++ src/libvirt-admin.c | 114 +++++++++++++++++++++ src/libvirt_admin_private.syms | 5 + src/libvirt_admin_public.syms | 3 + src/libvirt_private.syms | 4 + src/rpc/virnetserver.c | 37 +++++++ src/rpc/virnetserver.h | 13 +++ src/util/virerror.c | 6 ++ src/util/virthreadpool.c | 196 ++++++++++++++++++++++++------------ src/util/virthreadpool.h | 8 ++ tools/virt-admin.c | 132 ++++++++++++++++++++++++ 22 files changed, 1212 insertions(+), 254 deletions(-) -- 2.4.3

Commits 0472cef6, 9afc115f, 8cd1d546 exported typed params handlers internally, but a commit which would move the public definition from libvirt-host to libvirt-common was missing. --- include/libvirt/libvirt-common.h.in | 185 +++++++++++++++++++++++++++++++++++ include/libvirt/libvirt-host.h | 186 ------------------------------------ 2 files changed, 185 insertions(+), 186 deletions(-) diff --git a/include/libvirt/libvirt-common.h.in b/include/libvirt/libvirt-common.h.in index efbb91b..772e40f 100644 --- a/include/libvirt/libvirt-common.h.in +++ b/include/libvirt/libvirt-common.h.in @@ -120,6 +120,191 @@ typedef enum { # endif } virConnectCloseReason; +/** + * virTypedParameterType: + * + * Express the type of a virTypedParameter + */ +typedef enum { + VIR_TYPED_PARAM_INT = 1, /* integer case */ + VIR_TYPED_PARAM_UINT = 2, /* unsigned integer case */ + VIR_TYPED_PARAM_LLONG = 3, /* long long case */ + VIR_TYPED_PARAM_ULLONG = 4, /* unsigned long long case */ + VIR_TYPED_PARAM_DOUBLE = 5, /* double case */ + VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case */ + VIR_TYPED_PARAM_STRING = 7, /* string case */ + +# ifdef VIR_ENUM_SENTINELS + VIR_TYPED_PARAM_LAST +# endif +} virTypedParameterType; + +/** + * virTypedParameterFlags: + * + * Flags related to libvirt APIs that use virTypedParameter. + * + * These enums should not conflict with those of virDomainModificationImpact. + */ +typedef enum { + /* 1 << 0 is reserved for virDomainModificationImpact */ + /* 1 << 1 is reserved for virDomainModificationImpact */ + + /* Older servers lacked the ability to handle string typed + * parameters. Attempts to set a string parameter with an older + * server will fail at the client, but attempts to retrieve + * parameters must not return strings from a new server to an + * older client, so this flag exists to identify newer clients to + * newer servers. This flag is automatically set when needed, so + * the user does not have to worry about it; however, manually + * setting the flag can be used to reject servers that cannot + * return typed strings, even if no strings would be returned. + */ + VIR_TYPED_PARAM_STRING_OKAY = 1 << 2, + +} virTypedParameterFlags; + +/** + * VIR_TYPED_PARAM_FIELD_LENGTH: + * + * Macro providing the field length of virTypedParameter name + */ +# define VIR_TYPED_PARAM_FIELD_LENGTH 80 + +/** + * virTypedParameter: + * + * A named parameter, including a type and value. + * + * The types virSchedParameter, virBlkioParameter, and + * virMemoryParameter are aliases of this type, for use when + * targeting libvirt earlier than 0.9.2. + */ +typedef struct _virTypedParameter virTypedParameter; + +struct _virTypedParameter { + char field[VIR_TYPED_PARAM_FIELD_LENGTH]; /* parameter name */ + int type; /* parameter type, virTypedParameterType */ + union { + int i; /* type is INT */ + unsigned int ui; /* type is UINT */ + long long int l; /* type is LLONG */ + unsigned long long int ul; /* type is ULLONG */ + double d; /* type is DOUBLE */ + char b; /* type is BOOLEAN */ + char *s; /* type is STRING, may not be NULL */ + } value; /* parameter value */ +}; + +/** + * virTypedParameterPtr: + * + * a pointer to a virTypedParameter structure. + */ +typedef virTypedParameter *virTypedParameterPtr; + + +virTypedParameterPtr +virTypedParamsGet (virTypedParameterPtr params, + int nparams, + const char *name); +int +virTypedParamsGetInt (virTypedParameterPtr params, + int nparams, + const char *name, + int *value); +int +virTypedParamsGetUInt (virTypedParameterPtr params, + int nparams, + const char *name, + unsigned int *value); +int +virTypedParamsGetLLong (virTypedParameterPtr params, + int nparams, + const char *name, + long long *value); +int +virTypedParamsGetULLong (virTypedParameterPtr params, + int nparams, + const char *name, + unsigned long long *value); +int +virTypedParamsGetDouble (virTypedParameterPtr params, + int nparams, + const char *name, + double *value); +int +virTypedParamsGetBoolean(virTypedParameterPtr params, + int nparams, + const char *name, + int *value); +int +virTypedParamsGetString (virTypedParameterPtr params, + int nparams, + const char *name, + const char **value); +int +virTypedParamsAddInt (virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + int value); +int +virTypedParamsAddUInt (virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + unsigned int value); +int +virTypedParamsAddLLong (virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + long long value); +int +virTypedParamsAddULLong (virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + unsigned long long value); +int +virTypedParamsAddDouble (virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + double value); +int +virTypedParamsAddBoolean(virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + int value); +int +virTypedParamsAddString (virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + const char *value); +int +virTypedParamsAddStringList(virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + const char **values); +int +virTypedParamsAddFromString(virTypedParameterPtr *params, + int *nparams, + int *maxparams, + const char *name, + int type, + const char *value); +void +virTypedParamsClear (virTypedParameterPtr params, + int nparams); +void +virTypedParamsFree (virTypedParameterPtr params, + int nparams); + # ifdef __cplusplus } # endif diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index 8786fbb..07b5d15 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -140,192 +140,6 @@ struct _virSecurityModel { */ typedef virSecurityModel *virSecurityModelPtr; -/* Common data types shared among interfaces with name/type/value lists. */ - -/** - * virTypedParameterType: - * - * Express the type of a virTypedParameter - */ -typedef enum { - VIR_TYPED_PARAM_INT = 1, /* integer case */ - VIR_TYPED_PARAM_UINT = 2, /* unsigned integer case */ - VIR_TYPED_PARAM_LLONG = 3, /* long long case */ - VIR_TYPED_PARAM_ULLONG = 4, /* unsigned long long case */ - VIR_TYPED_PARAM_DOUBLE = 5, /* double case */ - VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case */ - VIR_TYPED_PARAM_STRING = 7, /* string case */ - -# ifdef VIR_ENUM_SENTINELS - VIR_TYPED_PARAM_LAST -# endif -} virTypedParameterType; - -/** - * virTypedParameterFlags: - * - * Flags related to libvirt APIs that use virTypedParameter. - * - * These enums should not conflict with those of virDomainModificationImpact. - */ -typedef enum { - /* 1 << 0 is reserved for virDomainModificationImpact */ - /* 1 << 1 is reserved for virDomainModificationImpact */ - - /* Older servers lacked the ability to handle string typed - * parameters. Attempts to set a string parameter with an older - * server will fail at the client, but attempts to retrieve - * parameters must not return strings from a new server to an - * older client, so this flag exists to identify newer clients to - * newer servers. This flag is automatically set when needed, so - * the user does not have to worry about it; however, manually - * setting the flag can be used to reject servers that cannot - * return typed strings, even if no strings would be returned. - */ - VIR_TYPED_PARAM_STRING_OKAY = 1 << 2, - -} virTypedParameterFlags; - -/** - * VIR_TYPED_PARAM_FIELD_LENGTH: - * - * Macro providing the field length of virTypedParameter name - */ -# define VIR_TYPED_PARAM_FIELD_LENGTH 80 - -/** - * virTypedParameter: - * - * A named parameter, including a type and value. - * - * The types virSchedParameter, virBlkioParameter, and - * virMemoryParameter are aliases of this type, for use when - * targeting libvirt earlier than 0.9.2. - */ -typedef struct _virTypedParameter virTypedParameter; - -struct _virTypedParameter { - char field[VIR_TYPED_PARAM_FIELD_LENGTH]; /* parameter name */ - int type; /* parameter type, virTypedParameterType */ - union { - int i; /* type is INT */ - unsigned int ui; /* type is UINT */ - long long int l; /* type is LLONG */ - unsigned long long int ul; /* type is ULLONG */ - double d; /* type is DOUBLE */ - char b; /* type is BOOLEAN */ - char *s; /* type is STRING, may not be NULL */ - } value; /* parameter value */ -}; - -/** - * virTypedParameterPtr: - * - * a pointer to a virTypedParameter structure. - */ -typedef virTypedParameter *virTypedParameterPtr; - - -virTypedParameterPtr -virTypedParamsGet (virTypedParameterPtr params, - int nparams, - const char *name); -int -virTypedParamsGetInt (virTypedParameterPtr params, - int nparams, - const char *name, - int *value); -int -virTypedParamsGetUInt (virTypedParameterPtr params, - int nparams, - const char *name, - unsigned int *value); -int -virTypedParamsGetLLong (virTypedParameterPtr params, - int nparams, - const char *name, - long long *value); -int -virTypedParamsGetULLong (virTypedParameterPtr params, - int nparams, - const char *name, - unsigned long long *value); -int -virTypedParamsGetDouble (virTypedParameterPtr params, - int nparams, - const char *name, - double *value); -int -virTypedParamsGetBoolean(virTypedParameterPtr params, - int nparams, - const char *name, - int *value); -int -virTypedParamsGetString (virTypedParameterPtr params, - int nparams, - const char *name, - const char **value); -int -virTypedParamsAddInt (virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - int value); -int -virTypedParamsAddUInt (virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - unsigned int value); -int -virTypedParamsAddLLong (virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - long long value); -int -virTypedParamsAddULLong (virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - unsigned long long value); -int -virTypedParamsAddDouble (virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - double value); -int -virTypedParamsAddBoolean(virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - int value); -int -virTypedParamsAddString (virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - const char *value); -int -virTypedParamsAddStringList(virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - const char **values); -int -virTypedParamsAddFromString(virTypedParameterPtr *params, - int *nparams, - int *maxparams, - const char *name, - int type, - const char *value); -void -virTypedParamsClear (virTypedParameterPtr params, - int nparams); -void -virTypedParamsFree (virTypedParameterPtr params, - int nparams); /* data types related to virNodePtr */ -- 2.4.3

Make all relevant changes to admin protocol, in order to achieve $(subj) --- cfg.mk | 2 +- src/admin/admin_protocol.x | 24 ++++++++++++++++++++++++ src/admin_protocol-structs | 25 +++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/cfg.mk b/cfg.mk index 5b864af..d1e58be 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1225,7 +1225,7 @@ exclude_file_name_regexp--sc_prohibit_include_public_headers_brackets = \ ^(tools/|examples/|include/libvirt/(virterror|libvirt(-(admin|qemu|lxc))?)\.h$$) exclude_file_name_regexp--sc_prohibit_int_ijk = \ - ^(src/remote_protocol-structs|src/remote/remote_protocol.x|cfg.mk|include/)$ + ^(src/remote_protocol-structs|src/remote/remote_protocol.x|cfg.mk|include/|src/admin_protocol-structs|src/admin/admin_protocol.x)$ exclude_file_name_regexp--sc_prohibit_getenv = \ ^tests/.*\.[ch]$$ diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x index 089ce57..7b0a3b3 100644 --- a/src/admin/admin_protocol.x +++ b/src/admin/admin_protocol.x @@ -22,6 +22,7 @@ * Author: Martin Kletzander <mkletzan@redhat.com> */ +%#include <libvirt/libvirt-admin.h> %#include "virxdrdefs.h" /*----- Data types. -----*/ @@ -41,12 +42,35 @@ typedef string admin_nonnull_string<ADMIN_STRING_MAX>; /* A long string, which may be NULL. */ typedef admin_nonnull_string *admin_string; +union admin_typed_param_value switch (int type) { + case VIR_TYPED_PARAM_INT: + int i; + case VIR_TYPED_PARAM_UINT: + unsigned int ui; + case VIR_TYPED_PARAM_LLONG: + hyper l; + case VIR_TYPED_PARAM_ULLONG: + unsigned hyper ul; + case VIR_TYPED_PARAM_DOUBLE: + double d; + case VIR_TYPED_PARAM_BOOLEAN: + int b; + case VIR_TYPED_PARAM_STRING: + admin_nonnull_string s; +}; + +struct admin_typed_param { + admin_nonnull_string field; + admin_typed_param_value value; +}; + /* A server which may NOT be NULL */ struct admin_nonnull_server { admin_nonnull_string name; }; /*----- Protocol. -----*/ + struct admin_connect_open_args { unsigned int flags; }; diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs index 8f2633a..7153a89 100644 --- a/src/admin_protocol-structs +++ b/src/admin_protocol-structs @@ -1,4 +1,29 @@ /* -*- c -*- */ +enum { + VIR_TYPED_PARAM_INT = 1, + VIR_TYPED_PARAM_UINT = 2, + VIR_TYPED_PARAM_LLONG = 3, + VIR_TYPED_PARAM_ULLONG = 4, + VIR_TYPED_PARAM_DOUBLE = 5, + VIR_TYPED_PARAM_BOOLEAN = 6, + VIR_TYPED_PARAM_STRING = 7, +}; +struct admin_typed_param_value { + int type; + union { + int i; + u_int ui; + int64_t l; + uint64_t ul; + double d; + int b; + admin_nonnull_string s; + } admin_typed_param_value_u; +}; +struct admin_typed_param { + admin_nonnull_string field; + admin_typed_param_value value; +}; struct admin_nonnull_server { admin_nonnull_string name; }; -- 2.4.3

manipulating a server requires a client-side server object reference. We cannot rely on client to call virAdmConnectListAllServers and further stored the result. Therefore offer a separate API to retrieve a specific server object for remote-side. --- daemon/admin.c | 26 ++++++++++++++++++++++++++ daemon/admin_server.c | 17 +++++++++++++++++ daemon/admin_server.h | 4 ++++ include/libvirt/libvirt-admin.h | 2 ++ include/libvirt/virterror.h | 1 + po/POTFILES.in | 3 ++- src/admin/admin_protocol.x | 15 ++++++++++++++- src/admin/admin_remote.c | 27 +++++++++++++++++++++++++++ src/admin_protocol-structs | 7 +++++++ src/libvirt-admin.c | 31 +++++++++++++++++++++++++++++++ src/libvirt_admin_private.syms | 2 ++ src/libvirt_admin_public.syms | 1 + src/util/virerror.c | 6 ++++++ 13 files changed, 140 insertions(+), 2 deletions(-) diff --git a/daemon/admin.c b/daemon/admin.c index 0c1ddc0..45b1190 100644 --- a/daemon/admin.c +++ b/daemon/admin.c @@ -178,4 +178,30 @@ adminDispatchConnectListServers(virNetServerPtr server ATTRIBUTE_UNUSED, VIR_FREE(servers); return rv; } + +static int +adminDispatchConnectServerLookupByName(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + struct admin_connect_server_lookup_by_name_args *args, + struct admin_connect_server_lookup_by_name_ret *ret) +{ + int rv = -1; + virAdmServerPtr srv = NULL; + struct daemonAdmClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!(srv = adminDaemonLookupServerByName(priv->dmn, args->name))) + goto cleanup; + + make_nonnull_server(&ret->server, srv); + rv = 0; + + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virObjectUnref(srv); + return rv; +} #include "admin_dispatch.h" diff --git a/daemon/admin_server.c b/daemon/admin_server.c index 0196bfe..de8bc71 100644 --- a/daemon/admin_server.c +++ b/daemon/admin_server.c @@ -72,3 +72,20 @@ adminDaemonListServers(virNetDaemonPtr dmn, virObjectListFree(srvs); return ret; } + +virAdmServerPtr +adminDaemonLookupServerByName(virNetDaemonPtr dmn, + const char *name) +{ + virNetServerPtr srv = NULL; + + if (!(srv = virNetDaemonGetServer(dmn, name))) { + virReportError(VIR_ERR_NO_SERVER, + _("no server with matching name '%s' found"), + name); + return NULL; + } + + virObjectUnref(srv); + return virAdmGetServer(NULL, name); +} diff --git a/daemon/admin_server.h b/daemon/admin_server.h index 2a5aa16..385c3e4 100644 --- a/daemon/admin_server.h +++ b/daemon/admin_server.h @@ -31,4 +31,8 @@ adminDaemonListServers(virNetDaemonPtr dmn, virAdmServerPtr **servers, unsigned int flags); +virAdmServerPtr +adminDaemonLookupServerByName(virNetDaemonPtr dmn, + const char *name); + #endif /* __LIBVIRTD_ADMIN_SERVER_H__ */ diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h index e9ec394..1f62a4d 100644 --- a/include/libvirt/libvirt-admin.h +++ b/include/libvirt/libvirt-admin.h @@ -106,6 +106,8 @@ int virAdmConnectUnregisterCloseCallback(virAdmConnectPtr conn, const char *virAdmServerGetName(virAdmServerPtr srv); +virAdmServerPtr virAdmConnectServerLookupByName(virAdmConnectPtr conn, + const char *name); # ifdef __cplusplus } # endif diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index c6d1a76..90621aa 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -310,6 +310,7 @@ typedef enum { CPU*/ VIR_ERR_XML_INVALID_SCHEMA = 92, /* XML document doesn't validate against schema */ VIR_ERR_MIGRATE_FINISH_OK = 93, /* Finish API succeeded but it is expected to return NULL */ + VIR_ERR_NO_SERVER = 94, /* server with matching name not found */ } virErrorNumber; /** diff --git a/po/POTFILES.in b/po/POTFILES.in index ff207cb..27980df 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,5 +1,6 @@ -daemon/admin_dispatch.h daemon/admin.c +daemon/admin_dispatch.h +daemon/admin_server.c daemon/libvirtd-config.c daemon/libvirtd.c daemon/qemu_dispatch.h diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x index 7b0a3b3..09b9c7d 100644 --- a/src/admin/admin_protocol.x +++ b/src/admin/admin_protocol.x @@ -89,6 +89,14 @@ struct admin_connect_list_servers_ret { unsigned int ret; }; +struct admin_connect_server_lookup_by_name_args { + admin_nonnull_string name; +}; + +struct admin_connect_server_lookup_by_name_ret { + admin_nonnull_server server; +}; + /* Define the program number, protocol version and procedure numbers here. */ const ADMIN_PROGRAM = 0x06900690; const ADMIN_PROTOCOL_VERSION = 1; @@ -130,5 +138,10 @@ enum admin_procedure { * @generate: none * @priority: high */ - ADMIN_PROC_CONNECT_LIST_SERVERS = 4 + ADMIN_PROC_CONNECT_LIST_SERVERS = 4, + + /** + * @generate: none + */ + ADMIN_PROC_CONNECT_SERVER_LOOKUP_BY_NAME = 5 }; diff --git a/src/admin/admin_remote.c b/src/admin/admin_remote.c index 3745b9e..570dce4 100644 --- a/src/admin/admin_remote.c +++ b/src/admin/admin_remote.c @@ -287,3 +287,30 @@ remoteAdminConnectListServers(virAdmConnectPtr conn, virObjectUnlock(priv); return rv; } + +static virAdmServerPtr +remoteAdminConnectServerLookupByName(virAdmConnectPtr conn, + const char *srvname) +{ + virAdmServerPtr rv = NULL; + remoteAdminPrivPtr priv = conn->privateData; + admin_connect_server_lookup_by_name_args args; + admin_connect_server_lookup_by_name_ret ret; + + args.name = (char *) srvname; + memset(&ret, 0, sizeof(ret)); + + virObjectLock(priv); + + if (call(conn, 0, ADMIN_PROC_CONNECT_SERVER_LOOKUP_BY_NAME, + (xdrproc_t)xdr_admin_connect_server_lookup_by_name_args, (char *) &args, + (xdrproc_t)xdr_admin_connect_server_lookup_by_name_ret, (char *) &ret) == -1) + goto cleanup; + + rv = get_nonnull_server(conn, ret.server); + xdr_free((xdrproc_t)xdr_admin_connect_server_lookup_by_name_ret, (char *) &ret); + + cleanup: + virObjectUnlock(priv); + return rv; +} diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs index 7153a89..141de25 100644 --- a/src/admin_protocol-structs +++ b/src/admin_protocol-structs @@ -44,9 +44,16 @@ struct admin_connect_list_servers_ret { } servers; u_int ret; }; +struct admin_connect_server_lookup_by_name_args { + admin_nonnull_string name; +}; +struct admin_connect_server_lookup_by_name_ret { + admin_nonnull_server server; +}; enum admin_procedure { ADMIN_PROC_CONNECT_OPEN = 1, ADMIN_PROC_CONNECT_CLOSE = 2, ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3, ADMIN_PROC_CONNECT_LIST_SERVERS = 4, + ADMIN_PROC_CONNECT_SERVER_LOOKUP_BY_NAME = 5, }; diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c index 3667444..d09c015 100644 --- a/src/libvirt-admin.c +++ b/src/libvirt-admin.c @@ -633,3 +633,34 @@ virAdmConnectListServers(virAdmConnectPtr conn, virDispatchError(NULL); return -1; } + +/** + * virAdmConnectServerLookupByName: + * @conn: daemon connection reference + * @name: name of the server which the method will look for + * + * Method looks up and returns a server object based on its name. + * + * Returns handle to server object or NULL in case of an error. + */ +virAdmServerPtr +virAdmConnectServerLookupByName(virAdmConnectPtr conn, + const char *name) +{ + virAdmServerPtr ret = NULL; + + VIR_DEBUG("conn=%p, name=%s", conn, name); + + virResetLastError(); + + virCheckAdmConnectReturn(conn, NULL); + virCheckNonNullArgGoto(name, error); + + if (!(ret = remoteAdminConnectServerLookupByName(conn, name))) + goto error; + + return ret; + error: + virDispatchError(NULL); + return NULL; +} diff --git a/src/libvirt_admin_private.syms b/src/libvirt_admin_private.syms index f22137b..cdd2203 100644 --- a/src/libvirt_admin_private.syms +++ b/src/libvirt_admin_private.syms @@ -10,6 +10,8 @@ xdr_admin_connect_get_lib_version_ret; xdr_admin_connect_list_servers_args; xdr_admin_connect_list_servers_ret; xdr_admin_connect_open_args; +xdr_admin_connect_server_lookup_by_name_args; +xdr_admin_connect_server_lookup_by_name_ret; # datatypes.h virAdmConnectClass; diff --git a/src/libvirt_admin_public.syms b/src/libvirt_admin_public.syms index 52ff2dc..84936c2 100644 --- a/src/libvirt_admin_public.syms +++ b/src/libvirt_admin_public.syms @@ -20,6 +20,7 @@ LIBVIRT_ADMIN_1.3.0 { virAdmConnectGetURI; virAdmConnectGetLibVersion; virAdmConnectRegisterCloseCallback; + virAdmConnectServerLookupByName; virAdmConnectUnregisterCloseCallback; virAdmConnectListServers; virAdmServerGetName; diff --git a/src/util/virerror.c b/src/util/virerror.c index e1bcf52..0acc914 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -1374,6 +1374,12 @@ virErrorMsg(virErrorNumber error, const char *info) case VIR_ERR_MIGRATE_FINISH_OK: errmsg = _("migration successfully aborted"); break; + case VIR_ERR_NO_SERVER: + if (info == NULL) + errmsg = _("Server not found"); + else + errmsg = _("Server not found: %s"); + break; } return errmsg; } -- 2.4.3

On Mon, Feb 29, 2016 at 04:03:49PM +0100, Erik Skultety wrote:
manipulating a server requires a client-side server object reference. We cannot rely on client to call virAdmConnectListAllServers and further stored the result. Therefore offer a separate API to retrieve a specific server object for remote-side. --- daemon/admin.c | 26 ++++++++++++++++++++++++++ daemon/admin_server.c | 17 +++++++++++++++++ daemon/admin_server.h | 4 ++++ include/libvirt/libvirt-admin.h | 2 ++ include/libvirt/virterror.h | 1 + po/POTFILES.in | 3 ++- src/admin/admin_protocol.x | 15 ++++++++++++++- src/admin/admin_remote.c | 27 +++++++++++++++++++++++++++ src/admin_protocol-structs | 7 +++++++ src/libvirt-admin.c | 31 +++++++++++++++++++++++++++++++ src/libvirt_admin_private.syms | 2 ++ src/libvirt_admin_public.syms | 1 + src/util/virerror.c | 6 ++++++ 13 files changed, 140 insertions(+), 2 deletions(-)
Before anyone ACKs it, I have very similar patch that could be combined with this one that I'm cleaning up, so I can post it here later on. Feel free to review, though. Martin

When either creating a threadpool, or creating a new thread to accomplish a job that had been placed into the jobqueue, every time thread-specific data need to be allocated, threadpool needs to be (re)-allocated and thread count indicators updated. Make the code clearer to read by compressing these operations into a more complex one. --- src/util/virthreadpool.c | 109 +++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 65 deletions(-) diff --git a/src/util/virthreadpool.c b/src/util/virthreadpool.c index f640448..8af4ec0 100644 --- a/src/util/virthreadpool.c +++ b/src/util/virthreadpool.c @@ -157,6 +157,43 @@ static void virThreadPoolWorker(void *opaque) virMutexUnlock(&pool->mutex); } +static int +virThreadPoolExpand(virThreadPoolPtr pool, size_t gain, bool priority) +{ + virThreadPtr workers = priority ? pool->prioWorkers : pool->workers; + size_t *curWorkers = priority ? &pool->nPrioWorkers : &pool->nWorkers; + size_t i = 0; + struct virThreadPoolWorkerData *data = NULL; + + if (VIR_EXPAND_N(workers, *curWorkers, gain) < 0) + return -1; + + for (i = 0; i < gain; i++) { + if (VIR_ALLOC(data) < 0) + goto error; + + data->pool = pool; + data->cond = priority ? &pool->prioCond : &pool->cond; + data->priority = priority; + + if (virThreadCreateFull(&workers[i], + false, + virThreadPoolWorker, + pool->jobFuncName, + true, + data) < 0) { + VIR_FREE(data); + goto error; + } + } + + return 0; + + error: + *curWorkers -= gain - i; + return -1; +} + virThreadPoolPtr virThreadPoolNewFull(size_t minWorkers, size_t maxWorkers, @@ -166,8 +203,6 @@ virThreadPoolNewFull(size_t minWorkers, void *opaque) { virThreadPoolPtr pool; - size_t i; - struct virThreadPoolWorkerData *data = NULL; if (minWorkers > maxWorkers) minWorkers = maxWorkers; @@ -188,58 +223,23 @@ virThreadPoolNewFull(size_t minWorkers, if (virCondInit(&pool->quit_cond) < 0) goto error; - if (VIR_ALLOC_N(pool->workers, minWorkers) < 0) - goto error; - pool->minWorkers = minWorkers; pool->maxWorkers = maxWorkers; - for (i = 0; i < minWorkers; i++) { - if (VIR_ALLOC(data) < 0) - goto error; - data->pool = pool; - data->cond = &pool->cond; - - if (virThreadCreateFull(&pool->workers[i], - false, - virThreadPoolWorker, - pool->jobFuncName, - true, - data) < 0) { - goto error; - } - pool->nWorkers++; - } + if (virThreadPoolExpand(pool, minWorkers, false) < 0) + goto error; if (prioWorkers) { if (virCondInit(&pool->prioCond) < 0) goto error; - if (VIR_ALLOC_N(pool->prioWorkers, prioWorkers) < 0) - goto error; - for (i = 0; i < prioWorkers; i++) { - if (VIR_ALLOC(data) < 0) - goto error; - data->pool = pool; - data->cond = &pool->prioCond; - data->priority = true; - - if (virThreadCreateFull(&pool->prioWorkers[i], - false, - virThreadPoolWorker, - pool->jobFuncName, - true, - data) < 0) { - goto error; - } - pool->nPrioWorkers++; - } + if (virThreadPoolExpand(pool, prioWorkers, true) < 0) + goto error; } return pool; error: - VIR_FREE(data); virThreadPoolFree(pool); return NULL; @@ -307,36 +307,15 @@ int virThreadPoolSendJob(virThreadPoolPtr pool, void *jobData) { virThreadPoolJobPtr job; - struct virThreadPoolWorkerData *data = NULL; virMutexLock(&pool->mutex); if (pool->quit) goto error; if (pool->freeWorkers - pool->jobQueueDepth <= 0 && - pool->nWorkers < pool->maxWorkers) { - if (VIR_EXPAND_N(pool->workers, pool->nWorkers, 1) < 0) - goto error; - - if (VIR_ALLOC(data) < 0) { - pool->nWorkers--; - goto error; - } - - data->pool = pool; - data->cond = &pool->cond; - - if (virThreadCreateFull(&pool->workers[pool->nWorkers - 1], - false, - virThreadPoolWorker, - pool->jobFuncName, - true, - data) < 0) { - VIR_FREE(data); - pool->nWorkers--; - goto error; - } - } + pool->nWorkers < pool->maxWorkers && + virThreadPoolExpand(pool, 1, false) < 0) + goto error; if (VIR_ALLOC(job) < 0) goto error; -- 2.4.3

Otherwise 'Unknown' error will be returned to client. --- po/POTFILES.in | 1 + src/util/virthreadpool.c | 1 + 2 files changed, 2 insertions(+) diff --git a/po/POTFILES.in b/po/POTFILES.in index 27980df..455b799 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -237,6 +237,7 @@ src/util/virstoragefile.c src/util/virstring.c src/util/virsysinfo.c src/util/virthreadjob.c +src/util/virthreadpool.c src/util/virtime.c src/util/virtpm.c src/util/virtypedparam.c diff --git a/src/util/virthreadpool.c b/src/util/virthreadpool.c index 8af4ec0..e2e9fe4 100644 --- a/src/util/virthreadpool.c +++ b/src/util/virthreadpool.c @@ -183,6 +183,7 @@ virThreadPoolExpand(virThreadPoolPtr pool, size_t gain, bool priority) true, data) < 0) { VIR_FREE(data); + virReportSystemError(errno, "%s", _("Failed to create thread")); goto error; } } -- 2.4.3

In order for the client to see all thread counts and limits, current total and free worker count getters need to be introduced. Client might also be interested in the job queue length, so provide a getter for that too. --- src/libvirt_private.syms | 3 +++ src/util/virthreadpool.c | 15 +++++++++++++++ src/util/virthreadpool.h | 3 +++ 3 files changed, 21 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4b40612..7658ebf 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2318,6 +2318,9 @@ virThreadJobSetWorker; # util/virthreadpool.h virThreadPoolFree; +virThreadPoolGetCurrentWorkers; +virThreadPoolGetFreeWorkers; +virThreadPoolGetJobQueueDepth; virThreadPoolGetMaxWorkers; virThreadPoolGetMinWorkers; virThreadPoolGetPriorityWorkers; diff --git a/src/util/virthreadpool.c b/src/util/virthreadpool.c index e2e9fe4..518b880 100644 --- a/src/util/virthreadpool.c +++ b/src/util/virthreadpool.c @@ -299,6 +299,21 @@ size_t virThreadPoolGetPriorityWorkers(virThreadPoolPtr pool) return pool->nPrioWorkers; } +size_t virThreadPoolGetCurrentWorkers(virThreadPoolPtr pool) +{ + return pool->nWorkers; +} + +size_t virThreadPoolGetFreeWorkers(virThreadPoolPtr pool) +{ + return pool->freeWorkers; +} + +size_t virThreadPoolGetJobQueueDepth(virThreadPoolPtr pool) +{ + return pool->jobQueueDepth; +} + /* * @priority - job priority * Return: 0 on success, -1 otherwise diff --git a/src/util/virthreadpool.h b/src/util/virthreadpool.h index 538b62f..bc0c907 100644 --- a/src/util/virthreadpool.h +++ b/src/util/virthreadpool.h @@ -46,6 +46,9 @@ virThreadPoolPtr virThreadPoolNewFull(size_t minWorkers, size_t virThreadPoolGetMinWorkers(virThreadPoolPtr pool); size_t virThreadPoolGetMaxWorkers(virThreadPoolPtr pool); size_t virThreadPoolGetPriorityWorkers(virThreadPoolPtr pool); +size_t virThreadPoolGetCurrentWorkers(virThreadPoolPtr pool); +size_t virThreadPoolGetFreeWorkers(virThreadPoolPtr pool); +size_t virThreadPoolGetJobQueueDepth(virThreadPoolPtr pool); void virThreadPoolFree(virThreadPoolPtr pool); -- 2.4.3

Before any getter or setter methods can be introduced, first specify a set of public attributes/flags that these methods will be compatible with. --- include/libvirt/libvirt-admin.h | 61 +++++++++++++++++++++++++++++++++++++++++ src/admin/admin_protocol.x | 3 ++ 2 files changed, 64 insertions(+) diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h index 1f62a4d..e12c5ce 100644 --- a/include/libvirt/libvirt-admin.h +++ b/include/libvirt/libvirt-admin.h @@ -108,6 +108,67 @@ const char *virAdmServerGetName(virAdmServerPtr srv); virAdmServerPtr virAdmConnectServerLookupByName(virAdmConnectPtr conn, const char *name); + +/* Manage threadpool attributes */ + +/** + * VIR_THREADPOOL_WORKERS_MIN: + * Macro for the threadpool minWorkers limit: represents the bottom limit to + * number of active workers in threadpool, as uint. + */ + +# define VIR_THREADPOOL_WORKERS_MIN "minWorkers" + +/** + * VIR_THREADPOOL_WORKERS_MAX: + * Macro for the threadpool maxWorkers limit: represents the upper limit to + * number of active workers in threadpool, as uint. The value of this limit has + * to be greater than VIR_THREADPOOL_WORKERS_MIN at all times. + */ + +# define VIR_THREADPOOL_WORKERS_MAX "maxWorkers" + +/** + * VIR_THREADPOOL_WORKERS_PRIORITY: + * Macro for the threadpool nPrioWorkers attribute: represents the current number + * of active priority workers in threadpool, as uint. + */ + +# define VIR_THREADPOOL_WORKERS_PRIORITY "prioWorkers" + +/** + * VIR_THREADPOOL_WORKERS_FREE: + * Macro for the threadpool freeWorkers attribute: represents the current number + * of free workers available to accomplish a job, as uint. + * + * NOTE: This attribute is read-only and any attempt to set it will be denied + * by daemon + */ + +# define VIR_THREADPOOL_WORKERS_FREE "freeWorkers" + +/** + * VIR_THREADPOOL_WORKERS_CURRENT: + * Macro for the threadpool nWorkers attribute: represents the current number + * of active ordinary workers in threadpool, as uint. + * + * NOTE: This attribute is read-only and any attempt to set it will be denied + * by daemon + */ + +# define VIR_THREADPOOL_WORKERS_CURRENT "nWorkers" + +/** + * VIR_THREADPOOL_JOB_QUEUE_DEPTH: + * Macro for the threadpool jobQueueDepth attribute: represents the current + * number of jobs waiting in a queue to be processed, as uint. + * + * NOTE: This attribute is read-only and any attempt to set it will be denied + * by daemon + */ + +# define VIR_THREADPOOL_JOB_QUEUE_DEPTH "jobQueueDepth" + # ifdef __cplusplus } # endif diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x index 09b9c7d..9d56a69 100644 --- a/src/admin/admin_protocol.x +++ b/src/admin/admin_protocol.x @@ -36,6 +36,9 @@ const ADMIN_STRING_MAX = 4194304; /* Upper limit on list of servers */ const ADMIN_SERVER_LIST_MAX = 16384; +/* Upper limit on number of threadpool stats */ +const ADMIN_SERVER_THREADPOOL_STATS_MAX = 32; + /* A long string, which may NOT be NULL. */ typedef string admin_nonnull_string<ADMIN_STRING_MAX>; -- 2.4.3

New API to retrieve current server workerpool specs. Since it uses typed parameters, more specs to retrieve can be further included in the pool of supported ones. --- daemon/admin.c | 60 +++++++++++++++++++++++++++++++++++ daemon/admin_server.c | 69 +++++++++++++++++++++++++++++++++++++++++ daemon/admin_server.h | 6 ++++ include/libvirt/libvirt-admin.h | 6 ++++ src/admin/admin_protocol.x | 20 ++++++++++-- src/admin/admin_remote.c | 43 +++++++++++++++++++++++++ src/admin_protocol-structs | 11 +++++++ src/libvirt-admin.c | 46 +++++++++++++++++++++++++++ src/libvirt_admin_private.syms | 2 ++ src/libvirt_admin_public.syms | 1 + src/rpc/virnetserver.c | 22 +++++++++++++ src/rpc/virnetserver.h | 13 ++++++++ 12 files changed, 296 insertions(+), 3 deletions(-) diff --git a/daemon/admin.c b/daemon/admin.c index 45b1190..8dc396e 100644 --- a/daemon/admin.c +++ b/daemon/admin.c @@ -37,6 +37,7 @@ #include "virnetserver.h" #include "virstring.h" #include "virthreadjob.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_ADMIN @@ -204,4 +205,63 @@ adminDispatchConnectServerLookupByName(virNetServerPtr server ATTRIBUTE_UNUSED, virObjectUnref(srv); return rv; } + +static int +adminDispatchServerGetThreadpoolParameters(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + struct admin_server_get_threadpool_parameters_args *args, + struct admin_server_get_threadpool_parameters_ret *ret) +{ + int rv = -1; + virNetServerPtr srv = NULL; + virTypedParameterPtr params = NULL; + int nparams = 0; + struct daemonAdmClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!(srv = virNetDaemonGetServer(priv->dmn, args->server.name))) { + virReportError(VIR_ERR_NO_SERVER, + _("no server with matching name '%s' found"), + args->server.name); + goto cleanup; + } + + if (adminDaemonGetThreadPoolParameters(srv, ¶ms, &nparams, + args->flags) < 0) + goto cleanup; + + if (nparams > ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of threadpool parameters %d exceeds max " + "allowed limit: %d"), nparams, + ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX); + goto cleanup; + } + + if (nparams) { + if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0) + goto cleanup; + + ret->params.params_len = nparams; + + if (virTypedParamsSerialize(params, nparams, + (virTypedParameterRemotePtr *) &ret->params.params_val, + &ret->params.params_len, 0) < 0) + goto cleanup; + } else { + ret->params.params_len = 0; + ret->params.params_val = NULL; + } + + rv = 0; + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + + virTypedParamsFree(params, nparams); + virObjectUnref(srv); + return rv; +} #include "admin_dispatch.h" diff --git a/daemon/admin_server.c b/daemon/admin_server.c index de8bc71..861a98c 100644 --- a/daemon/admin_server.c +++ b/daemon/admin_server.c @@ -31,6 +31,7 @@ #include "virnetdaemon.h" #include "virnetserver.h" #include "virstring.h" +#include "virthreadpool.h" #define VIR_FROM_THIS VIR_FROM_ADMIN @@ -89,3 +90,71 @@ adminDaemonLookupServerByName(virNetDaemonPtr dmn, virObjectUnref(srv); return virAdmGetServer(NULL, name); } + +int +adminDaemonGetThreadPoolParameters(virNetServerPtr srv, + virTypedParameterPtr *params, + int *nparams, + unsigned int flags) +{ + int ret = -1; + int maxparams = 0; + size_t minWorkers; + size_t maxWorkers; + size_t nWorkers; + size_t freeWorkers; + size_t nPrioWorkers; + size_t jobQueueDepth; + virTypedParameterPtr tmpparams = NULL; + + virCheckFlags(0, -1); + + if (virNetServerGetThreadPoolParameters(srv, &minWorkers, &maxWorkers, + &nWorkers, &freeWorkers, + &nPrioWorkers, + &jobQueueDepth) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to retrieve threadpool parameters")); + goto cleanup; + } + + if (virTypedParamsAddUInt(&tmpparams, nparams, + &maxparams, VIR_THREADPOOL_WORKERS_MIN, + minWorkers) < 0) + goto cleanup; + + if (virTypedParamsAddUInt(&tmpparams, nparams, + &maxparams, VIR_THREADPOOL_WORKERS_MAX, + maxWorkers) < 0) + goto cleanup; + + if (virTypedParamsAddUInt(&tmpparams, nparams, + &maxparams, VIR_THREADPOOL_WORKERS_CURRENT, + nWorkers) < 0) + goto cleanup; + + if (virTypedParamsAddUInt(&tmpparams, nparams, + &maxparams, VIR_THREADPOOL_WORKERS_FREE, + freeWorkers) < 0) + goto cleanup; + + if (virTypedParamsAddUInt(&tmpparams, nparams, + &maxparams, VIR_THREADPOOL_WORKERS_PRIORITY, + nPrioWorkers) < 0) + goto cleanup; + + if (virTypedParamsAddUInt(&tmpparams, nparams, + &maxparams, VIR_THREADPOOL_JOB_QUEUE_DEPTH, + jobQueueDepth) < 0) + goto cleanup; + + *params = tmpparams; + tmpparams = NULL; + ret = 0; + + cleanup: + if (tmpparams) + virTypedParamsFree(tmpparams, *nparams); + + return ret; +} diff --git a/daemon/admin_server.h b/daemon/admin_server.h index 385c3e4..7794bf1 100644 --- a/daemon/admin_server.h +++ b/daemon/admin_server.h @@ -35,4 +35,10 @@ virAdmServerPtr adminDaemonLookupServerByName(virNetDaemonPtr dmn, const char *name); +int +adminDaemonGetThreadPoolParameters(virNetServerPtr srv, + virTypedParameterPtr *params, + int *nparams, + unsigned int flags); + #endif /* __LIBVIRTD_ADMIN_SERVER_H__ */ diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h index e12c5ce..b96545b 100644 --- a/include/libvirt/libvirt-admin.h +++ b/include/libvirt/libvirt-admin.h @@ -169,6 +169,12 @@ virAdmServerPtr virAdmConnectServerLookupByName(virAdmConnectPtr conn, # define VIR_THREADPOOL_JOB_QUEUE_DEPTH "jobQueueDepth" +/* Tunables for a server workerpool */ +int virAdmServerGetThreadPoolParameters(virAdmServerPtr srv, + virTypedParameterPtr *params, + int *nparams, + unsigned int flags); + # ifdef __cplusplus } # endif diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x index 9d56a69..ed7bf67 100644 --- a/src/admin/admin_protocol.x +++ b/src/admin/admin_protocol.x @@ -36,8 +36,8 @@ const ADMIN_STRING_MAX = 4194304; /* Upper limit on list of servers */ const ADMIN_SERVER_LIST_MAX = 16384; -/* Upper limit on number of threadpool stats */ -const ADMIN_SERVER_THREADPOOL_STATS_MAX = 32; +/* Upper limit on number of threadpool parameters */ +const ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX = 32; /* A long string, which may NOT be NULL. */ typedef string admin_nonnull_string<ADMIN_STRING_MAX>; @@ -100,6 +100,15 @@ struct admin_connect_server_lookup_by_name_ret { admin_nonnull_server server; }; +struct admin_server_get_threadpool_parameters_args { + admin_nonnull_server server; + unsigned int flags; +}; + +struct admin_server_get_threadpool_parameters_ret { + admin_typed_param params<ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX>; +}; + /* Define the program number, protocol version and procedure numbers here. */ const ADMIN_PROGRAM = 0x06900690; const ADMIN_PROTOCOL_VERSION = 1; @@ -146,5 +155,10 @@ enum admin_procedure { /** * @generate: none */ - ADMIN_PROC_CONNECT_SERVER_LOOKUP_BY_NAME = 5 + ADMIN_PROC_CONNECT_SERVER_LOOKUP_BY_NAME = 5, + + /** + * @generate: none + */ + ADMIN_PROC_SERVER_GET_THREADPOOL_PARAMETERS = 6 }; diff --git a/src/admin/admin_remote.c b/src/admin/admin_remote.c index 570dce4..2717a17 100644 --- a/src/admin/admin_remote.c +++ b/src/admin/admin_remote.c @@ -22,6 +22,7 @@ #include <config.h> #include <rpc/rpc.h> +#include "virtypedparam.h" #include "admin_protocol.h" typedef struct _remoteAdminPriv remoteAdminPriv; @@ -54,6 +55,11 @@ get_nonnull_server(virAdmConnectPtr conn, admin_nonnull_server server) return virAdmGetServer(conn, server.name); } +static void +make_nonnull_server(admin_nonnull_server *srv_dst, virAdmServerPtr srv_src) +{ + srv_dst->name = srv_src->name; +} static int callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED, @@ -314,3 +320,40 @@ remoteAdminConnectServerLookupByName(virAdmConnectPtr conn, virObjectUnlock(priv); return rv; } + +static int +remoteAdminServerGetThreadPoolParameters(virAdmServerPtr srv, + virTypedParameterPtr *params, + int *nparams, + unsigned int flags) +{ + int rv = -1; + remoteAdminPrivPtr priv = srv->conn->privateData; + admin_server_get_threadpool_parameters_args args; + admin_server_get_threadpool_parameters_ret ret; + + args.flags = flags; + make_nonnull_server(&args.server, srv); + + memset(&ret, 0, sizeof(ret)); + virObjectLock(priv); + + if (call(srv->conn, 0, ADMIN_PROC_SERVER_GET_THREADPOOL_PARAMETERS, + (xdrproc_t)xdr_admin_server_get_threadpool_parameters_args, (char *) &args, + (xdrproc_t)xdr_admin_server_get_threadpool_parameters_ret, (char *) &ret) == -1) + goto cleanup; + + if (virTypedParamsDeserialize((virTypedParameterRemotePtr) ret.params.params_val, + ret.params.params_len, + ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX, + params, + nparams) < 0) + goto cleanup; + + rv = 0; + xdr_free((xdrproc_t)xdr_admin_server_get_threadpool_parameters_ret, (char *) &ret); + + cleanup: + virObjectUnlock(priv); + return rv; +} diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs index 141de25..d0bc367 100644 --- a/src/admin_protocol-structs +++ b/src/admin_protocol-structs @@ -50,10 +50,21 @@ struct admin_connect_server_lookup_by_name_args { struct admin_connect_server_lookup_by_name_ret { admin_nonnull_server server; }; +struct admin_server_get_threadpool_parameters_args { + admin_nonnull_server server; + u_int flags; +}; +struct admin_server_get_threadpool_parameters_ret { + struct { + u_int params_len; + admin_typed_param * params_val; + } params; +}; enum admin_procedure { ADMIN_PROC_CONNECT_OPEN = 1, ADMIN_PROC_CONNECT_CLOSE = 2, ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3, ADMIN_PROC_CONNECT_LIST_SERVERS = 4, ADMIN_PROC_CONNECT_SERVER_LOOKUP_BY_NAME = 5, + ADMIN_PROC_SERVER_GET_THREADPOOL_PARAMETERS = 6, }; diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c index d09c015..6165159 100644 --- a/src/libvirt-admin.c +++ b/src/libvirt-admin.c @@ -664,3 +664,49 @@ virAdmConnectServerLookupByName(virAdmConnectPtr conn, virDispatchError(NULL); return NULL; } + +/** + * virAdmServerGetThreadPoolParameters: + * @srv: a valid server object reference + * @params: a pointer which will be allocated to store all returned parameters + * @nparams: a pointer which will hold the number of params returned in @params + * @flags: extra flags for virAdmServerGetThreadPoolStatsFlags + * + * This methods retrieves threadpool parameters from @srv. Upon successful + * completion, @params will be allocated automatically to hold all returned + * params and setting @nparams accordingly. + * When extracting parameters from @params, following search keys are + * supported: + * VIR_THREADPOOL_WORKERS_MIN + * VIR_THREADPOOL_WORKERS_MAX + * VIR_THREADPOOL_WORKERS_PRIORITY + * VIR_THREADPOOL_WORKERS_FREE + * VIR_THREADPOOL_WORKERS_CURRENT + * + * Returns 0 on success, -1 in case of an error. + */ +int +virAdmServerGetThreadPoolParameters(virAdmServerPtr srv, + virTypedParameterPtr *params, + int *nparams, + unsigned int flags) +{ + int ret = -1; + + VIR_DEBUG("srv=%p, params=%p, nparams=%p, flags=%x", + srv, params, nparams, flags); + + virResetLastError(); + + virCheckAdmServerReturn(srv, -1); + virCheckNonNullArgGoto(params, error); + + if ((ret = remoteAdminServerGetThreadPoolParameters(srv, params, nparams, + flags)) < 0) + goto error; + + return ret; + error: + virDispatchError(NULL); + return -1; +} diff --git a/src/libvirt_admin_private.syms b/src/libvirt_admin_private.syms index cdd2203..7d3067f 100644 --- a/src/libvirt_admin_private.syms +++ b/src/libvirt_admin_private.syms @@ -12,6 +12,8 @@ xdr_admin_connect_list_servers_ret; xdr_admin_connect_open_args; xdr_admin_connect_server_lookup_by_name_args; xdr_admin_connect_server_lookup_by_name_ret; +xdr_admin_server_get_threadpool_parameters_args; +xdr_admin_server_get_threadpool_parameters_ret; # datatypes.h virAdmConnectClass; diff --git a/src/libvirt_admin_public.syms b/src/libvirt_admin_public.syms index 84936c2..e89ad75 100644 --- a/src/libvirt_admin_public.syms +++ b/src/libvirt_admin_public.syms @@ -24,5 +24,6 @@ LIBVIRT_ADMIN_1.3.0 { virAdmConnectUnregisterCloseCallback; virAdmConnectListServers; virAdmServerGetName; + virAdmServerGetThreadPoolParameters; virAdmServerFree; }; diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 547e52e..cc809bf 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -861,3 +861,25 @@ virNetServerStart(virNetServerPtr srv) return virNetServerMDNSStart(srv->mdns); } + +int +virNetServerGetThreadPoolParameters(virNetServerPtr srv, + size_t *minWorkers, + size_t *maxWorkers, + size_t *nWorkers, + size_t *freeWorkers, + size_t *nPrioWorkers, + size_t *jobQueueDepth) +{ + virObjectLock(srv); + + *minWorkers = virThreadPoolGetMinWorkers(srv->workers); + *maxWorkers = virThreadPoolGetMaxWorkers(srv->workers); + *freeWorkers = virThreadPoolGetFreeWorkers(srv->workers); + *nWorkers = virThreadPoolGetCurrentWorkers(srv->workers); + *nPrioWorkers = virThreadPoolGetPriorityWorkers(srv->workers); + *jobQueueDepth = virThreadPoolGetJobQueueDepth(srv->workers); + + virObjectUnlock(srv); + return 0; +} diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index 89d8db9..f392c73 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -85,4 +85,17 @@ void virNetServerUpdateServices(virNetServerPtr srv, bool enabled); int virNetServerStart(virNetServerPtr srv); +int +virNetServerGetThreadPoolParameters(virNetServerPtr srv, + size_t *minWorkers, + size_t *maxWorkers, + size_t *nWorkers, + size_t *freeWorkers, + size_t *nPrioWorkers, + size_t *jobQueueDepth); + +int virNetServerSetThreadPoolParameters(virNetServerPtr srv, + long long int minWorkers, + long long int maxWorkers, + long long int prioWorkers); #endif /* __VIR_NET_SERVER_H__ */ -- 2.4.3

Since threadpool increments the current number of threads according to current load, i.e. how many jobs are waiting in the queue. The count however, is constrained by max and min limits of workers. The logic of this new API works like this: 1) setting the minimum a) When the limit is increased, depending on the current number of threads, new threads are possibly spawned if the current number of threads is less than the new minimum limit b) Decreasing the minimum limit has no possible effect on the current number of threads 2) setting the maximum a) Icreasing the maximum limit has no immediate effect on the current number of threads, it only allows the threadpool to spawn more threads when new jobs, that would otherwise end up queued, arrive. b) Decreasing the maximum limit may affect the current number of threads, if the current number of threads is less than the new maximum limit. Since there may be some ongoing time-consuming jobs that would effectively block this API from killing any threads. Therefore, this API is asynchronous with best-effort execution, i.e. the necessary number of workers will be terminated once they finish their previous job, unless other workers had already terminated, decreasing the limit to the requested value. 3) setting priority workers - both increase and decrease in count of these workers have an immediate impact on the current number of workers, new ones will be spawned or some of them get terminated respectively. --- daemon/admin.c | 43 +++++++++++++++++++++++ daemon/admin_server.c | 43 +++++++++++++++++++++++ daemon/admin_server.h | 5 +++ include/libvirt/libvirt-admin.h | 5 +++ src/admin/admin_protocol.x | 13 ++++++- src/admin/admin_remote.c | 34 ++++++++++++++++++ src/admin_protocol-structs | 9 +++++ src/libvirt-admin.c | 37 ++++++++++++++++++++ src/libvirt_admin_private.syms | 1 + src/libvirt_admin_public.syms | 1 + src/libvirt_private.syms | 1 + src/rpc/virnetserver.c | 15 ++++++++ src/util/virthreadpool.c | 77 +++++++++++++++++++++++++++++++++++++++-- src/util/virthreadpool.h | 5 +++ 14 files changed, 285 insertions(+), 4 deletions(-) diff --git a/daemon/admin.c b/daemon/admin.c index 8dc396e..af60ea5 100644 --- a/daemon/admin.c +++ b/daemon/admin.c @@ -264,4 +264,47 @@ adminDispatchServerGetThreadpoolParameters(virNetServerPtr server ATTRIBUTE_UNUS virObjectUnref(srv); return rv; } + +static int +adminDispatchServerSetThreadpoolParameters(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + struct admin_server_set_threadpool_parameters_args *args) +{ + int rv = -1; + virNetServerPtr srv = NULL; + virTypedParameterPtr params = NULL; + int nparams = 0; + struct daemonAdmClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!(srv = virNetDaemonGetServer(priv->dmn, args->server.name))) { + virReportError(VIR_ERR_NO_SERVER, + _("no server with matching name '%s' found"), + args->server.name); + goto cleanup; + } + + if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val, + args->params.params_len, + ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX, + ¶ms, + &nparams) < 0) + goto cleanup; + + + if (adminDaemonSetThreadPoolParameters(srv, params, + nparams, args->flags) < 0) + goto cleanup; + + rv = 0; + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + + virTypedParamsFree(params, nparams); + virObjectUnref(srv); + return rv; +} #include "admin_dispatch.h" diff --git a/daemon/admin_server.c b/daemon/admin_server.c index 861a98c..11ec139 100644 --- a/daemon/admin_server.c +++ b/daemon/admin_server.c @@ -32,6 +32,7 @@ #include "virnetserver.h" #include "virstring.h" #include "virthreadpool.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_ADMIN @@ -158,3 +159,45 @@ adminDaemonGetThreadPoolParameters(virNetServerPtr srv, return ret; } + +int +adminDaemonSetThreadPoolParameters(virNetServerPtr srv, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + long long int minWorkers = -1; + long long int maxWorkers = -1; + long long int prioWorkers = -1; + virTypedParameterPtr param = NULL; + + virCheckFlags(0, -1); + + if (virTypedParamsValidate(params, nparams, + VIR_THREADPOOL_WORKERS_MIN, + VIR_TYPED_PARAM_UINT, + VIR_THREADPOOL_WORKERS_MAX, + VIR_TYPED_PARAM_UINT, + VIR_THREADPOOL_WORKERS_PRIORITY, + VIR_TYPED_PARAM_UINT, + NULL) < 0) + return -1; + + if ((param = virTypedParamsGet(params, nparams, + VIR_THREADPOOL_WORKERS_MIN))) + minWorkers = param->value.ui; + + if ((param = virTypedParamsGet(params, nparams, + VIR_THREADPOOL_WORKERS_MAX))) + maxWorkers = param->value.ui; + + if ((param = virTypedParamsGet(params, nparams, + VIR_THREADPOOL_WORKERS_PRIORITY))) + prioWorkers = param->value.ui; + + if (virNetServerSetThreadPoolParameters(srv, minWorkers, + maxWorkers, prioWorkers) < 0) + return -1; + + return 0; +} diff --git a/daemon/admin_server.h b/daemon/admin_server.h index 7794bf1..86958f3 100644 --- a/daemon/admin_server.h +++ b/daemon/admin_server.h @@ -40,5 +40,10 @@ adminDaemonGetThreadPoolParameters(virNetServerPtr srv, virTypedParameterPtr *params, int *nparams, unsigned int flags); +int +adminDaemonSetThreadPoolParameters(virNetServerPtr srv, + virTypedParameterPtr params, + int nparams, + unsigned int flags); #endif /* __LIBVIRTD_ADMIN_SERVER_H__ */ diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h index b96545b..d24ba7c 100644 --- a/include/libvirt/libvirt-admin.h +++ b/include/libvirt/libvirt-admin.h @@ -175,6 +175,11 @@ int virAdmServerGetThreadPoolParameters(virAdmServerPtr srv, int *nparams, unsigned int flags); +int virAdmServerSetThreadPoolParameters(virAdmServerPtr srv, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + # ifdef __cplusplus } # endif diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x index ed7bf67..bf98a09 100644 --- a/src/admin/admin_protocol.x +++ b/src/admin/admin_protocol.x @@ -109,6 +109,12 @@ struct admin_server_get_threadpool_parameters_ret { admin_typed_param params<ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX>; }; +struct admin_server_set_threadpool_parameters_args { + admin_nonnull_server server; + admin_typed_param params<ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX>; + unsigned int flags; +}; + /* Define the program number, protocol version and procedure numbers here. */ const ADMIN_PROGRAM = 0x06900690; const ADMIN_PROTOCOL_VERSION = 1; @@ -160,5 +166,10 @@ enum admin_procedure { /** * @generate: none */ - ADMIN_PROC_SERVER_GET_THREADPOOL_PARAMETERS = 6 + ADMIN_PROC_SERVER_GET_THREADPOOL_PARAMETERS = 6, + + /** + * @generate: none + */ + ADMIN_PROC_SERVER_SET_THREADPOOL_PARAMETERS = 7 }; diff --git a/src/admin/admin_remote.c b/src/admin/admin_remote.c index 2717a17..0318ff2 100644 --- a/src/admin/admin_remote.c +++ b/src/admin/admin_remote.c @@ -357,3 +357,37 @@ remoteAdminServerGetThreadPoolParameters(virAdmServerPtr srv, virObjectUnlock(priv); return rv; } + +static int +remoteAdminServerSetThreadPoolParameters(virAdmServerPtr srv, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + remoteAdminPrivPtr priv = srv->conn->privateData; + int rv = -1; + admin_server_set_threadpool_parameters_args args; + + args.flags = flags; + make_nonnull_server(&args.server, srv); + + if (virTypedParamsSerialize(params, nparams, + (virTypedParameterRemotePtr *) &args.params.params_val, + &args.params.params_len, + 0) < 0) + goto cleanup; + + + if (call(srv->conn, 0, ADMIN_PROC_SERVER_SET_THREADPOOL_PARAMETERS, + (xdrproc_t)xdr_admin_server_set_threadpool_parameters_args, (char *) &args, + (xdrproc_t)xdr_void, (char *) NULL) == -1) + goto cleanup; + + rv = 0; + + cleanup: + virTypedParamsRemoteFree((virTypedParameterRemotePtr) args.params.params_val, + args.params.params_len); + virObjectUnlock(priv); + return rv; +} diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs index d0bc367..ccc9998 100644 --- a/src/admin_protocol-structs +++ b/src/admin_protocol-structs @@ -60,6 +60,14 @@ struct admin_server_get_threadpool_parameters_ret { admin_typed_param * params_val; } params; }; +struct admin_server_set_threadpool_parameters_args { + admin_nonnull_server server; + struct { + u_int params_len; + admin_typed_param * params_val; + } params; + u_int flags; +}; enum admin_procedure { ADMIN_PROC_CONNECT_OPEN = 1, ADMIN_PROC_CONNECT_CLOSE = 2, @@ -67,4 +75,5 @@ enum admin_procedure { ADMIN_PROC_CONNECT_LIST_SERVERS = 4, ADMIN_PROC_CONNECT_SERVER_LOOKUP_BY_NAME = 5, ADMIN_PROC_SERVER_GET_THREADPOOL_PARAMETERS = 6, + ADMIN_PROC_SERVER_SET_THREADPOOL_PARAMETERS = 7, }; diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c index 6165159..c5a33bc 100644 --- a/src/libvirt-admin.c +++ b/src/libvirt-admin.c @@ -710,3 +710,40 @@ virAdmServerGetThreadPoolParameters(virAdmServerPtr srv, virDispatchError(NULL); return -1; } + +/** + * virAdmServerSetThreadPoolParameters: + * @srv: a valid server object reference + * @params: pointer to threadpool parameter objects + * @nparams: number of parameters in @params + * @flags: bitwise-OR of extra flags virAdmServerSetThreadPoolParametersFlags + * + * Change server threadpool parameters according to @params. Note that some + * tunables are read-only, thus any attempt to set them will result in a + * failure. + * + * Returns 0 on success, -1 in case of an error. + */ +int +virAdmServerSetThreadPoolParameters(virAdmServerPtr srv, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + VIR_DEBUG("srv=%p, params=%p, nparams=%x, flags=%x", + srv, params, nparams, flags); + + virResetLastError(); + + virCheckAdmServerReturn(srv, NULL); + virCheckNonNullArgGoto(params, error); + + if (remoteAdminServerSetThreadPoolParameters(srv, params, + nparams, flags) < 0) + goto error; + + return 0; + error: + virDispatchError(NULL); + return -1; +} diff --git a/src/libvirt_admin_private.syms b/src/libvirt_admin_private.syms index 7d3067f..95dfe35 100644 --- a/src/libvirt_admin_private.syms +++ b/src/libvirt_admin_private.syms @@ -14,6 +14,7 @@ xdr_admin_connect_server_lookup_by_name_args; xdr_admin_connect_server_lookup_by_name_ret; xdr_admin_server_get_threadpool_parameters_args; xdr_admin_server_get_threadpool_parameters_ret; +xdr_admin_server_set_threadpool_parameters_args; # datatypes.h virAdmConnectClass; diff --git a/src/libvirt_admin_public.syms b/src/libvirt_admin_public.syms index e89ad75..f5a8fc0 100644 --- a/src/libvirt_admin_public.syms +++ b/src/libvirt_admin_public.syms @@ -26,4 +26,5 @@ LIBVIRT_ADMIN_1.3.0 { virAdmServerGetName; virAdmServerGetThreadPoolParameters; virAdmServerFree; + virAdmServerSetThreadPoolParameters; }; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7658ebf..ecd8c46 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2326,6 +2326,7 @@ virThreadPoolGetMinWorkers; virThreadPoolGetPriorityWorkers; virThreadPoolNewFull; virThreadPoolSendJob; +virThreadPoolSetParameters; # util/virtime.h diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index cc809bf..6922443 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -883,3 +883,18 @@ virNetServerGetThreadPoolParameters(virNetServerPtr srv, virObjectUnlock(srv); return 0; } + +int +virNetServerSetThreadPoolParameters(virNetServerPtr srv, + long long int minWorkers, + long long int maxWorkers, + long long int prioWorkers) +{ + int ret; + + virObjectLock(srv); + ret = virThreadPoolSetParameters(srv->workers, minWorkers, + maxWorkers, prioWorkers); + virObjectUnlock(srv); + return ret; +} diff --git a/src/util/virthreadpool.c b/src/util/virthreadpool.c index 518b880..9dd8fba 100644 --- a/src/util/virthreadpool.c +++ b/src/util/virthreadpool.c @@ -73,6 +73,7 @@ struct _virThreadPool { size_t nWorkers; virThreadPtr workers; + size_t maxPrioWorkers; size_t nPrioWorkers; virThreadPtr prioWorkers; virCond prioCond; @@ -84,12 +85,22 @@ struct virThreadPoolWorkerData { bool priority; }; +/* Test whether the worker needs to quit if the current number of workers @count + * is greater than @limit actually allows. + */ +static inline bool virThreadPoolWorkerQuitHelper(size_t count, size_t limit) +{ + return count > limit; +} + static void virThreadPoolWorker(void *opaque) { struct virThreadPoolWorkerData *data = opaque; virThreadPoolPtr pool = data->pool; virCondPtr cond = data->cond; bool priority = data->priority; + size_t *curWorkers = priority ? &pool->nPrioWorkers : &pool->nWorkers; + size_t *maxLimit = priority ? &pool->maxPrioWorkers : &pool->maxWorkers; virThreadPoolJobPtr job = NULL; VIR_FREE(data); @@ -97,6 +108,14 @@ static void virThreadPoolWorker(void *opaque) virMutexLock(&pool->mutex); while (1) { + /* In order to support async worker termination, we need ensure that + * both busy and free workers know if they need to terminated. Thus, + * busy workers need to check for this fact before they start waiting for + * another job (and before taking another one from the queue); and + * free workers need to check for this right after waking up. + */ + if (virThreadPoolWorkerQuitHelper(*curWorkers, *maxLimit)) + goto out; while (!pool->quit && ((!priority && !pool->jobList.head) || (priority && !pool->jobList.firstPrio))) { @@ -109,6 +128,9 @@ static void virThreadPoolWorker(void *opaque) } if (!priority) pool->freeWorkers--; + + if (virThreadPoolWorkerQuitHelper(*curWorkers, *maxLimit)) + goto out; } if (pool->quit) @@ -160,12 +182,12 @@ static void virThreadPoolWorker(void *opaque) static int virThreadPoolExpand(virThreadPoolPtr pool, size_t gain, bool priority) { - virThreadPtr workers = priority ? pool->prioWorkers : pool->workers; + virThreadPtr *workers = priority ? &pool->prioWorkers : &pool->workers; size_t *curWorkers = priority ? &pool->nPrioWorkers : &pool->nWorkers; size_t i = 0; struct virThreadPoolWorkerData *data = NULL; - if (VIR_EXPAND_N(workers, *curWorkers, gain) < 0) + if (VIR_EXPAND_N(*workers, *curWorkers, gain) < 0) return -1; for (i = 0; i < gain; i++) { @@ -176,7 +198,7 @@ virThreadPoolExpand(virThreadPoolPtr pool, size_t gain, bool priority) data->cond = priority ? &pool->prioCond : &pool->cond; data->priority = priority; - if (virThreadCreateFull(&workers[i], + if (virThreadCreateFull(&(*workers)[i], false, virThreadPoolWorker, pool->jobFuncName, @@ -226,6 +248,7 @@ virThreadPoolNewFull(size_t minWorkers, pool->minWorkers = minWorkers; pool->maxWorkers = maxWorkers; + pool->maxPrioWorkers = prioWorkers; if (virThreadPoolExpand(pool, minWorkers, false) < 0) goto error; @@ -363,3 +386,51 @@ int virThreadPoolSendJob(virThreadPoolPtr pool, virMutexUnlock(&pool->mutex); return -1; } + +int +virThreadPoolSetParameters(virThreadPoolPtr pool, + long long int minWorkers, + long long int maxWorkers, + long long int prioWorkers) +{ + virMutexLock(&pool->mutex); + + if ((minWorkers >= 0 && minWorkers > pool->maxWorkers) || + (maxWorkers >= 0 && maxWorkers < pool->minWorkers) || + (minWorkers >= 0 && maxWorkers >= 0 && minWorkers > maxWorkers)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("minWorkers cannot be larger than maxWorkers")); + goto error; + } + + if (minWorkers >= 0) { + if ((size_t) minWorkers > pool->nWorkers && + virThreadPoolExpand(pool, minWorkers - pool->nWorkers, + false) < 0) + goto error; + pool->minWorkers = minWorkers; + } + + if (maxWorkers >= 0) { + pool->maxWorkers = maxWorkers; + virCondBroadcast(&pool->cond); + } + + if (prioWorkers >= 0) { + if (prioWorkers < pool->nPrioWorkers) { + virCondBroadcast(&pool->prioCond); + } else if ((size_t) prioWorkers > pool->nPrioWorkers && + virThreadPoolExpand(pool, prioWorkers - pool->nPrioWorkers, + true) < 0) { + goto error; + } + pool->maxPrioWorkers = prioWorkers; + } + + virMutexUnlock(&pool->mutex); + return 0; + + error: + virMutexUnlock(&pool->mutex); + return -1; +} diff --git a/src/util/virthreadpool.h b/src/util/virthreadpool.h index bc0c907..e1f362f 100644 --- a/src/util/virthreadpool.h +++ b/src/util/virthreadpool.h @@ -57,4 +57,9 @@ int virThreadPoolSendJob(virThreadPoolPtr pool, void *jobdata) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; +int virThreadPoolSetParameters(virThreadPoolPtr pool, + long long int minWorkers, + long long int maxWorkers, + long long int prioWorkers); + #endif -- 2.4.3

Wire up the server threadpool tunable APIs to virt-admin client. --- tools/virt-admin.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/tools/virt-admin.c b/tools/virt-admin.c index 3c818a3..21be830 100644 --- a/tools/virt-admin.c +++ b/tools/virt-admin.c @@ -350,6 +350,127 @@ cmdSrvList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return ret; } + +/* -------------------- + * Command srv-workertune + * -------------------- + */ + +static const vshCmdInfo info_srv_workertune[] = { + {.name = "help", + .data = N_("Get or set server workerpool parameters") + }, + {.name = "desc", + .data = N_("Get or set server workerpool parameters. Some parameters are " + "read-only, thus only \n" + " a subset of all supported parameters can actually be " + "set via OPTIONS.\n" + " To retrieve workerpool parameters, use the command " + "without any options: \n\n" + " virt-admin # srv-workertune <server>") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_srv_workertune[] = { + {.name = "server", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("Server to get threadpool parameters for."), + }, + {.name = "min-workers", + .type = VSH_OT_INT, + .help = N_("Change the value of bottom limit to number of workers."), + }, + {.name = "max-workers", + .type = VSH_OT_INT, + .help = N_("Change the value of top limit to number of workers."), + }, + {.name = "priority-workers", + .type = VSH_OT_INT, + .help = N_("Change the current number of priority workers"), + }, + {.name = NULL} +}; + +static bool +cmdSrvWorkertune(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virTypedParameterPtr params = NULL; + int nparams = 0; + int maxparams = 0; + unsigned int val; + unsigned int min, max; + int rv = 0; + size_t i; + bool ret = false; + const char *srvname = NULL; + virAdmServerPtr srv = NULL; + vshAdmControlPtr priv = ctl->privData; + + if (vshCommandOptStringReq(ctl, cmd, "server", &srvname) < 0) + return false; + +#define PARSE_WORKERTUNE_PARAM(NAME, FIELD) \ + if ((rv = vshCommandOptUInt(ctl, cmd, NAME, &val)) < 0) { \ + vshError(ctl, _("Unable to parse integer parameter '%s'"), NAME); \ + goto cleanup; \ + } else if (rv > 0) { \ + if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams, \ + FIELD, val) < 0) \ + goto save_error; \ + } + + PARSE_WORKERTUNE_PARAM("max-workers", VIR_THREADPOOL_WORKERS_MAX); + PARSE_WORKERTUNE_PARAM("min-workers", VIR_THREADPOOL_WORKERS_MIN); + PARSE_WORKERTUNE_PARAM("priority-workers", VIR_THREADPOOL_WORKERS_PRIORITY); + +#undef PARSE_WORKERTUNE_PARAM + + if (virTypedParamsGetUInt(params, nparams, + VIR_THREADPOOL_WORKERS_MAX, &max) && + virTypedParamsGetUInt(params, nparams, + VIR_THREADPOOL_WORKERS_MIN, &min) && min > max) { + vshError(ctl, "%s", _("--min-workers must be less than --max-workers")); + goto cleanup; + } + + if (!(srv = virAdmConnectServerLookupByName(priv->conn, srvname))) + goto cleanup; + + /* set server threadpool parameters */ + if (nparams) { + if (virAdmServerSetThreadPoolParameters(srv, params, + nparams, 0) < 0) + goto error; + } else { + if (virAdmServerGetThreadPoolParameters(srv, ¶ms, + &nparams, 0) < 0) { + vshError(ctl, "%s", + _("Unable to get server workerpool parameters")); + goto cleanup; + } + + for (i = 0; i < nparams; i++) + vshPrint(ctl, "%-15s: %d\n", params[i].field, params[i].value.ui); + } + + ret = true; + + cleanup: + virTypedParamsFree(params, nparams); + if (srv) + virAdmServerFree(srv); + return ret; + + save_error: + vshSaveLibvirtError(); + + error: + vshError(ctl, "%s", _("Unable to change server workerpool parameters")); + goto cleanup; +} + static void * vshAdmConnectionHandler(vshControl *ctl) { @@ -652,9 +773,20 @@ static const vshCmdDef monitoringCmds[] = { {.name = NULL} }; +static const vshCmdDef managementCmds[] = { + {.name = "srv-workertune", + .handler = cmdSrvWorkertune, + .opts = opts_srv_workertune, + .info = info_srv_workertune, + .flags = 0 + }, + {.name = NULL} +}; + static const vshCmdGrp cmdGroups[] = { {"Virt-admin itself", "virt-admin", vshAdmCmds}, {"Monitoring commands", "monitor", monitoringCmds}, + {"Management commands", "management", managementCmds}, {NULL, NULL, NULL} }; -- 2.4.3

On 29.02.2016 16:03, Erik Skultety wrote:
Erik Skultety (10): libvirt-host: Move virTypedParam* to libvirt-common admin: Enable usage of typed parameters admin: Introduce virAdmConnectServerLookupByName util: Refactor thread creation by introducing virThreadPoolExpand util: Report system error when virThreadCreateFull fails util: Add more getters to threadpool parameters admin: Prepare admin protocol for future worker related procedures admin: Introduce virAdmServerGethreadPoolParameters admin: Introduce virAdmServerSetThreadPoolParameters virt-admin: Introduce srv-workertune command
cfg.mk | 2 +- daemon/admin.c | 129 ++++++++++++++++++++++++ daemon/admin_server.c | 129 ++++++++++++++++++++++++ daemon/admin_server.h | 15 +++ include/libvirt/libvirt-admin.h | 74 ++++++++++++++ include/libvirt/libvirt-common.h.in | 185 ++++++++++++++++++++++++++++++++++ include/libvirt/libvirt-host.h | 186 ---------------------------------- include/libvirt/virterror.h | 1 + po/POTFILES.in | 4 +- src/admin/admin_protocol.x | 67 +++++++++++- src/admin/admin_remote.c | 104 +++++++++++++++++++ src/admin_protocol-structs | 52 ++++++++++ src/libvirt-admin.c | 114 +++++++++++++++++++++ src/libvirt_admin_private.syms | 5 + src/libvirt_admin_public.syms | 3 + src/libvirt_private.syms | 4 + src/rpc/virnetserver.c | 37 +++++++ src/rpc/virnetserver.h | 13 +++ src/util/virerror.c | 6 ++ src/util/virthreadpool.c | 196 ++++++++++++++++++++++++------------ src/util/virthreadpool.h | 8 ++ tools/virt-admin.c | 132 ++++++++++++++++++++++++ 22 files changed, 1212 insertions(+), 254 deletions(-)
I wanted to review this, but got a lot of rebase conflicts. Can you rebase and resend please? Michal
participants (3)
-
Erik Skultety
-
Martin Kletzander
-
Michal Privoznik