2 * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
3 * Copyright (C) 2018 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <lttng/trigger/trigger.h>
21 #include <common/error.h>
22 #include <common/config/session-config.h>
23 #include <common/defaults.h>
24 #include <common/utils.h>
25 #include <common/futex.h>
26 #include <common/align.h>
27 #include <common/time.h>
28 #include <common/hashtable/utils.h>
29 #include <common/kernel-ctl/kernel-ctl.h>
30 #include <sys/eventfd.h>
36 #include <lttng/notification/channel-internal.h>
37 #include <lttng/rotate-internal.h>
41 #include "rotation-thread.h"
42 #include "lttng-sessiond.h"
43 #include "health-sessiond.h"
46 #include "notification-thread-commands.h"
49 #include <urcu/list.h>
50 #include <urcu/rculfhash.h>
52 /* The session's lock must be held by the caller. */
54 int session_rename_chunk(struct ltt_session
*session
, char *current_path
,
58 struct consumer_socket
*socket
;
59 struct consumer_output
*output
;
60 struct lttng_ht_iter iter
;
64 DBG("Renaming session chunk path of session \"%s\" from %s to %s",
65 session
->name
, current_path
, new_path
);
68 * Either one of the sessions is enough to find the consumer_output
71 if (session
->kernel_session
) {
72 output
= session
->kernel_session
->consumer
;
73 uid
= session
->kernel_session
->uid
;
74 gid
= session
->kernel_session
->gid
;
75 } else if (session
->ust_session
) {
76 output
= session
->ust_session
->consumer
;
77 uid
= session
->ust_session
->uid
;
78 gid
= session
->ust_session
->gid
;
83 if (!output
|| !output
->socks
) {
84 ERR("No consumer output found for session \"%s\"",
92 * We have to iterate to find a socket, but we only need to send the
93 * rename command to one consumer, so we break after the first one.
95 cds_lfht_for_each_entry(output
->socks
->ht
, &iter
.iter
, socket
, node
.node
) {
96 pthread_mutex_lock(socket
->lock
);
97 ret
= consumer_rotate_rename(socket
, session
->id
, output
,
98 current_path
, new_path
, uid
, gid
);
99 pthread_mutex_unlock(socket
->lock
);
115 /* The session's lock must be held by the caller. */
117 int rename_first_chunk(struct ltt_session
*session
,
118 struct consumer_output
*consumer
, char *new_path
)
121 char current_full_path
[LTTNG_PATH_MAX
], new_full_path
[LTTNG_PATH_MAX
];
123 /* Current domain path: <session>/kernel */
124 if (session
->net_handle
> 0) {
125 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
126 consumer
->dst
.net
.base_dir
, consumer
->subdir
);
127 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
128 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
134 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
135 consumer
->dst
.session_root_path
, consumer
->subdir
);
136 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
137 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
143 /* New domain path: <session>/<start-date>-<end-date>-<rotate-count>/kernel */
144 ret
= snprintf(new_full_path
, sizeof(new_full_path
), "%s/%s",
145 new_path
, consumer
->subdir
);
146 if (ret
< 0 || ret
>= sizeof(new_full_path
)) {
147 ERR("Failed to initialize new full path while renaming first rotation chunk of session \"%s\"",
153 * Move the per-domain fcurrenter inside the first rotation
156 ret
= session_rename_chunk(session
, current_full_path
, new_full_path
);
158 ret
= -LTTNG_ERR_UNK
;
169 * Rename a chunk folder after a rotation is complete.
170 * session_lock_list and session lock must be held.
172 * Returns 0 on success, a negative value on error.
174 int rename_completed_chunk(struct ltt_session
*session
, time_t ts
)
177 char new_path
[LTTNG_PATH_MAX
];
178 char datetime
[21], start_datetime
[21];
182 DBG("Renaming completed chunk for session %s", session
->name
);
183 timeinfo
= localtime(&ts
);
185 ERR("Failed to retrieve local time while renaming completed chunk");
190 strf_ret
= strftime(datetime
, sizeof(datetime
), "%Y%m%dT%H%M%S%z",
193 ERR("Failed to format timestamp while renaming completed session chunk");
198 if (session
->current_archive_id
== 1) {
201 timeinfo
= localtime(&session
->last_chunk_start_ts
);
203 ERR("Failed to retrieve local time while renaming completed chunk");
208 strf_ret
= strftime(start_time
, sizeof(start_time
),
209 "%Y%m%dT%H%M%S%z", timeinfo
);
211 ERR("Failed to format timestamp while renaming completed session chunk");
217 * On the first rotation, the current_rotate_path is the
218 * session_root_path, so we need to create the chunk folder
219 * and move the domain-specific folders inside it.
221 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
222 session
->rotation_chunk
.current_rotate_path
,
224 datetime
, session
->current_archive_id
);
225 if (ret
< 0 || ret
>= sizeof(new_path
)) {
226 ERR("Failed to format new chunk path while renaming session \"%s\"'s first chunk",
232 if (session
->kernel_session
) {
233 ret
= rename_first_chunk(session
,
234 session
->kernel_session
->consumer
,
237 ERR("Failed to rename kernel session trace folder to %s", new_path
);
239 * This is not a fatal error for the rotation
240 * thread, we just need to inform the client
241 * that a problem occurred with the rotation.
242 * Returning 0, same for the other errors
249 if (session
->ust_session
) {
250 ret
= rename_first_chunk(session
,
251 session
->ust_session
->consumer
,
254 ERR("Failed to rename userspace session trace folder to %s", new_path
);
261 * After the first rotation, all the trace data is already in
262 * its own chunk folder, we just need to append the suffix.
264 /* Recreate the session->rotation_chunk.current_rotate_path */
265 timeinfo
= localtime(&session
->last_chunk_start_ts
);
267 ERR("Failed to retrieve local time while renaming completed chunk");
271 strf_ret
= strftime(start_datetime
, sizeof(start_datetime
),
272 "%Y%m%dT%H%M%S%z", timeinfo
);
274 ERR("Failed to format timestamp while renaming completed session chunk");
278 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
279 session_get_base_path(session
),
281 datetime
, session
->current_archive_id
);
282 if (ret
< 0 || ret
>= sizeof(new_path
)) {
283 ERR("Failed to format new chunk path while renaming chunk of session \"%s\"",
288 ret
= session_rename_chunk(session
,
289 session
->rotation_chunk
.current_rotate_path
,
292 ERR("Failed to rename session trace folder from %s to %s",
293 session
->rotation_chunk
.current_rotate_path
,
301 * Store the path where the readable chunk is. This path is valid
302 * and can be queried by the client with rotate_pending until the next
303 * rotation is started.
305 ret
= lttng_strncpy(session
->rotation_chunk
.current_rotate_path
,
307 sizeof(session
->rotation_chunk
.current_rotate_path
));
309 ERR("Failed the current chunk's path of session \"%s\"",
318 session
->rotation_state
= LTTNG_ROTATION_STATE_ERROR
;
323 int rename_active_chunk(struct ltt_session
*session
)
327 session
->current_archive_id
++;
330 * The currently active tracing path is now the folder we
333 ret
= lttng_strncpy(session
->rotation_chunk
.current_rotate_path
,
334 session
->rotation_chunk
.active_tracing_path
,
335 sizeof(session
->rotation_chunk
.current_rotate_path
));
337 ERR("Failed to copy active tracing path");
341 ret
= rename_completed_chunk(session
, time(NULL
));
343 ERR("Failed to rename current rotation's path");
348 * We just renamed, the folder, we didn't do an actual rotation, so
349 * the active tracing path is now the renamed folder and we have to
350 * restore the rotate count.
352 ret
= lttng_strncpy(session
->rotation_chunk
.active_tracing_path
,
353 session
->rotation_chunk
.current_rotate_path
,
354 sizeof(session
->rotation_chunk
.active_tracing_path
));
356 ERR("Failed to rename active session chunk tracing path");
360 session
->current_archive_id
--;
364 int subscribe_session_consumed_size_rotation(struct ltt_session
*session
, uint64_t size
,
365 struct notification_thread_handle
*notification_thread_handle
)
368 enum lttng_condition_status condition_status
;
369 enum lttng_notification_channel_status nc_status
;
370 struct lttng_action
*action
;
372 session
->rotate_condition
= lttng_condition_session_consumed_size_create();
373 if (!session
->rotate_condition
) {
374 ERR("Failed to create session consumed size condition object");
379 condition_status
= lttng_condition_session_consumed_size_set_threshold(
380 session
->rotate_condition
, size
);
381 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
382 ERR("Could not set session consumed size condition threshold (size = %" PRIu64
")",
389 lttng_condition_session_consumed_size_set_session_name(
390 session
->rotate_condition
, session
->name
);
391 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
392 ERR("Could not set session consumed size condition session name (name = %s)",
398 action
= lttng_action_notify_create();
400 ERR("Could not create notify action");
405 session
->rotate_trigger
= lttng_trigger_create(session
->rotate_condition
,
407 if (!session
->rotate_trigger
) {
408 ERR("Could not create size-based rotation trigger");
413 nc_status
= lttng_notification_channel_subscribe(
414 rotate_notification_channel
, session
->rotate_condition
);
415 if (nc_status
!= LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
) {
416 ERR("Could not subscribe to session consumed size notification");
421 ret
= notification_thread_command_register_trigger(
422 notification_thread_handle
, session
->rotate_trigger
);
423 if (ret
< 0 && ret
!= -LTTNG_ERR_TRIGGER_EXISTS
) {
424 ERR("Register trigger, %s", lttng_strerror(ret
));
435 int unsubscribe_session_consumed_size_rotation(struct ltt_session
*session
,
436 struct notification_thread_handle
*notification_thread_handle
)
439 enum lttng_notification_channel_status status
;
441 status
= lttng_notification_channel_unsubscribe(
442 rotate_notification_channel
,
443 session
->rotate_condition
);
444 if (status
!= LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
) {
445 ERR("Session unsubscribe error: %d", (int) status
);
450 ret
= notification_thread_command_unregister_trigger(
451 notification_thread_handle
, session
->rotate_trigger
);
452 if (ret
!= LTTNG_OK
) {
453 ERR("Session unregister trigger error: %d", ret
);