Skip to content

Commit 7f4b3dd

Browse files
authored
DPL Analysis: cddb tables using FairMQ side channel metadata (#15516)
1 parent 06158ba commit 7f4b3dd

9 files changed

Lines changed: 369 additions & 126 deletions

File tree

Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "AnalysisCCDBHelpers.h"
1313
#include "CCDBFetcherHelper.h"
14+
#include "Framework/ArrowTypes.h"
1415
#include "Framework/DataProcessingStats.h"
1516
#include "Framework/DeviceSpec.h"
1617
#include "Framework/TimingInfo.h"
@@ -22,6 +23,7 @@
2223
#include "Framework/DanglingEdgesContext.h"
2324
#include "Framework/ConfigContext.h"
2425
#include "Framework/ConfigParamsHelper.h"
26+
#include <fairmq/Version.h>
2527
#include <arrow/array/builder_binary.h>
2628
#include <arrow/type.h>
2729
#include <arrow/type_fwd.h>
@@ -109,20 +111,49 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
109111
auto it = ccdbUrls.find(m.name);
110112
fieldMetadata->Append("url", it != ccdbUrls.end() ? it->second : m.defaultValue.asString());
111113
auto columnName = m.name.substr(strlen("ccdb:"));
114+
#if (FAIRMQ_VERSION_DEC >= 111000)
115+
fields.emplace_back(std::make_shared<arrow::Field>(columnName, soa::asArrowDataType<int64_t[3]>(), false, fieldMetadata));
116+
#else
112117
fields.emplace_back(std::make_shared<arrow::Field>(columnName, arrow::binary_view(), false, fieldMetadata));
118+
#endif
113119
}
114120
schemas.emplace_back(std::make_shared<arrow::Schema>(fields, schemaMetadata));
115121
}
116122

123+
#if (FAIRMQ_VERSION_DEC >= 111000)
124+
std::vector<std::pair<uint32_t, std::shared_ptr<arrow::FixedSizeListBuilder>>> allbuilders;
125+
#else
126+
std::vector<std::pair<uint32_t, std::shared_ptr<arrow::BinaryViewBuilder>>> allbuilders;
127+
#endif
128+
allbuilders.resize([&schemas]() { size_t size = 0; for (auto& schema : schemas) { size += schema->num_fields(); }; return size; }());
129+
auto* pool = arrow::default_memory_pool();
130+
131+
int idx = 0;
132+
int sidx = 0;
133+
for (auto const& schema : schemas) {
134+
for (auto const& _ : schema->fields()) {
135+
#if (FAIRMQ_VERSION_DEC >= 111000)
136+
auto value_builder = std::make_shared<arrow::Int64Builder>();
137+
allbuilders[idx] = std::make_pair(sidx, std::make_shared<arrow::FixedSizeListBuilder>(pool, std::move(value_builder), 3));
138+
#else
139+
allbuilders[idx] = std::make_pair(sidx, std::make_shared<arrow::BinaryViewBuilder>());
140+
#endif
141+
++idx;
142+
}
143+
++sidx;
144+
}
145+
117146
std::shared_ptr<CCDBFetcherHelper> helper = std::make_shared<CCDBFetcherHelper>();
118147
CCDBFetcherHelper::initialiseHelper(*helper, options);
119148
std::unordered_map<std::string, int> bindings;
120149
fillValidRoutes(*helper, spec.outputs, bindings);
121150

