755fb6734072113af804e59f6e1e81089adb6b1f
[lttng-tools.git] / src / bin / lttng-relayd / stream.c
1 /*
2 * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
3 * David Goulet <dgoulet@efficios.com>
4 * 2015 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 * 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License, version 2 only, as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 51
18 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #define _LGPL_SOURCE
22 #include <common/common.h>
23 #include <common/utils.h>
24 #include <common/defaults.h>
25 #include <common/sessiond-comm/relayd.h>
26 #include <urcu/rculist.h>
27 #include <sys/stat.h>
28
29 #include "lttng-relayd.h"
30 #include "index.h"
31 #include "stream.h"
32 #include "viewer-stream.h"
33
34 #include <sys/types.h>
35 #include <fcntl.h>
36
37 #define FILE_IO_STACK_BUFFER_SIZE 65536
38
39 /* Should be called with RCU read-side lock held. */
40 bool stream_get(struct relay_stream *stream)
41 {
42 return urcu_ref_get_unless_zero(&stream->ref);
43 }
44
45 /*
46 * Get stream from stream id from the streams hash table. Return stream
47 * if found else NULL. A stream reference is taken when a stream is
48 * returned. stream_put() must be called on that stream.
49 */
50 struct relay_stream *stream_get_by_id(uint64_t stream_id)
51 {
52 struct lttng_ht_node_u64 *node;
53 struct lttng_ht_iter iter;
54 struct relay_stream *stream = NULL;
55
56 rcu_read_lock();
57 lttng_ht_lookup(relay_streams_ht, &stream_id, &iter);
58 node = lttng_ht_iter_get_node_u64(&iter);
59 if (!node) {
60 DBG("Relay stream %" PRIu64 " not found", stream_id);
61 goto end;
62 }
63 stream = caa_container_of(node, struct relay_stream, node);
64 if (!stream_get(stream)) {
65 stream = NULL;
66 }
67 end:
68 rcu_read_unlock();
69 return stream;
70 }
71
72 static void stream_complete_rotation(struct relay_stream *stream)
73 {
74 DBG("Rotation completed for stream %" PRIu64, stream->stream_handle);
75 lttng_trace_chunk_put(stream->trace_chunk);
76 stream->trace_chunk = stream->ongoing_rotation.value.next_trace_chunk;
77 stream->ongoing_rotation = (typeof(stream->ongoing_rotation)) {};
78 }
79
80 static int stream_create_data_output_file_from_trace_chunk(
81 struct relay_stream *stream,
82 struct lttng_trace_chunk *trace_chunk,
83 bool force_unlink,
84 struct stream_fd **out_stream_fd)
85 {
86 int ret, fd;
87 char stream_path[LTTNG_PATH_MAX];
88 enum lttng_trace_chunk_status status;
89 const int flags = O_RDWR | O_CREAT | O_TRUNC;
90 const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
91
92 ASSERT_LOCKED(stream->lock);
93
94 ret = utils_stream_file_path(stream->path_name, stream->channel_name,
95 stream->tracefile_size, stream->tracefile_current_index,
96 NULL, stream_path, sizeof(stream_path));
97 if (ret < 0) {
98 goto end;
99 }
100
101 if (stream->tracefile_wrapped_around || force_unlink) {
102 /*
103 * The on-disk ring-buffer has wrapped around.
104 * Newly created stream files will replace existing files. Since
105 * live clients may be consuming existing files, the file about
106 * to be replaced is unlinked in order to not overwrite its
107 * content.
108 */
109 status = lttng_trace_chunk_unlink_file(trace_chunk,
110 stream_path);
111 if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
112 PERROR("Failed to unlink stream file \"%s\" during trace file rotation",
113 stream_path);
114 /*
115 * Don't abort if the file doesn't exist, it is
116 * unexpected, but should not be a fatal error.
117 */
118 if (errno != ENOENT) {
119 ret = -1;
120 goto end;
121 }
122 }
123 }
124
125 status = lttng_trace_chunk_open_file(
126 trace_chunk, stream_path, flags, mode, &fd);
127 if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
128 ERR("Failed to open stream file \"%s\"", stream->channel_name);
129 ret = -1;
130 goto end;
131 }
132
133 *out_stream_fd = stream_fd_create(fd);
134 if (!*out_stream_fd) {
135 if (close(ret)) {
136 PERROR("Error closing stream file descriptor %d", ret);
137 }
138 ret = -1;
139 goto end;
140 }
141 end:
142 return ret;
143 }
144
145 static int stream_rotate_data_file(struct relay_stream *stream)
146 {
147 int ret = 0;
148
149 DBG("Rotating stream %" PRIu64 " data file",
150 stream->stream_handle);
151
152 if (stream->stream_fd) {
153 stream_fd_put(stream->stream_fd);
154 stream->stream_fd = NULL;
155 }
156
157 stream->tracefile_wrapped_around = false;
158 stream->tracefile_current_index = 0;
159
160 if (stream->ongoing_rotation.value.next_trace_chunk) {
161 struct stream_fd *new_stream_fd = NULL;
162 enum lttng_trace_chunk_status chunk_status;
163
164 chunk_status = lttng_trace_chunk_create_subdirectory(
165 stream->ongoing_rotation.value.next_trace_chunk,
166 stream->path_name);
167 if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
168 ret = -1;
169 goto end;
170 }
171
172 /* Rotate the data file. */
173 ret = stream_create_data_output_file_from_trace_chunk(stream,
174 stream->ongoing_rotation.value.next_trace_chunk,
175 false, &new_stream_fd);
176 stream->stream_fd = new_stream_fd;
177 if (ret < 0) {
178 ERR("Failed to rotate stream data file");
179 goto end;
180 }
181 }
182 stream->tracefile_size_current = 0;
183 stream->pos_after_last_complete_data_index = 0;
184 stream->ongoing_rotation.value.data_rotated = true;
185
186 if (stream->ongoing_rotation.value.index_rotated) {
187 /* Rotation completed; reset its state. */
188 stream_complete_rotation(stream);
189 }
190 end:
191 return ret;
192 }
193
194 /*
195 * If too much data has been written in a tracefile before we received the
196 * rotation command, we have to move the excess data to the new tracefile and
197 * perform the rotation. This can happen because the control and data
198 * connections are separate, the indexes as well as the commands arrive from
199 * the control connection and we have no control over the order so we could be
200 * in a situation where too much data has been received on the data connection
201 * before the rotation command on the control connection arrives.
202 */
203 static int rotate_truncate_stream(struct relay_stream *stream)
204 {
205 int ret;
206 off_t lseek_ret, previous_stream_copy_origin;
207 uint64_t copy_bytes_left, misplaced_data_size;
208 bool acquired_reference;
209 struct stream_fd *previous_stream_fd = NULL;
210 struct lttng_trace_chunk *previous_chunk = NULL;
211
212 if (!LTTNG_OPTIONAL_GET(stream->ongoing_rotation).next_trace_chunk) {
213 ERR("Protocol error encoutered in %s(): stream rotation "
214 "sequence number is before the current sequence number "
215 "and the next trace chunk is unset. Honoring this "
216 "rotation command would result in data loss",
217 __FUNCTION__);
218 ret = -1;
219 goto end;
220 }
221
222 ASSERT_LOCKED(stream->lock);
223 /*
224 * Acquire a reference to the current trace chunk to ensure
225 * it is not reclaimed when `stream_rotate_data_file` is called.
226 * Failing to do so would violate the contract of the trace
227 * chunk API as an active file descriptor would outlive the
228 * trace chunk.
229 */
230 acquired_reference = lttng_trace_chunk_get(stream->trace_chunk);
231 assert(acquired_reference);
232 previous_chunk = stream->trace_chunk;
233
234 /*
235 * Steal the stream's reference to its stream_fd. A new
236 * stream_fd will be created when the rotation completes and
237 * the orinal stream_fd will be used to copy the "extra" data
238 * to the new file.
239 */
240 assert(stream->stream_fd);
241 previous_stream_fd = stream->stream_fd;
242 stream->stream_fd = NULL;
243
244 assert(!stream->is_metadata);
245 assert(stream->tracefile_size_current >
246 stream->pos_after_last_complete_data_index);
247 misplaced_data_size = stream->tracefile_size_current -
248 stream->pos_after_last_complete_data_index;
249 copy_bytes_left = misplaced_data_size;
250 previous_stream_copy_origin = stream->pos_after_last_complete_data_index;
251
252 ret = stream_rotate_data_file(stream);
253 if (ret) {
254 goto end;
255 }
256
257 assert(stream->stream_fd);
258 /*
259 * Seek the current tracefile to the position at which the rotation
260 * should have occurred.
261 */
262 lseek_ret = lseek(previous_stream_fd->fd, previous_stream_copy_origin,
263 SEEK_SET);
264 if (lseek_ret < 0) {
265 PERROR("Failed to seek to offset %" PRIu64
266 " while copying extra data received before a stream rotation",
267 (uint64_t) previous_stream_copy_origin);
268 ret = -1;
269 goto end;
270 }
271
272 /* Move data from the old file to the new file. */
273 while (copy_bytes_left) {
274 ssize_t io_ret;
275 char copy_buffer[FILE_IO_STACK_BUFFER_SIZE];
276 const off_t copy_size_this_pass = min_t(
277 off_t, copy_bytes_left, sizeof(copy_buffer));
278
279 io_ret = lttng_read(previous_stream_fd->fd, copy_buffer,
280 copy_size_this_pass);
281 if (io_ret < (ssize_t) copy_size_this_pass) {
282 if (io_ret == -1) {
283 PERROR("Failed to read %" PRIu64
284 " bytes from fd %i in %s(), returned %zi",
285 copy_size_this_pass,
286 previous_stream_fd->fd,
287 __FUNCTION__, io_ret);
288 } else {
289 ERR("Failed to read %" PRIu64
290 " bytes from fd %i in %s(), returned %zi",
291 copy_size_this_pass,
292 previous_stream_fd->fd,
293 __FUNCTION__, io_ret);
294 }
295 ret = -1;
296 goto end;
297 }
298
299 io_ret = lttng_write(stream->stream_fd->fd, copy_buffer,
300 copy_size_this_pass);
301 if (io_ret < (ssize_t) copy_size_this_pass) {
302 if (io_ret == -1) {
303 PERROR("Failed to write %" PRIu64
304 " bytes from fd %i in %s(), returned %zi",
305 copy_size_this_pass,
306 stream->stream_fd->fd,
307 __FUNCTION__, io_ret);
308 } else {
309 ERR("Failed to write %" PRIu64
310 " bytes from fd %i in %s(), returned %zi",
311 copy_size_this_pass,
312 stream->stream_fd->fd,
313 __FUNCTION__, io_ret);
314 }
315 ret = -1;
316 goto end;
317 }
318 copy_bytes_left -= copy_size_this_pass;
319 }
320
321 /* Truncate the file to get rid of the excess data. */
322 ret = ftruncate(previous_stream_fd->fd, previous_stream_copy_origin);
323 if (ret) {
324 PERROR("Failed to truncate current stream file to offset %" PRIu64,
325 previous_stream_copy_origin);
326 goto end;
327 }
328
329 /*
330 * Update the offset and FD of all the eventual indexes created by the
331 * data connection before the rotation command arrived.
332 */
333 ret = relay_index_switch_all_files(stream);
334 if (ret < 0) {
335 ERR("Failed to rotate index file");
336 goto end;
337 }
338
339 stream->tracefile_size_current = misplaced_data_size;
340 /* Index and data contents are back in sync. */
341 stream->pos_after_last_complete_data_index = 0;
342 ret = 0;
343 end:
344 lttng_trace_chunk_put(previous_chunk);
345 stream_fd_put(previous_stream_fd);
346 return ret;
347 }
348
349 /*
350 * Check if a stream's data file (as opposed to index) should be rotated
351 * (for session rotation).
352 * Must be called with the stream lock held.
353 *
354 * Return 0 on success, a negative value on error.
355 */
356 static int try_rotate_stream_data(struct relay_stream *stream)
357 {
358 int ret = 0;
359
360 if (caa_likely(!stream->ongoing_rotation.is_set)) {
361 /* No rotation expected. */
362 goto end;
363 }
364
365 if (stream->ongoing_rotation.value.data_rotated) {
366 /* Rotation of the data file has already occurred. */
367 goto end;
368 }
369
370 if (stream->prev_data_seq == -1ULL ||
371 stream->prev_data_seq + 1 < stream->ongoing_rotation.value.seq_num) {
372 /*
373 * The next packet that will be written is not part of the next
374 * chunk yet.
375 */
376 DBG("Stream %" PRIu64 " not yet ready for rotation (rotate_at_seq_num = %" PRIu64
377 ", prev_data_seq = %" PRIu64 ")",
378 stream->stream_handle,
379 stream->ongoing_rotation.value.seq_num,
380 stream->prev_data_seq);
381 goto end;
382 } else if (stream->prev_data_seq > stream->ongoing_rotation.value.seq_num) {
383 /*
384 * prev_data_seq is checked here since indexes and rotation
385 * commands are serialized with respect to each other.
386 */
387 DBG("Rotation after too much data has been written in tracefile "
388 "for stream %" PRIu64 ", need to truncate before "
389 "rotating", stream->stream_handle);
390 ret = rotate_truncate_stream(stream);
391 if (ret) {
392 ERR("Failed to truncate stream");
393 goto end;
394 }
395 } else {
396 ret = stream_rotate_data_file(stream);
397 }
398
399 end:
400 return ret;
401 }
402
403 /*
404 * Close the current index file if it is open, and create a new one.
405 *
406 * Return 0 on success, -1 on error.
407 */
408 static int create_index_file(struct relay_stream *stream,
409 struct lttng_trace_chunk *chunk)
410 {
411 int ret;
412 uint32_t major, minor;
413 char *index_subpath = NULL;
414 enum lttng_trace_chunk_status status;
415
416 ASSERT_LOCKED(stream->lock);
417
418 /* Put ref on previous index_file. */
419 if (stream->index_file) {
420 lttng_index_file_put(stream->index_file);
421 stream->index_file = NULL;
422 }
423 major = stream->trace->session->major;
424 minor = stream->trace->session->minor;
425
426 if (!chunk) {
427 ret = 0;
428 goto end;
429 }
430 ret = asprintf(&index_subpath, "%s/%s", stream->path_name,
431 DEFAULT_INDEX_DIR);
432 if (ret < 0) {
433 goto end;
434 }
435
436 status = lttng_trace_chunk_create_subdirectory(chunk,
437 index_subpath);
438 free(index_subpath);
439 if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
440 ret = -1;
441 goto end;
442 }
443 stream->index_file = lttng_index_file_create_from_trace_chunk(
444 chunk, stream->path_name,
445 stream->channel_name, stream->tracefile_size,
446 stream->tracefile_current_index,
447 lttng_to_index_major(major, minor),
448 lttng_to_index_minor(major, minor), true);
449 if (!stream->index_file) {
450 ret = -1;
451 goto end;
452 }
453
454 ret = 0;
455
456 end:
457 return ret;
458 }
459
460 /*
461 * Check if a stream's index file should be rotated (for session rotation).
462 * Must be called with the stream lock held.
463 *
464 * Return 0 on success, a negative value on error.
465 */
466 static int try_rotate_stream_index(struct relay_stream *stream)
467 {
468 int ret = 0;
469
470 if (!stream->ongoing_rotation.is_set) {
471 /* No rotation expected. */
472 goto end;
473 }
474
475 if (stream->ongoing_rotation.value.index_rotated) {
476 /* Rotation of the index has already occurred. */
477 goto end;
478 }
479
480 if (stream->prev_index_seq == -1ULL ||
481 stream->prev_index_seq + 1 < stream->ongoing_rotation.value.seq_num) {
482 DBG("Stream %" PRIu64 " index not yet ready for rotation (rotate_at_seq_num = %" PRIu64 ", prev_index_seq = %" PRIu64 ")",
483 stream->stream_handle,
484 stream->ongoing_rotation.value.seq_num,
485 stream->prev_index_seq);
486 goto end;
487 } else {
488 /* The next index belongs to the new trace chunk; rotate. */
489 assert(stream->prev_index_seq + 1 ==
490 stream->ongoing_rotation.value.seq_num);
491 DBG("Rotating stream %" PRIu64 " index file",
492 stream->stream_handle);
493 ret = create_index_file(stream,
494 stream->ongoing_rotation.value.next_trace_chunk);
495 stream->ongoing_rotation.value.index_rotated = true;
496
497 if (stream->ongoing_rotation.value.data_rotated &&
498 stream->ongoing_rotation.value.index_rotated) {
499 /* Rotation completed; reset its state. */
500 DBG("Rotation completed for stream %" PRIu64,
501 stream->stream_handle);
502 stream_complete_rotation(stream);
503 }
504 }
505
506 end:
507 return ret;
508 }
509
510 static int stream_set_trace_chunk(struct relay_stream *stream,
511 struct lttng_trace_chunk *chunk)
512 {
513 int ret = 0;
514 enum lttng_trace_chunk_status status;
515 bool acquired_reference;
516 struct stream_fd *new_stream_fd = NULL;
517
518 status = lttng_trace_chunk_create_subdirectory(chunk,
519 stream->path_name);
520 if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
521 ret = -1;
522 goto end;
523 }
524
525 lttng_trace_chunk_put(stream->trace_chunk);
526 acquired_reference = lttng_trace_chunk_get(chunk);
527 assert(acquired_reference);
528 stream->trace_chunk = chunk;
529
530 if (stream->stream_fd) {
531 stream_fd_put(stream->stream_fd);
532 stream->stream_fd = NULL;
533 }
534 ret = stream_create_data_output_file_from_trace_chunk(stream, chunk,
535 false, &new_stream_fd);
536 stream->stream_fd = new_stream_fd;
537 end:
538 return ret;
539 }
540
541 /*
542 * We keep ownership of path_name and channel_name.
543 */
544 struct relay_stream *stream_create(struct ctf_trace *trace,
545 uint64_t stream_handle, char *path_name,
546 char *channel_name, uint64_t tracefile_size,
547 uint64_t tracefile_count)
548 {
549 int ret;
550 struct relay_stream *stream = NULL;
551 struct relay_session *session = trace->session;
552 bool acquired_reference = false;
553 struct lttng_trace_chunk *current_trace_chunk;
554
555 stream = zmalloc(sizeof(struct relay_stream));
556 if (stream == NULL) {
557 PERROR("relay stream zmalloc");
558 goto error_no_alloc;
559 }
560
561 stream->stream_handle = stream_handle;
562 stream->prev_data_seq = -1ULL;
563 stream->prev_index_seq = -1ULL;
564 stream->last_net_seq_num = -1ULL;
565 stream->ctf_stream_id = -1ULL;
566 stream->tracefile_size = tracefile_size;
567 stream->tracefile_count = tracefile_count;
568 stream->path_name = path_name;
569 stream->channel_name = channel_name;
570 stream->beacon_ts_end = -1ULL;
571 lttng_ht_node_init_u64(&stream->node, stream->stream_handle);
572 pthread_mutex_init(&stream->lock, NULL);
573 urcu_ref_init(&stream->ref);
574 ctf_trace_get(trace);
575 stream->trace = trace;
576
577 pthread_mutex_lock(&trace->session->lock);
578 current_trace_chunk = trace->session->current_trace_chunk;
579 if (current_trace_chunk) {
580 acquired_reference = lttng_trace_chunk_get(current_trace_chunk);
581 }
582 pthread_mutex_unlock(&trace->session->lock);
583 if (!acquired_reference) {
584 ERR("Cannot create stream for channel \"%s\" as a reference to the session's current trace chunk could not be acquired",
585 channel_name);
586 ret = -1;
587 goto end;
588 }
589
590 stream->indexes_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
591 if (!stream->indexes_ht) {
592 ERR("Cannot created indexes_ht");
593 ret = -1;
594 goto end;
595 }
596
597 pthread_mutex_lock(&stream->lock);
598 ret = stream_set_trace_chunk(stream, current_trace_chunk);
599 pthread_mutex_unlock(&stream->lock);
600 if (ret) {
601 ERR("Failed to set the current trace chunk of session \"%s\" on newly created stream of channel \"%s\"",
602 trace->session->session_name,
603 stream->channel_name);
604 ret = -1;
605 goto end;
606 }
607 stream->tfa = tracefile_array_create(stream->tracefile_count);
608 if (!stream->tfa) {
609 ret = -1;
610 goto end;
611 }
612
613 stream->is_metadata = !strcmp(stream->channel_name,
614 DEFAULT_METADATA_NAME);
615 stream->in_recv_list = true;
616
617 /*
618 * Add the stream in the recv list of the session. Once the end stream
619 * message is received, all session streams are published.
620 */
621 pthread_mutex_lock(&session->recv_list_lock);
622 cds_list_add_rcu(&stream->recv_node, &session->recv_list);
623 session->stream_count++;
624 pthread_mutex_unlock(&session->recv_list_lock);
625
626 /*
627 * Both in the ctf_trace object and the global stream ht since the data
628 * side of the relayd does not have the concept of session.
629 */
630 lttng_ht_add_unique_u64(relay_streams_ht, &stream->node);
631 stream->in_stream_ht = true;
632
633 DBG("Relay new stream added %s with ID %" PRIu64, stream->channel_name,
634 stream->stream_handle);
635 ret = 0;
636
637 end:
638 if (ret) {
639 if (stream->stream_fd) {
640 stream_fd_put(stream->stream_fd);
641 stream->stream_fd = NULL;
642 }
643 stream_put(stream);
644 stream = NULL;
645 }
646 if (acquired_reference) {
647 lttng_trace_chunk_put(current_trace_chunk);
648 }
649 return stream;
650
651 error_no_alloc:
652 /*
653 * path_name and channel_name need to be freed explicitly here
654 * because we cannot rely on stream_put().
655 */
656 free(path_name);
657 free(channel_name);
658 return NULL;
659 }
660
661 /*
662 * Called with the session lock held.
663 */
664 void stream_publish(struct relay_stream *stream)
665 {
666 struct relay_session *session;
667
668 pthread_mutex_lock(&stream->lock);
669 if (stream->published) {
670 goto unlock;
671 }
672
673 session = stream->trace->session;
674
675 pthread_mutex_lock(&session->recv_list_lock);
676 if (stream->in_recv_list) {
677 cds_list_del_rcu(&stream->recv_node);
678 stream->in_recv_list = false;
679 }
680 pthread_mutex_unlock(&session->recv_list_lock);
681
682 pthread_mutex_lock(&stream->trace->stream_list_lock);
683 cds_list_add_rcu(&stream->stream_node, &stream->trace->stream_list);
684 pthread_mutex_unlock(&stream->trace->stream_list_lock);
685
686 stream->published = true;
687 unlock:
688 pthread_mutex_unlock(&stream->lock);
689 }
690
691 /*
692 * Stream must be protected by holding the stream lock or by virtue of being
693 * called from stream_destroy.
694 */
695 static void stream_unpublish(struct relay_stream *stream)
696 {
697 if (stream->in_stream_ht) {
698 struct lttng_ht_iter iter;
699 int ret;
700
701 iter.iter.node = &stream->node.node;
702 ret = lttng_ht_del(relay_streams_ht, &iter);
703 assert(!ret);
704 stream->in_stream_ht = false;
705 }
706 if (stream->published) {
707 pthread_mutex_lock(&stream->trace->stream_list_lock);
708 cds_list_del_rcu(&stream->stream_node);
709 pthread_mutex_unlock(&stream->trace->stream_list_lock);
710 stream->published = false;
711 }
712 }
713
714 static void stream_destroy(struct relay_stream *stream)
715 {
716 if (stream->indexes_ht) {
717 /*
718 * Calling lttng_ht_destroy in call_rcu worker thread so
719 * we don't hold the RCU read-side lock while calling
720 * it.
721 */
722 lttng_ht_destroy(stream->indexes_ht);
723 }
724 if (stream->tfa) {
725 tracefile_array_destroy(stream->tfa);
726 }
727 free(stream->path_name);
728 free(stream->channel_name);
729 free(stream);
730 }
731
732 static void stream_destroy_rcu(struct rcu_head *rcu_head)
733 {
734 struct relay_stream *stream =
735 caa_container_of(rcu_head, struct relay_stream, rcu_node);
736
737 stream_destroy(stream);
738 }
739
740 /*
741 * No need to take stream->lock since this is only called on the final
742 * stream_put which ensures that a single thread may act on the stream.
743 */
744 static void stream_release(struct urcu_ref *ref)
745 {
746 struct relay_stream *stream =
747 caa_container_of(ref, struct relay_stream, ref);
748 struct relay_session *session;
749
750 session = stream->trace->session;
751
752 DBG("Releasing stream id %" PRIu64, stream->stream_handle);
753
754 pthread_mutex_lock(&session->recv_list_lock);
755 session->stream_count--;
756 if (stream->in_recv_list) {
757 cds_list_del_rcu(&stream->recv_node);
758 stream->in_recv_list = false;
759 }
760 pthread_mutex_unlock(&session->recv_list_lock);
761
762 stream_unpublish(stream);
763
764 if (stream->stream_fd) {
765 stream_fd_put(stream->stream_fd);
766 stream->stream_fd = NULL;
767 }
768 if (stream->index_file) {
769 lttng_index_file_put(stream->index_file);
770 stream->index_file = NULL;
771 }
772 if (stream->trace) {
773 ctf_trace_put(stream->trace);
774 stream->trace = NULL;
775 }
776 stream_complete_rotation(stream);
777 lttng_trace_chunk_put(stream->trace_chunk);
778 stream->trace_chunk = NULL;
779
780 call_rcu(&stream->rcu_node, stream_destroy_rcu);
781 }
782
783 void stream_put(struct relay_stream *stream)
784 {
785 rcu_read_lock();
786 assert(stream->ref.refcount != 0);
787 /*
788 * Wait until we have processed all the stream packets before
789 * actually putting our last stream reference.
790 */
791 urcu_ref_put(&stream->ref, stream_release);
792 rcu_read_unlock();
793 }
794
795 int stream_set_pending_rotation(struct relay_stream *stream,
796 struct lttng_trace_chunk *next_trace_chunk,
797 uint64_t rotation_sequence_number)
798 {
799 int ret = 0;
800 const struct relay_stream_rotation rotation = {
801 .seq_num = rotation_sequence_number,
802 .next_trace_chunk = next_trace_chunk,
803 };
804
805 if (stream->ongoing_rotation.is_set) {
806 ERR("Attempted to set a pending rotation on a stream already being rotated (protocol error)");
807 ret = -1;
808 goto end;
809 }
810
811 if (next_trace_chunk) {
812 const bool reference_acquired =
813 lttng_trace_chunk_get(next_trace_chunk);
814
815 assert(reference_acquired);
816 }
817 LTTNG_OPTIONAL_SET(&stream->ongoing_rotation, rotation);
818
819 DBG("Setting pending rotation: stream_id = %" PRIu64 ", rotation_seq_num = %" PRIu64,
820 stream->stream_handle, rotation_sequence_number);
821 if (stream->is_metadata) {
822 /*
823 * A metadata stream has no index; consider it already rotated.
824 */
825 stream->ongoing_rotation.value.index_rotated = true;
826 ret = stream_rotate_data_file(stream);
827 } else {
828 ret = try_rotate_stream_data(stream);
829 if (ret < 0) {
830 goto end;
831 }
832
833 ret = try_rotate_stream_index(stream);
834 if (ret < 0) {
835 goto end;
836 }
837 }
838 end:
839 return ret;
840 }
841
842 void try_stream_close(struct relay_stream *stream)
843 {
844 bool session_aborted;
845 struct relay_session *session = stream->trace->session;
846
847 DBG("Trying to close stream %" PRIu64, stream->stream_handle);
848
849 pthread_mutex_lock(&session->lock);
850 session_aborted = session->aborted;
851 pthread_mutex_unlock(&session->lock);
852
853 pthread_mutex_lock(&stream->lock);
854 /*
855 * Can be called concurently by connection close and reception of last
856 * pending data.
857 */
858 if (stream->closed) {
859 pthread_mutex_unlock(&stream->lock);
860 DBG("closing stream %" PRIu64 " aborted since it is already marked as closed", stream->stream_handle);
861 return;
862 }
863
864 stream->close_requested = true;
865
866 if (stream->last_net_seq_num == -1ULL) {
867 /*
868 * Handle connection close without explicit stream close
869 * command.
870 *
871 * We can be clever about indexes partially received in
872 * cases where we received the data socket part, but not
873 * the control socket part: since we're currently closing
874 * the stream on behalf of the control socket, we *know*
875 * there won't be any more control information for this
876 * socket. Therefore, we can destroy all indexes for
877 * which we have received only the file descriptor (from
878 * data socket). This takes care of consumerd crashes
879 * between sending the data and control information for
880 * a packet. Since those are sent in that order, we take
881 * care of consumerd crashes.
882 */
883 DBG("relay_index_close_partial_fd");
884 relay_index_close_partial_fd(stream);
885 /*
886 * Use the highest net_seq_num we currently have pending
887 * As end of stream indicator. Leave last_net_seq_num
888 * at -1ULL if we cannot find any index.
889 */
890 stream->last_net_seq_num = relay_index_find_last(stream);
891 DBG("Updating stream->last_net_seq_num to %" PRIu64, stream->last_net_seq_num);
892 /* Fall-through into the next check. */
893 }
894
895 if (stream->last_net_seq_num != -1ULL &&
896 ((int64_t) (stream->prev_data_seq - stream->last_net_seq_num)) < 0
897 && !session_aborted) {
898 /*
899 * Don't close since we still have data pending. This
900 * handles cases where an explicit close command has
901 * been received for this stream, and cases where the
902 * connection has been closed, and we are awaiting for
903 * index information from the data socket. It is
904 * therefore expected that all the index fd information
905 * we need has already been received on the control
906 * socket. Matching index information from data socket
907 * should be Expected Soon(TM).
908 *
909 * TODO: We should implement a timer to garbage collect
910 * streams after a timeout to be resilient against a
911 * consumerd implementation that would not match this
912 * expected behavior.
913 */
914 pthread_mutex_unlock(&stream->lock);
915 DBG("closing stream %" PRIu64 " aborted since it still has data pending", stream->stream_handle);
916 return;
917 }
918 /*
919 * We received all the indexes we can expect.
920 */
921 stream_unpublish(stream);
922 stream->closed = true;
923 /* Relay indexes are only used by the "consumer/sessiond" end. */
924 relay_index_close_all(stream);
925
926 /*
927 * If we are closed by an application exiting (per-pid buffers),
928 * we need to put our reference on the stream trace chunk right
929 * away, because otherwise still holding the reference on the
930 * trace chunk could allow a viewer stream (which holds a reference
931 * to the stream) to postpone destroy waiting for the chunk to cease
932 * to exist endlessly until the viewer is detached.
933 */
934
935 /* Put stream fd before put chunk. */
936 if (stream->stream_fd) {
937 stream_fd_put(stream->stream_fd);
938 stream->stream_fd = NULL;
939 }
940 if (stream->index_file) {
941 lttng_index_file_put(stream->index_file);
942 stream->index_file = NULL;
943 }
944 lttng_trace_chunk_put(stream->trace_chunk);
945 stream->trace_chunk = NULL;
946 pthread_mutex_unlock(&stream->lock);
947 DBG("Succeeded in closing stream %" PRIu64, stream->stream_handle);
948 stream_put(stream);
949 }
950
951 int stream_init_packet(struct relay_stream *stream, size_t packet_size,
952 bool *file_rotated)
953 {
954 int ret = 0;
955
956 ASSERT_LOCKED(stream->lock);
957
958 if (!stream->stream_fd || !stream->trace_chunk) {
959 ERR("Protocol error: received a packet for a stream that doesn't have a current trace chunk: stream_id = %" PRIu64 ", channel_name = %s",
960 stream->stream_handle, stream->channel_name);
961 ret = -1;
962 goto end;
963 }
964
965 if (caa_likely(stream->tracefile_size == 0)) {
966 /* No size limit set; nothing to check. */
967 goto end;
968 }
969
970 /*
971 * Check if writing the new packet would exceed the maximal file size.
972 */
973 if (caa_unlikely((stream->tracefile_size_current + packet_size) >
974 stream->tracefile_size)) {
975 const uint64_t new_file_index =
976 (stream->tracefile_current_index + 1) %
977 stream->tracefile_count;
978
979 if (new_file_index < stream->tracefile_current_index) {
980 stream->tracefile_wrapped_around = true;
981 }
982 DBG("New stream packet causes stream file rotation: stream_id = %" PRIu64
983 ", current_file_size = %" PRIu64
984 ", packet_size = %zu, current_file_index = %" PRIu64
985 " new_file_index = %" PRIu64,
986 stream->stream_handle,
987 stream->tracefile_size_current, packet_size,
988 stream->tracefile_current_index, new_file_index);
989 tracefile_array_file_rotate(stream->tfa, TRACEFILE_ROTATE_WRITE);
990 stream->tracefile_current_index = new_file_index;
991
992 if (stream->stream_fd) {
993 stream_fd_put(stream->stream_fd);
994 stream->stream_fd = NULL;
995 }
996 ret = stream_create_data_output_file_from_trace_chunk(stream,
997 stream->trace_chunk, false, &stream->stream_fd);
998 if (ret) {
999 ERR("Failed to perform trace file rotation of stream %" PRIu64,
1000 stream->stream_handle);
1001 goto end;
1002 }
1003
1004 /*
1005 * Reset current size because we just performed a stream
1006 * rotation.
1007 */
1008 stream->tracefile_size_current = 0;
1009 *file_rotated = true;
1010 } else {
1011 *file_rotated = false;
1012 }
1013 end:
1014 return ret;
1015 }
1016
1017 /* Note that the packet is not necessarily complete. */
1018 int stream_write(struct relay_stream *stream,
1019 const struct lttng_buffer_view *packet, size_t padding_len)
1020 {
1021 int ret = 0;
1022 ssize_t write_ret;
1023 size_t padding_to_write = padding_len;
1024 char padding_buffer[FILE_IO_STACK_BUFFER_SIZE];
1025
1026 ASSERT_LOCKED(stream->lock);
1027 memset(padding_buffer, 0,
1028 min(sizeof(padding_buffer), padding_to_write));
1029
1030 if (!stream->stream_fd || !stream->trace_chunk) {
1031 ERR("Protocol error: received a packet for a stream that doesn't have a current trace chunk: stream_id = %" PRIu64 ", channel_name = %s",
1032 stream->stream_handle, stream->channel_name);
1033 ret = -1;
1034 goto end;
1035 }
1036 if (packet) {
1037 write_ret = lttng_write(stream->stream_fd->fd,
1038 packet->data, packet->size);
1039 if (write_ret != packet->size) {
1040 PERROR("Failed to write to stream file of %sstream %" PRIu64,
1041 stream->is_metadata ? "metadata " : "",
1042 stream->stream_handle);
1043 ret = -1;
1044 goto end;
1045 }
1046 }
1047
1048 while (padding_to_write > 0) {
1049 const size_t padding_to_write_this_pass =
1050 min(padding_to_write, sizeof(padding_buffer));
1051
1052 write_ret = lttng_write(stream->stream_fd->fd,
1053 padding_buffer, padding_to_write_this_pass);
1054 if (write_ret != padding_to_write_this_pass) {
1055 PERROR("Failed to write padding to file of %sstream %" PRIu64,
1056 stream->is_metadata ? "metadata " : "",
1057 stream->stream_handle);
1058 ret = -1;
1059 goto end;
1060 }
1061 padding_to_write -= padding_to_write_this_pass;
1062 }
1063
1064 if (stream->is_metadata) {
1065 stream->metadata_received += packet ? packet->size : 0;
1066 stream->metadata_received += padding_len;
1067 }
1068
1069 DBG("Wrote to %sstream %" PRIu64 ": data_length = %zu, padding_length = %zu",
1070 stream->is_metadata ? "metadata " : "",
1071 stream->stream_handle,
1072 packet ? packet->size : (size_t) 0, padding_len);
1073 end:
1074 return ret;
1075 }
1076
1077 /*
1078 * Update index after receiving a packet for a data stream.
1079 *
1080 * Called with the stream lock held.
1081 *
1082 * Return 0 on success else a negative value.
1083 */
1084 int stream_update_index(struct relay_stream *stream, uint64_t net_seq_num,
1085 bool rotate_index, bool *flushed, uint64_t total_size)
1086 {
1087 int ret = 0;
1088 uint64_t data_offset;
1089 struct relay_index *index;
1090
1091 assert(stream->trace_chunk);
1092 ASSERT_LOCKED(stream->lock);
1093 /* Get data offset because we are about to update the index. */
1094 data_offset = htobe64(stream->tracefile_size_current);
1095
1096 DBG("handle_index_data: stream %" PRIu64 " net_seq_num %" PRIu64 " data offset %" PRIu64,
1097 stream->stream_handle, net_seq_num, stream->tracefile_size_current);
1098
1099 /*
1100 * Lookup for an existing index for that stream id/sequence
1101 * number. If it exists, the control thread has already received the
1102 * data for it, thus we need to write it to disk.
1103 */
1104 index = relay_index_get_by_id_or_create(stream, net_seq_num);
1105 if (!index) {
1106 ret = -1;
1107 goto end;
1108 }
1109
1110 if (rotate_index || !stream->index_file) {
1111 ret = create_index_file(stream, stream->trace_chunk);
1112 if (ret) {
1113 ERR("Failed to create index file for stream %" PRIu64,
1114 stream->stream_handle);
1115 /* Put self-ref for this index due to error. */
1116 relay_index_put(index);
1117 index = NULL;
1118 goto end;
1119 }
1120 }
1121
1122 if (relay_index_set_file(index, stream->index_file, data_offset)) {
1123 ret = -1;
1124 /* Put self-ref for this index due to error. */
1125 relay_index_put(index);
1126 index = NULL;
1127 goto end;
1128 }
1129
1130 ret = relay_index_try_flush(index);
1131 if (ret == 0) {
1132 tracefile_array_file_rotate(stream->tfa, TRACEFILE_ROTATE_READ);
1133 tracefile_array_commit_seq(stream->tfa);
1134 stream->index_received_seqcount++;
1135 *flushed = true;
1136 } else if (ret > 0) {
1137 index->total_size = total_size;
1138 /* No flush. */
1139 ret = 0;
1140 } else {
1141 /*
1142 * ret < 0
1143 *
1144 * relay_index_try_flush is responsible for the self-reference
1145 * put of the index object on error.
1146 */
1147 ERR("relay_index_try_flush error %d", ret);
1148 ret = -1;
1149 }
1150 end:
1151 return ret;
1152 }
1153
1154 int stream_complete_packet(struct relay_stream *stream, size_t packet_total_size,
1155 uint64_t sequence_number, bool index_flushed)
1156 {
1157 int ret = 0;
1158
1159 ASSERT_LOCKED(stream->lock);
1160
1161 stream->tracefile_size_current += packet_total_size;
1162 if (index_flushed) {
1163 stream->pos_after_last_complete_data_index =
1164 stream->tracefile_size_current;
1165 stream->prev_index_seq = sequence_number;
1166 ret = try_rotate_stream_index(stream);
1167 if (ret < 0) {
1168 goto end;
1169 }
1170 }
1171
1172 stream->prev_data_seq = sequence_number;
1173 ret = try_rotate_stream_data(stream);
1174
1175 end:
1176 return ret;
1177 }
1178
1179 int stream_add_index(struct relay_stream *stream,
1180 const struct lttcomm_relayd_index *index_info)
1181 {
1182 int ret = 0;
1183 struct relay_index *index;
1184
1185 ASSERT_LOCKED(stream->lock);
1186
1187 /* Live beacon handling */
1188 if (index_info->packet_size == 0) {
1189 DBG("Received live beacon for stream %" PRIu64,
1190 stream->stream_handle);
1191
1192 /*
1193 * Only flag a stream inactive when it has already
1194 * received data and no indexes are in flight.
1195 */
1196 if (stream->index_received_seqcount > 0
1197 && stream->indexes_in_flight == 0) {
1198 stream->beacon_ts_end = index_info->timestamp_end;
1199 }
1200 ret = 0;
1201 goto end;
1202 } else {
1203 stream->beacon_ts_end = -1ULL;
1204 }
1205
1206 if (stream->ctf_stream_id == -1ULL) {
1207 stream->ctf_stream_id = index_info->stream_id;
1208 }
1209
1210 index = relay_index_get_by_id_or_create(stream, index_info->net_seq_num);
1211 if (!index) {
1212 ret = -1;
1213 ERR("Failed to get or create index %" PRIu64,
1214 index_info->net_seq_num);
1215 goto end;
1216 }
1217 if (relay_index_set_control_data(index, index_info,
1218 stream->trace->session->minor)) {
1219 ERR("set_index_control_data error");
1220 relay_index_put(index);
1221 ret = -1;
1222 goto end;
1223 }
1224 ret = relay_index_try_flush(index);
1225 if (ret == 0) {
1226 tracefile_array_file_rotate(stream->tfa, TRACEFILE_ROTATE_READ);
1227 tracefile_array_commit_seq(stream->tfa);
1228 stream->index_received_seqcount++;
1229 stream->pos_after_last_complete_data_index += index->total_size;
1230 stream->prev_index_seq = index_info->net_seq_num;
1231
1232 ret = try_rotate_stream_index(stream);
1233 if (ret < 0) {
1234 goto end;
1235 }
1236 } else if (ret > 0) {
1237 /* no flush. */
1238 ret = 0;
1239 } else {
1240 /*
1241 * ret < 0
1242 *
1243 * relay_index_try_flush is responsible for the self-reference
1244 * put of the index object on error.
1245 */
1246 ERR("relay_index_try_flush error %d", ret);
1247 ret = -1;
1248 }
1249 end:
1250 return ret;
1251 }
1252
1253 static void print_stream_indexes(struct relay_stream *stream)
1254 {
1255 struct lttng_ht_iter iter;
1256 struct relay_index *index;
1257
1258 rcu_read_lock();
1259 cds_lfht_for_each_entry(stream->indexes_ht->ht, &iter.iter, index,
1260 index_n.node) {
1261 DBG("index %p net_seq_num %" PRIu64 " refcount %ld"
1262 " stream %" PRIu64 " trace %" PRIu64
1263 " session %" PRIu64,
1264 index,
1265 index->index_n.key,
1266 stream->ref.refcount,
1267 index->stream->stream_handle,
1268 index->stream->trace->id,
1269 index->stream->trace->session->id);
1270 }
1271 rcu_read_unlock();
1272 }
1273
1274 int stream_reset_file(struct relay_stream *stream)
1275 {
1276 ASSERT_LOCKED(stream->lock);
1277
1278 if (stream->stream_fd) {
1279 stream_fd_put(stream->stream_fd);
1280 stream->stream_fd = NULL;
1281 }
1282
1283 stream->tracefile_size_current = 0;
1284 stream->prev_data_seq = 0;
1285 stream->prev_index_seq = 0;
1286 /* Note that this does not reset the tracefile array. */
1287 stream->tracefile_current_index = 0;
1288 stream->pos_after_last_complete_data_index = 0;
1289
1290 return stream_create_data_output_file_from_trace_chunk(stream,
1291 stream->trace_chunk, true, &stream->stream_fd);
1292 }
1293
1294 void print_relay_streams(void)
1295 {
1296 struct lttng_ht_iter iter;
1297 struct relay_stream *stream;
1298
1299 if (!relay_streams_ht) {
1300 return;
1301 }
1302
1303 rcu_read_lock();
1304 cds_lfht_for_each_entry(relay_streams_ht->ht, &iter.iter, stream,
1305 node.node) {
1306 if (!stream_get(stream)) {
1307 continue;
1308 }
1309 DBG("stream %p refcount %ld stream %" PRIu64 " trace %" PRIu64
1310 " session %" PRIu64,
1311 stream,
1312 stream->ref.refcount,
1313 stream->stream_handle,
1314 stream->trace->id,
1315 stream->trace->session->id);
1316 print_stream_indexes(stream);
1317 stream_put(stream);
1318 }
1319 rcu_read_unlock();
1320 }
This page took 0.091004 seconds and 3 git commands to generate.