@@ -104,6 +104,10 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
104104 schemaMetadata->Append (" sourceMatcher" , DataSpecUtils::describe (std::get<ConcreteDataMatcher>(DataSpecUtils::fromMetadataString (m.defaultValue .get <std::string>()).matcher )));
105105 continue ;
106106 }
107+ if (m.name == " timestamp-column" || m.name == " uniformity-column" ) {
108+ schemaMetadata->Append (m.name , m.defaultValue .asString ());
109+ continue ;
110+ }
107111 if (!m.name .starts_with (" ccdb:" )) {
108112 continue ;
109113 }
@@ -144,15 +148,44 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
144148 auto & schema = schemas[i];
145149 std::vector<CCDBFetcherHelper::FetchOp> ops;
146150 auto inputBinding = *schema->metadata ()->Get (" sourceTable" );
147- auto inputMatcher = DataSpecUtils::fromString (*schema->metadata ()->Get (" sourceMatcher" ));
148151 auto outRouteDesc = *schema->metadata ()->Get (" outputRoute" );
149152 std::string outBinding = *schema->metadata ()->Get (" outputBinding" );
153+ auto timestampColumnName = schema->metadata ()->Contains (" timestamp-column" ) ? *schema->metadata ()->Get (" timestamp-column" ) : std::string{" fTimestamp" };
154+ auto uniformityColumnName = schema->metadata ()->Contains (" uniformity-column" ) ? *schema->metadata ()->Get (" uniformity-column" ) : timestampColumnName;
150155 O2_SIGNPOST_EVENT_EMIT_INFO (ccdb, sid, " fetchFromAnalysisCCDB" ,
151156 " Fetching CCDB objects for %{public}s's columns with timestamps from %{public}s and putting them in route %{public}s" ,
152157 outBinding.c_str (), inputBinding.c_str (), outRouteDesc.c_str ());
153- auto table = inputs.get <TableConsumer>(inputMatcher)->asArrowTable ();
154- // FIXME: make the fTimestamp column configurable.
155- auto timestampColumn = table->GetColumnByName (" fTimestamp" );
158+ // The timestamp and uniformity columns may live in different source tables (the
159+ // run number is on aod::BCs, the timestamp on aod::Timestamps). Locate each by
160+ // name across every declared source, and read them positionally.
161+ std::shared_ptr<arrow::ChunkedArray> timestampColumn;
162+ std::shared_ptr<arrow::ChunkedArray> uniformityColumn;
163+ auto const & schemaKeys = schema->metadata ()->keys ();
164+ auto const & schemaValues = schema->metadata ()->values ();
165+ for (size_t mi = 0 ; mi < schemaKeys.size (); ++mi) {
166+ if (schemaKeys[mi] != " sourceMatcher" ) {
167+ continue ;
168+ }
169+ auto sourceTable = inputs.get <TableConsumer>(DataSpecUtils::fromString (schemaValues[mi]))->asArrowTable ();
170+ if (auto column = sourceTable->GetColumnByName (timestampColumnName); column && !timestampColumn) {
171+ timestampColumn = column;
172+ }
173+ if (auto column = sourceTable->GetColumnByName (uniformityColumnName); column && !uniformityColumn) {
174+ uniformityColumn = column;
175+ }
176+ }
177+ if (!timestampColumn) {
178+ LOGP (fatal, " No source table of {} provides the timestamp column \" {}\" " , outBinding, timestampColumnName);
179+ }
180+ if (!uniformityColumn) {
181+ LOGP (fatal, " No source table of {} provides the uniformity column \" {}\" " , outBinding, uniformityColumnName);
182+ }
183+ // Positional reading is only sound if the two sources are row-aligned; ASoA has
184+ // no type-level way to state that, so it is checked here.
185+ if (uniformityColumn->length () != timestampColumn->length ()) {
186+ LOGP (fatal, " Uniformity column \" {}\" has {} rows but timestamp column \" {}\" has {}; the two sources of {} are not row-aligned" ,
187+ uniformityColumnName, uniformityColumn->length (), timestampColumnName, timestampColumn->length (), outBinding);
188+ }
156189 auto reserveSize = timestampColumn->length ();
157190 O2_SIGNPOST_EVENT_EMIT_INFO (ccdb, sid, " fetchFromAnalysisCCDB" ,
158191 " There are %zu bindings available" , bindings.size ());
@@ -179,11 +212,50 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
179212
180213 std::vector<DataAllocator::CacheId> lastIds (numBuilders, DataAllocator::CacheId{.value = -1 , .handle = -1 , .segment = -1 });
181214
215+ // Rows sharing a uniformity value resolve to the same objects, so the query is
216+ // issued once per distinct value and the resulting handles are repeated for the
217+ // rest of the run. When uniformity is the timestamp itself (the default) this
218+ // degenerates to the previous behaviour, one query per row.
219+ std::vector<int64_t > uniformity;
220+ bool const shortCircuit = uniformityColumn.get () != timestampColumn.get ();
221+ if (shortCircuit) {
222+ uniformity.reserve (reserveSize);
223+ for (auto uci = 0 ; uci < uniformityColumn->num_chunks (); ++uci) {
224+ auto uchunk = uniformityColumn->chunk (uci);
225+ auto const length = uchunk->data ()->length ;
226+ switch (uchunk->type_id ()) {
227+ case arrow::Type::INT32 :
228+ for (int64_t ui = 0 ; ui < length; ++ui) {
229+ uniformity.push_back (uchunk->data ()->GetValuesSafe <int32_t >(1 )[ui]);
230+ }
231+ break ;
232+ case arrow::Type::INT64 :
233+ case arrow::Type::UINT64 :
234+ for (int64_t ui = 0 ; ui < length; ++ui) {
235+ uniformity.push_back (uchunk->data ()->GetValuesSafe <int64_t >(1 )[ui]);
236+ }
237+ break ;
238+ default :
239+ LOGP (fatal, " Uniformity column \" {}\" of {} has unsupported arrow type {}" ,
240+ uniformityColumnName, outBinding, uchunk->type ()->ToString ());
241+ }
242+ }
243+ }
244+ int64_t row = -1 ;
245+ int64_t previousUniformity = 0 ;
246+ bool haveResponses = false ;
247+ std::vector<CCDBFetcherHelper::Response> responses;
248+
182249 for (auto ci = 0 ; ci < timestampColumn->num_chunks (); ++ci) {
183250 std::shared_ptr<arrow::Array> chunk = timestampColumn->chunk (ci);
184251 auto const * timestamps = chunk->data ()->GetValuesSafe <size_t >(1 );
185252
186253 for (int64_t ri = 0 ; ri < chunk->data ()->length ; ri++) {
254+ ++row;
255+ bool const sameAsPrevious = shortCircuit && haveResponses && uniformity[row] == previousUniformity;
256+ if (shortCircuit) {
257+ previousUniformity = uniformity[row];
258+ }
187259 ops.clear ();
188260 int64_t timestamp = timestamps[ri];
189261 for (auto & field : schema->fields ()) {
@@ -198,7 +270,10 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/)
198270 .queryRate = 0 ,
199271 });
200272 }
201- auto responses = CCDBFetcherHelper::populateCacheWith (helper, ops, timingInfo, dtc, allocator);
273+ if (!sameAsPrevious) {
274+ responses = CCDBFetcherHelper::populateCacheWith (helper, ops, timingInfo, dtc, allocator);
275+ haveResponses = true ;
276+ }
202277 O2_SIGNPOST_START (ccdb, sid, " handlingResponses" ,
203278 " Got %zu responses from server." ,
204279 responses.size ());
0 commit comments