Skip to content

Commit 5036d9e

Browse files
committed
Add command to migrate away from BasicCCDBManager in Analysis
1 parent 19a89c5 commit 5036d9e

1 file changed

Lines changed: 148 additions & 0 deletions

File tree

.claude/commands/migrate-ccdb.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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

Comments
 (0)