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 /* The session's lock must be held by the caller. */
55 int session_rename_chunk(struct ltt_session
*session
, char *current_path
,
59 struct consumer_socket
*socket
;
60 struct consumer_output
*output
;
61 struct lttng_ht_iter iter
;
65 DBG("Renaming session chunk path of session \"%s\" from %s to %s",
66 session
->name
, current_path
, new_path
);
69 * Either one of the sessions is enough to find the consumer_output
72 if (session
->kernel_session
) {
73 output
= session
->kernel_session
->consumer
;
74 uid
= session
->kernel_session
->uid
;
75 gid
= session
->kernel_session
->gid
;
76 } else if (session
->ust_session
) {
77 output
= session
->ust_session
->consumer
;
78 uid
= session
->ust_session
->uid
;
79 gid
= session
->ust_session
->gid
;
84 if (!output
|| !output
->socks
) {
85 ERR("No consumer output found for session \"%s\"",
93 * We have to iterate to find a socket, but we only need to send the
94 * rename command to one consumer, so we break after the first one.
96 cds_lfht_for_each_entry(output
->socks
->ht
, &iter
.iter
, socket
, node
.node
) {
97 pthread_mutex_lock(socket
->lock
);
98 ret
= consumer_rotate_rename(socket
, session
->id
, output
,
99 current_path
, new_path
, uid
, gid
);
100 pthread_mutex_unlock(socket
->lock
);
116 /* The session's lock must be held by the caller. */
118 int rename_first_chunk(struct ltt_session
*session
,
119 struct consumer_output
*consumer
, char *new_path
)
122 char current_full_path
[LTTNG_PATH_MAX
], new_full_path
[LTTNG_PATH_MAX
];
124 /* Current domain path: <session>/kernel */
125 if (session
->net_handle
> 0) {
126 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
127 consumer
->dst
.net
.base_dir
, consumer
->subdir
);
128 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
129 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
135 ret
= snprintf(current_full_path
, sizeof(current_full_path
), "%s/%s",
136 consumer
->dst
.session_root_path
, consumer
->subdir
);
137 if (ret
< 0 || ret
>= sizeof(current_full_path
)) {
138 ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
144 /* New domain path: <session>/<start-date>-<end-date>-<rotate-count>/kernel */
145 ret
= snprintf(new_full_path
, sizeof(new_full_path
), "%s/%s",
146 new_path
, consumer
->subdir
);
147 if (ret
< 0 || ret
>= sizeof(new_full_path
)) {
148 ERR("Failed to initialize new full path while renaming first rotation chunk of session \"%s\"",
154 * Move the per-domain fcurrenter inside the first rotation
157 ret
= session_rename_chunk(session
, current_full_path
, new_full_path
);
159 ret
= -LTTNG_ERR_UNK
;
170 * Rename a chunk folder after a rotation is complete.
171 * session_lock_list and session lock must be held.
173 * Returns 0 on success, a negative value on error.
175 int rename_complete_chunk(struct ltt_session
*session
, time_t ts
)
178 char datetime
[16], start_datetime
[16];
179 char new_path
[LTTNG_PATH_MAX
];
183 DBG("Renaming completed chunk for session %s", session
->name
);
184 timeinfo
= localtime(&ts
);
186 ERR("Failed to retrieve local time while renaming completed chunk");
190 strf_ret
= strftime(datetime
, sizeof(datetime
), "%Y%m%d-%H%M%S",
193 ERR("Failed to format timestamp while renaming completed session chunk");
198 if (session
->rotate_count
== 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%d-%H%M%S", 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
->rotate_count
);
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
), "%Y%m%d-%H%M%S", timeinfo
);
273 ERR("Failed to format timestamp while renaming completed session chunk");
277 ret
= snprintf(new_path
, sizeof(new_path
), "%s/%s-%s-%" PRIu64
,
278 session_get_base_path(session
),
280 datetime
, session
->rotate_count
);
281 if (ret
< 0 || ret
>= sizeof(new_path
)) {
282 ERR("Failed to format new chunk path while renaming chunk of session \"%s\"",
287 ret
= session_rename_chunk(session
,
288 session
->rotation_chunk
.current_rotate_path
,
291 ERR("Failed to rename session trace folder from %s to %s",
292 session
->rotation_chunk
.current_rotate_path
,
300 * Store the path where the readable chunk is. This path is valid
301 * and can be queried by the client with rotate_pending until the next
302 * rotation is started.
304 ret
= lttng_strncpy(session
->rotation_chunk
.current_rotate_path
,
306 sizeof(session
->rotation_chunk
.current_rotate_path
));
308 ERR("Failed the current chunk's path of session \"%s\"",
317 session
->rotation_status
= LTTNG_ROTATION_STATUS_ERROR
;