tests/cli/test-intersection.sh: rewrite test to avoid shellcheck warning
[babeltrace.git] / src / plugins / ctf / fs-src / query.cpp
CommitLineData
04c0ba87 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
04c0ba87
JG
3 *
4 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 *
0235b0db 6 * Babeltrace CTF file system Reader Component queries
04c0ba87
JG
7 */
8
c802cacb
SM
9#include <glib.h>
10#include <glib/gstdio.h>
c802cacb
SM
11#include <sys/types.h>
12
13#include <babeltrace2/babeltrace.h>
14
c02af779 15#include "cpp-common/bt2/exc.hpp"
a9a4f6b9 16#include "cpp-common/bt2c/file-utils.hpp"
69d91bb3 17#include "cpp-common/bt2c/glib-up.hpp"
8d049eb2 18
69d91bb3
SM
19#include "plugins/common/param-validation/param-validation.h"
20
a9a4f6b9
FD
21#include "../common/src/metadata/metadata-stream-parser-utils.hpp"
22#include "../common/src/metadata/tsdl/metadata-stream-decoder.hpp"
873c329a 23#include "data-stream-file.hpp"
087cd0f5 24#include "fs.hpp"
cdf7de78 25#include "metadata.hpp"
c802cacb 26#include "query.hpp"
55314f2a 27
4164020e 28#define METADATA_TEXT_SIG "/* CTF 1.8"
04c0ba87 29
4164020e
SM
30struct range
31{
32 int64_t begin_ns = 0;
33 int64_t end_ns = 0;
34 bool set = false;
97ade20b
JG
35};
36
69d91bb3
SM
37static bt_param_validation_map_value_entry_descr metadataInfoQueryParamsDesc[] = {
38 {"path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
39 bt_param_validation_value_descr::makeString()},
40 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
41
c02af779 42bt2::Value::Shared metadata_info_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
04c0ba87 43{
69d91bb3
SM
44 gchar *validateError = nullptr;
45 const auto validationStatus = bt_param_validation_validate(
46 params.libObjPtr(), metadataInfoQueryParamsDesc, &validateError);
4164020e 47
69d91bb3
SM
48 if (validationStatus == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
49 throw bt2::MemoryError {};
50 } else if (validationStatus == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
51 const bt2c::GCharUP deleter {validateError};
52
53 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "{}", validateError);
4164020e
SM
54 }
55
69d91bb3 56 const auto path = params["path"]->asString().value();
4164020e 57
a9a4f6b9
FD
58 try {
59 const auto buffer = bt2c::dataFromFile(fmt::format("{}/metadata", path), logger, true);
60 ctf::src::MetadataStreamDecoder decoder {logger};
61 auto plainText = decoder.decode(buffer);
62 const auto result = bt2::MapValue::create();
4164020e 63
a9a4f6b9
FD
64 /*
65 * If the metadata does not already start with the plaintext metadata
66 * signature, prepend it.
67 */
68 if (plainText.rfind(METADATA_TEXT_SIG, 0) != 0) {
69 plainText.insert(0, std::string {METADATA_TEXT_SIG} + " */\n\n");
70 }
c719eabb 71
a9a4f6b9
FD
72 result->insert("text", plainText.data());
73 result->insert("is-packetized", decoder.pktInfo().has_value());
74 return result;
75 } catch (const bt2c::Error&) {
76 BT_CPPLOGE_APPEND_CAUSE_AND_RETHROW_SPEC(logger, "Error reading metadata file");
4164020e 77 }
97ade20b 78}
9ec238a8 79
f9f2dd71 80static void add_range(const bt2::MapValue info, const range& range, const char *range_name)
97ade20b 81{
f9f2dd71 82 if (!range.set) {
4164020e 83 /* Not an error. */
c02af779 84 return;
4164020e
SM
85 }
86
c02af779 87 const auto rangeMap = info.insertEmptyMap(range_name);
f9f2dd71
SM
88 rangeMap.insert("begin", range.begin_ns);
89 rangeMap.insert("end", range.end_ns);
97ade20b
JG
90}
91
f9f2dd71 92static void populate_stream_info(struct ctf_fs_ds_file_group *group, const bt2::MapValue groupInfo)
97ade20b 93{
4164020e
SM
94 /*
95 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
96 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
97 * the timestamp_begin of the first index entry and the timestamp_end
98 * of the last index entry.
99 */
c46b32d8 100 BT_ASSERT(!group->index.entries.empty());
4164020e
SM
101
102 /* First entry. */
c46b32d8 103 const auto& first_ds_index_entry = group->index.entries.front();
4164020e
SM
104
105 /* Last entry. */
c46b32d8 106 const auto& last_ds_index_entry = group->index.entries.back();
4164020e 107
f9f2dd71
SM
108 range stream_range;
109 stream_range.begin_ns = first_ds_index_entry.timestamp_begin_ns;
110 stream_range.end_ns = last_ds_index_entry.timestamp_end_ns;
4164020e
SM
111
112 /*
113 * If any of the begin and end timestamps is not set it means that
114 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
115 * in their packet context so we can't set the range.
116 */
f9f2dd71 117 stream_range.set = stream_range.begin_ns != UINT64_C(-1) && stream_range.end_ns != UINT64_C(-1);
4164020e 118
c02af779 119 add_range(groupInfo, stream_range, "range-ns");
3045bbcb 120 groupInfo.insert("port-name", ctf_fs_make_port_name(group));
97ade20b
JG
121}
122
c02af779
SM
123static void populate_trace_info(const struct ctf_fs_trace *trace, const bt2::MapValue traceInfo,
124 const bt2c::Logger& logger)
97ade20b 125{
4164020e 126 /* Add trace range info only if it contains streams. */
cdf7de78 127 if (trace->ds_file_groups.empty()) {
cee8a466
SM
128 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error,
129 "Trace has no streams: trace-path={}", trace->path);
4164020e
SM
130 }
131
c02af779 132 const auto fileGroups = traceInfo.insertEmptyArray("stream-infos");
4164020e
SM
133
134 /* Find range of all stream groups, and of the trace. */
cdf7de78 135 for (const auto& group : trace->ds_file_groups) {
c02af779 136 const auto groupInfo = fileGroups.appendEmptyMap();
f9f2dd71 137 populate_stream_info(group.get(), groupInfo);
4164020e 138 }
97ade20b
JG
139}
140
c02af779 141bt2::Value::Shared trace_infos_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
97ade20b 142{
c5a5a936 143 const auto parameters = read_src_fs_parameters(params, logger);
e1d200e5 144 ctf_fs_component ctf_fs {parameters.clkClsCfg, logger};
4164020e 145
c5a5a936
SM
146 if (ctf_fs_component_create_ctf_fs_trace(
147 &ctf_fs, parameters.inputs,
4d6634b8 148 parameters.traceName ? parameters.traceName->c_str() : nullptr, {})) {
c02af779 149 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "Failed to create trace");
4164020e
SM
150 }
151
c02af779
SM
152 const auto result = bt2::ArrayValue::create();
153 const auto traceInfo = result->appendEmptyMap();
5e502e99 154 populate_trace_info(ctf_fs.trace.get(), traceInfo, logger);
c7eee084 155
c02af779 156 return result;
04c0ba87 157}
73760435 158
69d91bb3
SM
159static bt_param_validation_map_value_entry_descr supportInfoQueryParamsDesc[] = {
160 {"type", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
161 bt_param_validation_value_descr::makeString()},
162 {"input", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
163 bt_param_validation_value_descr::makeString()},
164 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
165
c02af779 166bt2::Value::Shared support_info_query(const bt2::ConstMapValue params, const bt2c::Logger& logger)
73760435 167{
69d91bb3
SM
168 gchar *validateError = NULL;
169 const auto validationStatus = bt_param_validation_validate(
170 params.libObjPtr(), supportInfoQueryParamsDesc, &validateError);
171
172 if (validationStatus == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
173 throw bt2::MemoryError {};
174 } else if (validationStatus == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
175 const bt2c::GCharUP deleter {validateError};
176
177 BT_CPPLOGE_APPEND_CAUSE_AND_THROW_SPEC(logger, bt2::Error, "{}", validateError);
178 }
179
180 const auto type = params["type"]->asString().value();
4164020e 181
c02af779 182 if (strcmp(type, "directory") != 0) {
69d91bb3
SM
183 /*
184 * The input type is not a directory so we are 100% sure it's not a CTF
185 * 1.8 trace as it would need a directory with at least 1 metadata file
186 * and 1 data stream file.
187 */
c02af779
SM
188 const auto result = bt2::MapValue::create();
189 result->insert("weight", 0.0f);
190 return result;
4164020e
SM
191 }
192
69d91bb3 193 const auto input = params["input"]->asString().value();
4164020e 194
a9a4f6b9
FD
195 const auto result = bt2::MapValue::create();
196 try {
197 const auto buffer = bt2c::dataFromFile(fmt::format("{}/metadata", input), logger, false);
198 const auto parseRet = ctf::src::parseMetadataStream({}, {}, buffer, logger);
4164020e 199
a9a4f6b9 200 BT_ASSERT(parseRet.traceCls);
4164020e
SM
201
202 /*
a9a4f6b9
FD
203 * We were able to parse the metadata file, so we are confident it's a
204 * CTF trace.
4164020e 205 */
a9a4f6b9
FD
206 /* ⚠️ TODO: also consider namespace and name */
207 result->insert("weight", 0.75);
208 if (parseRet.traceCls->uid()) {
209 result->insert("group", *parseRet.traceCls->uid());
4164020e 210 }
a9a4f6b9
FD
211 } catch (const bt2c::NoSuchFileOrDirectoryError&) {
212 /*
213 * Failing to find the metadata file is not an error, it simply
214 * indicates that the directory is not a trace. Report appropriate
215 * weight of zero.
216 */
217 result->insert("weight", 0.0);
4164020e
SM
218 }
219
c02af779 220 return result;
73760435 221}
This page took 0.115888 seconds and 4 git commands to generate.