[sheepdog] [PATCH 1/2] sheep: introduce async request handling
Hitoshi Mitake
mitake.hitoshi at gmail.com
Tue Dec 17 07:13:26 CET 2013
At Mon, 16 Dec 2013 21:16:38 +0800,
Liu Yuan wrote:
>
> This patch introduces async request framework that has the following usage
> patern:
>
> iocb = local_req_init();
>
> loop:
> ...
> exec_local_req_async(req, iocb);
> ...
>
> ret = local_req_wait(iocb);
>
> wait until all the reqs finish, if any req fails, just return it from
> local_req_wait();
>
> Request throttling should be handled by the async user.
>
> Signed-off-by: Liu Yuan <namei.unix at gmail.com>
> ---
> sheep/request.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++----
> sheep/sheep.c | 2 +-
> sheep/sheep_priv.h | 13 +++++++-
> 3 files changed, 92 insertions(+), 8 deletions(-)
Just a quick review.
>
> diff --git a/sheep/request.c b/sheep/request.c
> index dfca8ee..53ccc04 100644
> --- a/sheep/request.c
> +++ b/sheep/request.c
> @@ -499,6 +499,15 @@ static void free_local_request(struct request *req)
> free(req);
> }
>
> +static void submit_local_request(struct request *req)
> +{
> + pthread_mutex_lock(&sys->local_req_lock);
> + list_add_tail(&req->request_list, &sys->local_req_queue);
> + pthread_mutex_unlock(&sys->local_req_lock);
> +
> + eventfd_xwrite(sys->local_req_efd, 1);
> +}
> +
It seems that sys->local_req_efd is initialized with the return value
of eventfd(0, 0); IIUC, event write to a fd created by eventfd(0, 0)
can be blocked. SHould we use eventfd(0, EFD_NONBLOCK); for
asynchronous requests?
> /*
> * Exec the request locally and synchronously.
> *
> @@ -514,16 +523,13 @@ worker_fn int exec_local_req(struct sd_req *rq, void *data)
> req->rq = *rq;
> req->local_req_efd = eventfd(0, 0);
> if (req->local_req_efd < 0) {
> + sd_err("eventfd failed, %m");
> /* Fake the result to ask for retry */
> req->rp.result = SD_RES_NETWORK_ERROR;
> goto out;
> }
>
> - pthread_mutex_lock(&sys->local_req_lock);
> - list_add_tail(&req->request_list, &sys->local_req_queue);
> - pthread_mutex_unlock(&sys->local_req_lock);
> -
> - eventfd_xwrite(sys->local_req_efd, 1);
> + submit_local_request(req);
> eventfd_xread(req->local_req_efd);
> out:
> /* fill rq with response header as exec_req does */
> @@ -536,6 +542,73 @@ out:
> return ret;
> }
>
> +static void local_req_async_handler(int fd, int events, void *data)
> +{
> + struct request *req = data;
> + struct request_iocb *iocb = req->iocb;
> +
> + if (events & EPOLLERR)
> + sd_err("request handler error");
> + eventfd_xread(fd);
> +
> + if (unlikely(req->rp.result != SD_RES_SUCCESS))
> + iocb->result = req->rp.result;
> +
> + if (uatomic_sub_return(&iocb->count, 1) == 0)
> + eventfd_xwrite(iocb->efd, 1);
> +
> + unregister_event(req->local_req_efd);
> + close(req->local_req_efd);
> + free_local_request(req);
> +}
> +
> +worker_fn struct request_iocb *local_req_init(void)
> +{
> + struct request_iocb *iocb = xzalloc(sizeof(*iocb));
> +
> + iocb->efd = eventfd(0, 0);
> + if (iocb->efd < 0) {
> + sd_err("eventfd failed, %m");
> + free(iocb);
> + return NULL;
> + }
> + iocb->result = SD_RES_SUCCESS;
> + return iocb;
> +}
> +
> +worker_fn int local_req_wait(struct request_iocb *iocb)
> +{
> + int ret;
> +
> + eventfd_xread(iocb->efd);
> +
> + ret = iocb->result;
> + close(iocb->efd);
> + free(iocb);
> + return ret;
> +}
> +
> +worker_fn int exec_local_req_async(struct sd_req *rq, void *data,
> + struct request_iocb *iocb)
> +{
> + struct request *req;
> +
> + req = alloc_local_request(data, rq->data_length);
> + req->rq = *rq;
> + req->local_req_efd = eventfd(0, EFD_NONBLOCK);
> + if (req->local_req_efd < 0) {
> + sd_err("eventfd failed, %m");
> + return SD_RES_SYSTEM_ERROR;
> + }
> +
> + uatomic_inc(&iocb->count);
> + req->iocb = iocb;
> + register_event(req->local_req_efd, local_req_async_handler,
> req);
We cannot call register_event() in worker threads. It modifies data
structures of the main event loop.
Thanks,
Hitoshi
More information about the sheepdog
mailing list