src.ctf.fs: store index entry objects instead of pointers
[deliverable/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
27a14e13
SM
9#define BT_CLOG_CFG logCfg
10#define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/QUERY"
98903a3e 11
087cd0f5 12#include "query.hpp"
04c0ba87 13#include <stdbool.h>
493917ba
SM
14#include <glib.h>
15#include <glib/gstdio.h>
16#include <fcntl.h>
17#include <sys/types.h>
18#include <sys/stat.h>
578e048b 19#include "common/assert.h"
087cd0f5 20#include "metadata.hpp"
71332bf4
SM
21#include "../common/src/metadata/tsdl/metadata-stream-decoder.hpp"
22#include "../common/src/metadata/metadata-stream-parser-utils.hpp"
578e048b 23#include "common/common.h"
91d81473 24#include "common/macros.h"
6aa47d30 25#include "plugins/common/param-validation/param-validation.h"
3fadfbc0 26#include <babeltrace2/babeltrace.h>
087cd0f5 27#include "fs.hpp"
27a14e13 28#include "cpp-common/cfg-logging-error-reporting.hpp"
396a8f9f 29#include "cpp-common/cfg-logging-error-reporting-throw.hpp"
e1871ef7 30#include "cpp-common/libc-up.hpp"
396a8f9f 31#include "cpp-common/exc.hpp"
71332bf4 32#include "cpp-common/file-utils.hpp"
f1946ada 33#include "cpp-common/make-unique.hpp"
55314f2a 34
4164020e 35#define METADATA_TEXT_SIG "/* CTF 1.8"
04c0ba87 36
4164020e
SM
37struct range
38{
39 int64_t begin_ns = 0;
40 int64_t end_ns = 0;
41 bool set = false;
97ade20b
JG
42};
43
6aa47d30
SM
44static 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
04c0ba87 49BT_HIDDEN
396a8f9f 50bt2::Value::Shared metadata_info_query(bt2::ConstMapValue params, const bt2_common::LogCfg& logCfg)
04c0ba87 51{
6aa47d30
SM
52 gchar *validateError = NULL;
53 auto validationStatus = bt_param_validation_validate(
54 params.libObjPtr(), metadataInfoQueryParamsDesc, &validateError);
4164020e 55
6aa47d30
SM
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());
4164020e
SM
63 }
64
71332bf4 65 const auto path = params["path"]->asString().value();
6aa47d30 66
71332bf4
SM
67 try {
68 const auto buffer =
69 bt2_common::dataFromFile(std::string {path.to_string() + "/metadata"}.c_str());
4164020e 70
71332bf4 71 ctf::src::MetadataStreamDecoder decoder {logCfg};
4164020e 72
71332bf4
SM
73 auto plainText =
74 decoder.decode(buffer.data(), bt2_common::DataLen::fromBytes(buffer.size()));
4164020e 75
71332bf4
SM
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 }
4164020e 84
71332bf4 85 result->insert("text", plainText.data());
c7eee084 86
71332bf4
SM
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 }
97ade20b 92}
9ec238a8 93
396a8f9f 94static void add_range(bt2::MapValue info, struct range *range, const char *range_name)
97ade20b 95{
4164020e
SM
96 if (!range->set) {
97 /* Not an error. */
396a8f9f 98 return;
4164020e
SM
99 }
100
396a8f9f
SM
101 bt2::MapValue rangeMap = info.insertEmptyMap(range_name);
102 rangeMap.insert("begin", range->begin_ns);
103 rangeMap.insert("end", range->end_ns);
97ade20b
JG
104}
105
396a8f9f
SM
106static void populate_stream_info(struct ctf_fs_ds_file_group *group, bt2::MapValue groupInfo,
107 struct range *stream_range, const bt2_common::LogCfg& logCfg)
97ade20b 108{
4164020e
SM
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);
5ce40cf7 116 BT_ASSERT(!group->index->entries.empty());
4164020e
SM
117
118 /* First entry. */
3505f709 119 const ctf_fs_ds_index_entry& first_ds_index_entry = group->index->entries.front();
4164020e
SM
120
121 /* Last entry. */
3505f709 122 const ctf_fs_ds_index_entry& last_ds_index_entry = group->index->entries.back();
4164020e 123
3505f709
SM
124 stream_range->begin_ns = first_ds_index_entry.timestamp_begin_ns;
125 stream_range->end_ns = last_ds_index_entry.timestamp_end_ns;
4164020e
SM
126
127 /*
128 * If any of the begin and end timestamps is not set it means that
129 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
130 * in their packet context so we can't set the range.
131 */
132 stream_range->set =
133 stream_range->begin_ns != UINT64_C(-1) && stream_range->end_ns != UINT64_C(-1);
134
396a8f9f 135 add_range(groupInfo, stream_range, "range-ns");
4164020e 136
a373ad9a
SM
137 std::string portName = ctf_fs_make_port_name(group);
138 groupInfo.insert("port-name", portName.c_str());
97ade20b
JG
139}
140
396a8f9f
SM
141static void populate_trace_info(const struct ctf_fs_trace *trace, bt2::MapValue traceInfo,
142 const bt2_common::LogCfg& logCfg)
97ade20b 143{
4164020e 144 /* Add trace range info only if it contains streams. */
1d732493 145 if (trace->ds_file_groups.empty()) {
396a8f9f 146 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "Trace has no streams: trace-path=%s",
94b0446f 147 trace->path.c_str());
4164020e
SM
148 }
149
396a8f9f 150 bt2::ArrayValue fileGroups = traceInfo.insertEmptyArray("stream-infos");
4164020e
SM
151
152 /* Find range of all stream groups, and of the trace. */
1d732493 153 for (const ctf_fs_ds_file_group::UP& group : trace->ds_file_groups) {
4164020e 154 range group_range;
396a8f9f 155 bt2::MapValue groupInfo = fileGroups.appendEmptyMap();
1d732493 156 populate_stream_info(group.get(), groupInfo, &group_range, logCfg);
4164020e 157 }
97ade20b
JG
158}
159
160BT_HIDDEN
396a8f9f 161bt2::Value::Shared trace_infos_query(bt2::ConstMapValue params, const bt2_common::LogCfg& logCfg)
97ade20b 162{
f1946ada 163 ctf_fs_component::UP ctf_fs = bt2_common::makeUnique<ctf_fs_component>(logCfg);
4164020e 164
396a8f9f
SM
165 const bt_value *inputs_value = NULL;
166 const bt_value *trace_name_value;
167
168 if (!read_src_fs_parameters(params.libObjPtr(), &inputs_value, &trace_name_value,
169 ctf_fs.get())) {
170 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "Failed to read parameters");
4164020e
SM
171 }
172
6bcdb2d6
SM
173 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs.get(), inputs_value, trace_name_value,
174 nullptr)) {
396a8f9f 175 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "Failed to create trace");
4164020e
SM
176 }
177
396a8f9f
SM
178 bt2::ArrayValue::Shared result = bt2::ArrayValue::create();
179 bt2::MapValue traceInfo = result->appendEmptyMap();
86285034 180 populate_trace_info(ctf_fs->trace.get(), traceInfo, logCfg);
c7eee084 181
396a8f9f 182 return result;
04c0ba87 183}
73760435 184
6aa47d30
SM
185static struct bt_param_validation_map_value_entry_descr supportInfoQueryParamsDesc[] = {
186 {"type", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
187 bt_param_validation_value_descr::makeString()},
188 {"input", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_MANDATORY,
189 bt_param_validation_value_descr::makeString()},
190 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END};
191
73760435 192BT_HIDDEN
396a8f9f 193bt2::Value::Shared support_info_query(bt2::ConstMapValue params, const bt2_common::LogCfg& logCfg)
73760435 194{
6aa47d30
SM
195 gchar *validateError = NULL;
196 auto validationStatus = bt_param_validation_validate(
197 params.libObjPtr(), supportInfoQueryParamsDesc, &validateError);
198
199 if (validationStatus == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
200 throw bt2_common::MemoryError {};
201 } else if (validationStatus == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
202 const std::string error {validateError};
203
204 g_free(validateError);
205 BT_CLOGE_APPEND_CAUSE_AND_THROW(bt2_common::Error, "%s", error.data());
206 }
207
208 bpstd::string_view type = params["type"]->asString().value();
4164020e 209
396a8f9f 210 if (type != "directory") {
6aa47d30
SM
211 /*
212 * The input type is not a directory so we are 100% sure it's not a CTF
213 * 1.8 trace as it would need a directory with at least 1 metadata file
214 * and 1 data stream file.
215 */
396a8f9f
SM
216 bt2::MapValue::Shared result = bt2::MapValue::create();
217 result->insert("weight", 0.0f);
218 return result;
4164020e
SM
219 }
220
6aa47d30 221 bpstd::string_view input = params["input"]->asString().value();
4164020e 222
71332bf4
SM
223 auto result = bt2::MapValue::create();
224 try {
225 const auto buffer =
226 bt2_common::dataFromFile(std::string {input.to_string() + "/metadata"}.c_str());
227 ctf::src::MetadataStreamParser::ParseRet parseRet = ctf::src::parseMetadataStream(
228 {}, nullptr, buffer.data(), buffer.data() + buffer.size(), logCfg);
229 ctf::src::TraceCls *ctfTraceCls = parseRet.first.get();
230 BT_ASSERT(ctfTraceCls);
4164020e
SM
231
232 /*
71332bf4
SM
233 * We were able to parse the metadata file, so we are confident it's a
234 * CTF trace.
4164020e 235 */
71332bf4
SM
236 result->insert("weight", 0.75);
237 if (ctfTraceCls->uuid()) {
238 result->insert("group", ctfTraceCls->uuid()->str());
4164020e 239 }
71332bf4
SM
240 } catch (const bt2_common::NoSuchFileOrDirectoryError&) {
241 /*
242 * Failing to find the metadata file is not an error, it simply
243 * indicates that the directory is not a trace. Report appropriate
244 * weight of zero.
245 */
246 bt_current_thread_clear_error();
247 result->insert("weight", 0.0);
4164020e 248 }
396a8f9f 249 return result;
73760435 250}
This page took 0.09184 seconds and 5 git commands to generate.