Allow concurrent processing of RPC calls in daemon

This commit is contained in:
Daniel P. Berrange 2009-01-20 19:25:15 +00:00
parent 84ef468ba8
commit f61341173b
8 changed files with 604 additions and 322 deletions

View File

@ -1,3 +1,12 @@
Tue Jan 20 19:24:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
* qemud/qemud.c, qemud/qemud.h, qemud/remote.c: Allow the
processing of multiple concurrent RPC calls per client
connection.
* qemud/libvirtd.conf, qemud/libvirtd.aug,
qemud/test_libvirtd.aug: Add config param for controlling
number of requests per client.
Tue Jan 20 18:16:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com> Tue Jan 20 18:16:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
* src/xm_internal.c: Fix 2 misleading comments & potential * src/xm_internal.c: Fix 2 misleading comments & potential

View File

@ -53,6 +53,8 @@ module Libvirtd =
let processing_entry = int_entry "min_workers" let processing_entry = int_entry "min_workers"
| int_entry "max_workers" | int_entry "max_workers"
| int_entry "max_clients" | int_entry "max_clients"
| int_entry "max_requests"
| int_entry "max_client_requests"
let logging_entry = int_entry "log_level" let logging_entry = int_entry "log_level"
| str_entry "log_filters" | str_entry "log_filters"

View File

@ -247,6 +247,22 @@
#min_workers = 5 #min_workers = 5
#max_workers = 20 #max_workers = 20
# Total global limit on concurrent RPC calls. Should be
# at least as large as max_workers. Beyond this, RPC requests
# will be read into memory and queued. This directly impact
# memory usage, currently each request requires 256 KB of
# memory. So by default upto 5 MB of memory is used
#
# XXX this isn't actually enforced yet, only the per-client
# limit is used so far
#max_requests = 20
# Limit on concurrent requests from a single client
# connection. To avoid one client monopolizing the server
# this should be a small fraction of the global max_requests
# and max_workers parameter
#max_client_requests = 5
################################################################# #################################################################
# #
# Logging controls # Logging controls

File diff suppressed because it is too large Load Diff

View File

