[Analysis] Ceph programming instance interface Librbd (C ++) -- image creation and data read/write, cephlibrbd
Currently, we have two ways to use Ceph Block Storage :?
-Use QEMU/KVM to interact with Ceph Block devices through librbd. This mainly provides block storage devices for virtual machines, as shown in ;?
-Use the kernel module to interact with the Host kernel, mainly to provide block device support for physical machines.
Librbd is the abstraction of Block Storage interfaces provided by Ceph. It provides multiple interfaces, such as C/C ++ and Python. For C ++, the two most important classes areRBD? And?Image .?RBD? It is mainly responsible for creating, deleting, and cloning images.Image? Class is responsible for reading and writing images.
Preparations
For any client application, you must first connect to a running Ceph cluster.
Obtain cluster handle
// Declare the Rados object and initialize librados: Rados rados; ret = rados. init ("admin"); // just use the client. admin keyringif (ret <0) {// let's handle any error that might have come back std: cerr <"couldn't initialize rados! Err "<ret <std: endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else {std :: cout <"we just set up a rados cluster object" <std: endl;} // obtain the configuration file information:/etc/ceph. conf // 1. according to the command line parameter/* ret = rados. conf_parse_argv (argc, argv); if (ret <0) {// This really can't happen, but we need to check to be a good citizen. std: cerr <"failed to parse config options! Error "<ret <std: endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else {std: cout <" we just parsed our config options "<std:: endl; // We also want to apply the config file if the user specified // one, and conf_parse_argv won't do that for us. for (int I = 0; I <argc; ++ I) {if (strcmp (argv [I], "-c") = 0) | (strcmp (argv [I], "-- conf") = 0) {ret = rados. conf_read_file (argv [I + 1]); if (Ret <0) {// This cocould fail if the config file is malformed, but it 'd be hard. std: cerr <"failed to parse config file" <argv [I + 1] <"! Error "<ret <std: endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} break ;}}* // 2. in the program, specify ret = rados. conf_read_file ("/etc/ceph. conf "); if (ret <0) {// This cocould fail if the config file is malformed, but it 'd be hard. std: cerr <"failed to parse config file! Err "<ret <std: endl; ret = EXIT_FAILURE; return EXIT_FAILURE ;}
Connect to a cluster
ret = rados.connect();if (ret < 0) { std::cerr << "couldn't connect to cluster! err " << ret << std::endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else { std::cout << "we just connected to the rados cluster" << std::endl;}
Create an I/O Context
If there is no storage pool, you need to create a new storage pool first.
Create a storage pool
Const char * pool_name = "gnar"; ret = rados. pool_create (pool_name); if (ret <0) {std: cerr <"couldn't create pool! Error "<ret <std: endl; ret = EXIT_FAILURE; rados. shutdown (); // disconnect cluster connection return EXIT_FAILURE;} else {std: cout <"we just created a new pool named" <pool_name <std :: endl ;}
Create an I/O Context
Librados: IoCtx io_ctx; // I/O context const char * pool_name = "gnar"; ret = rados. ioctx_create (pool_name, io_ctx); if (ret <0) {std: cerr <"couldn't setup ioctx! Err "<ret <std: endl; ret = EXIT_FAILURE; rados. shutdown (); // disconnect cluster connection return EXIT_FAILURE;} else {std: cout <"we just created an ioctx for our pool" <std: endl ;}
Several RBD image APIs
Declare An RBD object and create an rbd Image
Librbd: RBD rbd; const char * image_name = "rumboo"; uint64_t init_size = (uint64_t) 200*1024*1024; // The image initialization size is mbuint64_t features = 1; // affects the number of feature int order = 22; // The default value is 22, that is, 4 MB (1 <22) ret = rbd. create2 (io_ctx, image_name, init_size, features, & order); if (ret <0) {std: cerr <"couldn't create rbd image! Err "<ret <std: endl; ret = EXIT_FAILURE; io_ctx.close (); // disable the I/O context rados. shutdown (); // disconnect cluster connection return EXIT_FAILURE;} else {std: cout <"We just created an rbd image" <std: endl ;}
Open the rbd Image
Librbd: RBD rbd; const char * image_name = "rumboo"; librbd: Image image; ret = rbd. open (io_ctx, image, image_name); if (ret <0) {std: cerr <"couldn't open rbd image! Err "<ret <std: endl; ret = EXIT_FAILURE; io_ctx.close (); // disable the I/O context rados. shutdown (); // disconnect the cluster connection return EXIT_FAILURE;} else {std: cout <"We just opened an rbd image" <std: endl ;}
View image size
uint64_t size = 0;ret = image.size(&size);if (ret < 0) { std::cerr << "couldn't get image size! err " << ret << std::endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else { std::cout << "The size of the image is " << size << std::endl;}
Resize an image
Size = (uint64_t) 500*1024*1024; // adjust the image size by 500 MBret = image. resize (size); if (ret <0) {std: cerr <"couldn't change the size of the image! Err "<ret <std: endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else {std :: cout <"We just change the size of the image" <std: endl ;}
View image ID
std::string id;ret = image.get_id(&id);if (ret < 0) { std::cerr << "couldn't get image ID! err " << ret << std::endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else { std::cout << "The ID of the image is " << id << std::endl;}
View image features
features = 0;ret = image.features(&features);if (ret < 0) { std::cerr << "couldn't get image features! err " << ret << std::endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else { std::cout << "The features of the image are " << features << std::endl;}
View image status information
librbd::image_info_t info;ret = image.stat(info, sizeof(info));if (ret < 0) { std::cerr << "couldn't get image stat_info! err " << ret << std::endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else { std::cout << "info.size is " << info.size << std::endl; std::cout << "info.obj_size is " << info.obj_size << std::endl; std::cout << "info.num_objs is " << info.num_objs << std::endl; std::cout << "info.order is " << info.order << std::endl; std::cout << "info.block_name_prefix is " << info.block_name_prefix << std::endl;}
View the storage pool ID
std::cout << "data pool id is " << image.get_data_pool_id() << std::endl;
1
View block_name_prefix
std::cout << "block name prefix is " << image.get_block_name_prefix() << std::endl;
View flags
uint64_t flags = 0;ret = image.get_flags(&flags);if (ret < 0) { std::cerr << "couldn't get image flags! err " << ret << std::endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else { std::cout << "image flags is " << flags << std::endl;}
View striped Parameters
std::cout << "image stripe unit is " << image.get_stripe_unit() << std::endl;std::cout << "image stripe count is " << image.get_stripe_count() << std::endl;
RBD image data read/write
Data read/write-synchronous
Optional ofs_w = (optional) 0; // read/write offset uint64_t ofs_r = (uint64_t) 0; size_t len_w = 100; // read/write length size_t len_r = 100; ceph: bufferlist bl_w; // read/write bufferlistceph: bufferlist bl_r; const char * fn_ I = "input"; // read/Write File Name const char * fn_o = "output"; std: string error; ret = bl_r.read_file (fn_ I, & error); std: cout <"read file ret =" <ret <std: endl; if (ret <0) {std: cerr <"couldn't read file! Err "<ret <std: endl; ret = EXIT_FAILURE; image. close (); // close the rbd image io_ctx.close (); // close the I/O context rados. shutdown (); // disconnect the cluster connection return EXIT_FAILURE;} else {std: cout <"We just read a file" <std: endl ;} ssize_t ret_w = image. write2 (ofs_w, len_w, bl_r, 0); ssize_t ret_r = image. read2 (ofs_r, len_r, bl_w, 0); ret = bl_1_write_file (fn_o, 0644); std: cout <"write file ret =" <ret <std :: endl; if (re T <0) {std: cerr <"couldn't write file! Err "<ret <std: endl; ret = EXIT_FAILURE; image. close (); // close the rbd image io_ctx.close (); // close the I/O context rados. shutdown (); // disconnect cluster connection return EXIT_FAILURE;} else {std: cout <"We just wrote a file" <std: endl ;}
Data read/write-asynchronous
Std: string data = "foo"; uint64_t ofs_aiow = (uint64_t) 100; // read/write offset uint64_t ofs_aior = (uint64_t) 100; size_lent _aiow = 600; // read/write length size_t len_aior = 600; ceph: bufferlist bytes; // read/write bufferlistceph: bufferlist bl_aior; librbd: RBD: AioCompletion * write_completion = new librbd:: AioCompletion (NULL, (librbd: callback_t) simple_write_cb); // read and write AioCompletionlibrbd: RBD: AioCompletion * read_complet Ion = new librbd: RBD: AioCompletion (NULL, (librbd: callback_t) simple_read_cb); for (int I = 0; I <200; ++ I) {bl_aior.append (data);} std: cout <bl_aior.to_str () <std: endl; ret = image. aio_write2 (ofs_aiow, len_aiow, bl_aior, write_completion, 0); if (ret <0) {std: cerr <"couldn't start write! Error "<ret <std: endl; ret = EXIT_FAILURE; image. close (); // close the rbd image io_ctx.close (); // close the I/O context rados. shutdown (); // disconnect the cluster connection return EXIT_FAILURE;} write_completion-> wait_for_complete (); // wait until the write is completed ret_w = write_completion-> get_return_value (); if (ret_w <0) {std: cerr <"couldn't write! Error "<ret <std: endl; ret_w = EXIT_FAILURE; image. close (); // close the rbd image io_ctx.close (); // close the I/O context rados. shutdown (); // disconnect the cluster connection return EXIT_FAILURE;} else {std: cout <"we just write data successfully, return value is" <ret_w <std :: endl;} ret = image. aio_read2 (ofs_aior, len_aior, bl_aiow, read_completion, 0); if (ret <0) {std: cerr <"couldn't start read! Error "<ret <std: endl; ret = EXIT_FAILURE; image. close (); // close the rbd image io_ctx.close (); // close the I/O context rados. shutdown (); // disconnect the cluster connection return EXIT_FAILURE;} read_completion-> wait_for_complete (); // wait until the read is completed ret_r = read_completion-> get_return_value (); if (ret_r <0) {std: cerr <"couldn't read! Error "<ret <std: endl; ret_r = EXIT_FAILURE; image. close (); // close the rbd image io_ctx.close (); // close the I/O context rados. shutdown (); // disconnect the cluster connection return EXIT_FAILURE;} else {std: cout <"we just read data successfully, return value is" <ret_r <std :: endl;} std: cout <bl_aio1_to_str () <std: endl; write_completion-> release (); read_completion-> release (); void simple_write_cb (librbd :: completion_t cb, void * arg) {Std: cout <"write completion cb called! "<Std: endl;} // simple callback function for librbd: RBD: AioCompletionvoid simple_read_cb (librbd: completion_t cb, void * arg) {std :: cout <"read completion cb called! "<Std: endl ;}
Finishing work
At last, you must not forget to close the rbd image and I/O context and disconnect the cluster.
Ret = image. close (); // close the rbd image if (ret <0) {std: cerr <"couldn't close rbd image! Err "<ret <std: endl; ret = EXIT_FAILURE; return EXIT_FAILURE;} else {std: cout <" we just closed an rbd image "<std:: endl;} io_ctx.close (); // close the I/O context rados. shutdown (); // disconnect the cluster and return EXIT_SUCCESS;