From 3ba2a77766df37025ba45403119ca319aab11bab Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Fri, 30 Oct 2026 14:02:52 +0100 Subject: [PATCH 1/2] getCCDBTimeMachineTimestamp.py: do second CCDB query before uploading new object --- GRID/utils/getCCDBTimeMachineTimestamp.py | 33 ++++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/GRID/utils/getCCDBTimeMachineTimestamp.py b/GRID/utils/getCCDBTimeMachineTimestamp.py index f5b4619e6..f293501bc 100755 --- a/GRID/utils/getCCDBTimeMachineTimestamp.py +++ b/GRID/utils/getCCDBTimeMachineTimestamp.py @@ -211,7 +211,7 @@ def query_CCDBTimeMachineTS(base_url, user, period, passname): Queries CCDBTimeMachineTS from CCDB for a given period and pass. Returns: - obtained NotAfter timestamp (int) or None + (tuple) (obtained NotAfter timestamp (int), True) or (None, False) """ # Construct user ID-specific cert and key paths cert_path, key_path = make_cert_paths() @@ -235,9 +235,9 @@ def filter_known_fields(cls, data: dict) -> dict: print(f"[getCCDBTimeMachineTimestamp] Found object for {clean_meta['Period']}, Pass: {clean_meta['Pass']}, " f"NotAfter: {clean_meta['NotAfter']} ({human(clean_meta['NotAfter'])}), uploaded by LPMProductionTag {clean_meta['LPMProductionTag']}", file=sys.stderr) - return clean_meta['NotAfter'] + return clean_meta['NotAfter'], True - return None + return None, False def upload_CCDBTimeMachineTS(base_url, user, keys): @@ -288,20 +288,27 @@ def get_CCDBTimeMachineTS(production_tag, year, period, run, passname, Returns: int: Either the queried or the estimated NotAfter timestamp """ + found = False if not skip_ccdb_query: - not_after = query_CCDBTimeMachineTS(ccdb_url, username, period, passname) - else: - not_after = None + not_after, found = query_CCDBTimeMachineTS(ccdb_url, username, period, passname) - if not_after is not None and force_overwrite == True: - print("[getCCDBTimeMachineTimestamp] Existing object will be overwritten", file=sys.stderr) - - if not_after == None or force_overwrite == True: + if not found or force_overwrite: print("[getCCDBTimeMachineTimestamp] Estimating CCDBTimeMachineTS for " f"LPMProductionTag: {production_tag}, Period: {period}, Pass: {passname}", file=sys.stderr) not_after = get_NotAfter(year, period, run, passname, samples, ccdb_check_path, ccdb_check) - time_machine_ts = CCDBTimeMachineTS(production_tag, period, passname, not_after) + if publish_to_ccdb: + if not found: + # check again in case another subjob uploaded an object in the meantime + not_after_q, found = query_CCDBTimeMachineTS(ccdb_url, username, period, passname) + + if found: + if force_overwrite: + print("[getCCDBTimeMachineTimestamp] Existing object will be overwritten", file=sys.stderr) + else: + return not_after_q + + time_machine_ts = CCDBTimeMachineTS(production_tag, period, passname, not_after) upload_CCDBTimeMachineTS(ccdb_url, username, dataclasses.asdict(time_machine_ts)) return not_after @@ -335,11 +342,11 @@ def main(): help="overwrite the current CCDBTimeMachineTS object in the CCDB if one exists") parser.add_argument("--ccdb-url", default="https://alice-ccdb.cern.ch", help="ccdb host for the upload") - parser.add_argument("--username", default="aliprod", + parser.add_argument("--username", default=os.environ.get("JALIEN_USER"), help="username to be used for the upload to CCDB") args = parser.parse_args() - missing = [n for n in ("year", "period", "run", "passname") if not getattr(args, n)] + missing = [n for n in ("production_tag", "year", "period", "run", "passname", "username") if not getattr(args, n)] if missing: parser.error("missing required value(s): " + ", ".join(missing)) From 5c2b525748de7b8790a3cb56c8de6b8bea231a5f Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Fri, 30 Oct 2026 15:58:01 +0100 Subject: [PATCH 2/2] [WIP] Get CCDB time machine timestamp from CCDB by default in anchorMC.sh Related JIRA ticket: https://its.cern.ch/jira/browse/O2-6543 This will use the script GRID/utils/getCCDBTimeMachineTimestamp.py in anchorMC.sh to obtain the CCDB time machine timestamp from the CCDB (or estimate it from the given anchored apass output files). This is now the default behavior. If the timestamp cannot be obtained, anchorMC.sh exits with an error. If set, the JDL vairable `ALIEN_JDL_CCDB_CONDITION_NOT_AFTER` can still be used to set the `--condition-not-after` timestamp by hand instead of obtaining it from CCDB. The default object path for the time machine timestamp is `Users/a/aliprod/CCDBTimeMachineTS`. All objects are uploaded with validity `1:2`, and the metadata contains the pass, period, NotAfter and LPMProductionTag (to track the productions which uploaded the object). So there should be one object per reconstruction pass per period, valid for all runs of the given pass and period. Some test examples are already uploaded in http://ccdb-test.cern.ch:8080/browse/Users/e/ehellbar/CCDBTimeMachineTS. This PR contains two commits: 1) in getCCDBTimeMachineTimestamp.py - add a second CCDB query to check for existing objects right before the upload of a new object, to check if between the last empty query and now (after the estimation of the not-after timestamp from the reco output) another job was faster and already uploaded the object. This is an attempt to avoid duplicate objects for the same period/pass uploaded by a single LPMProductionTag. NB: a more elegent way to create these CCDBTimeMachineTS objects by default could be at the beginning or the end of the actual data reconstruction pass. 2) use getCCDBTimeMachineTimestamp.py in anchorMC.sh to obtain the CCDB time machine timestamp by default, keeping the current `ALIEN_JDL_CCDB_CONDITION_NOT_AFTER` option to enforce it by hand I mark this as WIP since the following is still missing: - treatment of MC specific CCDB objects: There is a handful of MC CCDB paths (TPC corrections, GLO/Param/MatLUT) for which the objects are uploaded independently of the data calibration objects, so the NotAfter as it is obtained here might invalidate the correct object to use. With Giulio, Ruben and Costin, we are working on an elegant way to handle this. - I still need to run a small test on the grid to finally validate the implementation. --- MC/run/ANCHOR/anchorMC.sh | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/MC/run/ANCHOR/anchorMC.sh b/MC/run/ANCHOR/anchorMC.sh index 00615a253..679171e28 100755 --- a/MC/run/ANCHOR/anchorMC.sh +++ b/MC/run/ANCHOR/anchorMC.sh @@ -354,7 +354,29 @@ remainingargs="${ALIEN_JDL_ANCHOR_SIM_OPTIONS} ${remainingargs} --anchor-config ALIEN_JDL_O2DPG_ASYNC_RECO_FROMSTAGE=${ALIEN_JDL_O2DPG_ASYNC_RECO_FROMSTAGE:-RECO} remainingargs="${remainingargs} ${ALIEN_JDL_O2DPG_ASYNC_RECO_TAG:+--alternative-reco-software ${PWD}/env_async.env@${ALIEN_JDL_O2DPG_ASYNC_RECO_FROMSTAGE}}" # potentially add CCDB timemachine timestamp -remainingargs="${remainingargs} ${ALIEN_JDL_CCDB_CONDITION_NOT_AFTER:+--condition-not-after ${ALIEN_JDL_CCDB_CONDITION_NOT_AFTER}}" +if [[ -n ${ALIEN_JDL_CCDB_CONDITION_NOT_AFTER} ]]; then + # override CCDB time machine timestamp by hand, use e.g. 3385078236000 to effectively disable it + ARG_CONDITION_NOT_AFTER="--condition-not-after ${ALIEN_JDL_CCDB_CONDITION_NOT_AFTER}" +else + # options to set CCDB url, disable upload and force overwrite of an existing timestamp; default to production CCDB, uploading the object and not overwriting + : ${CCDBTIMEMACHINE_CCDB_URL:=https://alice-ccdb.cern.ch} + [[ ${CCDBTIMEMACHINE_SKIP_UPLOAD:-} != "1" ]] && CCDBTIMEMACHINE_OPTIONS+=" --publish-to-ccdb" + [[ ${CCDBTIMEMACHINE_FORCE_OVERWRITE:-} == "1" ]] && CCDBTIMEMACHINE_OPTIONS+=" --force-overwrite" + + # obtain CCDB time machine timestamp from CCDB or, if not available, estimate it from the creation time of the reconstruction output files + CCDBTIMEMACHINE_CMD="${O2DPG_ROOT}/GRID/utils/getCCDBTimeMachineTimestamp.py --ccdb-url $CCDBTIMEMACHINE_CCDB_URL ${CCDBTIMEMACHINE_OPTIONS:-}" + echo "Running command to obtain CCDB time machine timestamp: ${CCDBTIMEMACHINE_CMD}" + CCDBTIMEMACHINE_TS=$(${CCDBTIMEMACHINE_CMD}) + + # return an error if the timestamp could not be obtained + if [[ -n ${CCDBTIMEMACHINE_TS} ]]; then + ARG_CONDITION_NOT_AFTER="--condition-not-after ${CCDBTIMEMACHINE_TS}" + else + echo_error "Could not obtain CCDB time machine timestamp. Exiting." + exit 1 + fi +fi +remainingargs="${remainingargs} ${ARG_CONDITION_NOT_AFTER:-}" echo_info "baseargs passed to o2dpg_sim_workflow_anchored.py: ${baseargs}" echo_info "remainingargs forwarded to o2dpg_sim_workflow.py: ${remainingargs}"