|
| 1 | +Migrate the specified file (or all files mentioned in the conversation) from `Service<o2::ccdb::BasicCCDBManager>` to the declarative CCDB table approach. |
| 2 | + |
| 3 | +## Background |
| 4 | + |
| 5 | +The old approach uses `Service<o2::ccdb::BasicCCDBManager>` and calls `ccdb->getForTimeStamp<T>(path, timestamp)` at runtime. The new approach declares CCDB columns and timestamped tables using macros, so the framework fetches objects automatically and exposes them as columns on BC rows. |
| 6 | + |
| 7 | +**New API summary:** |
| 8 | + |
| 9 | +```cpp |
| 10 | +// In namespace o2::aod (or a sub-namespace): |
| 11 | +DECLARE_SOA_CCDB_COLUMN(StructName, getterName, ConcreteType, "CCDB/Object/Path"); |
| 12 | + |
| 13 | +DECLARE_SOA_TIMESTAMPED_TABLE(TableName, aod::Timestamps, o2::aod::timestamp::Timestamp, 1, "TABLEDESC", |
| 14 | + ns::StructName, ns::OtherColumn); |
| 15 | + |
| 16 | +// In the task — basic usage: |
| 17 | +using MyBCs = soa::Join<aod::BCsWithTimestamps, aod::TableName>; |
| 18 | +void process(MyBCs const& bcs) { |
| 19 | + for (auto const& bc : bcs) { |
| 20 | + auto const& obj = bc.getterName(); // reference to cached deserialized object; treat as immutable |
| 21 | + } |
| 22 | +} |
| 23 | +``` |
| 24 | +
|
| 25 | +**Configurable CCDB paths** (`ConfigurableCCDBPath<Column>`): |
| 26 | +
|
| 27 | +If the original task used a `Configurable<std::string>` to supply the CCDB path, the path can remain user-overridable after migration using `ConfigurableCCDBPath<Column>`. This is a typed `Configurable<std::string>` whose option name is automatically set to `"ccdb:" + Column::mLabel` (where `mLabel = "f" + StructName`), defaulting to the compile-time path in the column declaration. The framework reads this option name when resolving CCDB URLs, so users can still redirect the path via JSON config. |
| 28 | +
|
| 29 | +The Configurable is purely declarative for the path-override mechanism: declaring it is sufficient — you do **not** pass `.value` to a getter or fetcher. The accessor remains `bc.getterName()`. The `.value` member is still available if the task wants to log the resolved path. |
| 30 | +
|
| 31 | +```cpp |
| 32 | +struct MyTask { |
| 33 | + // Replaces: Configurable<std::string> grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "..."}; |
| 34 | + ConfigurableCCDBPath<ns::GRPMagField> grpMagFieldPath; // option name = "ccdb:fGRPMagField" |
| 35 | +
|
| 36 | + void process(MyBCs const& bcs) { |
| 37 | + auto const& grpmag = bcs.iteratorAt(0).grpMagField(); // path override is honoured automatically |
| 38 | + LOGP(info, "Using GRPMagField path: {}", grpMagFieldPath.value); |
| 39 | + } |
| 40 | +}; |
| 41 | +``` |
| 42 | + |
| 43 | +Required headers (add if missing): `<Framework/ASoA.h>`, `<Framework/AnalysisDataModel.h>`, `<Framework/Configurable.h>` |
| 44 | +Headers to remove (if no longer needed): `<CCDB/BasicCCDBManager.h>` |
| 45 | + |
| 46 | +## What to do |
| 47 | + |
| 48 | +Read the target file(s) and perform the following migration. Do NOT do a complete migration if the patterns are ambiguous or out of scope — instead note what was skipped and why. |
| 49 | + |
| 50 | +### Step 1 — Inventory |
| 51 | + |
| 52 | +Find every `ccdb->getForTimeStamp<T>(path, ts)` call (and variants like `fCCDB->getForTimeStamp`, `mCcdb->getForTimeStamp`). For each call record: |
| 53 | +- The concrete C++ type `T` |
| 54 | +- The CCDB path string (may be a `Configurable` variable — record the default value and the Configurable's name) |
| 55 | +- The timestamp source (BC timestamp, computed value, etc.) |
| 56 | +- Where the result is used |
| 57 | + |
| 58 | +**Deduplicate**: for the same (type, path) pair, declare only one CCDB column. Multiple call sites collapse into multiple uses of the same getter. |
| 59 | + |
| 60 | +### Step 2 — Identify scope |
| 61 | + |
| 62 | +Determine whether each fetch is: |
| 63 | +- **Per-BC/per-collision** (called inside `process()` with a timestamp from a BC) — these can be migrated |
| 64 | +- **Per-run** (called once when `runNumber` changes, guarded by `mRunNumber == ...`) — these can be migrated; the framework caches per unique timestamp automatically |
| 65 | +- **Global/init-time** (called in `init()` with a fixed timestamp, not keyed to a BC) — these **cannot** be migrated to CCDB tables; leave them as-is and note this |
| 66 | + |
| 67 | +Skip the migration for any global/init-time fetches. Skip the whole file if all fetches are global. |
| 68 | + |
| 69 | +### Step 3 — Declare CCDB columns and table |
| 70 | + |
| 71 | +In the `o2::aod` namespace (or a private sub-namespace inside the file, before the task struct), declare: |
| 72 | + |
| 73 | +```cpp |
| 74 | +namespace o2::aod |
| 75 | +{ |
| 76 | +namespace myccdbtask // use a short, unique snake_case name derived from the task name |
| 77 | +{ |
| 78 | +DECLARE_SOA_CCDB_COLUMN(StructName, getterName, fully::qualified::ConcreteType, "CCDB/Path"); //! |
| 79 | +// one per unique (type, path) pair |
| 80 | +} // namespace myccdbtask |
| 81 | + |
| 82 | +DECLARE_SOA_TIMESTAMPED_TABLE(MyTaskCCDBObjects, aod::Timestamps, o2::aod::timestamp::Timestamp, 1, "MYTASKCCDB", //! |
| 83 | + myccdbtask::StructName /*, ... */); |
| 84 | +} // namespace o2::aod |
| 85 | +``` |
| 86 | +
|
| 87 | +Rules for naming: |
| 88 | +- `StructName` / `getterName`: derive from the type name, e.g. `GRPMagField` / `grpMagField`, `MeanVertex` / `meanVertex` |
| 89 | +- Table name: `<TaskStruct>CCDBObjects`, e.g. `SkimmerDalitzEECCDBObjects` |
| 90 | +- `_Desc_` string: short ALL-CAPS string unique within the binary (≤ 16 chars to fit the AOD descriptor), e.g. `"DALZECC"`, `"TOFCALIB"` |
| 91 | +- Namespace: lowercase snake-case derived from the task name (avoid collisions with other CCDB column namespaces in the file) |
| 92 | +- Use the **default value** of any `Configurable` path as the compile-time path in the `DECLARE_SOA_CCDB_COLUMN` macro; if the path has no obvious default, leave a `// TODO: verify path` comment |
| 93 | +
|
| 94 | +### Step 4 — Update the task struct |
| 95 | +
|
| 96 | +1. **Remove** `Service<o2::ccdb::BasicCCDBManager> ccdb;` (and any variant field name) |
| 97 | +2. **Remove** `int mRunNumber;` (or similar run-caching variables) **only if** their sole purpose was to guard CCDB re-fetches |
| 98 | +3. **Remove** `ccdb->setURL(...)`, `ccdb->setCaching(...)`, `ccdb->setLocalObjectValidityChecking()`, `ccdb->setCreatedNotAfter(...)`, `ccdb->setFatalWhenNull(...)` from `init()` |
| 99 | +4. **Remove** the entire `initCCDB()`/`initMagField()` helper method if it only did CCDB fetching; otherwise remove just the CCDB lines from it |
| 100 | +5. **Handle path Configurables** — for each `Configurable<std::string>` that held a CCDB path: |
| 101 | + - If the path was used as the sole argument to `getForTimeStamp` and the user may want to override it at runtime: **replace** it with `ConfigurableCCDBPath<ns::ColumnName>` (e.g. `ConfigurableCCDBPath<ns::GRPMagField> grpMagFieldPath;`). The member name should match the getter for clarity. Keep a comment explaining what path it controls. |
| 102 | + - If the path was never intended to be user-facing (e.g. internal fixed paths): **remove** it outright; the compile-time path in `DECLARE_SOA_CCDB_COLUMN` is sufficient. |
| 103 | + - Always remove Configurables that were only used for CCDB manager setup and not for paths: `ccdb-url`, `ccdb-no-later-than`, `skipGRPOquery`, `d_bz_input` (if only used to bypass CCDB), etc. |
| 104 | +6. **Remove** cached pointer member variables (e.g. `GRPMagField* grpmag = nullptr`) if they were only populated by CCDB fetches that are now replaced |
| 105 | +
|
| 106 | +### Step 5 — Update process() signatures |
| 107 | +
|
| 108 | +Define one alias near the top of the task or just below the table declaration: |
| 109 | +```cpp |
| 110 | +using MyBCs = soa::Join<aod::BCsWithTimestamps, aod::MyTaskCCDBObjects>; |
| 111 | +``` |
| 112 | + |
| 113 | +Then for each `process()` that used to call `getForTimeStamp`: |
| 114 | + |
| 115 | +- If `process()` already takes `aod::BCsWithTimestamps const&` directly: change it to `MyBCs const&`. |
| 116 | +- If `process()` accesses BCs via `collision.bc_as<aod::BCsWithTimestamps>()`: add `MyBCs const&` to the process signature (so the framework knows to provide it) and replace the `bc_as<>` type with `MyBCs`. |
| 117 | +- If `process()` does not currently mention BCs but called `ccdb->getForTimeStamp(path, collision.bc_as<...>().timestamp())`: add `MyBCs const&` to the signature and obtain the BC via `collision.bc_as<MyBCs>()`. |
| 118 | +- Replace every `ccdb->getForTimeStamp<T>(path, ts)` call with `bc.getterName()`. The returned reference is to a cached deserialized object; treat it as immutable. |
| 119 | +- Null-pointer checks (`if (!grpmag)`) on the result become unnecessary — the framework guarantees the object is present (or the task fails early). Remove them. |
| 120 | +- If a helper template like `initCCDB(collision)` was called per-collision, inline its remaining (non-CCDB) work or drop it. |
| 121 | + |
| 122 | +### Step 6 — Fix includes |
| 123 | + |
| 124 | +- Remove `#include <CCDB/BasicCCDBManager.h>` if no other code in the file still uses `BasicCCDBManager` |
| 125 | +- Ensure `#include <Framework/ASoA.h>` is present (may already be included transitively) |
| 126 | +- Keep all type headers (e.g. `<DataFormatsParameters/GRPMagField.h>`) since they are still needed for the concrete type |
| 127 | + |
| 128 | +### Step 7 — Final review |
| 129 | + |
| 130 | +After making changes: |
| 131 | +- Check that every remaining use of `ccdb` / `fCCDB` / `mCcdb` has been handled |
| 132 | +- Check that `mRunNumber` (or similar) is fully removed if unused |
| 133 | +- Check that any leftover `Configurable<std::string>` for a path is either replaced by `ConfigurableCCDBPath<>` or removed |
| 134 | +- Search for stale references to removed Configurables (e.g. `grpmagPath.value` lingering in log messages — switch to `grpMagFieldPath.value`) |
| 135 | +- If `init()` is now empty, it can be removed |
| 136 | +- Note any patterns that were intentionally skipped |
| 137 | + |
| 138 | +## Important limitations — tell the user if any apply |
| 139 | + |
| 140 | +- **Configurable paths**: CCDB column paths are compile-time constants in the macro. Add `ConfigurableCCDBPath<Column>` to allow runtime override; its default is `Column::query` so it always agrees with the macro by construction. |
| 141 | +- **`getRunDuration()` calls**: these use `BasicCCDBManager` statically and are unrelated to per-BC fetching — do not touch them. |
| 142 | +- **`ctpRateFetcher` / other helpers**: out of scope. |
| 143 | +- **Multiple tasks in one file**: tasks can share a single CCDB table declaration if they need the same objects; otherwise each task gets its own with a unique `_Desc_`. |
| 144 | +- **Non-BC timestamps**: if the timestamp comes from something other than a BC (e.g. computed manually), the migration is non-trivial — flag it instead of forcing it. |
| 145 | +- **Global/init-time fetches** (e.g. `efficiencyGlobal.cxx` style): not migratable — the timestamped-table mechanism requires a row in a BC-keyed table. |
| 146 | +- **Magnetic-field side effects**: tasks that compute `d_bz` from a fetched `GRPMagField` and seed a propagator can keep that logic, just sourcing the object from `bc.grpMagField()` instead of `ccdb->getForTimeStamp(...)`. |
| 147 | + |
| 148 | +$ARGUMENTS |
0 commit comments