From 044aff9bd41e0126b89f1ad672e196c3aa1654b7 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 31 May 2013 22:00:17 +0200 Subject: Add be request queue For some backend targets it might be not desirable to run requests in parallel but to serialize them. To avoid that each provider has to implement a queue for this target this patch implements a generic queue which collects incoming requests before they are send to the target. --- src/providers/data_provider_be.c | 119 +++++++++++++++++++++++++++++++++++++++ src/providers/dp_backend.h | 11 ++++ 2 files changed, 130 insertions(+) diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c index cd6715680..1d61a88b7 100644 --- a/src/providers/data_provider_be.c +++ b/src/providers/data_provider_be.c @@ -301,6 +301,125 @@ static errno_t be_file_request(TALLOC_CTX *mem_ctx, return EOK; } +static errno_t be_queue_request(TALLOC_CTX *queue_mem_ctx, + struct bet_queue_item **req_queue, + TALLOC_CTX *req_mem_ctx, + struct be_req *be_req, + be_req_fn_t fn) +{ + struct bet_queue_item *item; + int ret; + + if (*req_queue == NULL) { + DEBUG(SSSDBG_TRACE_ALL, ("Queue is empty, " \ + "running request immediately.\n")); + ret = be_file_request(req_mem_ctx, be_req, fn); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("be_file_request failed.\n")); + return ret; + } + } + + item = talloc_zero(queue_mem_ctx, struct bet_queue_item); + if (item == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_zero failed, cannot add item to " \ + "request queue.\n")); + } else { + DEBUG(SSSDBG_TRACE_ALL, ("Adding request to queue.\n")); + item->mem_ctx = req_mem_ctx; + item->be_req = be_req; + item->fn = fn; + + DLIST_ADD_END(*req_queue, item, struct bet_queue_item *); + } + + return EOK; +} + +static void be_queue_next_request(struct be_req *be_req, enum bet_type type) +{ + struct bet_queue_item *item; + struct bet_queue_item *current = NULL; + struct bet_queue_item **req_queue; + int ret; + DBusMessage *reply; + uint16_t err_maj; + uint32_t err_min; + const char *err_msg = "Cannot file back end request"; + struct be_req *next_be_req = NULL; + dbus_bool_t dbret; + DBusConnection *dbus_conn; + + req_queue = &be_req->becli->bectx->bet_info[type].req_queue; + + if (*req_queue == NULL) { + DEBUG(SSSDBG_TRACE_ALL, ("Queue is empty, nothing to do.\n")); + return; + } + + DLIST_FOR_EACH(item, *req_queue) { + if (item->be_req == be_req) { + current = item; + break; + } + } + + if (current != NULL) { + DLIST_REMOVE(*req_queue, current); + } + + if (*req_queue == NULL) { + DEBUG(SSSDBG_TRACE_ALL, ("Request queue is empty.\n")); + return; + } + + next_be_req = (*req_queue)->be_req; + + ret = be_file_request((*req_queue)->mem_ctx, next_be_req, (*req_queue)->fn); + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_ALL, ("Queued request filed successfully.\n")); + return; + } + + DEBUG(SSSDBG_OP_FAILURE, ("be_file_request failed.\n")); + + be_queue_next_request(next_be_req, type); + + reply = (DBusMessage *) next_be_req->pvt; + + if (reply) { + /* Return a reply if one was requested + * There may not be one if this request began + * while we were offline + */ + err_maj = DP_ERR_FATAL; + err_min = ret; + + dbret = dbus_message_append_args(reply, + DBUS_TYPE_UINT16, &err_maj, + DBUS_TYPE_UINT32, &err_min, + DBUS_TYPE_STRING, &err_msg, + DBUS_TYPE_INVALID); + + if (!dbret) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to generate dbus reply\n")); + dbus_message_unref(reply); + goto done; + } + + dbus_conn = sbus_get_connection(next_be_req->becli->conn); + if (dbus_conn == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("D-BUS not connected\n")); + goto done; + } + dbus_connection_send(dbus_conn, reply, NULL); + dbus_message_unref(reply); + } + +done: + talloc_free(next_be_req); +} + bool be_is_offline(struct be_ctx *ctx) { time_t now = time(NULL); diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h index e0e2210c3..9a8df4cd8 100644 --- a/src/providers/dp_backend.h +++ b/src/providers/dp_backend.h @@ -68,11 +68,22 @@ struct loaded_be { void *handle; }; +struct bet_queue_item { + struct bet_queue_item *prev; + struct bet_queue_item *next; + + TALLOC_CTX *mem_ctx; + struct be_req *be_req; + be_req_fn_t fn; + +}; + struct bet_info { enum bet_type bet_type; struct bet_ops *bet_ops; void *pvt_bet_data; char *mod_name; + struct bet_queue_item *req_queue; }; struct be_offline_status { -- cgit