]> git.proxmox.com Git - ceph.git/blob - ceph/doc/rados/api/librados.rst
update sources to v12.1.2
[ceph.git] / ceph / doc / rados / api / librados.rst
1 ==============
2 Librados (C)
3 ==============
4
5 .. highlight:: c
6
7 `librados` provides low-level access to the RADOS service. For an
8 overview of RADOS, see :doc:`../../architecture`.
9
10
11 Example: connecting and writing an object
12 =========================================
13
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::
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
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()`)::
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
38 Once 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
46 Then 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
58 Note that the pool you try to access must exist.
59
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()`::
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
72 In 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()`::
73
74 rados_ioctx_destroy(io);
75 rados_shutdown(cluster);
76
77
78 Asychronous IO
79 ==============
80
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:
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
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::
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
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::
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
119 Finally, we need to free the memory used by the completion with :c:func:`rados_aio_release`::
120
121 rados_aio_release(comp);
122
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
129 latencies::
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
180 Note that all the :c:type:`rados_completion_t` must be freed with :c:func:`rados_aio_release` to avoid leaking memory.
181
182
183 API calls
184 =========
185
186 .. autodoxygenfile:: rados_types.h
187 .. autodoxygenfile:: librados.h