[sheepdog] [PATCH 1/2] sheep: introduce async request handling

Liu Yuan namei.unix at gmail.com
Tue Dec 17 07:17:30 CET 2013


On Tue, Dec 17, 2013 at 03:13:26PM +0900, Hitoshi Mitake wrote:
> 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?

sys->local_req_efd = eventfd(0, EFD_NONBLOCK); # line 912

> 
> >  /*
> >   * 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.
> 

what kind of data structure? i notice epoll_ctl is thread safe.

Thanks
Yuan



More information about the sheepdog mailing list