122-
return adaptStateless([schemas, bindings, helper](InputRecord& inputs, DataTakingContext& dtc, DataAllocator& allocator, TimingInfo& timingInfo, DataProcessingStats& stats) {
151+
return adaptStateless([schemas, bindings, helper, allbuilders](InputRecord& inputs, DataTakingContext& dtc, DataAllocator& allocator, TimingInfo& timingInfo, DataProcessingStats& stats) {
123152
O2_SIGNPOST_ID_GENERATE(sid, ccdb);
124153
O2_SIGNPOST_START(ccdb, sid, "fetchFromAnalysisCCDB", "Fetching CCDB objects for analysis%" PRIu64, (uint64_t)timingInfo.timeslice);
125-
for (auto& schema : schemas) {
154+
std::ranges::for_each(allbuilders, [](auto& builder) { builder.second->Reset(); });
155+
for (auto i = 0U; i < schemas.size(); ++i) {
156+
auto& schema = schemas[i];
126157
std::vector<CCDBFetcherHelper::FetchOp> ops;
127158
auto inputBinding = *schema->metadata()->Get("sourceTable");
128159
auto inputMatcher = DataSpecUtils::fromString(*schema->metadata()->Get("sourceMatcher"));
@@ -134,20 +165,32 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
134165
auto table = inputs.get<TableConsumer>(inputMatcher)->asArrowTable();
135166
// FIXME: make the fTimestamp column configurable.
136167
auto timestampColumn = table->GetColumnByName("fTimestamp");
168+
auto reserveSize = timestampColumn->length();
137169
O2_SIGNPOST_EVENT_EMIT_INFO(ccdb, sid, "fetchFromAnalysisCCDB",
138170
"There are %zu bindings available", bindings.size());
139-
for (auto& binding : bindings) {
171+
for (auto const& binding : bindings) {
140172
O2_SIGNPOST_EVENT_EMIT_INFO(ccdb, sid, "fetchFromAnalysisCCDB",
141173
"* %{public}s: %d",
142174
binding.first.c_str(), binding.second);
143175
}
144176
int outputRouteIndex = bindings.at(outRouteDesc);
145177
auto& spec = helper->routes[outputRouteIndex].matcher;
146-
std::vector<std::shared_ptr<arrow::BinaryViewBuilder>> builders;
147-
for (auto const& _ : schema->fields()) {
148-
builders.emplace_back(std::make_shared<arrow::BinaryViewBuilder>());
178+
auto concrete = DataSpecUtils::asConcreteDataMatcher(spec);
179+
Output output{concrete.origin, concrete.description, concrete.subSpec};
180+
auto builders = allbuilders | std::views::filter([&i](auto const& builder) { return builder.first == i; });
181+
unsigned int numBuilders = std::ranges::count_if(allbuilders, [&i](auto const& builder) { return builder.first == i; });
182+
arrow::Status status;
183+
std::ranges::for_each(builders, [&status, &reserveSize](auto& builder) {
184+
if (reserveSize > builder.second->capacity()) {
185+
status &= builder.second->Reserve(reserveSize - builder.second->capacity());
186+
}
187+
});
188+
if (!status.ok()) {
189+
throw framework::runtime_error_f("Failed to reserve arrays: ", status.ToString().c_str());
149190
}
150191

192+
std::vector<DataAllocator::CacheId> lastIds(numBuilders, DataAllocator::CacheId{.value = -1, .handle = -1, .segment = -1});
193+
151194
for (auto ci = 0; ci < timestampColumn->num_chunks(); ++ci) {
152195
std::shared_ptr<arrow::Array> chunk = timestampColumn->chunk(ci);
153196
auto const* timestamps = chunk->data()->GetValuesSafe<size_t>(1);
@@ -171,15 +214,30 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
171214
O2_SIGNPOST_START(ccdb, sid, "handlingResponses",
172215
"Got %zu responses from server.",
173216
responses.size());
174-
if (builders.size() != responses.size()) {
175-
LOGP(fatal, "Not enough responses (expected {}, found {})", builders.size(), responses.size());
217+
if (numBuilders != responses.size()) {
218+
LOGP(fatal, "Not enough responses (expected {}, found {})", numBuilders, responses.size());
176219
}
177220
arrow::Status result;
178-
for (size_t bi = 0; bi < responses.size(); bi++) {
179-
auto& builder = builders[bi];
221+
222+
int bi = 0;
223+
for (auto& builder : builders) {
180224
auto& response = responses[bi];
225+
auto& lastId = lastIds[bi];
226+
if (response.id.value != lastId.value) {
227+
lastId.value = response.id.value;
228+
allocator.adoptFromCache(output, response.id, header::gSerializationMethodCCDB);
229+
}
230+
#if (FAIRMQ_VERSION_DEC >= 111000)
231+
result &= builder.second->Append();
232+
auto* value_builder = dynamic_cast<arrow::Int64Builder*>(builder.second->value_builder());
233+
result &= value_builder->Append(response.id.handle);
234+
result &= value_builder->Append(response.id.segment);
235+
result &= value_builder->Append(response.size);
236+
#else
181237
char const* address = reinterpret_cast<char const*>(response.id.value);
182-
result &= builder->Append(std::string_view(address, response.size));
238+
result &= builder.second->Append(std::string_view(address, response.size));
239+
#endif
240+
++bi;
183241
}
184242
if (!result.ok()) {
185243
LOGP(fatal, "Error adding results from CCDB");
@@ -188,12 +246,9 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
188246
}
189247
}
190248
arrow::ArrayVector arrays;
191-
for (auto& builder : builders) {
192-
arrays.push_back(*builder->Finish());
193-
}
249+
std::ranges::for_each(builders, [&arrays](auto& builder) { arrays.push_back(*builder.second->Finish()); });
194250
auto outTable = arrow::Table::Make(schema, arrays);
195-
auto concrete = DataSpecUtils::asConcreteDataMatcher(spec);
196-
allocator.adopt(Output{concrete.origin, concrete.description, concrete.subSpec}, outTable);
251+
allocator.adopt(output, outTable);
197252
}
198253

199254
stats.updateStats({(int)ProcessingStatsId::CCDB_CACHE_FETCHED_BYTES, DataProcessingStats::Op::Set, (int64_t)helper->totalFetchedBytes});

Framework/CCDBSupport/src/CCDBFetcherHelper.cxx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,16 @@ auto CCDBFetcherHelper::populateCacheWith(std::shared_ptr<CCDBFetcherHelper> con
167167
DataTakingContext& dtc,
168168
DataAllocator& allocator) -> std::vector<CCDBFetcherHelper::Response>
169169
{
170-
int objCnt = -1;
171170
// We use the timeslice, so that we hook into the same interval as the rest of the
172171
// callback.
173172
static bool isOnline = isOnlineRun(dtc);
174173

175174
auto sid = _o2_signpost_id_t{(int64_t)timingInfo.timeslice};
176175
O2_SIGNPOST_START(ccdb, sid, "populateCacheWith", "Starting to populate cache with CCDB objects");
177176
std::vector<Response> responses;
178-
for (auto& op : ops) {
177+
for (auto const& op : ops) {
179178
int64_t timestampToUse = op.timestamp;
180179
O2_SIGNPOST_EVENT_EMIT(ccdb, sid, "populateCacheWith", "Fetching object for route %{public}s", DataSpecUtils::describe(op.spec).data());
181-
objCnt++;
182180
auto concrete = DataSpecUtils::asConcreteDataMatcher(op.spec);
183181
Output output{concrete.origin, concrete.description, concrete.subSpec};
184182
auto&& v = allocator.makeVector<char>(output);
@@ -198,7 +196,7 @@ auto CCDBFetcherHelper::populateCacheWith(std::shared_ptr<CCDBFetcherHelper> con
198196
concrete.origin.as<std::string>(), concrete.description.as<std::string>(), int(concrete.subSpec));
199197
}
200198
}
201-
for (auto m : op.metadata) {
199+
for (auto const& m : op.metadata) {
202200
O2_SIGNPOST_EVENT_EMIT(ccdb, sid, "populateCacheWith", "Adding metadata %{public}s: %{public}s to the request", m.key.data(), m.value.data());
203201
metadata[m.key] = m.value;
204202
}
@@ -215,7 +213,7 @@ auto CCDBFetcherHelper::populateCacheWith(std::shared_ptr<CCDBFetcherHelper> con
215213
uint64_t cachePopulatedAt = url2uuid->second.cachePopulatedAt;
216214
// If timestamp is before the time the element was cached or after the claimed validity, we need to check validity, again
217215
// when online.
218-
bool cacheExpired = (validUntil <= timestampToUse) || (op.timestamp < cachePopulatedAt);
216+
bool cacheExpired = (validUntil <= (uint64_t)timestampToUse) || ((uint64_t)op.timestamp < cachePopulatedAt);
219217
if (isOnline || cacheExpired) {
220218
if (!helper->useTFSlice) {
221219
checkValidity = chRate > 0 ? (std::abs(int(timingInfo.tfCounter - url2uuid->second.lastCheckedTF)) >= chRate) : (timingInfo.tfCounter % -chRate) == 0;
@@ -291,7 +289,7 @@ auto CCDBFetcherHelper::populateCacheWith(std::shared_ptr<CCDBFetcherHelper> con
291289
O2_SIGNPOST_EVENT_EMIT(ccdb, sid, "populateCacheWith", "Reusing %{public}s for %{public}s (DPL id %" PRIu64 ")", path.data(), headers["ETag"].data(), cacheId.value);
292290
helper->mapURL2UUID[path].cacheHit++;
293291
responses.emplace_back(Response{.id = cacheId, .size = helper->mapURL2UUID[path].size, .request = nullptr});
294-
allocator.adoptFromCache(output, cacheId, header::gSerializationMethodCCDB);
292+
// allocator.adoptFromCache(output, cacheId, header::gSerializationMethodCCDB);
295293
// the outputBuffer was not used, can we destroy it?
296294
}
297295
O2_SIGNPOST_END(ccdb, sid, "populateCacheWith", "Finished populating cache with CCDB objects");

0 commit comments

Comments
 (0)