7
`Librados` provides low-level access to the RADOS service. For an
8
overview of RADOS, see :doc:`/architecture`.
11
Example: connecting and writing an object
12
=========================================
14
To use `Librados`, you instantiate a :c:type:`rados_t` variable (a cluster handle) and
15
call :c:func:`rados_create()` with a pointer to it::
20
err = rados_create(&cluster, NULL);
22
fprintf(stderr, "%s: cannot create a cluster handle: %s\n", argv[0], strerror(-err));
26
Then you configure your :c:type:`rados_t` to connect to your cluster,
27
either by setting individual values (:c:func:`rados_conf_set()`),
28
using a configuration file (:c:func:`rados_conf_read_file()`), using
29
command line options (:c:func:`rados_conf_parse_argv`), or an
30
environment variable (:c:func:`rados_conf_parse_env()`)::
32
err = rados_conf_read_file(cluster, "/path/to/myceph.conf");
34
fprintf(stderr, "%s: cannot read config file: %s\n", argv[0], strerror(-err));
38
Once the cluster handle is configured, you can connect to the cluster with :c:func:`rados_connect()`::
40
err = rados_connect(cluster);
42
fprintf(stderr, "%s: cannot connect to cluster: %s\n", argv[0], strerror(-err));
46
Then you open an "IO context", a :c:type:`rados_ioctx_t`, with :c:func:`rados_ioctx_create()`::
49
char *poolname = "mypool";
51
err = rados_ioctx_create(cluster, poolname, &io);
53
fprintf(stderr, "%s: cannot open rados pool %s: %s\n", argv[0], poolname, strerror(-err));
54
rados_shutdown(cluster);
58
Note that the pool you try to access must exist.
60
Then you can use the RADOS data manipulation functions, for example
61
write into an object called ``greeting`` with
62
:c:func:`rados_write_full()`::
64
err = rados_write_full(io, "greeting", "hello", 5);
66
fprintf(stderr, "%s: cannot write pool %s: %s\n", argv[0], poolname, strerror(-err));
67
rados_ioctx_destroy(io);
68
rados_shutdown(cluster);
72
In the end, you'll want to close your IO context and connection to RADOS with :c:func:`rados_ioctx_destroy()` and :c:func:`rados_shutdown()`::
74
rados_ioctx_destroy(io);
75
rados_shutdown(cluster);
81
When doing lots of IO, you often don't need to wait for one operation
82
to complete before starting the next one. `Librados` provides
83
asynchronous versions of several operations:
85
* :c:func:`rados_aio_write`
86
* :c:func:`rados_aio_append`
87
* :c:func:`rados_aio_write_full`
88
* :c:func:`rados_aio_read`
90
For each operation, you must first create a
91
:c:type:`rados_completion_t` that represents what to do when the
92
operation is safe or complete by calling
93
:c:func:`rados_aio_create_completion`. If you don't need anything
94
special to happen, you can pass NULL::
96
rados_completion_t comp;
97
err = rados_aio_create_completion(NULL, NULL, NULL, &comp);
99
fprintf(stderr, "%s: could not create aio completion: %s\n", argv[0], strerror(-err));
100
rados_ioctx_destroy(io);
101
rados_shutdown(cluster);
105
Now you can call any of the aio operations, and wait for it to
106
be in memory or on disk on all replicas::
108
err = rados_aio_write(io, "foo", comp, "bar", 3, 0);
110
fprintf(stderr, "%s: could not schedule aio write: %s\n", argv[0], strerror(-err));
111
rados_aio_release(comp);
112
rados_ioctx_destroy(io);
113
rados_shutdown(cluster);
116
rados_wait_for_complete(comp); // in memory
117
rados_wait_for_safe(comp); // on disk
119
Finally, we need to free the memory used by the completion with :c:func:`rados_aio_release`::
121
rados_aio_release(comp);
123
You can use the callbacks to tell your application when writes are
124
durable, or when read buffers are full. For example, if you wanted to
125
measure the latency of each operation when appending to several
126
objects, you could schedule several writes and store the ack and
127
commit time in the corresponding callback, then wait for all of them
128
to complete using :c:func:`rados_aio_flush` before analyzing the
132
struct timeval start;
133
struct timeval ack_end;
134
struct timeval commit_end;
137
void ack_callback(rados_completion_t comp, void *arg) {
138
req_duration *dur = (req_duration *) arg;
139
gettimeofday(&dur->ack_end, NULL);
142
void commit_callback(rados_completion_t comp, void *arg) {
143
req_duration *dur = (req_duration *) arg;
144
gettimeofday(&dur->commit_end, NULL);
147
int output_append_latency(rados_ioctx_t io, const char *data, size_t len, size_t num_writes) {
148
req_duration times[num_writes];
149
rados_completion_t comps[num_writes];
150
for (size_t i = 0; i < num_writes; ++i) {
151
gettimeofday(×[i].start, NULL);
152
int err = rados_aio_create_completion((void*) ×[i], ack_callback, commit_callback, &comps[i]);
154
fprintf(stderr, "Error creating rados completion: %s\n", strerror(-err));
158
snprintf(obj_name, sizeof(obj_name), "foo%ld", (unsigned long)i);
159
err = rados_aio_append(io, obj_name, comps[i], data, len);
161
fprintf(stderr, "Error from rados_aio_append: %s", strerror(-err));
165
// wait until all requests finish *and* the callbacks complete
167
// the latencies can now be analyzed
168
printf("Request # | Ack latency (s) | Commit latency (s)\n");
169
for (size_t i = 0; i < num_writes; ++i) {
170
// don't forget to free the completions
171
rados_aio_release(comps[i]);
172
struct timeval ack_lat, commit_lat;
173
timersub(×[i].ack_end, ×[i].start, &ack_lat);
174
timersub(×[i].commit_end, ×[i].start, &commit_lat);
175
printf("%9ld | %8ld.%06ld | %10ld.%06ld\n", (unsigned long) i, ack_lat.tv_sec, ack_lat.tv_usec, commit_lat.tv_sec, commit_lat.tv_usec);
180
Note that all the :c:type:`rados_completion_t` must be freed with :c:func:`rados_aio_release` to avoid leaking memory.
186
.. doxygenfile:: librados.h