Skip to content

Commit 8390552

Browse files
authored
Merge pull request #675 from Climate-REF/perf/skip-redundant-validate
perf(ingest): drop redundant per-dataset validate_data_catalog call
2 parents 074d56c + 43cdd29 commit 8390552

4 files changed

Lines changed: 59 additions & 4 deletions

File tree

changelog/675.improvement.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Skip the redundant per-dataset `validate_data_catalog` call inside `register_dataset`.
2+
The production ingest path already validates the catalog (and each streamed chunk) once
3+
up-front, so the inner re-validation only duplicated work. Cuts ~20% off ingest wall time
4+
on a 50k-file / 500-dataset synthetic CMIP6 archive. A cheap per-slice guard (no groupby)
5+
remains so callers that bypass the upstream validation contract still get a clear error
6+
instead of silently registering inconsistent metadata.

packages/climate-ref/conftest.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,19 @@ def db_seeded_template(tmp_path_session, cmip6_data_catalog, obs4mips_data_catal
8484
database = Database(f"sqlite:///{template_db_path}")
8585
database.migrate(config)
8686

87-
# Seed the CMIP6 sample datasets
87+
# Seed the CMIP6 sample datasets. ``register_dataset`` trusts callers to
88+
# have already validated the catalog, so do that here before iterating.
8889
adapter = CMIP6DatasetAdapter()
90+
cmip6_validated = adapter.validate_data_catalog(cmip6_data_catalog)
8991
with database.session.begin():
90-
for instance_id, data_catalog_dataset in cmip6_data_catalog.groupby(adapter.slug_column):
92+
for instance_id, data_catalog_dataset in cmip6_validated.groupby(adapter.slug_column):
9193
adapter.register_dataset(database, data_catalog_dataset)
9294

9395
# Seed the obs4MIPs sample datasets
9496
adapter_obs = Obs4MIPsDatasetAdapter()
97+
obs4mips_validated = adapter_obs.validate_data_catalog(obs4mips_data_catalog)
9598
with database.session.begin():
96-
for instance_id, data_catalog_dataset in obs4mips_data_catalog.groupby(adapter_obs.slug_column):
99+
for instance_id, data_catalog_dataset in obs4mips_validated.groupby(adapter_obs.slug_column):
97100
adapter_obs.register_dataset(database, data_catalog_dataset)
98101

99102
with database.session.begin():

packages/climate-ref/src/climate_ref/datasets/base.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,26 +204,45 @@ def register_dataset( # noqa: PLR0912, PLR0915
204204
"""
205205
Register a dataset in the database using the data catalog
206206
207+
This assumes that the data catalog has already been validated with `validate_data_catalog`
208+
to ensure that the dataset-specific metadata is consistent across all files in the dataset.
209+
207210
Parameters
208211
----------
209212
db
210213
Database instance
211214
data_catalog_dataset
212215
A subset of the data catalog containing the metadata for a single dataset
213216
217+
218+
Raises
219+
------
220+
RefException
221+
If the data catalog contains validation errors that should have been caught by
222+
`validate_data_catalog` (i.e. multiple unique slugs in `slug_column`).
223+
224+
214225
Returns
215226
-------
216227
:
217228
Registration result with dataset and file change information
218229
"""
219230
DatasetModel = self.dataset_cls
220231

221-
self.validate_data_catalog(data_catalog_dataset)
222232
unique_slugs = data_catalog_dataset[self.slug_column].unique()
223233
if len(unique_slugs) != 1:
224234
raise RefException(f"Found multiple datasets in the same directory: {unique_slugs}")
225235
slug = unique_slugs[0]
226236

237+
# Callers are responsible for validating the catalog with ``validate_data_catalog`` before invoking.
238+
# This is a strict subset of ``validate_data_catalog`` to catch skipping upstream validation.
239+
slice_meta = data_catalog_dataset[list(self.dataset_specific_metadata)]
240+
if (slice_meta.nunique(dropna=False) > 1).any():
241+
raise RefException(
242+
f"Dataset {slug} has inconsistent dataset-specific metadata; "
243+
"callers must pre-validate the catalog with validate_data_catalog."
244+
)
245+
227246
# Check if the incoming data is unfinalised (DRS parser) and the dataset
228247
# already exists as finalised. In that case, skip the entire update to
229248
# avoid regressing metadata that was populated during finalisation.

packages/climate-ref/tests/unit/datasets/test_datasets.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,33 @@ def test_register_dataset_multiple_datasets_error(monkeypatch, test_db):
338338
adapter.register_dataset(db=db, data_catalog_dataset=df)
339339

340340

341+
def test_register_dataset_inconsistent_metadata_raises(monkeypatch, test_db):
342+
"""Callers that bypass validate_data_catalog must still be protected from
343+
silently registering a slice whose dataset-specific metadata varies."""
344+
adapter, db = test_db
345+
346+
df = _mk_df(
347+
rows=[
348+
{
349+
"path": "a.nc",
350+
"start_time": "2001-01-01",
351+
"end_time": "2001-12-31",
352+
"experiment_id": "historical",
353+
},
354+
{
355+
"path": "b.nc",
356+
"start_time": "2002-01-01",
357+
"end_time": "2002-12-31",
358+
"experiment_id": "ssp585",
359+
},
360+
]
361+
)
362+
363+
with pytest.raises(RefException, match="inconsistent dataset-specific metadata"):
364+
with db.session.begin():
365+
adapter.register_dataset(db=db, data_catalog_dataset=df)
366+
367+
341368
def test_register_dataset_updates_dataset_metadata(monkeypatch, test_db):
342369
"""Test that changes to dataset metadata are properly captured and result in UPDATED state"""
343370
adapter, db = test_db

0 commit comments

Comments
 (0)