[sheepdog] [PATCH] cache: introduce 'cache info' command
Liu Yuan
namei.unix at gmail.com
Fri Aug 9 10:33:41 CEST 2013
usage:
$ collie vdi cache info # Get the cache informatin of the node
Example:
yliu at ubuntu-precise:~/sheepdog$ collie/collie vdi cache info
Name Tag Total Dirty Clean
test 88 MB 68 MB 20 MB
data 88 MB 0.0 MB 88 MB
Cache size 200 MB, used 176 MB
Signed-off-by: Liu Yuan <namei.unix at gmail.com>
---
Hi Kazutaka,
I think this patch can safely go to v0.7.0 since it is doesn't change any
existing code.
collie/vdi.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
include/internal_proto.h | 15 +++++++++++
sheep/object_cache.c | 31 ++++++++++++++++++++++
sheep/ops.c | 17 ++++++++++++
sheep/sheep_priv.h | 1 +
5 files changed, 129 insertions(+)
diff --git a/collie/vdi.c b/collie/vdi.c
index 1a0abf3..00ecba5 100644
--- a/collie/vdi.c
+++ b/collie/vdi.c
@@ -1971,11 +1971,76 @@ out:
return ret;
}
+static int vid_to_name_tag(uint32_t vid, char *name, char *tag)
+{
+ struct sd_inode inode;
+ int ret;
+
+ ret = sd_read_object(vid_to_vdi_oid(vid), &inode, sizeof(inode), 0,
+ true);
+ if (ret != SD_RES_SUCCESS)
+ return ret;
+
+ pstrcpy(name, SD_MAX_VDI_LEN, inode.name);
+ pstrcpy(tag, SD_MAX_VDI_TAG_LEN, inode.tag);
+
+ return SD_RES_SUCCESS;
+}
+
+static int vdi_cache_info(int argc, char **argv)
+{
+ struct object_cache_info info = {};
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ char size_str[UINT64_DECIMAL_SIZE], used_str[UINT64_DECIMAL_SIZE];
+ int ret, i;
+
+ sd_init_req(&hdr, SD_OP_GET_CACHE_INFO);
+ hdr.data_length = sizeof(info);
+ ret = collie_exec_req(sdhost, sdport, &hdr, &info);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to get cache infomation: %s\n",
+ sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ fprintf(stdout, "Name\tTag\tTotal\tDirty\tClean\n");
+ for (i = 0; i < info.count; i++) {
+ char total_str[UINT64_DECIMAL_SIZE],
+ dirty_str[UINT64_DECIMAL_SIZE],
+ clean_str[UINT64_DECIMAL_SIZE];
+ uint64_t total = info.caches[i].total * SD_DATA_OBJ_SIZE,
+ dirty = info.caches[i].dirty * SD_DATA_OBJ_SIZE,
+ clean = total - dirty;
+ char name[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
+
+ size_to_str(total, total_str, sizeof(total_str));
+ size_to_str(dirty, dirty_str, sizeof(dirty_str));
+ size_to_str(clean, clean_str, sizeof(clean_str));
+ ret = vid_to_name_tag(info.caches[i].vid, name, tag);
+ if (ret != SD_RES_SUCCESS)
+ return EXIT_FAILURE;
+ fprintf(stdout, "%s\t%s\t%s\t%s\t%s\n",
+ name, tag, total_str, dirty_str, clean_str);
+ }
+
+ size_to_str(info.size, size_str, sizeof(size_str));
+ size_to_str(info.used, used_str, sizeof(used_str));
+ fprintf(stdout, "\nCache size %s, used %s\n", size_str, used_str);
+
+ return EXIT_SUCCESS;
+}
+
static struct subcommand vdi_cache_cmd[] = {
{"flush", NULL, NULL, "flush the cache of the vdi specified.",
NULL, SUBCMD_FLAG_NEED_ARG, vdi_cache_flush},
{"delete", NULL, NULL, "delete the cache of the vdi specified in all nodes.",
NULL, SUBCMD_FLAG_NEED_ARG, vdi_cache_delete},
+ {"info", NULL, NULL, "show usage of the cache",
+ NULL, 0, vdi_cache_info},
{NULL,},
};
diff --git a/include/internal_proto.h b/include/internal_proto.h
index 3ca46cf..da091f6 100644
--- a/include/internal_proto.h
+++ b/include/internal_proto.h
@@ -76,6 +76,7 @@
#define SD_OP_MD_UNPLUG 0xB3
#define SD_OP_GET_HASH 0xB4
#define SD_OP_REWEIGHT 0xB5
+#define SD_OP_GET_CACHE_INFO 0xB6
/* internal flags for hdr.flags, must be above 0x80 */
#define SD_FLAG_CMD_RECOVERY 0x0080
@@ -196,4 +197,18 @@ struct recovery_state {
uint64_t nr_total;
};
+#define CACHE_MAX 1024
+struct cache_info {
+ uint32_t vid;
+ uint32_t dirty;
+ uint32_t total;
+};
+
+struct object_cache_info {
+ uint64_t size;
+ uint64_t used;
+ struct cache_info caches[CACHE_MAX];
+ int count;
+};
+
#endif /* __INTERNAL_PROTO_H__ */
diff --git a/sheep/object_cache.c b/sheep/object_cache.c
index 7bfe6d4..c238725 100644
--- a/sheep/object_cache.c
+++ b/sheep/object_cache.c
@@ -54,6 +54,7 @@ struct object_cache {
uint32_t vid; /* The VID of this VDI */
uint32_t push_count; /* How many push threads queued in push phase. */
uint32_t dirty_count; /* How many dirty object in this cache */
+ uint32_t total_count; /* Count of objects include dirty and clean */
struct hlist_node hash; /* VDI is linked to the global hash lists */
struct rb_root lru_tree; /* For faster object search */
struct list_head lru_head; /* Per VDI LRU list for reclaimer */
@@ -298,6 +299,7 @@ free_cache_entry(struct object_cache_entry *entry)
rb_erase(&entry->node, &oc->lru_tree);
list_del_init(&entry->lru_list);
+ oc->total_count--;
if (!list_empty(&entry->dirty_list))
del_from_dirty_list(entry);
sd_destroy_lock(&entry->lock);
@@ -713,6 +715,7 @@ static void add_to_lru_cache(struct object_cache *oc, uint32_t idx, bool create)
panic("the object already exist");
uatomic_add(&gcache.capacity, CACHE_OBJECT_SIZE);
list_add_tail(&entry->lru_list, &oc->lru_head);
+ oc->total_count++;
if (create) {
/* Cache lock assure it is not raced with pusher */
entry->bmap = UINT64_MAX;
@@ -1399,3 +1402,31 @@ void object_cache_format(void)
}
uatomic_set(&gcache.capacity, 0);
}
+
+int object_cache_get_info(struct object_cache_info *info)
+{
+ int j = 0;
+
+ info->used = gcache.capacity * 1024 * 1024;
+ info->size = sys->object_cache_size * 1024 * 1024;
+
+ for (int i = 0; i < HASH_SIZE; i++) {
+ struct hlist_head *head = cache_hashtable + i;
+ struct object_cache *cache;
+ struct hlist_node *node;
+
+ sd_read_lock(&hashtable_lock[i]);
+ hlist_for_each_entry(cache, node, head, hash) {
+ read_lock_cache(cache);
+ info->caches[j].vid = cache->vid;
+ info->caches[j].dirty = cache->dirty_count;
+ info->caches[j].total = cache->total_count;
+ j++;
+ unlock_cache(cache);
+ }
+ sd_unlock(&hashtable_lock[i]);
+ }
+ info->count = j;
+
+ return sizeof(*info);
+}
diff --git a/sheep/ops.c b/sheep/ops.c
index f0d89df..5bc0b84 100644
--- a/sheep/ops.c
+++ b/sheep/ops.c
@@ -734,6 +734,17 @@ static int local_get_hash(struct request *request)
rsp->hash.digest);
}
+static int local_get_cache_info(struct request *request)
+{
+ struct sd_rsp *rsp = &request->rp;
+
+ assert(request->rq.data_length == sizeof(struct object_cache_info));
+ rsp->data_length = object_cache_get_info((struct object_cache_info *)
+ request->data);
+
+ return SD_RES_SUCCESS;
+}
+
/* Return SD_RES_INVALID_PARMS to ask client not to send flush req again */
static int local_flush_vdi(struct request *req)
{
@@ -1188,6 +1199,12 @@ static struct sd_op_template sd_ops[] = {
.process_work = local_get_hash,
},
+ [SD_OP_GET_CACHE_INFO] = {
+ .name = "GET_CACHE_INFO",
+ .type = SD_OP_TYPE_LOCAL,
+ .process_work = local_get_cache_info,
+ },
+
/* gateway I/O operations */
[SD_OP_CREATE_AND_WRITE_OBJ] = {
.name = "CREATE_AND_WRITE_OBJ",
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index 6c3cc50..dae02d1 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -393,6 +393,7 @@ int object_cache_flush_and_del(const struct request *req);
void object_cache_delete(uint32_t vid);
int object_cache_init(const char *p);
int object_cache_remove(uint64_t oid);
+int object_cache_get_info(struct object_cache_info *info);
/* store layout migration */
int sd_migrate_store(int from, int to);
--
1.7.9.5
More information about the sheepdog
mailing list