e90b352ee46c1f56e81fb01d8b730586fa5f935c
[babeltrace.git] / src / plugins / ctf / lttng-live / metadata.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
5 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 */
8
9 #include "compat/memstream.h"
10
11 #include "../common/src/metadata/tsdl/ctf-meta-configure-ir-trace.hpp"
12 #include "../common/src/metadata/tsdl/decoder.hpp"
13 #include "lttng-live.hpp"
14 #include "metadata.hpp"
15
16 #define TSDL_MAGIC 0x75d11d57
17
18 struct packet_header
19 {
20 uint32_t magic;
21 uint8_t uuid[16];
22 uint32_t checksum;
23 uint32_t content_size;
24 uint32_t packet_size;
25 uint8_t compression_scheme;
26 uint8_t encryption_scheme;
27 uint8_t checksum_scheme;
28 uint8_t major;
29 uint8_t minor;
30 } __attribute__((__packed__));
31
32 static bool stream_classes_all_have_default_clock_class(bt_trace_class *tc,
33 const bt2c::Logger& logger)
34 {
35 uint64_t i, sc_count;
36 const bt_clock_class *cc = NULL;
37 const bt_stream_class *sc;
38 bool ret = true;
39
40 sc_count = bt_trace_class_get_stream_class_count(tc);
41 for (i = 0; i < sc_count; i++) {
42 sc = bt_trace_class_borrow_stream_class_by_index_const(tc, i);
43
44 BT_ASSERT(sc);
45
46 cc = bt_stream_class_borrow_default_clock_class_const(sc);
47 if (!cc) {
48 ret = false;
49 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger,
50 "Stream class doesn't have a default clock class: "
51 "sc-id={}, sc-name=\"{}\"",
52 bt_stream_class_get_id(sc), bt_stream_class_get_name(sc));
53 goto end;
54 }
55 }
56
57 end:
58 return ret;
59 }
60 /*
61 * Iterate over the stream classes and returns the first clock class
62 * encountered. This is useful to create message iterator inactivity message as
63 * we don't need a particular clock class.
64 */
65 static const bt_clock_class *borrow_any_clock_class(bt_trace_class *tc)
66 {
67 uint64_t i, sc_count;
68 const bt_clock_class *cc = NULL;
69 const bt_stream_class *sc;
70
71 sc_count = bt_trace_class_get_stream_class_count(tc);
72 for (i = 0; i < sc_count; i++) {
73 sc = bt_trace_class_borrow_stream_class_by_index_const(tc, i);
74 BT_ASSERT_DBG(sc);
75
76 cc = bt_stream_class_borrow_default_clock_class_const(sc);
77 if (cc) {
78 goto end;
79 }
80 }
81 end:
82 BT_ASSERT_DBG(cc);
83 return cc;
84 }
85
86 enum lttng_live_iterator_status lttng_live_metadata_update(struct lttng_live_trace *trace)
87 {
88 struct lttng_live_session *session = trace->session;
89 struct lttng_live_metadata *metadata = trace->metadata;
90 size_t size, len_read = 0;
91 char *metadata_buf = NULL;
92 bool keep_receiving;
93 FILE *fp = NULL;
94 enum ctf_metadata_decoder_status decoder_status;
95 enum lttng_live_iterator_status status = LTTNG_LIVE_ITERATOR_STATUS_OK;
96 enum lttng_live_get_one_metadata_status metadata_status;
97
98 BT_CPPLOGD_SPEC(metadata->logger, "Updating metadata for trace: session-id={}, trace-id={}",
99 session->id, trace->id);
100
101 /* No metadata stream yet. */
102 if (!metadata) {
103 if (session->closed) {
104 /*
105 * The session is closed AND we never received any
106 * metadata this indicates that we will never receive
107 * any metadata.
108 */
109 status = LTTNG_LIVE_ITERATOR_STATUS_END;
110 } else if (session->new_streams_needed) {
111 status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
112 } else {
113 session->new_streams_needed = true;
114 status = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
115 }
116 goto end;
117 }
118
119 if (trace->metadata_stream_state != LTTNG_LIVE_METADATA_STREAM_STATE_NEEDED) {
120 goto end;
121 }
122
123 /*
124 * Open a new write only file handle to populate the `metadata_buf`
125 * memory buffer so we can write in loop in it easily.
126 */
127 fp = bt_open_memstream(&metadata_buf, &size);
128 if (!fp) {
129 if (errno == EINTR && lttng_live_graph_is_canceled(session->lttng_live_msg_iter)) {
130 session->lttng_live_msg_iter->was_interrupted = true;
131 status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
132 } else {
133 BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(metadata->logger, "Metadata open_memstream", ".");
134 status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
135 }
136 goto end;
137 }
138
139 keep_receiving = true;
140 /* Grab all available metadata. */
141 while (keep_receiving) {
142 size_t reply_len = 0;
143 /*
144 * lttng_live_get_one_metadata_packet() asks the Relay Daemon
145 * for new metadata. If new metadata is received, the function
146 * writes it to the provided file handle and updates the
147 * reply_len output parameter. We call this function in loop
148 * until it returns _END meaning that no new metadata is
149 * available.
150 * We may receive a _CLOSED status if the metadata stream we
151 * are requesting is no longer available on the relay.
152 * If we receive an _ERROR status, it means there was a
153 * networking, allocating, or some other unrecoverable error.
154 */
155 metadata_status = lttng_live_get_one_metadata_packet(trace, fp, &reply_len);
156
157 switch (metadata_status) {
158 case LTTNG_LIVE_GET_ONE_METADATA_STATUS_OK:
159 len_read += reply_len;
160 break;
161 case LTTNG_LIVE_GET_ONE_METADATA_STATUS_END:
162 keep_receiving = false;
163 break;
164 case LTTNG_LIVE_GET_ONE_METADATA_STATUS_CLOSED:
165 BT_CPPLOGD_SPEC(
166 metadata->logger,
167 "Metadata stream was closed by the Relay, the trace is no longer active: "
168 "trace-id={}, metadata-stream-id={}",
169 trace->id, metadata->stream_id);
170 /*
171 * The stream was closed and we received everything
172 * there was to receive for this metadata stream.
173 * We go on with the decoding of what we received. So
174 * that data stream can be decoded.
175 */
176 keep_receiving = false;
177 trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_CLOSED;
178 break;
179 case LTTNG_LIVE_GET_ONE_METADATA_STATUS_ERROR:
180 BT_CPPLOGE_APPEND_CAUSE_SPEC(metadata->logger,
181 "Error getting one trace metadata packet: trace-id={}",
182 trace->id);
183 goto error;
184 default:
185 bt_common_abort();
186 }
187 }
188
189 /* The memory buffer `metadata_buf` contains all the metadata. */
190 if (bt_close_memstream(&metadata_buf, &size, fp)) {
191 BT_CPPLOGW_ERRNO_SPEC(metadata->logger, "Metadata bt_close_memstream", ".");
192 }
193
194 fp = NULL;
195
196 if (len_read == 0) {
197 if (!trace->trace) {
198 status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
199 goto end;
200 }
201
202 /* The relay sent zero bytes of metadata. */
203 trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NOT_NEEDED;
204 goto end;
205 }
206
207 /*
208 * Open a new reading file handle on the `metadata_buf` and pass it to
209 * the metadata decoder.
210 */
211 fp = bt_fmemopen(metadata_buf, len_read, "rb");
212 if (!fp) {
213 if (errno == EINTR && lttng_live_graph_is_canceled(session->lttng_live_msg_iter)) {
214 session->lttng_live_msg_iter->was_interrupted = true;
215 status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
216 } else {
217 BT_CPPLOGE_ERRNO_APPEND_CAUSE_SPEC(metadata->logger,
218 "Cannot memory-open metadata buffer", ".");
219 status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
220 }
221 goto end;
222 }
223
224 /*
225 * The call to ctf_metadata_decoder_append_content() will append
226 * new metadata to our current trace class.
227 */
228 BT_CPPLOGD_SPEC(metadata->logger, "Appending new metadata to the ctf_trace class");
229 decoder_status = ctf_metadata_decoder_append_content(metadata->decoder.get(), fp);
230 switch (decoder_status) {
231 case CTF_METADATA_DECODER_STATUS_OK:
232 if (!trace->trace_class) {
233 struct ctf_trace_class *tc =
234 ctf_metadata_decoder_borrow_ctf_trace_class(metadata->decoder.get());
235
236 trace->trace_class = ctf_metadata_decoder_get_ir_trace_class(metadata->decoder.get());
237 trace->trace = bt_trace_create(trace->trace_class);
238 if (!trace->trace) {
239 BT_CPPLOGE_APPEND_CAUSE_SPEC(metadata->logger, "Failed to create bt_trace");
240 goto error;
241 }
242 if (ctf_trace_class_configure_ir_trace(tc, trace->trace)) {
243 BT_CPPLOGE_APPEND_CAUSE_SPEC(metadata->logger,
244 "Failed to configure ctf trace class");
245 goto error;
246 }
247 if (!stream_classes_all_have_default_clock_class(trace->trace_class,
248 metadata->logger)) {
249 /* Error logged in function. */
250 goto error;
251 }
252 trace->clock_class = borrow_any_clock_class(trace->trace_class);
253 }
254
255 /* The metadata was updated successfully. */
256 trace->metadata_stream_state = LTTNG_LIVE_METADATA_STREAM_STATE_NOT_NEEDED;
257
258 break;
259 default:
260 goto error;
261 }
262
263 goto end;
264
265 error:
266 status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
267 end:
268 if (fp) {
269 int closeret;
270
271 closeret = fclose(fp);
272 if (closeret) {
273 BT_CPPLOGW_ERRNO_SPEC(metadata->logger, "Error on fclose", ".");
274 }
275 }
276 free(metadata_buf);
277 return status;
278 }
279
280 int lttng_live_metadata_create_stream(struct lttng_live_session *session, uint64_t ctf_trace_id,
281 uint64_t stream_id)
282 {
283 struct lttng_live_trace *trace;
284
285 ctf_metadata_decoder_config cfg {session->logger};
286 cfg.self_comp = session->self_comp;
287 cfg.clock_class_offset_s = 0;
288 cfg.clock_class_offset_ns = 0;
289 cfg.create_trace_class = true;
290
291 lttng_live_metadata *metadata = new lttng_live_metadata {session->logger};
292 metadata->stream_id = stream_id;
293
294 metadata->decoder = ctf_metadata_decoder_create(&cfg);
295 if (!metadata->decoder) {
296 BT_CPPLOGE_APPEND_CAUSE_SPEC(session->logger, "Failed to create CTF metadata decoder");
297 goto error;
298 }
299 trace = lttng_live_session_borrow_or_create_trace_by_id(session, ctf_trace_id);
300 if (!trace) {
301 BT_CPPLOGE_APPEND_CAUSE_SPEC(session->logger, "Failed to borrow trace");
302 goto error;
303 }
304 trace->metadata = metadata;
305 return 0;
306
307 error:
308 delete metadata;
309 return -1;
310 }
311
312 void lttng_live_metadata_fini(struct lttng_live_trace *trace)
313 {
314 struct lttng_live_metadata *metadata = trace->metadata;
315
316 if (!metadata) {
317 return;
318 }
319 trace->metadata = NULL;
320 delete metadata;
321 }
This page took 0.036409 seconds and 3 git commands to generate.