[sheepdog] [PATCH] add a buffer to object list cache as a second level cache
Liu Yuan
namei.unix at gmail.com
Tue May 22 10:14:58 CEST 2012
On 05/22/2012 02:00 PM, levin li wrote:
> From: levin li <xingke.lwp at taobao.com>
>
> It's inefficient for get_obj_list() to traverse the object
> list rbtree to get the object list every time, so I add a buffer
> to cache the list, every time in get_obj_list() if the rbtree
> has changed which is detected by the version number, we update
> the buffer, then we can just read the buffer by memcpy() if the
> object list has not been changed, instead of traverse the full
> rbtree.
>
> Signed-off-by: levin li <xingke.lwp at taobao.com>
> ---
> sheep/object_list_cache.c | 42 ++++++++++++++++++++++++++++++++++--------
> sheep/ops.c | 4 +++-
> sheep/sheep_priv.h | 6 +++++-
> 3 files changed, 42 insertions(+), 10 deletions(-)
>
> diff --git a/sheep/object_list_cache.c b/sheep/object_list_cache.c
> index 28cdbbc..2f3ae3d 100644
> --- a/sheep/object_list_cache.c
> +++ b/sheep/object_list_cache.c
> @@ -16,6 +16,7 @@
> #include <unistd.h>
> #include <sys/types.h>
> #include <pthread.h>
> +#include <errno.h>
>
> #include "sheep_priv.h"
> #include "strbuf.h"
> @@ -37,6 +38,10 @@ int init_objlist_cache(void)
> pthread_rwlock_init(&obj_list_cache.lock, NULL);
> obj_list_cache.root = RB_ROOT;
> obj_list_cache.cache_size = 0;
> + obj_list_cache.tree_version = 1;
> + obj_list_cache.buf_version = 0;
> + obj_list_cache.buf_size = 0;
> + obj_list_cache.buffer = NULL;
>
> if (sd_store) {
> buf = zalloc(1 << 22);
> @@ -123,8 +128,10 @@ int check_and_insert_objlist_cache(uint64_t oid)
> p = objlist_cache_rb_insert(&obj_list_cache.root, entry);
> if (p)
> free(entry);
> - else
> + else {
> obj_list_cache.cache_size++;
> + obj_list_cache.tree_version++;
> + }
> pthread_rwlock_unlock(&obj_list_cache.lock);
>
> return 0;
> @@ -134,18 +141,37 @@ int get_obj_list(const struct sd_list_req *hdr, struct sd_list_rsp *rsp, void *d
> {
> uint64_t *list = (uint64_t *)data;
> int nr = 0;
> - int res = SD_RES_SUCCESS;
> struct objlist_cache_entry *entry;
> struct rb_node *p;
>
> + rsp->data_length = obj_list_cache.cache_size * sizeof(uint64_t);
> +
> pthread_rwlock_rdlock(&obj_list_cache.lock);
> - for (p = rb_first(&obj_list_cache.root); p; p = rb_next(p)) {
> - entry = rb_entry(p, struct objlist_cache_entry, node);
> - list[nr++] = entry->oid;
> + if (obj_list_cache.tree_version == obj_list_cache.buf_version)
> + memcpy(list, obj_list_cache.buffer, rsp->data_length);
> + else {
> + for (p = rb_first(&obj_list_cache.root); p; p = rb_next(p)) {
> + entry = rb_entry(p, struct objlist_cache_entry, node);
> + list[nr++] = entry->oid;
> + }
> +
> + if (obj_list_cache.buf_size <
> + obj_list_cache.cache_size * sizeof(uint64_t)) {
> + int new_size;
> +
> + new_size = obj_list_cache.cache_size * sizeof(uint64_t);
> + obj_list_cache.buffer =
> + realloc(obj_list_cache.buffer, new_size);
> +
> + if (ENOMEM != errno) {
> + obj_list_cache.buf_version =
> + obj_list_cache.tree_version;
> + obj_list_cache.buf_size = new_size;
> + memcpy(obj_list_cache.buffer, list, new_size);
> + }
> + }
> }
> pthread_rwlock_unlock(&obj_list_cache.lock);
>
> - rsp->data_length = nr * sizeof(uint64_t);
> -
> - return res;
> + return SD_RES_SUCCESS;
> }
> diff --git a/sheep/ops.c b/sheep/ops.c
> index b4df70f..582ed24 100644
> --- a/sheep/ops.c
> +++ b/sheep/ops.c
> @@ -712,8 +712,10 @@ static int store_remove_obj(struct request *req)
> ret = SD_RES_EIO;
> }
> pthread_rwlock_wrlock(&obj_list_cache.lock);
> - if (!objlist_cache_rb_remove(&obj_list_cache.root, oid))
> + if (!objlist_cache_rb_remove(&obj_list_cache.root, oid)) {
> obj_list_cache.cache_size--;
> + obj_list_cache.tree_version++;
> + }
> pthread_rwlock_unlock(&obj_list_cache.lock);
> out:
> strbuf_release(&buf);
> diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
> index 21ee282..3c46ca5 100644
> --- a/sheep/sheep_priv.h
> +++ b/sheep/sheep_priv.h
> @@ -203,8 +203,12 @@ static inline struct store_driver *find_store_driver(const char *name)
> }
>
> struct objlist_cache {
> - struct rb_root root;
> + int tree_version;
> + int buf_version;
> + int buf_size;
> + uint64_t *buffer;
> int cache_size;
> + struct rb_root root;
> pthread_rwlock_t lock;
> };
>
How about use strbuf to manage the buffer? This is a several metabytes
buffer, I think strbuf could deal well with it and would simplify the
buffer management.
Thanks,
Yuan
More information about the sheepdog
mailing list