@ -65,15 +65,6 @@
#define qemudDebug DEBUG #define qemudDebug DEBUG
enum qemud_mode {
QEMUD_MODE_RX_HEADER, /* Receiving the fixed length RPC header data */
QEMUD_MODE_RX_PAYLOAD, /* Receiving the variable length RPC payload data */
QEMUD_MODE_WAIT_DISPATCH, /* Message received, waiting for worker to process */
QEMUD_MODE_IN_DISPATCH, /* RPC call being processed */
QEMUD_MODE_TX_PACKET, /* Transmitting reply to RPC call */
QEMUD_MODE_TLS_HANDSHAKE, /* Performing TLS handshake */
};
/* Whether we're passing reads & writes through a sasl SSF */ /* Whether we're passing reads & writes through a sasl SSF */
enum qemud_sasl_ssf { enum qemud_sasl_ssf {
QEMUD_SASL_SSF_NONE = 0, QEMUD_SASL_SSF_NONE = 0,
@ -87,6 +78,16 @@ enum qemud_sock_type {
QEMUD_SOCK_TYPE_TLS = 2, QEMUD_SOCK_TYPE_TLS = 2,
}; };
struct qemud_client_message {
char buffer [REMOTE_MESSAGE_MAX + REMOTE_MESSAGE_HEADER_XDR_LEN];
unsigned int bufferLength;
unsigned int bufferOffset;
int async : 1;
struct qemud_client_message *next;
};
/* Stores the per-client connection state */ /* Stores the per-client connection state */
struct qemud_client { struct qemud_client {
virMutex lock; virMutex lock;
@ -97,7 +98,6 @@ struct qemud_client {
int watch; int watch;
int readonly:1; int readonly:1;
int closing:1; int closing:1;
enum qemud_mode mode;
struct sockaddr_storage addr; struct sockaddr_storage addr;
socklen_t addrlen; socklen_t addrlen;
@ -105,6 +105,7 @@ struct qemud_client {
int type; /* qemud_sock_type */ int type; /* qemud_sock_type */
gnutls_session_t tlssession; gnutls_session_t tlssession;
int auth; int auth;
int handshake : 1; /* If we're in progress for TLS handshake */
#if HAVE_SASL #if HAVE_SASL
sasl_conn_t *saslconn; sasl_conn_t *saslconn;
int saslSSF; int saslSSF;
@ -117,12 +118,20 @@ struct qemud_client {
char *saslUsername; char *saslUsername;
#endif #endif
unsigned int incomingSerial; /* Count of meages in 'dx' or 'tx' queue
unsigned int outgoingSerial; * ie RPC calls in progress. Does not count
* async events which are not used for
char buffer [REMOTE_MESSAGE_MAX]; * throttling calculations */
unsigned int bufferLength; int nrequests;
unsigned int bufferOffset; /* Zero or one messages being received. Zero if
* nrequests >= max_clients and throttling */
struct qemud_client_message *rx;
/* Zero or many messages waiting for a worker
* to process them */
struct qemud_client_message *dx;
/* Zero or many messages waiting for transmit
* back to client, including async events */
struct qemud_client_message *tx;
/* This is only valid if a remote open call has been made on this /* This is only valid if a remote open call has been made on this
* connection, otherwise it will be NULL. Also if remote close is * connection, otherwise it will be NULL. Also if remote close is
@ -181,16 +190,20 @@ void qemudLog(int priority, const char *fmt, ...)
int qemudSetCloseExec(int fd); int qemudSetCloseExec(int fd);
int qemudSetNonBlock(int fd); int qemudSetNonBlock(int fd);
unsigned int int
remoteDispatchClientRequest (struct qemud_server *server, remoteDispatchClientRequest (struct qemud_server *server,
struct qemud_client *client); struct qemud_client *client,
struct qemud_client_message *req);
void qemudDispatchClientWrite(struct qemud_server *server, int qemudRegisterClientEvent(struct qemud_server *server,
struct qemud_client *client); struct qemud_client *client,
int update);
#if HAVE_POLKIT void qemudDispatchClientFailure(struct qemud_client *client);
int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
#endif void
qemudClientMessageQueuePush(struct qemud_client_message **queue,
struct qemud_client_message *msg);
int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED, int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom, virDomainPtr dom,
@ -198,4 +211,9 @@ int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
int detail, int detail,
void *opaque); void *opaque);
#if HAVE_POLKIT
int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
#endif
#endif #endif

View File

@ -111,6 +111,7 @@ static const dispatch_data const dispatch_table[] = {
/* Prototypes */ /* Prototypes */
static void static void
remoteDispatchDomainEventSend (struct qemud_client *client, remoteDispatchDomainEventSend (struct qemud_client *client,
struct qemud_client_message *msg,
virDomainPtr dom, virDomainPtr dom,
int event, int event,
int detail); int detail);
@ -219,9 +220,10 @@ remoteDispatchConnError (remote_error *rerr,
* Server object is unlocked * Server object is unlocked
* Client object is locked * Client object is locked
*/ */
unsigned int int
remoteDispatchClientRequest (struct qemud_server *server, remoteDispatchClientRequest (struct qemud_server *server,
struct qemud_client *client) struct qemud_client *client,
struct qemud_client_message *msg)
{ {
XDR xdr; XDR xdr;
remote_message_header req, rep; remote_message_header req, rep;
@ -229,7 +231,8 @@ remoteDispatchClientRequest (struct qemud_server *server,
dispatch_args args; dispatch_args args;
dispatch_ret ret; dispatch_ret ret;
const dispatch_data *data = NULL; const dispatch_data *data = NULL;
int rv = -1, len; int rv = -1;
unsigned int len;
virConnectPtr conn = NULL; virConnectPtr conn = NULL;
memset(&args, 0, sizeof args); memset(&args, 0, sizeof args);
@ -237,7 +240,10 @@ remoteDispatchClientRequest (struct qemud_server *server,
memset(&rerr, 0, sizeof rerr); memset(&rerr, 0, sizeof rerr);
/* Parse the header. */ /* Parse the header. */
xdrmem_create (&xdr, client->buffer, client->bufferLength, XDR_DECODE); xdrmem_create (&xdr,
msg->buffer + REMOTE_MESSAGE_HEADER_XDR_LEN,
msg->bufferLength - REMOTE_MESSAGE_HEADER_XDR_LEN,
XDR_DECODE);
if (!xdr_remote_message_header (&xdr, &req)) if (!xdr_remote_message_header (&xdr, &req))
goto fatal_error; goto fatal_error;
@ -333,10 +339,10 @@ rpc_error:
rep.status = rv < 0 ? REMOTE_ERROR : REMOTE_OK; rep.status = rv < 0 ? REMOTE_ERROR : REMOTE_OK;
/* Serialise the return header. */ /* Serialise the return header. */
xdrmem_create (&xdr, client->buffer, sizeof client->buffer, XDR_ENCODE); xdrmem_create (&xdr, msg->buffer, sizeof msg->buffer, XDR_ENCODE);
len = 0; /* We'll come back and write this later. */ len = 0; /* We'll come back and write this later. */
if (!xdr_int (&xdr, &len)) { if (!xdr_u_int (&xdr, &len)) {
if (rv == 0) xdr_free (data->ret_filter, (char*)&ret); if (rv == 0) xdr_free (data->ret_filter, (char*)&ret);
goto fatal_error; goto fatal_error;
} }
@ -364,17 +370,21 @@ rpc_error:
if (xdr_setpos (&xdr, 0) == 0) if (xdr_setpos (&xdr, 0) == 0)
goto fatal_error; goto fatal_error;
if (!xdr_int (&xdr, &len)) if (!xdr_u_int (&xdr, &len))
goto fatal_error; goto fatal_error;
xdr_destroy (&xdr); xdr_destroy (&xdr);
return len;
msg->bufferLength = len;
msg->bufferOffset = 0;
return 0;
fatal_error: fatal_error:
/* Seriously bad stuff happened, so we'll kill off this client /* Seriously bad stuff happened, so we'll kill off this client
and not send back any RPC error */ and not send back any RPC error */
xdr_destroy (&xdr); xdr_destroy (&xdr);
return 0; return -1;
} }
int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED, int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
@ -386,9 +396,20 @@ int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
struct qemud_client *client = opaque; struct qemud_client *client = opaque;
REMOTE_DEBUG("Relaying domain event %d %d", event, detail); REMOTE_DEBUG("Relaying domain event %d %d", event, detail);
if(client) { if (client) {
remoteDispatchDomainEventSend (client, dom, event, detail); struct qemud_client_message *ev;
qemudDispatchClientWrite(client->server,client);
if (VIR_ALLOC(ev) < 0)
return -1;
virMutexLock(&client->lock);
remoteDispatchDomainEventSend (client, ev, dom, event, detail);
if (qemudRegisterClientEvent(client->server, client, 1) < 0)
qemudDispatchClientFailure(client);
virMutexUnlock(&client->lock);
} }
return 0; return 0;
} }
@ -4202,13 +4223,14 @@ remoteDispatchDomainEventsDeregister (struct qemud_server *server ATTRIBUTE_UNUS
static void static void
remoteDispatchDomainEventSend (struct qemud_client *client, remoteDispatchDomainEventSend (struct qemud_client *client,
struct qemud_client_message *msg,
virDomainPtr dom, virDomainPtr dom,
int event, int event,
int detail) int detail)
{ {
remote_message_header rep; remote_message_header rep;
XDR xdr; XDR xdr;
int len; unsigned int len;
remote_domain_event_ret data; remote_domain_event_ret data;
if (!client) if (!client)
@ -4222,11 +4244,11 @@ remoteDispatchDomainEventSend (struct qemud_client *client,
rep.status = REMOTE_OK; rep.status = REMOTE_OK;
/* Serialise the return header and event. */ /* Serialise the return header and event. */
xdrmem_create (&xdr, client->buffer, sizeof client->buffer, XDR_ENCODE); xdrmem_create (&xdr, msg->buffer, sizeof msg->buffer, XDR_ENCODE);
len = 0; /* We'll come back and write this later. */ len = 0; /* We'll come back and write this later. */
if (!xdr_int (&xdr, &len)) { if (!xdr_u_int (&xdr, &len)) {
/*remoteDispatchError (client, NULL, "%s", _("xdr_int failed (1)"));*/ /*remoteDispatchError (client, NULL, "%s", _("xdr_u_int failed (1)"));*/
xdr_destroy (&xdr); xdr_destroy (&xdr);
return; return;
} }
@ -4254,8 +4276,8 @@ remoteDispatchDomainEventSend (struct qemud_client *client,
return; return;
} }
if (!xdr_int (&xdr, &len)) { if (!xdr_u_int (&xdr, &len)) {
/*remoteDispatchError (client, NULL, "%s", _("xdr_int failed (2)"));*/ /*remoteDispatchError (client, NULL, "%s", _("xdr_u_int failed (2)"));*/
xdr_destroy (&xdr); xdr_destroy (&xdr);
return; return;
} }
@ -4263,9 +4285,10 @@ remoteDispatchDomainEventSend (struct qemud_client *client,
xdr_destroy (&xdr); xdr_destroy (&xdr);
/* Send it. */ /* Send it. */
client->mode = QEMUD_MODE_TX_PACKET; msg->async = 1;
client->bufferLength = len; msg->bufferLength = len;
client->bufferOffset = 0; msg->bufferOffset = 0;
qemudClientMessageQueuePush(&client->tx, msg);
} }
/*----- Helpers. -----*/ /*----- Helpers. -----*/

View File

@ -246,6 +246,19 @@ max_clients = 20
# of clients allowed # of clients allowed
min_workers = 5 min_workers = 5
max_workers = 20 max_workers = 20
# Total global limit on concurrent RPC calls. Should be
# at least as large as max_workers. Beyond this, RPC requests
# will be read into memory and queued. This directly impact
# memory usage, currently each request requires 256 KB of
# memory. So by default upto 5 MB of memory is used
max_requests = 20
# Limit on concurrent requests from a single client
# connection. To avoid one client monopolizing the server
# this should be a small fraction of the global max_requests
# and max_workers parameter
max_client_requests = 5
" "
test Libvirtd.lns get conf = test Libvirtd.lns get conf =
@ -499,3 +512,16 @@ max_workers = 20
{ "#comment" = "of clients allowed"} { "#comment" = "of clients allowed"}
{ "min_workers" = "5" } { "min_workers" = "5" }
{ "max_workers" = "20" } { "max_workers" = "20" }
{ "#empty" }
{ "#comment" = "Total global limit on concurrent RPC calls. Should be" }
{ "#comment" = "at least as large as max_workers. Beyond this, RPC requests" }
{ "#comment" = "will be read into memory and queued. This directly impact" }
{ "#comment" = "memory usage, currently each request requires 256 KB of" }
{ "#comment" = "memory. So by default upto 5 MB of memory is used" }
{ "max_requests" = "20" }
{ "#empty" }
{ "#comment" = "Limit on concurrent requests from a single client" }
{ "#comment" = "connection. To avoid one client monopolizing the server" }
{ "#comment" = "this should be a small fraction of the global max_requests" }
{ "#comment" = "and max_workers parameter" }
{ "max_client_requests" = "5" }

View File

@ -5663,13 +5663,13 @@ prepareCall(virConnectPtr conn,
/* Length must include the length word itself (always encoded in /* Length must include the length word itself (always encoded in
* 4 bytes as per RFC 4506). * 4 bytes as per RFC 4506).
*/ */
rv->bufferLength += 4; rv->bufferLength += REMOTE_MESSAGE_HEADER_XDR_LEN;
/* Encode the length word. */ /* Encode the length word. */
xdrmem_create (&xdr, rv->buffer, 4, XDR_ENCODE); xdrmem_create (&xdr, rv->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
if (!xdr_int (&xdr, (int *)&rv->bufferLength)) { if (!xdr_u_int (&xdr, &rv->bufferLength)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC, error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC,
_("xdr_int (length word)")); _("xdr_u_int (length word)"));
goto error; goto error;
} }
xdr_destroy (&xdr); xdr_destroy (&xdr);
@ -5965,20 +5965,26 @@ static int
processCallRecvLen(virConnectPtr conn, struct private_data *priv, processCallRecvLen(virConnectPtr conn, struct private_data *priv,
int in_open) { int in_open) {
XDR xdr; XDR xdr;
int len; unsigned int len;
xdrmem_create (&xdr, priv->buffer, priv->bufferLength, XDR_DECODE); xdrmem_create (&xdr, priv->buffer, priv->bufferLength, XDR_DECODE);
if (!xdr_int (&xdr, &len)) { if (!xdr_u_int (&xdr, &len)) {
error (in_open ? NULL : conn, error (in_open ? NULL : conn,
VIR_ERR_RPC, _("xdr_int (length word, reply)")); VIR_ERR_RPC, _("xdr_u_int (length word, reply)"));
return -1; return -1;
} }
xdr_destroy (&xdr); xdr_destroy (&xdr);
/* Length includes length word - adjust to real length to read. */ if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
len -= 4; error (in_open ? NULL : conn,
VIR_ERR_RPC, _("packet received from server too small"));
return -1;
}
if (len < 0 || len > REMOTE_MESSAGE_MAX) { /* Length includes length word - adjust to real length to read. */
len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
if (len > REMOTE_MESSAGE_MAX) {
error (in_open ? NULL : conn, error (in_open ? NULL : conn,
VIR_ERR_RPC, _("packet received from server too large")); VIR_ERR_RPC, _("packet received from server too large"));
return -1; return -1;