2 * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <lttng/trigger/trigger.h>
20 #include <common/error.h>
21 #include <common/config/session-config.h>
22 #include <common/defaults.h>
23 #include <common/utils.h>
24 #include <common/futex.h>
25 #include <common/align.h>
26 #include <common/time.h>
27 #include <common/hashtable/utils.h>
28 #include <common/kernel-ctl/kernel-ctl.h>
29 #include <sys/eventfd.h>
35 #include <lttng/notification/channel-internal.h>
36 #include <lttng/rotate-internal.h>
40 #include "rotation-thread.h"
41 #include "lttng-sessiond.h"
42 #include "health-sessiond.h"
45 #include "notification-thread-commands.h"
48 #include <urcu/list.h>
49 #include <urcu/rculfhash.h>
51 unsigned long hash_channel_key(struct rotation_channel_key
*key
)
53 return hash_key_u64(&key
->key
, lttng_ht_seed
) ^ hash_key_ulong(
54 (void *) (unsigned long) key
->domain
, lttng_ht_seed
);
57 int rotate_add_channel_pending(uint64_t key
, enum lttng_domain_type domain
,
58 struct ltt_session
*session
)
61 struct rotation_channel_info
*new_info
;
62 struct rotation_channel_key channel_key
= { .key
= key
,
65 new_info
= zmalloc(sizeof(struct rotation_channel_info
));
70 new_info
->channel_key
.key
= key
;
71 new_info
->channel_key
.domain
= domain
;
72 new_info
->session_id
= session
->id
;
73 cds_lfht_node_init(&new_info
->rotate_channels_ht_node
);
75 session
->nr_chan_rotate_pending
++;
76 cds_lfht_add(channel_pending_rotate_ht
,
77 hash_channel_key(&channel_key
),
78 &new_info
->rotate_channels_ht_node
);
89 /* The session's lock must be held by the caller. */
91 int session_rename_chunk(struct ltt_session
*session
, char *current_path
,
95 struct consumer_socket
*socket
;
96 struct consumer_output
*output
;
97 struct lttng_ht_iter iter
;
101 DBG("Renaming session chunk path of session \"%s\" from %s to %s",
102 session
->name
, current_path
, new_path
);
105 * Either one of the sessions is enough to find the consumer_output
108 if (session
->kernel_session
) {
109 output
= session
->kernel_session
->consumer
;
110 uid
= session
->kernel_session
->uid
;
111 gid
= session
->kernel_session
->gid
;
112 } else if (session
->ust_session
) {
113 output
= session
->ust_session
->consumer
;
114 uid
= session
->ust_session
->uid
;
115 gid
= session
->ust_session
->gid
;
120 if (!output
|| !output
->socks
) {
121 ERR("No consumer output found for session \"%s\"",
129 * We have to iterate to find a socket, but we only need to send the
130 * rename command to one consumer, so we break after the first one.
132 cds_lfht_for_each_entry(output
->socks
->ht
, &iter
.iter
, socket
, node
.node
) {
133 pthread_mutex_lock(socket
->lock
);
134 ret
= consumer_rotate_rename(socket
, session
->id
, output
,
135 current_path
, new_path
, uid
, gid
);
136 pthread_mutex_unlock(socket
->lock
);
152 /* The session's lock must be held by the caller. */
154 int rename_first_chunk(struct ltt_session
*session
,
155 struct consumer_output
*consumer
, char *new_path
)
158 char current_full_path
[LTTNG_PATH_MAX
], new_full_path
[LTTNG_PATH_MAX
];
160 /* Current domain path: <session>/kernel */
161 if (session
->net_handle
> 0) {
162 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
163 consumer
->dst
.net
.base_dir
, consumer
->subdir
);
164 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
165 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
171 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
172 consumer
->dst
.session_root_path
, consumer
->subdir
);
173 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
174 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
180 /* New domain path: <session>/<start-date>-<end-date>-<rotate-count>/kernel */
181 ret
= snprintf(new_full_path
, sizeof(new_full_path
), "%s/%s",
182 new_path
, consumer
->subdir
);
183 if (ret
< 0 || ret
>= sizeof(new_full_path
)) {
184 ERR("Failed to initialize new full path while renaming first rotation chunk of session \"%s\"",
190 * Move the per-domain fcurrenter inside the first rotation
193 ret
= session_rename_chunk(session
, current_full_path
, new_full_path
);
195 ret
= -LTTNG_ERR_UNK
;
206 * Rename a chunk folder after a rotation is complete.
207 * session_lock_list and session lock must be held.
209 * Returns 0 on success, a negative value on error.
211 int rename_complete_chunk(struct ltt_session
*session
, time_t ts
)
214 char new_path
[LTTNG_PATH_MAX
];
215 char datetime
[21], start_datetime
[21];
219 DBG("Renaming completed chunk for session %s", session
->name
);
220 timeinfo
= localtime(&ts
);
222 ERR("Failed to retrieve local time while renaming completed chunk");
227 strf_ret
= strftime(datetime
, sizeof(datetime
), "%Y%m%dT%H%M%S%z",
230 ERR("Failed to format timestamp while renaming completed session chunk");
235 if (session
->current_archive_id
== 1) {
238 timeinfo
= localtime(&session
->last_chunk_start_ts
);
240 ERR("Failed to retrieve local time while renaming completed chunk");
245 strf_ret
= strftime(start_time
, sizeof(start_time
),
246 "%Y%m%dT%H%M%S%z", timeinfo
);
248 ERR("Failed to format timestamp while renaming completed session chunk");
254 * On the first rotation, the current_rotate_path is the
255 * session_root_path, so we need to create the chunk folder
256 * and move the domain-specific folders inside it.
258 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
259 session
->rotation_chunk
.current_rotate_path
,
261 datetime
, session
->current_archive_id
);
262 if (ret
< 0 || ret
>= sizeof(new_path
)) {
263 ERR("Failed to format new chunk path while renaming session \"%s\"'s first chunk",
269 if (session
->kernel_session
) {
270 ret
= rename_first_chunk(session
,
271 session
->kernel_session
->consumer
,
274 ERR("Failed to rename kernel session trace folder to %s", new_path
);
276 * This is not a fatal error for the rotation
277 * thread, we just need to inform the client
278 * that a problem occurred with the rotation.
279 * Returning 0, same for the other errors
286 if (session
->ust_session
) {
287 ret
= rename_first_chunk(session
,
288 session
->ust_session
->consumer
,
291 ERR("Failed to rename userspace session trace folder to %s", new_path
);
298 * After the first rotation, all the trace data is already in
299 * its own chunk folder, we just need to append the suffix.
301 /* Recreate the session->rotation_chunk.current_rotate_path */
302 timeinfo
= localtime(&session
->last_chunk_start_ts
);
304 ERR("Failed to retrieve local time while renaming completed chunk");
308 strf_ret
= strftime(start_datetime
, sizeof(start_datetime
),
309 "%Y%m%dT%H%M%S%z", timeinfo
);
311 ERR("Failed to format timestamp while renaming completed session chunk");
315 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
316 session_get_base_path(session
),
318 datetime
, session
->current_archive_id
);
319 if (ret
< 0 || ret
>= sizeof(new_path
)) {
320 ERR("Failed to format new chunk path while renaming chunk of session \"%s\"",
325 ret
= session_rename_chunk(session
,
326 session
->rotation_chunk
.current_rotate_path
,
329 ERR("Failed to rename session trace folder from %s to %s",
330 session
->rotation_chunk
.current_rotate_path
,
338 * Store the path where the readable chunk is. This path is valid
339 * and can be queried by the client with rotate_pending until the next
340 * rotation is started.
342 ret
= lttng_strncpy(session
->rotation_chunk
.current_rotate_path
,
344 sizeof(session
->rotation_chunk
.current_rotate_path
));
346 ERR("Failed the current chunk's path of session \"%s\"",
355 session
->rotation_state
= LTTNG_ROTATION_STATE_ERROR
;
360 int relay_rotate_pending(struct ltt_session
*session
, uint64_t chunk_id
)
363 struct consumer_socket
*socket
;
364 struct consumer_output
*output
;
365 struct lttng_ht_iter iter
;
368 * Either one of the sessions is enough to find the consumer_output
371 if (session
->kernel_session
) {
372 output
= session
->kernel_session
->consumer
;
373 } else if (session
->ust_session
) {
374 output
= session
->ust_session
->consumer
;
379 if (!output
|| !output
->socks
) {
380 ERR("No consumer output found");
389 * We have to iterate to find a socket, but we only need to send the
390 * rotate pending command to one consumer, so we break after the first
393 cds_lfht_for_each_entry(output
->socks
->ht
, &iter
.iter
, socket
,
395 pthread_mutex_lock(socket
->lock
);
396 ret
= consumer_rotate_pending_relay(socket
, output
, session
->id
,
398 pthread_mutex_unlock(socket
->lock
);
407 int subscribe_session_consumed_size_rotation(struct ltt_session
*session
, uint64_t size
,
408 struct notification_thread_handle
*notification_thread_handle
)
411 enum lttng_condition_status condition_status
;
412 enum lttng_notification_channel_status nc_status
;
413 struct lttng_action
*action
;
415 session
->rotate_condition
= lttng_condition_session_consumed_size_create();
416 if (!session
->rotate_condition
) {
417 ERR("Failed to create session consumed size condition object");
422 condition_status
= lttng_condition_session_consumed_size_set_threshold(
423 session
->rotate_condition
, size
);
424 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
425 ERR("Could not set session consumed size condition threshold (size = %" PRIu64
")",
432 lttng_condition_session_consumed_size_set_session_name(
433 session
->rotate_condition
, session
->name
);
434 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
435 ERR("Could not set session consumed size condition session name (name = %s)",
441 action
= lttng_action_notify_create();
443 ERR("Could not create notify action");
448 session
->rotate_trigger
= lttng_trigger_create(session
->rotate_condition
,
450 if (!session
->rotate_trigger
) {
451 ERR("Could not create size-based rotation trigger");
456 nc_status
= lttng_notification_channel_subscribe(
457 rotate_notification_channel
, session
->rotate_condition
);
458 if (nc_status
!= LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
) {
459 ERR("Could not subscribe to session consumed size notification");
464 ret
= notification_thread_command_register_trigger(
465 notification_thread_handle
, session
->rotate_trigger
);
466 if (ret
< 0 && ret
!= -LTTNG_ERR_TRIGGER_EXISTS
) {
467 ERR("Register trigger, %s", lttng_strerror(ret
));
478 int unsubscribe_session_consumed_size_rotation(struct ltt_session
*session
,
479 struct notification_thread_handle
*notification_thread_handle
)
482 enum lttng_notification_channel_status status
;
484 status
= lttng_notification_channel_unsubscribe(
485 rotate_notification_channel
,
486 session
->rotate_condition
);
487 if (status
!= LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
) {
488 ERR("Session unsubscribe error: %d", (int) status
);
493 ret
= notification_thread_command_unregister_trigger(
494 notification_thread_handle
, session
->rotate_trigger
);
495 if (ret
!= LTTNG_OK
) {
496 ERR("Session unregister trigger error: %d", ret
);