mirror of
https://github.com/ceph/ceph
synced 2024-12-18 01:16:55 +00:00
doc: Modified doc examples to use rados_create2.
Signed-off-by: John Wilkins <john.wilkins@inktank.com>
This commit is contained in:
parent
7d5674cf78
commit
54e588c84b
@ -6,10 +6,8 @@ The :term:`Ceph Storage Cluster` provides the basic storage service that allows
|
||||
:term:`Ceph` to uniquely deliver **object, block, and file storage** in one
|
||||
unified system. However, you are not limited to using the RESTful, block, or
|
||||
POSIX interfaces. Based upon :abbr:`RADOS (Reliable Autonomic Distributed Object
|
||||
Store)`, the ``librados`` API, enables you to create your own interface to the
|
||||
Ceph Storage Cluster. In fact, :term:`Ceph Object Storage`, :term:`Ceph Block
|
||||
Device` and :term:`Ceph Filesystem` all use ``librados``, or the same general
|
||||
functionality of ``librados`` to access the Ceph Storage Cluster.
|
||||
Store)`, the ``librados`` API enables you to create your own interface to the
|
||||
Ceph Storage Cluster.
|
||||
|
||||
The ``librados`` API enables you to interact with the two types of daemons in
|
||||
the Ceph Storage Cluster:
|
||||
@ -40,8 +38,8 @@ and Java. Your client app needs to import ``librados``, which means it must be
|
||||
installed on your client host first.
|
||||
|
||||
|
||||
Getting ``librados`` for C/C++ and Python
|
||||
-----------------------------------------
|
||||
Getting librados for C/C++ and Python
|
||||
-------------------------------------
|
||||
|
||||
To install ``librados`` for C/C++ and Python, execute the following for
|
||||
Debian/Ubuntu distributions::
|
||||
@ -62,8 +60,8 @@ For Python, you can find the required library under ``/usr/share/pyshared``. ::
|
||||
ls /usr/share/pyshared
|
||||
|
||||
|
||||
Getting ``librados`` for Java
|
||||
-----------------------------
|
||||
Getting librados for Java
|
||||
-------------------------
|
||||
|
||||
To install ``librados`` for Java, you need to execute the following procedure:
|
||||
|
||||
@ -204,12 +202,17 @@ it and connecting to the cluster might look something like this:
|
||||
|
||||
main (const char argv**)
|
||||
{
|
||||
/* Declare the cluster handle. */
|
||||
|
||||
/* Declare the cluster handle and required arguments. */
|
||||
rados_t cluster;
|
||||
char cluster_name[] = "ceph";
|
||||
char user_name[] = "client.admin";
|
||||
uint64_t flags;
|
||||
|
||||
/* Initialize the cluster handle with the "ceph" cluster name and the "client.admin" user */
|
||||
int err;
|
||||
|
||||
/* Initialize the cluster handle with the "admin" user */
|
||||
err = rados_create(&cluster, "admin");
|
||||
err = rados_create2(&cluster, cluster_name, user_name, flags);
|
||||
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "%s: Couldn't create the cluster handle! %s\n", argv[0], strerror(-err));
|
||||
exit(EXIT_FAILURE);
|
||||
@ -217,6 +220,7 @@ it and connecting to the cluster might look something like this:
|
||||
printf("\nCreated a cluster handle.\n");
|
||||
}
|
||||
|
||||
|
||||
/* Read a Ceph configuration file to configure the cluster handle. */
|
||||
err = rados_conf_read_file(cluster, "/etc/ceph/ceph.conf");
|
||||
if (err < 0) {
|
||||
@ -266,14 +270,18 @@ initialize a ``Rados`` cluster handle object:
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
|
||||
/* Declare the cluster handle. */
|
||||
/* Declare the cluster handle and required variables. */
|
||||
librados::Rados cluster;
|
||||
|
||||
/* Initialize the cluster handle with the "admin" user */
|
||||
char cluster_name[] = "ceph";
|
||||
char user_name[] = "client.admin";
|
||||
uint64_t flags;
|
||||
|
||||
/* Initialize the cluster handle with the "ceph" cluster name and "client.admin" user */
|
||||
{
|
||||
ret = cluster.init("admin");
|
||||
ret = cluster.init2(user_name, cluster_name, flags);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Couldn't initialize the cluster handle! error " << ret << std::endl;
|
||||
ret = EXIT_FAILURE;
|
||||
@ -336,7 +344,7 @@ Python Example
|
||||
--------------
|
||||
|
||||
Python uses the ``admin`` user and the ``ceph`` cluster name by default. The
|
||||
wrapper converts C-based errors into exceptions.
|
||||
Python binding converts C-based errors into exceptions.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@ -344,7 +352,7 @@ wrapper converts C-based errors into exceptions.
|
||||
import rados
|
||||
|
||||
try:
|
||||
cluster = rados.Rados()
|
||||
cluster = rados.Rados(None, "client.admin", "ceph")
|
||||
print "Created cluster handle."
|
||||
|
||||
cluster.conf_read_file("/etc/ceph/ceph.conf")
|
||||
@ -358,11 +366,16 @@ wrapper converts C-based errors into exceptions.
|
||||
print "Connected to the cluster."
|
||||
|
||||
|
||||
Execute the example to verify that it connects to your cluster. ::
|
||||
|
||||
python ceph-client.py
|
||||
|
||||
|
||||
Java Example
|
||||
------------
|
||||
|
||||
Java requires you to specify the user ID, and uses the ``ceph`` cluster name by
|
||||
default . The wrapper converts C-based errors into exceptions.
|
||||
default . The Java binding converts C-based errors into exceptions.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
@ -375,8 +388,8 @@ default . The wrapper converts C-based errors into exceptions.
|
||||
public static void main (String args[]){
|
||||
|
||||
try {
|
||||
Rados cluster = new Rados("admin");
|
||||
System.out.println("Created a handle.");
|
||||
cluster = rados.Rados(None, "client.admin", "ceph")
|
||||
print "Created cluster handle."
|
||||
|
||||
File f = new File("/etc/ceph/ceph.conf");
|
||||
cluster.confReadFile(f);
|
||||
@ -392,6 +405,13 @@ default . The wrapper converts C-based errors into exceptions.
|
||||
}
|
||||
|
||||
|
||||
Compile the source; then, run it. If you have copied the JAR to
|
||||
``/usr/share/java`` and sym linked from your ``ext`` directory, you won't need
|
||||
to specify the classpath. For example::
|
||||
|
||||
javac CephClient.java
|
||||
java CephClient
|
||||
|
||||
|
||||
Step 3: Creating an I/O Context
|
||||
===============================
|
||||
@ -400,7 +420,8 @@ Once your app has a cluster handle and a connection to a Ceph Storage Cluster,
|
||||
you may create an I/O Context and begin reading and writing data. An I/O Context
|
||||
binds the connection to a specific pool. The user ID must have appropriate
|
||||
`CAPS`_ permissions to access the specified pool. For example, a user with read
|
||||
access but not write access will only be able to read data.
|
||||
access but not write access will only be able to read data. I/O Context
|
||||
functionality includes:
|
||||
|
||||
- Write/read data and extended attributes
|
||||
- List and iterate over objects and extended attributes
|
||||
@ -432,18 +453,27 @@ access but not write access will only be able to read data.
|
||||
| | |
|
||||
| read ack | |
|
||||
|<--------------+---------------|
|
||||
| | |
|
||||
| remove data | |
|
||||
|---------------+-------------->|
|
||||
| | |
|
||||
| remove ack | |
|
||||
|<--------------+---------------|
|
||||
|
||||
|
||||
|
||||
RADOS enables you to interact both synchronously and asynchronously. Once your
|
||||
app has an I/O Context, read/write operations only require you to know the
|
||||
object/xattr name. The CRUSH algorithm encapsulated in ``librados`` uses the
|
||||
cluster map to identify the appropriate OSD. The OSDs handle the replication,
|
||||
cluster map to identify the appropriate OSD. OSD daemons handle the replication,
|
||||
as described in `Smart Daemons Enable Hyperscale`_. The mapping of objects to
|
||||
placement groups is also performed by the library as described in
|
||||
`Calculating PG IDs`_.
|
||||
placement groups is also performed by the library as described in `Calculating
|
||||
PG IDs`_.
|
||||
|
||||
The following examples use the default ``data`` pool. However, you may also
|
||||
use the API to list pools, ensure they exist, or create and delete pools.
|
||||
use the API to list pools, ensure they exist, or create and delete pools. For
|
||||
the write operations, the examples illustrate how to use synchronous mode. For
|
||||
the read operations, the examples illustrate how to use asynchronous mode.
|
||||
|
||||
.. important:: Use caution when deleting pools with this API. If you delete
|
||||
a pool, the pool and ALL DATA in the pool will be lost.
|
||||
@ -462,7 +492,8 @@ C Example
|
||||
main (const char argv**)
|
||||
{
|
||||
/* Continued from previous C example, where cluster handle and
|
||||
connection are established. First declare an I/O Context. */
|
||||
* connection are established. First declare an I/O Context.
|
||||
*/
|
||||
|
||||
rados_ioctx_t io;
|
||||
char *poolname = "data";
|
||||
@ -475,7 +506,8 @@ C Example
|
||||
} else {
|
||||
printf("\nCreated I/O context.\n");
|
||||
}
|
||||
|
||||
|
||||
/* Write data to the cluster synchronously. */
|
||||
err = rados_write_full(io, "hw", "Hello World!", 12);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "%s: Cannot write object. %s %s\n", argv[0], poolname, strerror(-err));
|
||||
@ -497,9 +529,24 @@ C Example
|
||||
printf("\nWrote \"en_US\" to xattr \"lang\" for object \"hw\".\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read data from the cluster asynchronously.
|
||||
* First, set up asynchronous I/O completion. *
|
||||
*/
|
||||
rados_completion_t comp;
|
||||
err = rados_aio_create_completion(NULL, NULL, NULL, &comp);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "%s: Could not create aio completion: %s\n", argv[0], strerror(-err));
|
||||
rados_ioctx_destroy(io);
|
||||
rados_shutdown(cluster);
|
||||
exit(1);
|
||||
} else {
|
||||
printf("\nCreated AIO completion.\n");
|
||||
}
|
||||
|
||||
/* Next, read data using rados_aio_read. */
|
||||
char read_res[100];
|
||||
err = rados_read(io, "hw", read_res, 12, 0);
|
||||
err = rados_aio_read(io, "hw", comp, read_res, 12, 0);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "%s: Cannot read object. %s %s\n", argv[0], poolname, strerror(-err));
|
||||
rados_ioctx_destroy(io);
|
||||
@ -508,6 +555,13 @@ C Example
|
||||
} else {
|
||||
printf("\nRead object \"hw\". The contents are:\n %s \n", read_res);
|
||||
}
|
||||
|
||||
/* Wait for the operation to complete */
|
||||
rados_wait_for_complete(comp);
|
||||
|
||||
/* Release the asynchronous I/O complete handle to avoid memory leaks. */
|
||||
rados_aio_release(comp);
|
||||
|
||||
|
||||
char xattr_res[100];
|
||||
err = rados_getxattr(io, "hw", "lang", xattr_res, 5);
|
||||
@ -544,12 +598,153 @@ C Example
|
||||
|
||||
|
||||
|
||||
C++ Example
|
||||
-----------
|
||||
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <rados/librados.hpp>
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
|
||||
/* Continued from previous C++ example, where cluster handle and
|
||||
* connection are established. First declare an I/O Context.
|
||||
*/
|
||||
|
||||
librados::IoCtx io_ctx;
|
||||
const char *pool_name = "data";
|
||||
|
||||
{
|
||||
ret = cluster.ioctx_create(pool_name, io_ctx);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Couldn't set up ioctx! error " << ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
std::cout << "Created an ioctx for the pool." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Write an object synchronously. */
|
||||
{
|
||||
librados::bufferlist bl;
|
||||
bl.append("Hello World!");
|
||||
ret = io_ctx.write_full("hw", bl);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Couldn't write object! error " << ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
std::cout << "Wrote new object 'hw' " << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an xattr to the object.
|
||||
*/
|
||||
{
|
||||
librados::bufferlist lang_bl;
|
||||
lang_bl.append("en_US");
|
||||
ret = io_ctx.setxattr("hw", "lang", lang_bl);
|
||||
if (ret < 0) {
|
||||
std::cerr << "failed to set xattr version entry! error "
|
||||
<< ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
std::cout << "Set the xattr 'lang' on our object!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the object back asynchronously.
|
||||
*/
|
||||
{
|
||||
librados::bufferlist read_buf;
|
||||
int read_len = 4194304;
|
||||
|
||||
//Create I/O Completion.
|
||||
librados::AioCompletion *read_completion = librados::Rados::aio_create_completion();
|
||||
|
||||
//Send read request.
|
||||
ret = io_ctx.aio_read("hw", read_completion, &read_buf, read_len, 0);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Couldn't start read object! error " << ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Wait for the request to complete, and check that it succeeded.
|
||||
read_completion->wait_for_complete();
|
||||
ret = read_completion->get_return_value();
|
||||
if (ret < 0) {
|
||||
std::cerr << "Couldn't read object! error " << ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
std::cout << "Read object hw asynchronously with contents.\n"
|
||||
<< read_buf.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the xattr.
|
||||
*/
|
||||
{
|
||||
librados::bufferlist lang_res;
|
||||
ret = io_ctx.getxattr("hw", "lang", lang_res);
|
||||
if (ret < 0) {
|
||||
std::cerr << "failed to get xattr version entry! error "
|
||||
<< ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
std::cout << "Got the xattr 'lang' from object hw!"
|
||||
<< lang_res.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove the xattr.
|
||||
*/
|
||||
{
|
||||
ret = io_ctx.rmxattr("hw", "lang");
|
||||
if (ret < 0) {
|
||||
std::cerr << "Failed to remove xattr! error "
|
||||
<< ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
std::cout << "Removed the xattr 'lang' from our object!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the object.
|
||||
*/
|
||||
{
|
||||
ret = io_ctx.remove("hw");
|
||||
if (ret < 0) {
|
||||
std::cerr << "Couldn't remove object! error " << ret << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
std::cout << "Removed object 'hw'." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Step 4: Closing Sessions
|
||||
========================
|
||||
|
||||
Once you are finished with your I/O Context and cluster handle, you should
|
||||
close the connection and shutdown the handle. For asynchronous I/O, you should
|
||||
also ensure that your pending operations have completed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user