src.ctf.fs: pass clkClsCfg to ctf_fs_component constructor
[deliverable/babeltrace.git] / src / plugins / ctf / fs-src / query.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 *
6 * Babeltrace CTF file system Reader Component queries
7 */
8
9 #define BT_CLOG_CFG logCfg
10 #define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/QUERY"
11
12 #include "query.hpp"
13 #include <stdbool.h>
14 #include <glib.h>
15 #include <glib/gstdio.h>
16 #include <fcntl.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include "common/assert.h"
20 #include "metadata.hpp"
21 #include "../common/src/metadata/tsdl/metadata-stream-decoder.hpp"
22 #include "../common/src/metadata/metadata-stream-parser-utils.hpp"
23 #include "common/common.h"
24 #include "common/macros.h"
25 #include "plugins/common/param-validation/param-validation.h"
26 #include <babeltrace2/babeltrace.h>
27 #include "fs.hpp"
28 #include "cpp-common/cfg-logging-error-reporting.hpp"
29 #include "cpp-common/cfg-logging-error-reporting-throw.hpp"
30 #include "cpp-common/libc-up.hpp"
31 #include "cpp-common/exc.hpp"
32 #include "cpp-common/file-utils.hpp"
33 #include "cpp-common/make-unique.hpp"
34
35 #define METADATA_TEXT_SIG "/* CTF 1.8"
36
37 struct range
38 {
39 int64_t begin_ns = 0;
40 int64_t end_ns = 0;
41 bool set = false;
42 };
43
44 static struct bt_param_validation_map_value_entry_descr metadataInfoQueryParamsDesc[] = {
45 {"path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
46 bt_param_validation_value_descr::makeString()},
47 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
48
49 BT_HIDDEN
50 bt2::Value::Shared metadata_info_query(bt2::ConstMapValue params, const bt2_common::LogCfg& logCfg)
51 {
52 gchar *validateError = NULL;
53 auto validationStatus = bt_param_validation_validate(
54 params.libObjPtr(), metadataInfoQueryParamsDesc, &validateError);
55
56 if (validationStatus == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
57 throw bt2_common::MemoryError {};
58 } else if (validationStatus == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
59 const std::string error {validateError};
60
61 g_free(validateError);
62 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "%s", error.data());
63 }
64
65 const auto path = params["path"]->asString().value();
66
67 try {
68 const auto buffer =
69 bt2_common::dataFromFile(std::string {path.to_string() + "/metadata"}.c_str());
70
71 ctf::src::MetadataStreamDecoder decoder {logCfg};
72
73 auto plainText =
74 decoder.decode(buffer.data(), bt2_common::DataLen::fromBytes(buffer.size()));
75
76 auto result = bt2::MapValue::create();
77 /*
78 * If the metadata does not already start with the plaintext metadata
79 * signature, prepend it.
80 */
81 if (plainText.rfind(METADATA_TEXT_SIG, 0) != 0) {
82 plainText.insert(0, std::string {METADATA_TEXT_SIG} + " */\n\n");
83 }
84
85 result->insert("text", plainText.data());
86
87 result->insert("is-packetized", decoder.pktInfo().has_value());
88 return result;
89 } catch (const bt2_common::Error&) {
90 BT_CLOGE_APPEND_CAUSE_AND_RETHROW("Error getting plaintext metadata section from file");
91 }
92 }
93
94 static void add_range(bt2::MapValue info, struct range *range, const char *range_name)
95 {
96 if (!range->set) {
97 /* Not an error. */
98 return;
99 }
100
101 bt2::MapValue rangeMap = info.insertEmptyMap(range_name);
102 rangeMap.insert("begin", range->begin_ns);
103 rangeMap.insert("end", range->end_ns);
104 }
105
106 static void populate_stream_info(struct ctf_fs_ds_file_group *group, bt2::MapValue groupInfo,
107 struct range *stream_range, const bt2_common::LogCfg& logCfg)
108 {
109 /*
110 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
111 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
112 * the timestamp_begin of the first index entry and the timestamp_end
113 * of the last index entry.
114 */
115 BT_ASSERT(!group->index.entries.empty());
116
117 /* First entry. */
118 const ctf_fs_ds_index_entry& first_ds_index_entry = group->index.entries.front();
119
120 /* Last entry. */
121 const ctf_fs_ds_index_entry& last_ds_index_entry = group->index.entries.back();
122
123 stream_range->begin_ns = first_ds_index_entry.timestamp_begin_ns;
124 stream_range->end_ns = last_ds_index_entry.timestamp_end_ns;
125
126 /*
127 * If any of the begin and end timestamps is not set it means that
128 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
129 * in their packet context so we can't set the range.
130 */
131 stream_range->set =
132 stream_range->begin_ns != UINT64_C(-1) && stream_range->end_ns != UINT64_C(-1);
133
134 add_range(groupInfo, stream_range, "range-ns");
135
136 std::string portName = ctf_fs_make_port_name(group);
137 groupInfo.insert("port-name", portName.c_str());
138 }
139
140 static void populate_trace_info(const struct ctf_fs_trace *trace, bt2::MapValue traceInfo,
141 const bt2_common::LogCfg& logCfg)
142 {
143 /* Add trace range info only if it contains streams. */
144 if (trace->ds_file_groups.empty()) {
145 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "Trace has no streams: trace-path=%s",
146 trace->path.c_str());
147 }
148
149 bt2::ArrayValue fileGroups = traceInfo.insertEmptyArray("stream-infos");
150
151 /* Find range of all stream groups, and of the trace. */
152 for (const ctf_fs_ds_file_group::UP& group : trace->ds_file_groups) {
153 range group_range;
154 bt2::MapValue groupInfo = fileGroups.appendEmptyMap();
155 populate_stream_info(group.get(), groupInfo, &group_range, logCfg);
156 }
157 }
158
159 BT_HIDDEN
160 bt2::Value::Shared trace_infos_query(bt2::ConstMapValue params, const bt2_common::LogCfg& logCfg)
161 {
162 ctf::src::fs::Parameters parameters = read_src_fs_parameters(params, logCfg);
163 ctf_fs_component::UP ctf_fs =
164 bt2_common::makeUnique<ctf_fs_component>(parameters.clkClsCfg, logCfg);
165
166 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs.get(), parameters.inputs, parameters.traceName,
167 nullptr)) {
168 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "Failed to create trace");
169 }
170
171 bt2::ArrayValue::Shared result = bt2::ArrayValue::create();
172 bt2::MapValue traceInfo = result->appendEmptyMap();
173 populate_trace_info(ctf_fs->trace.get(), traceInfo, logCfg);
174
175 return result;
176 }
177
178 static struct bt_param_validation_map_value_entry_descr supportInfoQueryParamsDesc[] = {
179 {"type", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
180 bt_param_validation_value_descr::makeString()},
181 {"input", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
182 bt_param_validation_value_descr::makeString()},
183 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
184
185 BT_HIDDEN
186 bt2::Value::Shared support_info_query(bt2::ConstMapValue params, const bt2_common::LogCfg& logCfg)
187 {
188 gchar *validateError = NULL;
189 auto validationStatus = bt_param_validation_validate(
190 params.libObjPtr(), supportInfoQueryParamsDesc, &validateError);
191
192 if (validationStatus == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
193 throw bt2_common::MemoryError {};
194 } else if (validationStatus == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
195 const std::string error {validateError};
196
197 g_free(validateError);
198 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "%s", error.data());
199 }
200
201 bpstd::string_view type = params["type"]->asString().value();
202
203 if (type != "directory") {
204 /*
205 * The input type is not a directory so we are 100% sure it's not a CTF
206 * 1.8 trace as it would need a directory with at least 1 metadata file
207 * and 1 data stream file.
208 */
209 bt2::MapValue::Shared result = bt2::MapValue::create();
210 result->insert("weight", 0.0f);
211 return result;
212 }
213
214 bpstd::string_view input = params["input"]->asString().value();
215
216 auto result = bt2::MapValue::create();
217 try {
218 const auto buffer =
219 bt2_common::dataFromFile(std::string {input.to_string() + "/metadata"}.c_str());
220 ctf::src::MetadataStreamParser::ParseRet parseRet = ctf::src::parseMetadataStream(
221 {}, nullptr, buffer.data(), buffer.data() + buffer.size(), logCfg);
222 ctf::src::TraceCls *ctfTraceCls = parseRet.first.get();
223 BT_ASSERT(ctfTraceCls);
224
225 /*
226 * We were able to parse the metadata file, so we are confident it's a
227 * CTF trace.
228 */
229 result->insert("weight", 0.75);
230 if (ctfTraceCls->uuid()) {
231 result->insert("group", ctfTraceCls->uuid()->str());
232 }
233 } catch (const bt2_common::NoSuchFileOrDirectoryError&) {
234 /*
235 * Failing to find the metadata file is not an error, it simply
236 * indicates that the directory is not a trace. Report appropriate
237 * weight of zero.
238 */
239 bt_current_thread_clear_error();
240 result->insert("weight", 0.0);
241 }
242 return result;
243 }
This page took 0.056621 seconds and 5 git commands to generate.