Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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