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/rotate-internal.h>
39 #include "rotation-thread.h"
40 #include "lttng-sessiond.h"
41 #include "health-sessiond.h"
46 #include <urcu/list.h>
47 #include <urcu/rculfhash.h>
49 unsigned long hash_channel_key(struct rotation_channel_key
*key
)
51 return hash_key_u64(&key
->key
, lttng_ht_seed
) ^ hash_key_ulong(
52 (void *) (unsigned long) key
->domain
, lttng_ht_seed
);
55 int rotate_add_channel_pending(uint64_t key
, enum lttng_domain_type domain
,
56 struct ltt_session
*session
)
59 struct rotation_channel_info
*new_info
;
60 struct rotation_channel_key channel_key
= { .key
= key
,
63 new_info
= zmalloc(sizeof(struct rotation_channel_info
));
68 new_info
->channel_key
.key
= key
;
69 new_info
->channel_key
.domain
= domain
;
70 new_info
->session_id
= session
->id
;
71 cds_lfht_node_init(&new_info
->rotate_channels_ht_node
);
73 session
->nr_chan_rotate_pending
++;
74 cds_lfht_add(channel_pending_rotate_ht
,
75 hash_channel_key(&channel_key
),
76 &new_info
->rotate_channels_ht_node
);
87 /* The session's lock must be held by the caller. */
89 int session_rename_chunk(struct ltt_session
*session
, char *current_path
,
93 struct consumer_socket
*socket
;
94 struct consumer_output
*output
;
95 struct lttng_ht_iter iter
;
99 DBG("Renaming session chunk path of session \"%s\" from %s to %s",
100 session
->name
, current_path
, new_path
);
103 * Either one of the sessions is enough to find the consumer_output
106 if (session
->kernel_session
) {
107 output
= session
->kernel_session
->consumer
;
108 uid
= session
->kernel_session
->uid
;
109 gid
= session
->kernel_session
->gid
;
110 } else if (session
->ust_session
) {
111 output
= session
->ust_session
->consumer
;
112 uid
= session
->ust_session
->uid
;
113 gid
= session
->ust_session
->gid
;
118 if (!output
|| !output
->socks
) {
119 ERR("No consumer output found for session \"%s\"",
127 * We have to iterate to find a socket, but we only need to send the
128 * rename command to one consumer, so we break after the first one.
130 cds_lfht_for_each_entry(output
->socks
->ht
, &iter
.iter
, socket
, node
.node
) {
131 pthread_mutex_lock(socket
->lock
);
132 ret
= consumer_rotate_rename(socket
, session
->id
, output
,
133 current_path
, new_path
, uid
, gid
);
134 pthread_mutex_unlock(socket
->lock
);
150 /* The session's lock must be held by the caller. */
152 int rename_first_chunk(struct ltt_session
*session
,
153 struct consumer_output
*consumer
, char *new_path
)
156 char current_full_path
[LTTNG_PATH_MAX
], new_full_path
[LTTNG_PATH_MAX
];
158 /* Current domain path: <session>/kernel */
159 if (session
->net_handle
> 0) {
160 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
161 consumer
->dst
.net
.base_dir
, consumer
->subdir
);
162 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
163 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
169 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
170 consumer
->dst
.session_root_path
, consumer
->subdir
);
171 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
172 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
178 /* New domain path: <session>/<start-date>-<end-date>-<rotate-count>/kernel */
179 ret
= snprintf(new_full_path
, sizeof(new_full_path
), "%s/%s",
180 new_path
, consumer
->subdir
);
181 if (ret
< 0 || ret
>= sizeof(new_full_path
)) {
182 ERR("Failed to initialize new full path while renaming first rotation chunk of session \"%s\"",
188 * Move the per-domain fcurrenter inside the first rotation
191 ret
= session_rename_chunk(session
, current_full_path
, new_full_path
);
193 ret
= -LTTNG_ERR_UNK
;
204 * Rename a chunk folder after a rotation is complete.
205 * session_lock_list and session lock must be held.
207 * Returns 0 on success, a negative value on error.
209 int rename_complete_chunk(struct ltt_session
*session
, time_t ts
)
212 char datetime
[16], start_datetime
[16];
213 char new_path
[LTTNG_PATH_MAX
];
217 DBG("Renaming completed chunk for session %s", session
->name
);
218 timeinfo
= localtime(&ts
);
220 ERR("Failed to retrieve local time while renaming completed chunk");
224 strf_ret
= strftime(datetime
, sizeof(datetime
), "%Y%m%d-%H%M%S",
227 ERR("Failed to format timestamp while renaming completed session chunk");
232 if (session
->rotate_count
== 1) {
235 timeinfo
= localtime(&session
->last_chunk_start_ts
);
237 ERR("Failed to retrieve local time while renaming completed chunk");
242 strf_ret
= strftime(start_time
, sizeof(start_time
),
243 "%Y%m%d-%H%M%S", timeinfo
);
245 ERR("Failed to format timestamp while renaming completed session chunk");
251 * On the first rotation, the current_rotate_path is the
252 * session_root_path, so we need to create the chunk folder
253 * and move the domain-specific folders inside it.
255 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
256 session
->rotation_chunk
.current_rotate_path
,
258 datetime
, session
->rotate_count
);
259 if (ret
< 0 || ret
>= sizeof(new_path
)) {
260 ERR("Failed to format new chunk path while renaming session \"%s\"'s first chunk",
266 if (session
->kernel_session
) {
267 ret
= rename_first_chunk(session
,
268 session
->kernel_session
->consumer
,
271 ERR("Failed to rename kernel session trace folder to %s", new_path
);
273 * This is not a fatal error for the rotation
274 * thread, we just need to inform the client
275 * that a problem occurred with the rotation.
276 * Returning 0, same for the other errors
283 if (session
->ust_session
) {
284 ret
= rename_first_chunk(session
,
285 session
->ust_session
->consumer
,
288 ERR("Failed to rename userspace session trace folder to %s", new_path
);
295 * After the first rotation, all the trace data is already in
296 * its own chunk folder, we just need to append the suffix.
298 /* Recreate the session->rotation_chunk.current_rotate_path */
299 timeinfo
= localtime(&session
->last_chunk_start_ts
);
301 ERR("Failed to retrieve local time while renaming completed chunk");
305 strf_ret
= strftime(start_datetime
, sizeof(start_datetime
), "%Y%m%d-%H%M%S", timeinfo
);
307 ERR("Failed to format timestamp while renaming completed session chunk");
311 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
312 session_get_base_path(session
),
314 datetime
, session
->rotate_count
);
315 if (ret
< 0 || ret
>= sizeof(new_path
)) {
316 ERR("Failed to format new chunk path while renaming chunk of session \"%s\"",
321 ret
= session_rename_chunk(session
,
322 session
->rotation_chunk
.current_rotate_path
,
325 ERR("Failed to rename session trace folder from %s to %s",
326 session
->rotation_chunk
.current_rotate_path
,
334 * Store the path where the readable chunk is. This path is valid
335 * and can be queried by the client with rotate_pending until the next
336 * rotation is started.
338 ret
= lttng_strncpy(session
->rotation_chunk
.current_rotate_path
,
340 sizeof(session
->rotation_chunk
.current_rotate_path
));
342 ERR("Failed the current chunk's path of session \"%s\"",
351 session
->rotation_state
= LTTNG_ROTATION_STATE_ERROR
;
356 int relay_rotate_pending(struct ltt_session
*session
, uint64_t chunk_id
)
359 struct consumer_socket
*socket
;
360 struct consumer_output
*output
;
361 struct lttng_ht_iter iter
;
364 * Either one of the sessions is enough to find the consumer_output
367 if (session
->kernel_session
) {
368 output
= session
->kernel_session
->consumer
;
369 } else if (session
->ust_session
) {
370 output
= session
->ust_session
->consumer
;
375 if (!output
|| !output
->socks
) {
376 ERR("No consumer output found");
385 * We have to iterate to find a socket, but we only need to send the
386 * rotate pending command to one consumer, so we break after the first
389 cds_lfht_for_each_entry(output
->socks
->ht
, &iter
.iter
, socket
,
391 pthread_mutex_lock(socket
->lock
);
392 ret
= consumer_rotate_pending_relay(socket
, output
, session
->id
,
394 pthread_mutex_unlock(socket
->lock
);