Run clang-format on the whole tree
[lttng-tools.git] / src / bin / lttng-relayd / sessiond-trace-chunks.cpp
CommitLineData
0c1b0f77 1/*
ab5be9fa 2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
0c1b0f77 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
0c1b0f77 5 *
0c1b0f77
JG
6 */
7
c9e313bc 8#include "sessiond-trace-chunks.hpp"
28ab034a 9
c9e313bc
SM
10#include <common/defaults.hpp>
11#include <common/error.hpp>
28ab034a
JG
12#include <common/hashtable/hashtable.hpp>
13#include <common/hashtable/utils.hpp>
14#include <common/macros.hpp>
c9e313bc 15#include <common/string-utils/format.hpp>
28ab034a
JG
16#include <common/trace-chunk-registry.hpp>
17
0c1b0f77 18#include <inttypes.h>
28ab034a
JG
19#include <stdio.h>
20#include <urcu.h>
21#include <urcu/rculfhash.h>
22#include <urcu/ref.h>
0c1b0f77
JG
23
24/*
25 * Lifetime of trace chunks within the relay daemon.
26 *
27 * Trace chunks are shared accross connections initiated from a given
28 * session daemon. When a session is created by a consumer daemon, the
29 * UUID of its associated session daemon is transmitted (in the case of
30 * 2.11+ consumer daemons).
31 *
32 * The sessiond_trace_chunk_registry_new_session() and
33 * sessiond_trace_chunk_registry_session_closed() methods create and
34 * manage the reference count of lttng_trace_chunk_registry objects
35 * associated to the various sessiond instances served by the relay daemon.
36 *
37 * When all sessions associated with a given sessiond instance are
38 * destroyed, its registry is destroyed.
39 *
40 * lttng_trace_chunk objects are uniquely identified by the
41 * (sessiond_uuid, sessiond_session_id, chunk_id) tuple. If a trace chunk
42 * matching that tuple already exists, a new reference to the trace chunk
43 * is acquired and it is returned to the caller. Otherwise, a new trace
44 * chunk is created. This is how trace chunks are de-duplicated across
45 * multiple consumer daemons managed by the same session daemon.
46 *
47 * Note that trace chunks are always added to their matching
48 * lttng_trace_chunk_registry. They are automatically removed from the
49 * trace chunk registry when their reference count reaches zero.
50 */
51
52/*
53 * It is assumed that the sessiond_trace_chunk_registry is created and
54 * destroyed by the same thread.
55 */
56struct sessiond_trace_chunk_registry {
57 /* Maps an lttng_uuid to an lttng_trace_chunk_registry. */
58 struct cds_lfht *ht;
59};
60
f1494934 61namespace {
0c1b0f77
JG
62struct trace_chunk_registry_ht_key {
63 lttng_uuid sessiond_uuid;
64};
65
66struct trace_chunk_registry_ht_element {
67 struct trace_chunk_registry_ht_key key;
68 struct urcu_ref ref;
69 /* Node into the sessiond_trace_chunk_registry's hash table. */
70 struct cds_lfht_node ht_node;
71 /* Used for defered call_rcu reclaim. */
72 struct rcu_head rcu_node;
73 struct lttng_trace_chunk_registry *trace_chunk_registry;
74 struct sessiond_trace_chunk_registry *sessiond_trace_chunk_registry;
75};
f1494934 76} /* namespace */
0c1b0f77 77
28ab034a 78static unsigned long trace_chunk_registry_ht_key_hash(const struct trace_chunk_registry_ht_key *key)
0c1b0f77 79{
328c2fe7
JG
80 const uint64_t uuid_h1 = *reinterpret_cast<const uint64_t *>(&key->sessiond_uuid[0]);
81 const uint64_t uuid_h2 = *reinterpret_cast<const uint64_t *>(&key->sessiond_uuid[1]);
0c1b0f77 82
28ab034a 83 return hash_key_u64(&uuid_h1, lttng_ht_seed) ^ hash_key_u64(&uuid_h2, lttng_ht_seed);
0c1b0f77
JG
84}
85
86/* cds_lfht match function */
28ab034a 87static int trace_chunk_registry_ht_key_match(struct cds_lfht_node *node, const void *_key)
0c1b0f77 88{
28ab034a 89 const struct trace_chunk_registry_ht_key *key = (struct trace_chunk_registry_ht_key *) _key;
0c1b0f77
JG
90 struct trace_chunk_registry_ht_element *registry;
91
0114db0e 92 registry = lttng::utils::container_of(node, &trace_chunk_registry_ht_element::ht_node);
328c2fe7 93 return key->sessiond_uuid == registry->key.sessiond_uuid;
0c1b0f77
JG
94}
95
28ab034a 96static void trace_chunk_registry_ht_element_free(struct rcu_head *node)
0c1b0f77 97{
28ab034a
JG
98 struct trace_chunk_registry_ht_element *element =
99 lttng::utils::container_of(node, &trace_chunk_registry_ht_element::rcu_node);
0c1b0f77 100
0c1b0f77
JG
101 free(element);
102}
103
28ab034a 104static void trace_chunk_registry_ht_element_release(struct urcu_ref *ref)
0c1b0f77
JG
105{
106 struct trace_chunk_registry_ht_element *element =
28ab034a 107 lttng::utils::container_of(ref, &trace_chunk_registry_ht_element::ref);
c70636a7 108 char uuid_str[LTTNG_UUID_STR_LEN];
0c1b0f77
JG
109
110 lttng_uuid_to_str(element->key.sessiond_uuid, uuid_str);
111
28ab034a 112 DBG("Destroying trace chunk registry associated to sessiond {%s}", uuid_str);
0c1b0f77
JG
113 if (element->sessiond_trace_chunk_registry) {
114 /* Unpublish. */
115 rcu_read_lock();
28ab034a 116 cds_lfht_del(element->sessiond_trace_chunk_registry->ht, &element->ht_node);
0c1b0f77
JG
117 rcu_read_unlock();
118 element->sessiond_trace_chunk_registry = NULL;
119 }
120
c35f9726 121 lttng_trace_chunk_registry_destroy(element->trace_chunk_registry);
0c1b0f77
JG
122 /* Defered reclaim of the object */
123 call_rcu(&element->rcu_node, trace_chunk_registry_ht_element_free);
124}
125
28ab034a 126static bool trace_chunk_registry_ht_element_get(struct trace_chunk_registry_ht_element *element)
0c1b0f77
JG
127{
128 return urcu_ref_get_unless_zero(&element->ref);
129}
130
28ab034a 131static void trace_chunk_registry_ht_element_put(struct trace_chunk_registry_ht_element *element)
0c1b0f77 132{
cd65fb86
FD
133 if (!element) {
134 return;
135 }
136
0c1b0f77
JG
137 urcu_ref_put(&element->ref, trace_chunk_registry_ht_element_release);
138}
139
140/* Acquires a reference to the returned element on behalf of the caller. */
28ab034a
JG
141static struct trace_chunk_registry_ht_element *
142trace_chunk_registry_ht_element_find(struct sessiond_trace_chunk_registry *sessiond_registry,
143 const struct trace_chunk_registry_ht_key *key)
0c1b0f77
JG
144{
145 struct trace_chunk_registry_ht_element *element = NULL;
146 struct cds_lfht_node *node;
147 struct cds_lfht_iter iter;
148
149 rcu_read_lock();
150 cds_lfht_lookup(sessiond_registry->ht,
151 trace_chunk_registry_ht_key_hash(key),
152 trace_chunk_registry_ht_key_match,
153 key,
154 &iter);
155 node = cds_lfht_iter_get_node(&iter);
156 if (node) {
28ab034a
JG
157 element =
158 lttng::utils::container_of(node, &trace_chunk_registry_ht_element::ht_node);
0c1b0f77
JG
159 /*
160 * Only consider the look-up as successful if a reference
161 * could be acquired.
162 */
163 if (!trace_chunk_registry_ht_element_get(element)) {
164 element = NULL;
165 }
166 }
167 rcu_read_unlock();
168 return element;
169}
170
28ab034a
JG
171static int
172trace_chunk_registry_ht_element_create(struct sessiond_trace_chunk_registry *sessiond_registry,
173 const struct trace_chunk_registry_ht_key *key)
0c1b0f77
JG
174{
175 int ret = 0;
176 struct trace_chunk_registry_ht_element *new_element;
177 struct lttng_trace_chunk_registry *trace_chunk_registry;
c70636a7 178 char uuid_str[LTTNG_UUID_STR_LEN];
0c1b0f77
JG
179
180 lttng_uuid_to_str(key->sessiond_uuid, uuid_str);
181
182 trace_chunk_registry = lttng_trace_chunk_registry_create();
183 if (!trace_chunk_registry) {
184 ret = -1;
185 goto end;
186 }
187
64803277 188 new_element = zmalloc<trace_chunk_registry_ht_element>();
0c1b0f77
JG
189 if (!new_element) {
190 ret = -1;
191 goto end;
192 }
193
194 memcpy(&new_element->key, key, sizeof(new_element->key));
195 urcu_ref_init(&new_element->ref);
196 cds_lfht_node_init(&new_element->ht_node);
197 new_element->trace_chunk_registry = trace_chunk_registry;
e441f4e9 198 trace_chunk_registry = NULL;
0c1b0f77
JG
199
200 /* Attempt to publish the new element. */
201 rcu_read_lock();
202 while (1) {
203 struct cds_lfht_node *published_node;
204 struct trace_chunk_registry_ht_element *published_element;
205
28ab034a
JG
206 published_node =
207 cds_lfht_add_unique(sessiond_registry->ht,
208 trace_chunk_registry_ht_key_hash(&new_element->key),
209 trace_chunk_registry_ht_key_match,
210 &new_element->key,
211 &new_element->ht_node);
0c1b0f77
JG
212 if (published_node == &new_element->ht_node) {
213 /* New element published successfully. */
28ab034a
JG
214 DBG("Created trace chunk registry for sessiond {%s}", uuid_str);
215 new_element->sessiond_trace_chunk_registry = sessiond_registry;
0c1b0f77
JG
216 break;
217 }
218
219 /*
220 * An equivalent element was published during the creation of
221 * this element. Attempt to acquire a reference to the one that
222 * was already published and release the reference to the copy
223 * we created if successful.
224 */
28ab034a
JG
225 published_element = lttng::utils::container_of(
226 published_node, &trace_chunk_registry_ht_element::ht_node);
0c1b0f77
JG
227 if (trace_chunk_registry_ht_element_get(published_element)) {
228 DBG("Acquired reference to trace chunk registry of sessiond {%s}",
28ab034a 229 uuid_str);
0c1b0f77
JG
230 trace_chunk_registry_ht_element_put(new_element);
231 new_element = NULL;
232 break;
233 }
234 /*
235 * A reference to the previously published element could not
236 * be acquired. Hence, retry to publish our copy of the
237 * element.
238 */
239 }
240 rcu_read_unlock();
241end:
242 if (ret < 0) {
28ab034a 243 ERR("Failed to create trace chunk registry for session daemon {%s}", uuid_str);
0c1b0f77 244 }
e441f4e9 245 lttng_trace_chunk_registry_destroy(trace_chunk_registry);
0c1b0f77
JG
246 return ret;
247}
248
249struct sessiond_trace_chunk_registry *sessiond_trace_chunk_registry_create(void)
250{
251 struct sessiond_trace_chunk_registry *sessiond_registry =
28ab034a 252 zmalloc<sessiond_trace_chunk_registry>();
0c1b0f77
JG
253
254 if (!sessiond_registry) {
255 goto end;
256 }
257
28ab034a
JG
258 sessiond_registry->ht = cds_lfht_new(
259 DEFAULT_HT_SIZE, 1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
0c1b0f77
JG
260 if (!sessiond_registry->ht) {
261 goto error;
262 }
263
264end:
265 return sessiond_registry;
266error:
267 sessiond_trace_chunk_registry_destroy(sessiond_registry);
268 return NULL;
269}
270
28ab034a 271void sessiond_trace_chunk_registry_destroy(struct sessiond_trace_chunk_registry *sessiond_registry)
0c1b0f77
JG
272{
273 int ret = cds_lfht_destroy(sessiond_registry->ht, NULL);
274
a0377dfe 275 LTTNG_ASSERT(!ret);
0c1b0f77
JG
276 free(sessiond_registry);
277}
278
279int sessiond_trace_chunk_registry_session_created(
28ab034a 280 struct sessiond_trace_chunk_registry *sessiond_registry, const lttng_uuid& sessiond_uuid)
0c1b0f77
JG
281{
282 int ret = 0;
283 struct trace_chunk_registry_ht_key key;
284 struct trace_chunk_registry_ht_element *element;
285
328c2fe7 286 key.sessiond_uuid = sessiond_uuid;
0c1b0f77
JG
287
288 element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
289 if (element) {
c70636a7 290 char uuid_str[LTTNG_UUID_STR_LEN];
0c1b0f77
JG
291
292 lttng_uuid_to_str(sessiond_uuid, uuid_str);
28ab034a 293 DBG("Acquired reference to trace chunk registry of sessiond {%s}", uuid_str);
0c1b0f77
JG
294 goto end;
295 } else {
28ab034a 296 ret = trace_chunk_registry_ht_element_create(sessiond_registry, &key);
0c1b0f77
JG
297 }
298end:
299 return ret;
300}
301
302int sessiond_trace_chunk_registry_session_destroyed(
28ab034a 303 struct sessiond_trace_chunk_registry *sessiond_registry, const lttng_uuid& sessiond_uuid)
0c1b0f77
JG
304{
305 int ret = 0;
306 struct trace_chunk_registry_ht_key key;
307 struct trace_chunk_registry_ht_element *element;
c70636a7 308 char uuid_str[LTTNG_UUID_STR_LEN];
0c1b0f77
JG
309
310 lttng_uuid_to_str(sessiond_uuid, uuid_str);
328c2fe7 311 key.sessiond_uuid = sessiond_uuid;
0c1b0f77
JG
312
313 element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
314 if (element) {
28ab034a 315 DBG("Releasing reference to trace chunk registry of sessiond {%s}", uuid_str);
0c1b0f77
JG
316 /*
317 * Release the reference held by the session and the reference
318 * acquired through the "find" operation.
319 */
320 trace_chunk_registry_ht_element_put(element);
321 trace_chunk_registry_ht_element_put(element);
322 } else {
28ab034a 323 ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
0c1b0f77
JG
324 ret = -1;
325 }
326 return ret;
327}
328
28ab034a
JG
329struct lttng_trace_chunk *
330sessiond_trace_chunk_registry_publish_chunk(struct sessiond_trace_chunk_registry *sessiond_registry,
331 const lttng_uuid& sessiond_uuid,
332 uint64_t session_id,
333 struct lttng_trace_chunk *new_chunk)
0c1b0f77
JG
334{
335 enum lttng_trace_chunk_status status;
336 uint64_t chunk_id;
337 bool is_anonymous_chunk;
338 struct trace_chunk_registry_ht_key key;
339 struct trace_chunk_registry_ht_element *element = NULL;
c70636a7 340 char uuid_str[LTTNG_UUID_STR_LEN];
0c1b0f77
JG
341 char chunk_id_str[MAX_INT_DEC_LEN(typeof(chunk_id))] = "-1";
342 struct lttng_trace_chunk *published_chunk = NULL;
c5c79321 343 bool trace_chunk_already_published;
0c1b0f77
JG
344
345 lttng_uuid_to_str(sessiond_uuid, uuid_str);
328c2fe7 346 key.sessiond_uuid = sessiond_uuid;
0c1b0f77
JG
347
348 status = lttng_trace_chunk_get_id(new_chunk, &chunk_id);
22df7435 349 if (status == LTTNG_TRACE_CHUNK_STATUS_OK) {
0c1b0f77
JG
350 int ret;
351
28ab034a 352 ret = snprintf(chunk_id_str, sizeof(chunk_id_str), "%" PRIu64, chunk_id);
0c1b0f77
JG
353 if (ret < 0) {
354 lttng_strncpy(chunk_id_str, "-1", sizeof(chunk_id_str));
355 WARN("Failed to format trace chunk id");
356 }
357 is_anonymous_chunk = false;
22df7435 358 } else if (status == LTTNG_TRACE_CHUNK_STATUS_NONE) {
0c1b0f77
JG
359 is_anonymous_chunk = true;
360 } else {
361 ERR("Failed to get trace chunk id");
362 goto end;
363 }
364
22df7435 365 DBG("Attempting to publish trace chunk: sessiond {%s}, session_id = "
28ab034a
JG
366 "%" PRIu64 ", chunk_id = %s",
367 uuid_str,
368 session_id,
369 is_anonymous_chunk ? "anonymous" : chunk_id_str);
0c1b0f77 370
22df7435 371 element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
0c1b0f77
JG
372 if (!element) {
373 ERR("Failed to find registry of sessiond {%s}", uuid_str);
374 goto end;
375 }
376
28ab034a
JG
377 published_chunk = lttng_trace_chunk_registry_publish_chunk(element->trace_chunk_registry,
378 session_id,
379 new_chunk,
380 &trace_chunk_already_published);
c35f9726 381 /*
c5c79321
JG
382 * When the trace chunk is first published, two references to the
383 * published chunks exist. One is taken by the registry while the other
384 * is being returned to the caller. In the use case of the relay daemon,
385 * the reference held by the registry itself is undesirable.
c35f9726
JG
386 *
387 * We want the trace chunk to be removed from the registry as soon
388 * as it is not being used by the relay daemon (through a session
389 * or a stream). This differs from the behaviour of the consumer
390 * daemon which relies on an explicit command from the session
391 * daemon to release the registry's reference.
c5c79321
JG
392 *
393 * In cases where the trace chunk had already been published,
394 * the reference belonging to the sessiond trace chunk
395 * registry instance has already been 'put'. We simply return
396 * the published trace chunk with a reference taken on behalf of the
397 * caller.
c35f9726 398 */
c5c79321
JG
399 if (!trace_chunk_already_published) {
400 lttng_trace_chunk_put(published_chunk);
401 }
0c1b0f77
JG
402end:
403 trace_chunk_registry_ht_element_put(element);
404 return published_chunk;
405}
406
28ab034a
JG
407struct lttng_trace_chunk *sessiond_trace_chunk_registry_get_anonymous_chunk(
408 struct sessiond_trace_chunk_registry *sessiond_registry,
409 const lttng_uuid& sessiond_uuid,
410 uint64_t session_id)
0c1b0f77
JG
411{
412 struct lttng_trace_chunk *chunk = NULL;
413 struct trace_chunk_registry_ht_element *element;
414 struct trace_chunk_registry_ht_key key;
c70636a7 415 char uuid_str[LTTNG_UUID_STR_LEN];
0c1b0f77
JG
416
417 lttng_uuid_to_str(sessiond_uuid, uuid_str);
418
328c2fe7 419 key.sessiond_uuid = sessiond_uuid;
0c1b0f77
JG
420 element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
421 if (!element) {
28ab034a 422 ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
0c1b0f77
JG
423 goto end;
424 }
425
28ab034a
JG
426 chunk = lttng_trace_chunk_registry_find_anonymous_chunk(element->trace_chunk_registry,
427 session_id);
0c1b0f77
JG
428 trace_chunk_registry_ht_element_put(element);
429end:
430 return chunk;
431}
432
433struct lttng_trace_chunk *
28ab034a
JG
434sessiond_trace_chunk_registry_get_chunk(struct sessiond_trace_chunk_registry *sessiond_registry,
435 const lttng_uuid& sessiond_uuid,
436 uint64_t session_id,
437 uint64_t chunk_id)
0c1b0f77
JG
438{
439 struct lttng_trace_chunk *chunk = NULL;
440 struct trace_chunk_registry_ht_element *element;
441 struct trace_chunk_registry_ht_key key;
c70636a7 442 char uuid_str[LTTNG_UUID_STR_LEN];
0c1b0f77
JG
443
444 lttng_uuid_to_str(sessiond_uuid, uuid_str);
445
328c2fe7 446 key.sessiond_uuid = sessiond_uuid;
0c1b0f77
JG
447 element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
448 if (!element) {
28ab034a 449 ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
0c1b0f77
JG
450 goto end;
451 }
452
453 chunk = lttng_trace_chunk_registry_find_chunk(
28ab034a 454 element->trace_chunk_registry, session_id, chunk_id);
0c1b0f77
JG
455 trace_chunk_registry_ht_element_put(element);
456end:
457 return chunk;
458}
6b584c2e
JG
459
460int sessiond_trace_chunk_registry_chunk_exists(
28ab034a
JG
461 struct sessiond_trace_chunk_registry *sessiond_registry,
462 const lttng_uuid& sessiond_uuid,
463 uint64_t session_id,
464 uint64_t chunk_id,
465 bool *chunk_exists)
6b584c2e
JG
466{
467 int ret;
468 struct trace_chunk_registry_ht_element *element;
469 struct trace_chunk_registry_ht_key key;
470
328c2fe7 471 key.sessiond_uuid = sessiond_uuid;
6b584c2e
JG
472 element = trace_chunk_registry_ht_element_find(sessiond_registry, &key);
473 if (!element) {
c70636a7 474 char uuid_str[LTTNG_UUID_STR_LEN];
6b584c2e
JG
475
476 lttng_uuid_to_str(sessiond_uuid, uuid_str);
477 /*
478 * While this certainly means that the chunk does not exist,
479 * it is unexpected for a chunk existence query to target a
480 * session daemon that does not have an active
481 * connection/registry. This would indicate a protocol
482 * (or internal) error.
483 */
28ab034a 484 ERR("Failed to find trace chunk registry of sessiond {%s}", uuid_str);
6b584c2e
JG
485 ret = -1;
486 goto end;
487 }
488
489 ret = lttng_trace_chunk_registry_chunk_exists(
28ab034a 490 element->trace_chunk_registry, session_id, chunk_id, chunk_exists);
6b584c2e
JG
491 trace_chunk_registry_ht_element_put(element);
492end:
493 return ret;
494}
This page took 0.065097 seconds and 4 git commands to generate.