]> git.proxmox.com Git - ceph.git/blame - ceph/doc/rados/api/librados.rst
update sources to v12.1.2
[ceph.git] / ceph / doc / rados / api / librados.rst
CommitLineData
7c673cae
FG
1==============
2 Librados (C)
3==============
4
5.. highlight:: c
6
7`librados` provides low-level access to the RADOS service. For an
8overview of RADOS, see :doc:`../../architecture`.
9
10
11Example: connecting and writing an object
12=========================================
13
14To use `Librados`, you instantiate a :c:type:`rados_t` variable (a cluster handle) and
15call :c:func:`rados_create()` with a pointer to it::
16
17 int err;
18 rados_t cluster;
19
20 err = rados_create(&cluster, NULL);
21 if (err < 0) {
22 fprintf(stderr, "%s: cannot create a cluster handle: %s\n", argv[0], strerror(-err));
23 exit(1);
24 }
25
26Then you configure your :c:type:`rados_t` to connect to your cluster,
27either by setting individual values (:c:func:`rados_conf_set()`),
28using a configuration file (:c:func:`rados_conf_read_file()`), using
29command line options (:c:func:`rados_conf_parse_argv`), or an
30environment variable (:c:func:`rados_conf_parse_env()`)::
31
32 err = rados_conf_read_file(cluster, "/path/to/myceph.conf");
33 if (err < 0) {
34 fprintf(stderr, "%s: cannot read config file: %s\n", argv[0], strerror(-err));
35 exit(1);
36 }
37
38Once the cluster handle is configured, you can connect to the cluster with :c:func:`rados_connect()`::
39
40 err = rados_connect(cluster);
41 if (err < 0) {
42 fprintf(stderr, "%s: cannot connect to cluster: %s\n", argv[0], strerror(-err));
43 exit(1);
44 }
45
46Then you open an "IO context", a :c:type:`rados_ioctx_t`, with :c:func:`rados_ioctx_create()`::
47
48 rados_ioctx_t io;
49 char *poolname = "mypool";
50
51 err = rados_ioctx_create(cluster, poolname, &io);
52 if (err < 0) {
53 fprintf(stderr, "%s: cannot open rados pool %s: %s\n", argv[0], poolname, strerror(-err));
54 rados_shutdown(cluster);
55 exit(1);
56 }
57
58Note that the pool you try to access must exist.
59
60Then you can use the RADOS data manipulation functions, for example
61write into an object called ``greeting`` with
62:c:func:`rados_write_full()`::
63
64 err = rados_write_full(io, "greeting", "hello", 5);
65 if (err < 0) {
66 fprintf(stderr, "%s: cannot write pool %s: %s\n", argv[0], poolname, strerror(-err));
67 rados_ioctx_destroy(io);
68 rados_shutdown(cluster);
69 exit(1);
70 }
71
c07f9fc5 72In the end, you will want to close your IO context and connection to RADOS with :c:func:`rados_ioctx_destroy()` and :c:func:`rados_shutdown()`::
7c673cae
FG
73
74 rados_ioctx_destroy(io);
75 rados_shutdown(cluster);
76
77
78Asychronous IO
79==============
80
81When doing lots of IO, you often don't need to wait for one operation
82to complete before starting the next one. `Librados` provides
83asynchronous versions of several operations:
84
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`
89
90For each operation, you must first create a
91:c:type:`rados_completion_t` that represents what to do when the
92operation is safe or complete by calling
93:c:func:`rados_aio_create_completion`. If you don't need anything
94special to happen, you can pass NULL::
95
96 rados_completion_t comp;
97 err = rados_aio_create_completion(NULL, NULL, NULL, &comp);
98 if (err < 0) {
99 fprintf(stderr, "%s: could not create aio completion: %s\n", argv[0], strerror(-err));
100 rados_ioctx_destroy(io);
101 rados_shutdown(cluster);
102 exit(1);
103 }
104
105Now you can call any of the aio operations, and wait for it to
106be in memory or on disk on all replicas::
107
108 err = rados_aio_write(io, "foo", comp, "bar", 3, 0);
109 if (err < 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);
114 exit(1);
115 }
116 rados_aio_wait_for_complete(comp); // in memory
117 rados_aio_wait_for_safe(comp); // on disk
118
119Finally, we need to free the memory used by the completion with :c:func:`rados_aio_release`::
120
121 rados_aio_release(comp);
122
123You can use the callbacks to tell your application when writes are
124durable, or when read buffers are full. For example, if you wanted to
125measure the latency of each operation when appending to several
126objects, you could schedule several writes and store the ack and
127commit time in the corresponding callback, then wait for all of them
128to complete using :c:func:`rados_aio_flush` before analyzing the
129latencies::
130
131 typedef struct {
132 struct timeval start;
133 struct timeval ack_end;
134 struct timeval commit_end;
135 } req_duration;
136
137 void ack_callback(rados_completion_t comp, void *arg) {
138 req_duration *dur = (req_duration *) arg;
139 gettimeofday(&dur->ack_end, NULL);
140 }
141
142 void commit_callback(rados_completion_t comp, void *arg) {
143 req_duration *dur = (req_duration *) arg;
144 gettimeofday(&dur->commit_end, NULL);
145 }
146
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(&times[i].start, NULL);
152 int err = rados_aio_create_completion((void*) &times[i], ack_callback, commit_callback, &comps[i]);
153 if (err < 0) {
154 fprintf(stderr, "Error creating rados completion: %s\n", strerror(-err));
155 return err;
156 }
157 char obj_name[100];
158 snprintf(obj_name, sizeof(obj_name), "foo%ld", (unsigned long)i);
159 err = rados_aio_append(io, obj_name, comps[i], data, len);
160 if (err < 0) {
161 fprintf(stderr, "Error from rados_aio_append: %s", strerror(-err));
162 return err;
163 }
164 }
165 // wait until all requests finish *and* the callbacks complete
166 rados_aio_flush(io);
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(&times[i].ack_end, &times[i].start, &ack_lat);
174 timersub(&times[i].commit_end, &times[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);
176 }
177 return 0;
178 }
179
180Note that all the :c:type:`rados_completion_t` must be freed with :c:func:`rados_aio_release` to avoid leaking memory.
181
182
183API calls
184=========
185
186 .. autodoxygenfile:: rados_types.h
187 .. autodoxygenfile:: librados.h