Updating a dataset¶
This page is for maintainers. It describes how to add a new version of one dataset to the server and release it, without breaking the other datasets or older releases.
How datasets are served¶
- Each dataset is an HDF5 file in
s3://gadopt/g-drift/(DigitalOcean Spaces,syd1, public-read). The object name is the sha256 of the file content plus.h5. Thefilenamefield ingdrift/datasets.jsongives this name. gdrift/datasets.jsonalso lists the sha256 and the server ETag of each file.load_datasetchecks the sha256 of every file. On a mismatch it downloads the file again, and it raises if the new download also does not match.- A new version of a dataset has a new sha256, so it gets a new object name. Each release
keeps its own
datasets.json, so it keeps the object names of its own versions. For this reason, never delete or overwrite an object on the server. - gdrift 0.1.3 and earlier use a different object name:
hash_name(<dataset name>) + ".h5". These objects must also stay on the server unchanged. 0.1.1 cannot load LLNL-G3D-JPS, MITP08, SEMUCB-WM1 and HMSL-P06, because 0.1.2 replaced these four objects (see issue 41). tests/test_server_hashes.py(markerserver) compares every server ETag with the manifest. It also checks that the objects of 0.1.2 and 0.1.3 are unchanged, with the names and ETags intests/legacy_objects_v0.1.3.json. The publish workflow runs it, so the ETags must be correct before you tag.
Local files¶
- The loader caches downloads in
$GDRIFT_DATA_DIR. If this variable is not set, it uses the user cache directory (~/Library/Caches/gdrifton macOS,~/.cache/gdrifton Linux). - Before the loader downloads a file, it looks in
gdrift/data/in the package, under the content name and under the name-based name of 0.1.3 and earlier. It uses a file there only if its sha256 matches the manifest. The conversion scripts write new files to this directory, so you can test a new version before you upload it.
Things to avoid¶
- Do not delete or overwrite an object under
s3://gadopt/g-drift/. Older releases can point to it. scripts/fix_seismic_units.pyedits every seismic dataset ingdrift/data/in place and rewrites all ofdatasets.json. Its km/s test (max < 100) fails for a field with NaN.s3cmd infoshows the md5 that s3cmd stored, not the object ETag. Read the ETag with an unsignedhead_objectorcurl -sI.scripts/convert_seismic_models.pywrites its output intogdrift/data/andnew_seismic_manifest_entries.jsoninto the working directory. Run it from the repository root, or give--output-dir.
Procedure¶
- Fix the conversion code and rebuild the file. Compare it with the old file and with the source.
- Put the new sha256 into
datasets.json, and setfilenameto<sha256>.h5. Setetagtonull. Runpytest tests -q -m "not server"andflake8 gdrift examples tests. The tests load the new file fromgdrift/data/. Onlytest_every_dataset_has_an_etagfails, because the new files are not uploaded yet. - Upload the new files before you push. CI starts with an empty cache, so it downloads
the new files from the server. First make sure that the content name is not on the server
yet.
s3cmd putoverwrites an existing object without a warning. An existing object has the same content, because the name is its hash, but its ETag can change.curl -sI https://syd1.digitaloceanspaces.com/gadopt/g-drift/<sha256>.h5
If the answer is 404, upload the new file under its content name:
s3cmd -c ~/.s3cfg-gadopt put --acl-public --mime-type=application/x-hdf5 gdrift/data/<file> s3://gadopt/g-drift/<sha256>.h5
For several files, put them in gdrift/data-sia/<dataset name>.h5 and run
scripts/upload_to_s3.py --execute. It checks the sha256 of each file against the
manifest and skips any object that already exists.
4. Check each new object: download it through the CDN
(https://gadopt.syd1.cdn.digitaloceanspaces.com/g-drift/<sha256>.h5) and compare its
sha256 with the manifest.
5. Put the new ETags into datasets.json with
scripts/migrate_to_content_names.py --update-etags. It writes the manifest only if every
object exists. Check with git diff that only the etag lines of the new files change.
Run pytest tests/test_server_hashes.py -m server and the full test suite.
6. Commit on a branch, push, open the pull request, wait for green CI, and merge.
7. Tag the merge commit (vX.Y.Z) and push the tag. The publish workflow tests, builds,
publishes to TestPyPI and PyPI, and creates the GitHub release. Then set the notes with
gh release edit and name every change since the previous tag.
8. Check the release. Install it in a new venv with pip install gdrift==X.Y.Z. Do not use
an editable checkout, because it finds the files in gdrift/data/. Look at the
datasets.json of the installed package. Then load the changed datasets with an empty
GDRIFT_DATA_DIR.
Migration to content names¶
scripts/migrate_to_content_names.py copies each name-based object to its content name on
the server. It never deletes or overwrites an object. Before it copies a file, it checks
that the ETag of the name-based object equals the etag in datasets.json.
Do the migration before you push the code change. CI starts with an empty cache, so it downloads the content-named objects.
- Run the script without options. It checks every dataset and prints the
s3cmd cpcommands. Read the list of problems. It must be empty. If a dataset has a problem, do not copy or overwrite anything for it. Find out why its object does not match the manifest first. - Run it with
--executeto make the copies. - Run it with
--verify-downloadto check the sha256 of every copy through the CDN. It must report 0 mismatches or errors. - Run it with
--update-etags. A server-side copy can change the ETag. The script writesdatasets.jsononly if every content-named object exists. - Run
pytest tests/test_server_hashes.py -m server. Commit the ETag changes indatasets.jsonon the branch of the code change.