[sheepdog] [PATCH 2/6] sockfd: implement shrinking mechanism for handling EMFILE

Liu Yuan namei.unix at gmail.com
Mon Aug 19 08:36:49 CEST 2013


On Wed, Aug 14, 2013 at 01:27:37AM +0900, Hitoshi Mitake wrote:
> sockfd is a big fd consumer and cached fds should be closed when sheep
> faces EMFILE. This patch adds a new function, sockfd_shrink(), for
> closing unused cached fds.
> 
> Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
> ---
>  include/sockfd_cache.h |  1 +
>  lib/sockfd_cache.c     | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
> 
> diff --git a/include/sockfd_cache.h b/include/sockfd_cache.h
> index d91c56a..aaceaa7 100644
> --- a/include/sockfd_cache.h
> +++ b/include/sockfd_cache.h
> @@ -12,6 +12,7 @@ void sockfd_cache_add(const struct node_id *nid);
>  void sockfd_cache_add_group(const struct sd_node *nodes, int nr);
>  
>  int sockfd_init(void);
> +bool sockfd_shrink(void);
>  
>  /* sockfd_cache */
>  struct sockfd {
> diff --git a/lib/sockfd_cache.c b/lib/sockfd_cache.c
> index c9404ea..ef3fa7d 100644
> --- a/lib/sockfd_cache.c
> +++ b/lib/sockfd_cache.c
> @@ -47,6 +47,12 @@ static struct sockfd_cache sockfd_cache = {
>  };
>  
>  /*
> + * shrink_head: used by shrink_sockfd() for fair shrinking
> + * protected by sockfd_cache.lock
> + */
> +static struct rb_node *shrink_head;

Remove shrink_head please, let's start with a simple round rabin shrinker
first. By the way, if we need a more complex shrinking approach, I'd suggest use
LRU list to emit least recently used fd(s). But for now, LRU is kind of over
kill.

> +
> +/*
>   * Suppose request size from Guest is 512k, then 4M / 512k = 8, so at
>   * most 8 requests can be issued to the same sheep object. Based on this
>   * assumption, '8' would be effecient for servers that only host 2~4
> @@ -208,6 +214,9 @@ static bool sockfd_cache_destroy(const struct node_id *nid)
>  	rb_erase(&entry->rb, &sockfd_cache.root);
>  	sd_unlock(&sockfd_cache.lock);
>  
> +	if (&entry->rb == shrink_head)
> +		shrink_head = rb_next(&entry->rb);
> +
>  	destroy_all_slots(entry);
>  	free_cache_entry(entry);
>  
> @@ -529,3 +538,56 @@ void sockfd_cache_del(const struct node_id *nid, struct sockfd *sfd)
>  	sockfd_cache_del_node(nid);
>  	free(sfd);
>  }
> +
> +bool sockfd_shrink(void)
> +{
> +	bool ret = false;
> +	struct rb_node *p, *first;
> +
> +	sd_write_lock(&sockfd_cache.lock);
> +
> +	p = shrink_head ? shrink_head : rb_first(&sockfd_cache.root);
> +	if (!p) {
> +		sd_debug("There's no sockfd");
> +		goto out;
> +	}
> +
> +	first = p;
> +	do {
> +		struct sockfd_cache_entry *entry =
> +			rb_entry(p, struct sockfd_cache_entry, rb);
> +
> +		for (int i = 0; i < fds_count; i++) {
> +			if (!uatomic_set_true(&entry->fds[i].in_use))
> +				/* failed to grab, someone is using */
> +				continue;
> +
> +			if (entry->fds[i].fd == -1) {
> +				/* this fd is not used */
> +				uatomic_set_false(&entry->fds[i].in_use);
> +				continue;
> +			}
> +
> +			sd_debug("victim node: %s, fd: %d",
> +				 nid_to_str(&entry->nid), entry->fds[i].fd);
> +			close(entry->fds[i].fd);
> +			entry->fds[i].fd = -1;
> +			uatomic_set_false(&entry->fds[i].in_use);
> +
> +			shrink_head = rb_next(p);
> +
> +			ret = true;
> +			goto out;
> +		}
> +
> +		p = rb_next(p);
> +		if (!p)
> +			p = rb_first(&sockfd_cache.root);
> +	} while (first != p);
> +
> +	sd_debug("shrinking couldn't be done");
> +
> +out:
> +	sd_unlock(&sockfd_cache.lock);
> +	return ret;
> +}

Use for(entry = rb_first; entry; entry = rb_next) look cleaner for iteration

Thanks
Yuan



More information about the sheepdog mailing list