Skip to content

Add enriched dataset metadata and storage config registration - #396

Open
misiugodfrey wants to merge 8 commits into
mainfrom
misiug/dataGenValidation
Open

Add enriched dataset metadata and storage config registration#396
misiugodfrey wants to merge 8 commits into
mainfrom
misiug/dataGenValidation

Conversation

@misiugodfrey

@misiugodfrey misiugodfrey commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Motivation

Closes #389, closes #388, partially addresses #164.

When running benchmarks and posting results via post_results.py, the --storage-configuration-name flag has to be supplied manually by the user. There is no mechanism to verify that the storage configuration matches the actual dataset the benchmark ran on — a mismatch is silent and corrupts the database record. Similarly, metadata.json written by generate_data_files.py only recorded scale_factor and approx_row_group_bytes, making it impossible to fully reproduce a dataset or trace what configuration produced it.

Summary

  • Enriched metadata.json: generate_data_files.py now writes a complete record of how a dataset was generated — benchmark type, generator (tpchgen/duckdb) and version, scale factor, parquet version, codec definitions, row group settings, and the absolute data path. The schema is self-contained enough to fully replicate a dataset from metadata alone.

  • New register_storage_config.py: Standalone CLI that registers a dataset as a storage configuration in the benchmarking database (POST /api/storage-configs/). Auto-detects storage system type (via findmnt + lsblk) and GDS status (via lsmod); derives compression from codec definitions; auto-generates the config name as {machine}-{storage_system}-{benchmark_type}-sf{N}. Does a pre-flight GET to prevent duplicate names. Writes storage_configuration_name back into metadata.json after successful registration. Also callable inline via a --register flag group on generate_data_files.py for simple generate-and-register workflows — datasets that need modification before registration can call the script separately.

  • Auto-detection and validation in post_results.py: --storage-configuration-name is now optional. The script reads storage_configuration_name from metadata.json in the dataset directory (via data_dir in benchmark_result.json context). When a name is provided explicitly, it is validated against the registered name in metadata.json:

    • Matches registered name → proceeds silently
    • Differs from registered name → warning (mismatch)
    • No registered name in metadata → warning (could not validate)
    • Not provided and registered name found → auto-detected
    • Not provided and no registered name → error pointing to register_storage_config.py

Test plan

  • Generate TPC-H dataset via tpchgen and verify all new fields in metadata.json
  • Generate TPC-H dataset via DuckDB and verify tpchgen-only fields are absent
  • Generate TPC-DS dataset and verify benchmark_type and labels are correct
  • register_storage_config.py --dry-run on tpchgen dataset — verify payload shape, auto-detected fields, auto-generated name, and codec_definitions embedded in table_metadata
  • register_storage_config.py --dry-run on DuckDB dataset — verify tpchgen-only fields absent from table_metadata
  • post_results.py --dry-run without --storage-configuration-name — verified auto-detection from metadata.json via data_dir in benchmark context
  • _resolve_storage_configuration returns None with helpful message when storage_configuration_name absent from metadata.json
  • _resolve_storage_configuration returns None with helpful message when no metadata.json found
  • BenchmarkMetadata.data_dir correctly populated from benchmark result context
  • register_storage_config.py with a live API key — verify pre-flight collision check and storage_configuration_name written back to metadata.json
  • post_results.py with mismatched --storage-configuration-name — verify warning is printed
  • post_results.py with manually provided --storage-configuration-name and no registered name in metadata.json — verify warning is printed
  • post_results.py with no metadata.json and no flag — verify helpful error message
  • --register inline flag on generate_data_files.py
  • --convert-decimals-to-floats reflected correctly in metadata.json
  • --name override on register_storage_config.py

Enriches metadata.json written by generate_data_files.py to capture all
generation parameters (benchmark_type, generator, generator_version,
parquet_version, codec_definitions, convert_decimals_to_floats,
max_rows_per_file, approx_row_group_bytes, data_dir_path) so a dataset
can be fully replicated from metadata alone.

Adds register_storage_config.py, a new tool that POSTs a dataset to
/api/storage-configs/ and writes the resulting storage_configuration_name
back into metadata.json. Storage system type and GDS are auto-detected
from the filesystem (findmnt/lsblk/lsmod) with CLI overrides; the config
name is auto-generated as {machine}-{storage_system}-{benchmark_type}-sf{N}.
A pre-flight GET check prevents duplicate names. A --register flag group
on generate_data_files.py calls this step immediately after generation for
the common case; datasets that need modification before registration can
call register_storage_config.py separately.

Updates post_results.py to make --storage-configuration-name optional:
it is auto-detected from storage_configuration_name in metadata.json
found via data_dir in benchmark_result.json context. A mismatch between
an explicit flag value and the metadata value produces a warning rather
than an error, preserving intentional overrides.
findmnt without --target requires an exact mount point; using --target
correctly traverses up to find the filesystem for any given path.
@copy-pr-bot

copy-pr-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Moves the constant to the top of the file so it serves as the single
source of truth for both the actual tpchgen-cli invocation and the
metadata.json record, preventing them from silently diverging.
httpx is already in benchmark_data_tools/requirements.txt and the
script is imported as a module, so the PEP 723 block serves no purpose.
When --storage-configuration-name is explicitly supplied but the dataset
has no registered name in metadata.json, print a warning so the user
knows the provided name was not checked against the actual dataset.
rc = register_storage_config(
data_dir=Path(args.data_dir_path),
machine=args.register_machine,
name=args.register_name,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these should be automatically determined, but they can be manually overwritten via flag if desired.

default=False,
help="Register the dataset as a storage configuration after generation.",
)
reg.add_argument(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's debatable if we want to include these overrides; they should usually not be used.

return 1
storage_configuration_name = resolved_storage_config
elif resolved_storage_config and resolved_storage_config != storage_configuration_name:
print(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now we give some deference to the user when there is a mismatch - assuming the user wants to submit using an older storage configuration and they know what they are doing. We could make this a proper error, but right now I don't want to block older workflows.

Perhaps we strengthen this once we have generated new datasets and hardened their usage?

@misiugodfrey
misiugodfrey marked this pull request as ready for review July 31, 2026 17:40
@misiugodfrey
misiugodfrey requested a review from a team as a code owner July 31, 2026 17:40
def _detect_gds_enabled() -> bool:
"""Return True if the nvidia-fs kernel module (GPU Direct Storage) is loaded."""
try:
result = subprocess.run(["lsmod"], capture_output=True, text=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note that I think this is reflecting an issue with the database's data model: whether some dataset is over accessible over GDS is less about the dataset itself and more about the compute node and its path to the storage system. This check doesn't touch the dataset or its storage system: just the system that lsmod is running on.

Nothing to do for now, but LMK if this felt awkward to you too and maybe we can find a better way to model that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point. I think for now there should not be a difference since the system should always be running on the same nodes that access the data (this is true even on our slurm systems); but it's something I'll confirm in testing.

@misiugodfrey
misiugodfrey requested a review from qbacpey August 10, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Have benchmark generation include more info in metadata.json Automate post_results options

2 participants