Project
Loading...
Searching...
No Matches
DataDescriptorQueryBuilder.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14#include "Framework/InputSpec.h"
15
16#include <memory>
17#include <optional>
18#include <string>
19#include <vector>
20#include <regex>
21#include <iostream>
22
23using namespace o2::framework::data_matcher;
24
25namespace o2::framework
26{
27
54
55std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
56{
57 std::vector<QueryBuilderState> states;
58 states.push_back(IN_BEGIN_QUERY);
59
60 std::vector<InputSpec> result;
61 char const* next = config;
62 char const* cur = config;
63 char const* expectedSeparators;
64 char* endptr;
65 std::string errorString;
66 std::unique_ptr<DataDescriptorMatcher> currentMatcher;
67 std::vector<data_matcher::Node> nodes;
68 std::optional<std::string> currentBinding;
69 std::optional<std::string> currentOrigin;
70 std::optional<std::string> currentDescription;
71 std::optional<std::string> currentKey;
72 std::optional<std::string> currentValue;
73 std::optional<header::DataHeader::SubSpecificationType> currentSubSpec;
74 std::optional<uint64_t> currentTimeModulo;
75 Lifetime currentLifetime = Lifetime::Timeframe;
76 size_t currentNumber;
77
78 auto error = [&errorString, &states](std::string const& s) {
79 errorString = s;
80 states.push_back(IN_ERROR);
81 };
82
83 auto pushState = [&states](QueryBuilderState state) {
84 states.push_back(state);
85 };
86
87 auto checkModifier = [&states, &cur, &next, &error](QueryBuilderState state, const char* mod) {
88 const char* modifier = nullptr;
89 if (mod[0] != '\0' && (modifier = strpbrk(cur, mod)) != nullptr) {
90 switch (*modifier) {
91 case '!':
92 states.push_back(IN_NEGATION);
93 break;
94 default:
95 error("invalid modifier '" + std::string(modifier, 1) + "'");
96 return;
97 }
98 next = ++cur;
99 }
100 states.push_back(state);
101 };
102
103 auto token = [&states, &expectedSeparators](QueryBuilderState state, char const* sep) {
104 states.push_back(state);
105 expectedSeparators = sep;
106 };
107
108 auto assignLastStringMatch = [&next, &cur, &error, &pushState](std::string const& what, int maxSize, std::optional<std::string>& s, QueryBuilderState nextState) {
109 if ((next - cur == 0) || (next - cur > maxSize)) {
110 error(what + " needs to be between 1 and " + std::to_string(maxSize) + " char long");
111 return false;
112 }
113 s = std::string(cur, next - cur);
114 if (memchr("\0;", *next, 2)) {
115 pushState(IN_END_MATCHER);
116 cur = next;
117 return true;
118 }
119 pushState(nextState);
120 cur = next + 1;
121 return true;
122 };
123
124 auto assignLastNumericMatch = [&next, &cur, &error, &pushState, &currentNumber](std::string const&, auto& value,
125 QueryBuilderState nextState) {
126 if ((next - cur == 0)) {
127 error("number expected");
128 return false;
129 }
130 value = currentNumber;
131 if (memchr("\0;", *next, 2)) {
132 pushState(IN_END_MATCHER);
133 cur = next;
134 return true;
135 }
136 pushState(nextState);
137 cur = next + 1;
138 return true;
139 };
140
141 std::vector<ConfigParamSpec> attributes;
142
143 auto buildMatchingTree = [&nodes](std::string const& binding, std::vector<ConfigParamSpec> attributes) -> InputSpec {
144 auto lastMatcher =
145 std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Just,
147 for (size_t ni = 0, ne = nodes.size(); ni < ne; ++ni) {
148 auto& node = nodes[nodes.size() - 1 - ni];
149 auto tmp = std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::And,
150 std::move(node),
151 std::move(lastMatcher));
152 assert(lastMatcher.get() == nullptr);
153 lastMatcher = std::move(tmp);
154 }
155 Lifetime lifetime = Lifetime::Timeframe;
156 for (auto& attribute : attributes) {
157 if (attribute.name == "lifetime" && attribute.defaultValue.get<std::string>() == "condition") {
158 lifetime = Lifetime::Condition;
159 }
160 if (attribute.name == "lifetime" && attribute.defaultValue.get<std::string>() == "sporadic") {
161 lifetime = Lifetime::Sporadic;
162 }
163 }
164 return InputSpec{binding, std::move(*lastMatcher), lifetime, attributes};
165 };
166
167 auto pushMatcher = [&nodes, &states](auto&& matcher) {
168 if (states.empty() == false && states.back() == IN_NEGATION) {
169 states.pop_back();
170 auto notMatcher = std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Xor,
171 std::move(matcher),
173 nodes.push_back(std::move(notMatcher));
174 } else {
175 nodes.push_back(std::move(matcher));
176 }
177 };
178
179 while (states.empty() == false) {
180 auto const state = states.back();
181 states.pop_back();
182
183 switch (state) {
184 case IN_STRING: {
185 next = strpbrk(cur, expectedSeparators);
186 if (next == nullptr) {
187 next = cur + strlen(cur);
188 }
189 } break;
190 case IN_NUMBER: {
191 currentNumber = strtoll(cur, &endptr, 0);
192 if (endptr == cur) {
193 error("Expected a number");
194 }
195 next = endptr;
196 } break;
197 case IN_BEGIN_QUERY: {
198 (*cur == 0) ? pushState(IN_END_QUERY)
199 : pushState(IN_BEGIN_MATCHER);
200 } break;
201 case IN_BEGIN_MATCHER: {
202 nodes.clear();
203 attributes.clear();
204 // Reset per-query state, so a ;-separated query cannot inherit it.
205 currentBinding.reset();
206 currentOrigin.reset();
207 currentDescription.reset();
208 currentSubSpec.reset();
209 currentTimeModulo.reset();
210 pushState(IN_BEGIN_BINDING);
211 } break;
212 case IN_BEGIN_BINDING: {
213 pushState(IN_END_BINDING);
214 token(IN_STRING, ":/;,");
215 } break;
216 case IN_END_BINDING: {
217 // We are at the end of the string already.
218 // This is really an origin...
219 if (memchr("\0/;", *next, 3)) {
220 pushState(IN_END_ORIGIN);
221 continue;
222 }
223 if (next - cur == 0) {
224 error("empty binding string");
225 continue;
226 }
227 currentBinding = std::string(cur, next - cur);
228 pushState(IN_BEGIN_ORIGIN);
229 cur = next + 1;
230 } break;
231 case IN_BEGIN_ORIGIN: {
232 pushState(IN_END_ORIGIN);
233 token(IN_STRING, "/;?");
234 } break;
235 case IN_END_ORIGIN: {
236 if (*next == '/' && assignLastStringMatch("origin", 4, currentOrigin, IN_BEGIN_DESCRIPTION)) {
237 nodes.push_back(OriginValueMatcher{*currentOrigin});
238 } else if (*next == ';' && assignLastStringMatch("origin", 4, currentOrigin, IN_END_MATCHER)) {
239 nodes.push_back(OriginValueMatcher{*currentOrigin});
240 } else if (*next == '?' && assignLastStringMatch("origin", 4, currentOrigin, IN_BEGIN_ATTRIBUTES)) {
241 nodes.push_back(OriginValueMatcher{*currentOrigin});
242 } else if (*next == '\0' && assignLastStringMatch("origin", 4, currentOrigin, IN_END_MATCHER)) {
243 nodes.push_back(OriginValueMatcher{*currentOrigin});
244 } else {
245 error("origin needs to be between 1 and 4 char long");
246 }
247 } break;
249 pushState(IN_END_DESCRIPTION);
250 token(IN_STRING, "/;?");
251 } break;
252 case IN_END_DESCRIPTION: {
253 if (*next == '/' && assignLastStringMatch("description", 16, currentDescription, IN_BEGIN_SUBSPEC)) {
254 nodes.push_back(DescriptionValueMatcher{*currentDescription});
255 } else if (*next == ';' && assignLastStringMatch("description", 16, currentDescription, IN_END_MATCHER)) {
256 nodes.push_back(DescriptionValueMatcher{*currentDescription});
257 } else if (*next == '?' && assignLastStringMatch("description", 16, currentDescription, IN_BEGIN_ATTRIBUTES)) {
258 nodes.push_back(DescriptionValueMatcher{*currentDescription});
259 } else if (*next == '\0' && assignLastStringMatch("description", 16, currentDescription, IN_END_MATCHER)) {
260 nodes.push_back(DescriptionValueMatcher{*currentDescription});
261 } else {
262 error("description needs to be between 1 and 16 char long");
263 }
264 } break;
265 case IN_BEGIN_SUBSPEC: {
266 checkModifier(IN_END_SUBSPEC, "!");
267 token(IN_NUMBER, ";%?");
268 } break;
269 case IN_END_SUBSPEC: {
270 if (*next == '%' && assignLastNumericMatch("subspec", currentSubSpec, IN_BEGIN_TIMEMODULO)) {
271 } else if (*next == '?' && assignLastNumericMatch("subspec", currentSubSpec, IN_BEGIN_ATTRIBUTES)) {
272 } else if (*next == ';' && assignLastNumericMatch("subspec", currentSubSpec, IN_END_MATCHER)) {
273 } else if (*next == '\0' && assignLastNumericMatch("subspec", currentSubSpec, IN_END_MATCHER)) {
274 } else {
275 error("Expected a number");
276 break;
277 }
278 auto backup = states.back();
279 states.pop_back();
280 pushMatcher(SubSpecificationTypeValueMatcher{*currentSubSpec});
281 states.push_back(backup);
282 } break;
283 case IN_BEGIN_TIMEMODULO: {
284 pushState(IN_END_TIMEMODULO);
285 token(IN_NUMBER, ";?");
286 } break;
287 case IN_END_TIMEMODULO: {
288 assignLastNumericMatch("timemodulo", currentTimeModulo, IN_ERROR);
289 } break;
290 case IN_END_MATCHER: {
291 if (*cur == ';' && *(cur + 1) == '\0') {
292 error("Remove trailing ;");
293 continue;
294 }
295 // A query without a binding, e.g. "TST/A1", is named after its origin.
296 result.push_back(buildMatchingTree(currentBinding.value_or(currentOrigin.value_or("")), attributes));
297 if (*cur == '\0') {
298 pushState(IN_END_QUERY);
299 } else if (*cur == ';') {
300 cur += 1;
301 pushState(IN_BEGIN_MATCHER);
302 } else {
303 error("Unexpected character " + std::string(cur, 1));
304 }
305 } break;
306 case IN_BEGIN_ATTRIBUTES: {
307 pushState(IN_BEGIN_KEY);
308 } break;
309 case IN_BEGIN_KEY: {
310 pushState(IN_END_KEY);
311 token(IN_STRING, "=");
312 } break;
313 case IN_END_KEY: {
314 if (*next == '=') {
315 assignLastStringMatch("key", 1000, currentKey, IN_BEGIN_VALUE);
316 } else {
317 error("missing value for attribute key");
318 }
319 } break;
320 case IN_BEGIN_VALUE: {
321 pushState(IN_END_VALUE);
322 token(IN_STRING, "&;");
323 } break;
324 case IN_END_VALUE: {
325 if (*next == '&') {
326 assignLastStringMatch("value", 1000, currentValue, IN_BEGIN_KEY);
327 if (*currentKey == "lifetime" && currentValue == "condition") {
328 currentLifetime = Lifetime::Condition;
329 }
330 if (*currentKey == "ccdb-run-dependent") {
331 int val = currentValue == "false" ? 0 : (currentValue == "true" ? 1 : std::stoi(*currentValue));
332 attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Int, val, {}});
333 } else {
334 attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}});
335 }
336 } else if (*next == ';') {
337 assignLastStringMatch("value", 1000, currentValue, IN_END_ATTRIBUTES);
338 if (*currentKey == "lifetime" && currentValue == "condition") {
339 currentLifetime = Lifetime::Condition;
340 }
341 if (*currentKey == "ccdb-run-dependent") {
342 int val = currentValue == "false" ? 0 : (currentValue == "true" ? 1 : std::stoi(*currentValue));
343 attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Int, val, {}});
344 } else {
345 attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}});
346 }
347 } else if (*next == '\0') {
348 assignLastStringMatch("value", 1000, currentValue, IN_END_ATTRIBUTES);
349 if (*currentKey == "lifetime" && currentValue == "condition") {
350 currentLifetime = Lifetime::Condition;
351 }
352 if (*currentKey == "ccdb-run-dependent") {
353 int val = currentValue == "false" ? 0 : (currentValue == "true" ? 1 : std::stoi(*currentValue));
354 attributes.push_back(ConfigParamSpec{*currentKey, VariantType::Int, val, {}});
355 } else {
356 attributes.push_back(ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}});
357 }
358 } else {
359 error("missing value for string value");
360 }
361 } break;
362 case IN_END_ATTRIBUTES: {
363 pushState(IN_END_MATCHER);
364 } break;
365 case IN_NEGATION: {
366 error("property modifiers should have been handled before when inserting previous matcher");
367 } break;
368 case IN_ERROR: {
369 throw std::runtime_error("Parse error: " + errorString);
370 } break;
371 case IN_END_QUERY: {
372 } break;
373 default: {
374 error("Unhandled state");
375 } break;
376 }
377 }
378 return std::move(result);
379}
380
382{
383 static const std::regex delim(",");
384
385 std::sregex_token_iterator end;
386 std::sregex_token_iterator iter(config.begin(),
387 config.end(),
388 delim,
389 -1);
390
391 std::unique_ptr<DataDescriptorMatcher> next, result;
392
393 for (; iter != end; ++iter) {
394 std::smatch m;
395 auto s = iter->str();
396 auto newNode = buildNode(s);
397
398 if (result.get() == nullptr) {
399 result = std::move(newNode);
400 } else {
401 next = std::move(std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Or,
402 std::move(result),
403 std::move(newNode)));
404 result = std::move(next);
405 }
406 }
407
408 return std::move(DataDescriptorQuery{{}, std::move(result)});
409}
410
412{
413 static const std::regex delim1(",");
414 static const std::regex delim2(":");
415
416 std::sregex_token_iterator end;
417 std::sregex_token_iterator iter1(config.begin(),
418 config.end(),
419 delim1,
420 -1);
421
422 std::unique_ptr<DataDescriptorMatcher> next, result;
423
424 // looping over ','-separated items
425 for (; iter1 != end; ++iter1) {
426 auto s = iter1->str();
427
428 // get first part of item
429 std::sregex_token_iterator iter2(s.begin(),
430 s.end(),
431 delim2,
432 -1);
433 if (iter2 == end) {
434 continue;
435 }
436 s = iter2->str();
437
438 // create the corresponding DataDescriptorMatcher
439 std::smatch m;
440 auto newNode = buildNode(s);
441
442 if (result.get() == nullptr) {
443 result = std::move(newNode);
444 } else {
445 next = std::move(std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Or,
446 std::move(result),
447 std::move(newNode)));
448 result = std::move(next);
449 }
450 }
451
452 return std::move(DataDescriptorQuery{{}, std::move(result)});
453}
454
455std::unique_ptr<DataDescriptorMatcher> DataDescriptorQueryBuilder::buildNode(std::string const& nodeString)
456{
457
458 auto m = getTokens(nodeString);
459
460 std::unique_ptr<DataDescriptorMatcher> next;
461 auto newNode = std::make_unique<DataDescriptorMatcher>(
462 DataDescriptorMatcher::Op::And,
464 std::make_unique<DataDescriptorMatcher>(
465 DataDescriptorMatcher::Op::And,
468
469 return newNode;
470}
471
472std::vector<std::string> DataDescriptorQueryBuilder::getTokens(std::string const& nodeString)
473{
474
475 static const std::regex specTokenRE(R"re((\w{1,4})/(\w{1,16})/(\d*))re");
476 std::smatch match;
477
478 std::regex_match(nodeString, match, specTokenRE);
479
480 std::vector<std::string> result;
481 for (size_t i = 0; i < 4; ++i) {
482 result.push_back(match[i].str());
483 }
484 return result;
485}
486
487} // namespace o2::framework
std::string binding
size_t maxSize
std::string currentKey
std::unique_ptr< expressions::Node > node
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
char error[CURL_ERROR_SIZE]
SurfaceTrackState state
Something which can be matched against a header::DataDescription.
Something which can be matched against a header::DataOrigin.
Matcher on actual time, as reported in the DataProcessingHeader.
Something which can be matched against a header::SubSpecificationType.
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
const GLfloat * m
Definition glcorearb.h:4066
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint GLuint end
Definition glcorearb.h:469
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLuint GLfloat * val
Definition glcorearb.h:1582
GLuint * states
Definition glcorearb.h:4932
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
Lifetime
Possible Lifetime of objects being exchanged by the DPL.
Definition Lifetime.h:18
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
static std::vector< InputSpec > parse(const char *s="")
static std::unique_ptr< data_matcher::DataDescriptorMatcher > buildNode(std::string const &nodeString)
static DataDescriptorQuery buildFromExtendedKeepConfig(std::string const &config)
deprecated?
static std::vector< std::string > getTokens(std::string const &nodeString)
static DataDescriptorQuery buildFromKeepConfig(std::string const &config)
A typesafe reference to an element of the context.
const std::string str