ceph/src/testlibrbd.c

422 lines
12 KiB
C

// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
* Ceph - scalable distributed file system
*
* Copyright (C) 2011 New Dream Network
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2, as published by the Free Software
* Foundation. See file COPYING.
*
*/
#include "include/rados/librados.h"
#include "include/rbd/librbd.h"
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#define TEST_IMAGE "testimg"
#define TEST_IMAGE2 "testimg2"
#define TEST_POOL "librbdtest"
#define TEST_SNAP "testsnap"
#define TEST_IO_SIZE 512
#define TEST_IO_TO_SNAP_SIZE 80
#define MB_BYTES(mb) (mb << 20)
void test_create_and_stat(rados_ioctx_t io_ctx, const char *name, size_t size)
{
rbd_image_info_t info;
rbd_image_t image;
int order = 0;
assert(rbd_create(io_ctx, name, size, &order) == 0);
assert(rbd_open(io_ctx, name, &image, NULL) == 0);
assert(rbd_stat(image, &info, sizeof(info)) == 0);
printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
assert(info.size == size);
assert(info.order == order);
assert(rbd_close(image) == 0);
}
void test_resize_and_stat(rbd_image_t image, size_t size)
{
rbd_image_info_t info;
assert(rbd_resize(image, size) == 0);
assert(rbd_stat(image, &info, sizeof(info)) == 0);
printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
assert(info.size == size);
}
void test_ls(rados_ioctx_t io_ctx, size_t num_expected, ...)
{
int num_images, i, j;
char *expected, *names, *cur_name;
va_list ap;
size_t max_size = 1024;
names = (char *) malloc(sizeof(char *) * 1024);
num_images = rbd_list(io_ctx, names, &max_size);
printf("num images is: %d\nexpected: %d\n", num_images, (int)num_expected);
assert(num_images >= 0);
assert(num_images == (int)num_expected);
for (i = 0, cur_name = names; i < num_images; i++) {
printf("image: %s\n", cur_name);
cur_name += strlen(cur_name) + 1;
}
va_start(ap, num_expected);
for (i = num_expected; i > 0; i--) {
expected = va_arg(ap, char *);
printf("expected = %s\n", expected);
int found = 0;
for (j = 0, cur_name = names; j < num_images; j++) {
if (cur_name[0] == '_') {
cur_name += strlen(cur_name) + 1;
continue;
}
if (strcmp(cur_name, expected) == 0) {
printf("found %s\n", cur_name);
cur_name[0] = '_';
found = 1;
break;
}
}
assert(found);
}
va_end(ap);
for (i = 0, cur_name = names; i < num_images; i++) {
assert(cur_name[0] == '_');
cur_name += strlen(cur_name) + 1;
}
free(names);
}
void test_delete(rados_ioctx_t io_ctx, const char *name)
{
assert(rbd_remove(io_ctx, name) == 0);
}
void test_create_snap(rbd_image_t image, const char *name)
{
assert(rbd_snap_create(image, name) == 0);
}
void test_ls_snaps(rbd_image_t image, int num_expected, ...)
{
rbd_snap_info_t *snaps;
int num_snaps, i, j, expected_size, max_size = 10;
char *expected;
va_list ap;
snaps = (rbd_snap_info_t *) malloc(sizeof(rbd_snap_info_t *) * 10);
num_snaps = rbd_snap_list(image, snaps, &max_size);
printf("num snaps is: %d\nexpected: %d\n", num_snaps, num_expected);
assert(num_snaps == num_expected);
for (i = 0; i < num_snaps; i++) {
printf("snap: %s\n", snaps[i].name);
}
va_start(ap, num_expected);
for (i = num_expected; i > 0; i--) {
expected = va_arg(ap, char *);
expected_size = va_arg(ap, int);
int found = 0;
for (j = 0; j < num_snaps; j++) {
if (snaps[j].name == NULL)
continue;
if (strcmp(snaps[j].name, expected) == 0) {
printf("found %s with size %llu\n", snaps[j].name, (unsigned long long) snaps[j].size);
assert((int)snaps[j].size == expected_size);
free((void *) snaps[j].name);
snaps[j].name = NULL;
found = 1;
break;
}
}
assert(found);
}
va_end(ap);
for (i = 0; i < num_snaps; i++) {
assert(snaps[i].name == NULL);
}
free(snaps);
}
void test_delete_snap(rbd_image_t image, const char *name)
{
assert(rbd_snap_remove(image, name) == 0);
}
void simple_write_cb(rbd_completion_t cb, void *arg)
{
printf("write completion cb called!\n");
}
void simple_read_cb(rbd_completion_t cb, void *arg)
{
printf("read completion cb called!\n");
}
void aio_write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len)
{
rbd_completion_t comp;
rbd_aio_create_completion(NULL, (rbd_callback_t) simple_write_cb, &comp);
printf("created completion\n");
rbd_aio_write(image, off, len, test_data, comp);
printf("started write\n");
rbd_aio_wait_for_complete(comp);
int r = rbd_aio_get_return_value(comp);
printf("return value is: %d\n", r);
assert(r == 0);
printf("finished write\n");
rbd_aio_release(comp);
}
void write_test_data(rbd_image_t image, const char *test_data, uint64_t off, size_t len)
{
ssize_t written;
written = rbd_write(image, off, len, test_data);
printf("wrote: %d\n", (int) written);
assert(written == (ssize_t)len);
}
void aio_read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len)
{
rbd_completion_t comp;
char *result = malloc(len + 1);
assert(result);
rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
printf("created completion\n");
rbd_aio_read(image, off, len, result, comp);
printf("started read\n");
rbd_aio_wait_for_complete(comp);
int r = rbd_aio_get_return_value(comp);
printf("return value is: %d\n", r);
assert(r == (ssize_t)len);
rbd_aio_release(comp);
printf("read: %s\nexpected: %s\n", result, expected);
assert(memcmp(result, expected, len) == 0);
free(result);
}
void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len)
{
ssize_t read;
char *result = malloc(len + 1);
assert(result);
read = rbd_read(image, off, len, result);
printf("read: %d\n", (int) read);
assert(read == (ssize_t)len);
result[len] = '\0';
printf("read: %s\nexpected: %s\n", result, expected);
assert(memcmp(result, expected, len) == 0);
free(result);
}
void test_io(rados_ioctx_t io, rbd_image_t image)
{
char test_data[TEST_IO_SIZE + 1];
int i;
for (i = 0; i < TEST_IO_SIZE; ++i) {
test_data[i] = (char) (rand() % (126 - 33) + 33);
}
test_data[TEST_IO_SIZE] = '\0';
for (i = 0; i < 5; ++i)
write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
for (i = 5; i < 10; ++i)
aio_write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
for (i = 0; i < 5; ++i)
read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
for (i = 5; i < 10; ++i)
aio_read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE);
rbd_image_info_t info;
rbd_completion_t comp;
assert(rbd_stat(image, &info, sizeof(info)) == 0);
assert(rbd_write(image, info.size, 1, test_data) == -EINVAL);
assert(rbd_read(image, info.size, 1, test_data) == -EINVAL);
rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
assert(rbd_aio_write(image, info.size, 1, test_data, comp) == -EINVAL);
assert(rbd_aio_read(image, info.size, 1, test_data, comp) == -EINVAL);
}
void test_io_to_snapshot(rados_ioctx_t io_ctx, rbd_image_t image, size_t isize)
{
int i, r;
rbd_image_t image_at_snap;
char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
char test_data[TEST_IO_TO_SNAP_SIZE + 1];
for (i = 0; i < TEST_IO_TO_SNAP_SIZE - 1; ++i)
test_data[i] = (char) (i + 48);
test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';
r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
assert(r == TEST_IO_TO_SNAP_SIZE);
test_ls_snaps(image, 0);
test_create_snap(image, "orig");
test_ls_snaps(image, 1, "orig", isize);
read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
printf("write test data!\n");
write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
test_create_snap(image, "written");
test_ls_snaps(image, 2, "orig", isize, "written", isize);
read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
rbd_snap_set(image, "orig");
read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
rbd_snap_set(image, "written");
read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
rbd_snap_set(image, "orig");
r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
printf("write to snapshot returned %d\n", r);
assert(r < 0);
printf("%s\n", strerror(-r));
read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
rbd_snap_set(image, "written");
read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
r = rbd_snap_rollback(image, "orig");
printf("rbd_snap_rollback returned %d\n", r);
assert(r >= 0);
r = rbd_snap_set(image, NULL);
assert(r == 0);
write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
printf("opening testimg@orig\n");
assert(rbd_open(io_ctx, TEST_IMAGE, &image_at_snap, "orig") >= 0);
read_test_data(image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
printf("write to snapshot returned %d\n", r);
assert(r < 0);
printf("%s\n", strerror(-r));
assert(rbd_close(image_at_snap) == 0);
test_ls_snaps(image, 2, "orig", isize, "written", isize);
test_delete_snap(image, "written");
test_ls_snaps(image, 1, "orig", isize);
test_delete_snap(image, "orig");
test_ls_snaps(image, 0);
}
void test_rbd_copy(rados_ioctx_t io_ctx, rbd_image_t image)
{
int ret;
ret = rbd_copy(image, io_ctx, TEST_IMAGE2);
if (ret < 0) {
fprintf(stderr, "rbd_copy returned %d!\n", ret);
abort();
}
}
static int print_progress_percent(uint64_t offset, uint64_t src_size,
void *data)
{
float percent = ((float)offset * 100) / src_size;
printf("%3.2f%% done\n", percent);
return 0;
}
void test_rbd_copy_with_progress(rados_ioctx_t io_ctx, rbd_image_t image)
{
int ret;
ret = rbd_copy_with_progress(image, io_ctx, TEST_IMAGE2,
print_progress_percent, NULL);
if (ret < 0) {
fprintf(stderr, "rbd_copy_with_progress returned %d!\n", ret);
abort();
}
}
int main(int argc, const char **argv)
{
rados_t cluster;
rados_ioctx_t io_ctx;
rbd_image_t image;
srand(time(0));
assert(rados_create(&cluster, NULL) == 0);
assert(rados_conf_parse_argv(cluster, argc, argv) == 0);
assert(rados_conf_read_file(cluster, NULL) == 0);
assert(rados_connect(cluster) == 0);
if (rados_pool_lookup(cluster, TEST_POOL) != -ENOENT) {
int r = rados_pool_delete(cluster, TEST_POOL);
printf("rados_pool_delete returned %d\n", r);
}
int r = rados_pool_create(cluster, TEST_POOL);
printf("rados_pool_create returned %d\n", r);
assert(rados_ioctx_create(cluster, TEST_POOL, &io_ctx) == 0);
test_ls(io_ctx, 0);
test_create_and_stat(io_ctx, TEST_IMAGE, MB_BYTES(1));
assert(rbd_open(io_ctx, TEST_IMAGE, &image, NULL) == 0);
test_ls(io_ctx, 1, TEST_IMAGE);
test_ls_snaps(image, 0);
test_create_snap(image, TEST_SNAP);
test_ls_snaps(image, 1, TEST_SNAP, MB_BYTES(1));
test_resize_and_stat(image, MB_BYTES(2));
test_io(io_ctx, image);
test_create_snap(image, TEST_SNAP "1");
test_ls_snaps(image, 2, TEST_SNAP, MB_BYTES(1), TEST_SNAP "1", MB_BYTES(2));
test_delete_snap(image, TEST_SNAP);
test_ls_snaps(image, 1, TEST_SNAP "1", MB_BYTES(2));
test_delete_snap(image, TEST_SNAP "1");
test_ls_snaps(image, 0);
test_io_to_snapshot(io_ctx, image, MB_BYTES(2));
assert(rbd_close(image) == 0);
test_create_and_stat(io_ctx, TEST_IMAGE "1", MB_BYTES(2));
test_ls(io_ctx, 2, TEST_IMAGE, TEST_IMAGE "1");
test_delete(io_ctx, TEST_IMAGE);
test_ls(io_ctx, 1, TEST_IMAGE "1");
test_delete(io_ctx, TEST_IMAGE "1");
test_ls(io_ctx, 0);
test_rbd_copy(io_ctx, image);
test_delete(io_ctx, TEST_IMAGE2);
test_rbd_copy_with_progress(io_ctx, image);
rados_ioctx_destroy(io_ctx);
rados_shutdown(cluster);
return 0;
}