clang-tidy: add a subset of cppcoreguidelines and other style checks
[lttng-tools.git] / src / bin / lttng-sessiond / snapshot.cpp
1 /*
2 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include "snapshot.hpp"
10 #include "utils.hpp"
11
12 #include <common/defaults.hpp>
13
14 #include <inttypes.h>
15 #include <string.h>
16 #include <urcu/uatomic.h>
17
18 /*
19 * Return the atomically incremented value of next_output_id.
20 */
21 static inline unsigned long get_next_output_id(struct snapshot *snapshot)
22 {
23 return uatomic_add_return(&snapshot->next_output_id, 1);
24 }
25
26 /*
27 * Initialized snapshot output with the given values.
28 *
29 * Return 0 on success or else a negative value.
30 */
31 static int output_init(const struct ltt_session *session,
32 uint64_t max_size,
33 const char *name,
34 struct lttng_uri *uris,
35 size_t nb_uri,
36 struct consumer_output *consumer,
37 struct snapshot_output *output,
38 struct snapshot *snapshot)
39 {
40 int ret = 0, i;
41
42 memset(output, 0, sizeof(struct snapshot_output));
43
44 /*
45 * max_size of -1ULL means unset. Set to default (unlimited).
46 */
47 if (max_size == (uint64_t) -1ULL) {
48 max_size = 0;
49 }
50 output->max_size = max_size;
51
52 if (snapshot) {
53 output->id = get_next_output_id(snapshot);
54 }
55 lttng_ht_node_init_ulong(&output->node, (unsigned long) output->id);
56
57 if (name && name[0] != '\0') {
58 if (lttng_strncpy(output->name, name, sizeof(output->name))) {
59 ret = -LTTNG_ERR_INVALID;
60 goto error;
61 }
62 } else {
63 /* Set default name. */
64 ret = snprintf(output->name,
65 sizeof(output->name),
66 "%s-%" PRIu32,
67 DEFAULT_SNAPSHOT_NAME,
68 output->id);
69 if (ret < 0) {
70 ret = -ENOMEM;
71 goto error;
72 }
73 }
74
75 if (!consumer) {
76 goto end;
77 }
78
79 output->consumer = consumer_copy_output(consumer);
80 if (!output->consumer) {
81 ret = -ENOMEM;
82 goto error;
83 }
84 output->consumer->snapshot = 1;
85
86 /* No URL given. */
87 if (nb_uri == 0) {
88 ret = 0;
89 goto end;
90 }
91
92 if (uris[0].dtype == LTTNG_DST_PATH) {
93 memset(output->consumer->dst.session_root_path,
94 0,
95 sizeof(output->consumer->dst.session_root_path));
96 if (lttng_strncpy(output->consumer->dst.session_root_path,
97 uris[0].dst.path,
98 sizeof(output->consumer->dst.session_root_path))) {
99 ret = -LTTNG_ERR_INVALID;
100 goto error;
101 }
102 output->consumer->type = CONSUMER_DST_LOCAL;
103 ret = 0;
104 goto end;
105 }
106
107 if (nb_uri != 2) {
108 /* Absolutely needs two URIs for network. */
109 ret = -LTTNG_ERR_INVALID;
110 goto error;
111 }
112
113 for (i = 0; i < nb_uri; i++) {
114 /* Network URIs */
115 ret = consumer_set_network_uri(session, output->consumer, &uris[i]);
116 if (ret < 0) {
117 goto error;
118 }
119 }
120
121 error:
122 end:
123 return ret;
124 }
125
126 /*
127 * Initialize a snapshot output object using the given parameters and URI(s).
128 * The name value and uris can be NULL.
129 *
130 * Return 0 on success or else a negative value.
131 */
132 int snapshot_output_init_with_uri(const struct ltt_session *session,
133 uint64_t max_size,
134 const char *name,
135 struct lttng_uri *uris,
136 size_t nb_uri,
137 struct consumer_output *consumer,
138 struct snapshot_output *output,
139 struct snapshot *snapshot)
140 {
141 return output_init(session, max_size, name, uris, nb_uri, consumer, output, snapshot);
142 }
143
144 /*
145 * Initialize a snapshot output object using the given parameters. The name
146 * value and url can be NULL.
147 *
148 * Return 0 on success or else a negative value.
149 */
150 int snapshot_output_init(const struct ltt_session *session,
151 uint64_t max_size,
152 const char *name,
153 const char *ctrl_url,
154 const char *data_url,
155 struct consumer_output *consumer,
156 struct snapshot_output *output,
157 struct snapshot *snapshot)
158 {
159 int ret = 0, nb_uri;
160 struct lttng_uri *uris = nullptr;
161
162 /* Create an array of URIs from URLs. */
163 nb_uri = uri_parse_str_urls(ctrl_url, data_url, &uris);
164 if (nb_uri < 0) {
165 ret = nb_uri;
166 goto error;
167 }
168
169 ret = output_init(session, max_size, name, uris, nb_uri, consumer, output, snapshot);
170
171 error:
172 free(uris);
173 return ret;
174 }
175
176 struct snapshot_output *snapshot_output_alloc()
177 {
178 return zmalloc<snapshot_output>();
179 }
180
181 /*
182 * Delete output from the snapshot object.
183 */
184 void snapshot_delete_output(struct snapshot *snapshot, struct snapshot_output *output)
185 {
186 int ret;
187 struct lttng_ht_iter iter;
188
189 LTTNG_ASSERT(snapshot);
190 LTTNG_ASSERT(snapshot->output_ht);
191 LTTNG_ASSERT(output);
192
193 iter.iter.node = &output->node.node;
194 rcu_read_lock();
195 ret = lttng_ht_del(snapshot->output_ht, &iter);
196 rcu_read_unlock();
197 LTTNG_ASSERT(!ret);
198 /*
199 * This is safe because the ownership of a snapshot object is in a session
200 * for which the session lock need to be acquired to read and modify it.
201 */
202 snapshot->nb_output--;
203 }
204
205 /*
206 * Add output object to the snapshot.
207 */
208 void snapshot_add_output(struct snapshot *snapshot, struct snapshot_output *output)
209 {
210 LTTNG_ASSERT(snapshot);
211 LTTNG_ASSERT(snapshot->output_ht);
212 LTTNG_ASSERT(output);
213
214 rcu_read_lock();
215 lttng_ht_add_unique_ulong(snapshot->output_ht, &output->node);
216 rcu_read_unlock();
217 /*
218 * This is safe because the ownership of a snapshot object is in a session
219 * for which the session lock need to be acquired to read and modify it.
220 */
221 snapshot->nb_output++;
222 }
223
224 /*
225 * Destroy and free a snapshot output object.
226 */
227 void snapshot_output_destroy(struct snapshot_output *obj)
228 {
229 LTTNG_ASSERT(obj);
230
231 if (obj->consumer) {
232 consumer_output_send_destroy_relayd(obj->consumer);
233 consumer_output_put(obj->consumer);
234 }
235 free(obj);
236 }
237
238 /*
239 * RCU read side lock MUST be acquired before calling this since the returned
240 * pointer is in a RCU hash table.
241 *
242 * Return the reference on success or else NULL.
243 */
244 struct snapshot_output *snapshot_find_output_by_name(const char *name, struct snapshot *snapshot)
245 {
246 struct lttng_ht_iter iter;
247 struct snapshot_output *output = nullptr;
248
249 LTTNG_ASSERT(snapshot);
250 LTTNG_ASSERT(name);
251 ASSERT_RCU_READ_LOCKED();
252
253 cds_lfht_for_each_entry (snapshot->output_ht->ht, &iter.iter, output, node.node) {
254 if (!strncmp(output->name, name, strlen(name))) {
255 return output;
256 }
257 }
258
259 /* Not found */
260 return nullptr;
261 }
262
263 /*
264 * RCU read side lock MUST be acquired before calling this since the returned
265 * pointer is in a RCU hash table.
266 *
267 * Return the reference on success or else NULL.
268 */
269 struct snapshot_output *snapshot_find_output_by_id(uint32_t id, struct snapshot *snapshot)
270 {
271 struct lttng_ht_node_ulong *node;
272 struct lttng_ht_iter iter;
273 struct snapshot_output *output = nullptr;
274
275 LTTNG_ASSERT(snapshot);
276 ASSERT_RCU_READ_LOCKED();
277
278 lttng_ht_lookup(snapshot->output_ht, (void *) ((unsigned long) id), &iter);
279 node = lttng_ht_iter_get_node_ulong(&iter);
280 if (!node) {
281 DBG3("Snapshot output not found with id %" PRId32, id);
282 goto error;
283 }
284 output = lttng::utils::container_of(node, &snapshot_output::node);
285
286 error:
287 return output;
288 }
289
290 /*
291 * Initialized a snapshot object that was already allocated.
292 *
293 * Return 0 on success or else a negative errno value.
294 */
295 int snapshot_init(struct snapshot *obj)
296 {
297 int ret;
298
299 LTTNG_ASSERT(obj);
300
301 memset(obj, 0, sizeof(struct snapshot));
302
303 obj->output_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
304 if (!obj->output_ht) {
305 ret = -ENOMEM;
306 goto error;
307 }
308
309 ret = 0;
310
311 error:
312 return ret;
313 }
314
315 /*
316 * Destroy snapshot object but the pointer is not freed so it's safe to pass a
317 * static reference.
318 */
319 void snapshot_destroy(struct snapshot *obj)
320 {
321 struct lttng_ht_iter iter;
322 struct snapshot_output *output;
323
324 if (!obj->output_ht) {
325 return;
326 }
327
328 rcu_read_lock();
329 cds_lfht_for_each_entry (obj->output_ht->ht, &iter.iter, output, node.node) {
330 snapshot_delete_output(obj, output);
331 snapshot_output_destroy(output);
332 }
333 rcu_read_unlock();
334 lttng_ht_destroy(obj->output_ht);
335 }
This page took 0.04455 seconds and 4 git commands to generate.