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>
37 #include "rotation-thread.h"
38 #include "lttng-sessiond.h"
39 #include "health-sessiond.h"
44 #include <urcu/list.h>
45 #include <urcu/rculfhash.h>
47 unsigned long hash_channel_key(struct rotation_channel_key
*key
)
49 return hash_key_u64(&key
->key
, lttng_ht_seed
) ^ hash_key_ulong(
50 (void *) (unsigned long) key
->domain
, lttng_ht_seed
);
53 int rotate_add_channel_pending(uint64_t key
, enum lttng_domain_type domain
,
54 struct ltt_session
*session
)
57 struct rotation_channel_info
*new_info
;
58 struct rotation_channel_key channel_key
= { .key
= key
,
61 new_info
= zmalloc(sizeof(struct rotation_channel_info
));
66 new_info
->channel_key
.key
= key
;
67 new_info
->channel_key
.domain
= domain
;
68 new_info
->session_id
= session
->id
;
69 cds_lfht_node_init(&new_info
->rotate_channels_ht_node
);
71 session
->nr_chan_rotate_pending
++;
72 cds_lfht_add(channel_pending_rotate_ht
,
73 hash_channel_key(&channel_key
),
74 &new_info
->rotate_channels_ht_node
);
85 /* The session's lock must be held by the caller. */
87 int session_rename_chunk(struct ltt_session
*session
, char *current_path
,
91 struct consumer_socket
*socket
;
92 struct consumer_output
*output
;
93 struct lttng_ht_iter iter
;
97 DBG("Renaming session chunk path of session \"%s\" from %s to %s",
98 session
->name
, current_path
, new_path
);
101 * Either one of the sessions is enough to find the consumer_output
104 if (session
->kernel_session
) {
105 output
= session
->kernel_session
->consumer
;
106 uid
= session
->kernel_session
->uid
;
107 gid
= session
->kernel_session
->gid
;
108 } else if (session
->ust_session
) {
109 output
= session
->ust_session
->consumer
;
110 uid
= session
->ust_session
->uid
;
111 gid
= session
->ust_session
->gid
;
116 if (!output
|| !output
->socks
) {
117 ERR("No consumer output found for session \"%s\"",
125 * We have to iterate to find a socket, but we only need to send the
126 * rename command to one consumer, so we break after the first one.
128 cds_lfht_for_each_entry(output
->socks
->ht
, &iter
.iter
, socket
, node
.node
) {
129 pthread_mutex_lock(socket
->lock
);
130 ret
= consumer_rotate_rename(socket
, session
->id
, output
,
131 current_path
, new_path
, uid
, gid
);
132 pthread_mutex_unlock(socket
->lock
);
148 /* The session's lock must be held by the caller. */
150 int rename_first_chunk(struct ltt_session
*session
,
151 struct consumer_output
*consumer
, char *new_path
)
154 char current_full_path
[LTTNG_PATH_MAX
], new_full_path
[LTTNG_PATH_MAX
];
156 /* Current domain path: <session>/kernel */
157 if (session
->net_handle
> 0) {
158 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
159 consumer
->dst
.net
.base_dir
, consumer
->subdir
);
160 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
161 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
167 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
168 consumer
->dst
.session_root_path
, consumer
->subdir
);
169 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
170 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
176 /* New domain path: <session>/<start-date>-<end-date>-<rotate-count>/kernel */
177 ret
= snprintf(new_full_path
, sizeof(new_full_path
), "%s/%s",
178 new_path
, consumer
->subdir
);
179 if (ret
< 0 || ret
>= sizeof(new_full_path
)) {
180 ERR("Failed to initialize new full path while renaming first rotation chunk of session \"%s\"",
186 * Move the per-domain fcurrenter inside the first rotation
189 ret
= session_rename_chunk(session
, current_full_path
, new_full_path
);
191 ret
= -LTTNG_ERR_UNK
;
202 * Rename a chunk folder after a rotation is complete.
203 * session_lock_list and session lock must be held.
205 * Returns 0 on success, a negative value on error.
207 int rename_complete_chunk(struct ltt_session
*session
, time_t ts
)
210 char datetime
[16], start_datetime
[16];
211 char new_path
[LTTNG_PATH_MAX
];
215 DBG("Renaming completed chunk for session %s", session
->name
);
216 timeinfo
= localtime(&ts
);
218 ERR("Failed to retrieve local time while renaming completed chunk");
222 strf_ret
= strftime(datetime
, sizeof(datetime
), "%Y%m%d-%H%M%S",
225 ERR("Failed to format timestamp while renaming completed session chunk");
230 if (session
->rotate_count
== 1) {
233 timeinfo
= localtime(&session
->last_chunk_start_ts
);
235 ERR("Failed to retrieve local time while renaming completed chunk");
240 strf_ret
= strftime(start_time
, sizeof(start_time
),
241 "%Y%m%d-%H%M%S", timeinfo
);
243 ERR("Failed to format timestamp while renaming completed session chunk");
249 * On the first rotation, the current_rotate_path is the
250 * session_root_path, so we need to create the chunk folder
251 * and move the domain-specific folders inside it.
253 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
254 session
->rotation_chunk
.current_rotate_path
,
256 datetime
, session
->rotate_count
);
257 if (ret
< 0 || ret
>= sizeof(new_path
)) {
258 ERR("Failed to format new chunk path while renaming session \"%s\"'s first chunk",
264 if (session
->kernel_session
) {
265 ret
= rename_first_chunk(session
,
266 session
->kernel_session
->consumer
,
269 ERR("Failed to rename kernel session trace folder to %s", new_path
);
271 * This is not a fatal error for the rotation
272 * thread, we just need to inform the client
273 * that a problem occurred with the rotation.
274 * Returning 0, same for the other errors
281 if (session
->ust_session
) {
282 ret
= rename_first_chunk(session
,
283 session
->ust_session
->consumer
,
286 ERR("Failed to rename userspace session trace folder to %s", new_path
);
293 * After the first rotation, all the trace data is already in
294 * its own chunk folder, we just need to append the suffix.
296 /* Recreate the session->rotation_chunk.current_rotate_path */
297 timeinfo
= localtime(&session
->last_chunk_start_ts
);
299 ERR("Failed to retrieve local time while renaming completed chunk");
303 strf_ret
= strftime(start_datetime
, sizeof(start_datetime
), "%Y%m%d-%H%M%S", timeinfo
);
305 ERR("Failed to format timestamp while renaming completed session chunk");
309 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
310 session_get_base_path(session
),
312 datetime
, session
->rotate_count
);
313 if (ret
< 0 || ret
>= sizeof(new_path
)) {
314 ERR("Failed to format new chunk path while renaming chunk of session \"%s\"",
319 ret
= session_rename_chunk(session
,
320 session
->rotation_chunk
.current_rotate_path
,
323 ERR("Failed to rename session trace folder from %s to %s",
324 session
->rotation_chunk
.current_rotate_path
,
332 * Store the path where the readable chunk is. This path is valid
333 * and can be queried by the client with rotate_pending until the next
334 * rotation is started.
336 ret
= lttng_strncpy(session
->rotation_chunk
.current_rotate_path
,
338 sizeof(session
->rotation_chunk
.current_rotate_path
));
340 ERR("Failed the current chunk's path of session \"%s\"",
349 session
->rotation_status
= LTTNG_ROTATION_STATUS_ERROR
;